Commit Graph

24 Commits

Author SHA1 Message Date
428fc254ee fix(plugin): lift calendarScheduler to module scope (multi-register singleton)
Trying the prior multi-agent-handle fix in dind-t2 surfaced a second bug
that PR #7 didn't reach: `harborforge_calendar_status` still returned
`Calendar scheduler not running` even though the gateway log showed the
scheduler had started 30+ seconds before the agent's call.

## Root cause

`register()` is invoked once per agent — `grep -c "HarborForge plugin
registered" /tmp/gw-stdout.log` reports 5 for a 5-agent claw. Every
invocation creates its own `let calendarScheduler` closure binding. But
`gateway_start` fires once and we only call `startCalendarScheduler()`
through that single hook, so exactly one of the five closures sees the
handle and the other four keep their bindings at `null`.

The host's tool router picks one of the five duplicate
`harborforge_calendar_status` registrations to dispatch to — most of the
time it's one of the four "null" closures, which is why every wakeup the
agent saw `Calendar scheduler not running`.

## Fix

Lift `let calendarScheduler` out of `register()` and into module scope.
All five register-call closures now reference the same binding; once the
single `gateway_start` initialises it, every tool sees it.

`startCalendarScheduler()` now early-returns when `calendarScheduler` is
already set, so duplicate `gateway_start` firings (if the host ever does
that) don't double-install intervals.

Bumps version 0.3.2 → 0.3.3.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 10:54:36 +01:00
07a07b6876 fix(plugin): real per-agent slot handle for multi-agent calendar tools
In multi-agent sync mode every harborforge_calendar_* tool was returning
`calendarScheduler.<method> is not a function`. The cause: index.ts replaced
`calendarScheduler` (typed `CalendarScheduler | null`) with a `{ stop() }`
stub right after wiring the runSync/runCheck intervals, so `isRunning()`,
`getCurrentSlot()`, `completeCurrentSlot()`, `abortCurrentSlot()`,
`pauseCurrentSlot()`, `resumeCurrentSlot()`, `getState()`,
`isRestartPending()` and `getStateFilePath()` all blew up at call time.

Replaces the stub with a `MultiAgentSchedulerHandle` that:
  - tracks the last slot dispatched per agent (recorded by `wakeAgent`)
  - exposes status/complete/abort/pause/resume taking the calling agentId
  - resolves the implicit "current slot" via woken-cursor first then a
    cache scan over not_started/deferred/ongoing slots
  - PATCHes via `bridge.updateSlotAs(agentId, …)` so audit headers reflect
    the real caller (bridge constructor agentId is 'unused' in multi-agent)
  - mirrors the legacy `isRunning/isProcessing/getState/...` surface so
    the single-agent fallback (`CalendarScheduler`) keeps working unchanged

Each calendar tool factory now takes `OpenClawPluginToolContext`, reads
`ctx.agentId`, and dispatches through the handle. Single-agent path
(when `calendarScheduler` is a real `CalendarScheduler`) is preserved
behind `instanceof` checks.

Drops the dead `trackSessionCompletion` poll loop (only definition, no
caller) which referenced the removed `completeCurrentSlot`. Bumps
plugin version 0.2.0 → 0.3.2.

🤖 Generated with [Claude Code](https://claude.com/claude-code)

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-21 10:38:57 +01:00
9ba591795b fix: wake dedupe + inline slot context + complete contracts.tools
Three issues making HF→agent wakeup unusable in practice, surfaced by
DinD sim end-to-end test (recruiter agent + slot for 招募 manager task):

1. **Plugin re-woke the same slot every 30s.** The inline runCheck only
   destructured agentId from scheduleCache.getAgentsWithDueSlots() and
   dropped the slots array, then called wakeAgent without recording the
   wake. The simplified inline scheduler also never PATCHes slot status
   server-side from not_started→ongoing, so the next 30s check sees the
   slot still due and wakes again. After 4 wakes the agent's wakeup
   session was full of WAKEUP_OK noise.

   Fix: keep slots in runCheck, add an in-memory wakedSlotKeys set
   keyed by (agentId, slotId|virtual_id|scheduled_at). Dedupe on this
   set; clear it inside the sync interval (fresh wake budget per sync).
   Server-side slot transition still TODO (requires re-introducing the
   CalendarScheduler class path or PATCH /calendar/slots/.../agent-update
   here); the dedupe at least stops the wake spam.

2. **Wakeup message had no slot context.** The wakeup body just said
   'follow hf-wakeup workflow' with no slot id/event_data/task_code.
   The agent then had to call harborforge_calendar_status to learn
   anything — which itself is broken in the simplified scheduler (it
   queries a CalendarScheduler instance that never gets created).

   Fix: pass dueSlots into wakeAgent and inline the highest-priority
   slot's {slot_id, scheduled_at, priority, slot_type, event_data} as
   a JSON block in the wakeup message. The agent reads event_data.
   task_code directly and routes via workflow_lookup without any
   round-trip. Per PLG-CAL-001 docs in hf-hangman-lab SKILL.md, this
   is the documented contract; we are bringing the message in line.

3. **contracts.tools listed 5 of the 9 registered tools.** Manifest had
   harborforge_status/telemetry/monitor_telemetry/calendar_status/
   calendar_complete. Code also registers calendar_abort, calendar_pause,
   calendar_resume, harborforge_restart_status. With the new OpenClaw
   plugin host enforcement (same gotcha that bit Meridian — see
   zhi/Meridian#2), undeclared tools are silently dropped from the
   agent's tool list, so abort/pause/resume cannot be called by the
   agent. plugin doctor was emitting:
   'plugin tool is undeclared (harbor-forge): harborforge_calendar_abort'
   for each missing tool.

   Fix: add the 4 missing tool names to contracts.tools.

Also use api.config as the primary config source in wakeAgent (current
public API), falling back to runtime.config.loadConfig() for older
hosts — same pattern as the Meridian fix.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-20 12:02:25 +01:00
operator
64a9c431bf chore: convert plugin to ESM and migrate to current openclaw plugin SDK
ESM conversion:
- plugin/package.json: add "type": "module".
- plugin/tsconfig.json: switch module/moduleResolution to "nodenext"; bump
  target to ES2022.
- All relative imports across plugin/ now carry .js extensions as required
  by Node ESM (nodenext module resolution).
- plugin/index.ts: replace `require('./calendar/schedule-cache')` with a
  proper top-level import; switch `from 'os'` to `from 'node:os'`.

Plugin SDK convention update:
- Wrap default export with definePluginEntry({ id, name, description,
  register }) per the current openclaw plugin authoring contract.
- Modernize plugin/openclaw.plugin.json: drop entry/version, add
  activation.onStartup so gateway_start fires for this plugin at boot,
  declare contracts.tools listing the five harborforge_* tools.
- Add a local plugin/openclaw-sdk.d.ts with ambient declarations for the
  focused subpaths (openclaw/plugin-sdk/plugin-entry,
  openclaw/plugin-sdk/core). We deliberately do NOT add openclaw as an
  npm devDependency: the installer's `npm install --omit=dev` step trips
  over openclaw's own (deeply nested) dependency graph when listed via
  file:.../openclaw, and the runtime contract is provided by the gateway
  loader anyway.
- The local PluginAPI interface is preserved (broader than the standard
  OpenClawPluginApi — it surfaces `version`/`runtime`/`spawn`); the
  register function is cast at the definePluginEntry boundary.

Co-Authored-By: Claude Opus 4.7 (1M context) <noreply@anthropic.com>
2026-05-08 08:28:58 +00:00
operator
9195dc6bd1 feat: schedule cache, workflow-aligned prompts, dispatchInbound wakeup
1. ScheduleCache: local cache of today's schedule, synced every 5 min
   from HF backend via new getDaySchedule() API

2. Wakeup prompts updated to reference daily-routine skill workflows
   (task-handson, plan-schedule, slot-complete)

3. Agent wakeup via dispatchInboundMessageWithDispatcher (in-process)
   - Same mechanism as Discord plugin
   - Creates unique session per slot: agent:{agentId}:hf-calendar:slot-{slotId}
   - No WebSocket, CLI, or cron dependency
   - Verified working on test environment

Co-Authored-By: Claude Opus 4.6 (1M context) <noreply@anthropic.com>
2026-04-19 12:24:21 +00:00
operator
248adfaafd fix: use runtime API for version and agent list instead of subprocess
Use api.runtime.version for openclaw version and
api.runtime.config.loadConfig() for agent list. Eliminates the
periodic openclaw agents list subprocess that caused high CPU usage.
2026-04-16 15:53:20 +00:00
operator
2088cd12b4 fix: use OPENCLAW_SERVICE_VERSION for real version and increase agent list timeout
api.version returns plugin API version (0.2.0), not the openclaw release
version. Use OPENCLAW_SERVICE_VERSION env var set by the gateway instead.
Also increase listOpenClawAgents timeout from 15s to 30s since plugin
loading takes ~16s on T2.
2026-04-16 15:12:35 +00:00
bcd47d8b39 feat: populate monitor agents from openclaw list 2026-04-04 08:55:00 +00:00
3f8859424c refactor: remove monitor legacy compatibility 2026-04-04 08:05:50 +00:00
038862ef8c refactor: manage monitor via gateway hooks 2026-04-04 00:44:33 +00:00
zhi
3b0ea0ad12 PLG-CAL-004: Implement ScheduledGatewayRestart handling in plugin
- Add state persistence (persistState/restoreState) for recovery after restart
- Add handleScheduledGatewayRestart method that:
  - Persists current scheduler state to disk
  - Sends final heartbeat to backend before shutdown
  - Stops the calendar scheduler (pauses scheduled tasks)
- Add isRestartPending flag to prevent new slot processing during restart
- Add isScheduledGatewayRestart helper to detect restart events
- Update scheduler to detect and handle ScheduledGatewayRestart events
- Add new tools: harborforge_restart_status, harborforge_calendar_pause/resume
- Export isRestartPending and getStateFilePath methods
- Bump plugin version to 0.3.1
2026-04-01 09:41:02 +00:00
zhi
97021f97c0 PLG-CAL-002: Implement calendar scheduler for agent slot wakeup
- Add CalendarScheduler class to manage periodic heartbeat and slot execution
- Implement agent wakeup logic when Idle and slots are pending
- Handle slot status transitions (attended, ongoing, deferred)
- Support both real and virtual slot materialization
- Add task context building for different event types (job, system, entertainment)
- Integrate scheduler into main plugin index.ts
- Add new plugin tools: harborforge_calendar_status, complete, abort
2026-04-01 08:45:05 +00:00
zhi
e7ba982128 feat: push OpenClaw metadata to Monitor bridge periodically
- MonitorBridgeClient gains pushOpenClawMeta() method for POST /openclaw
- OpenClawMeta interface defines version/plugin_version/agents payload
- Plugin pushes metadata on gateway_start (delayed 2s) and periodically
- Interval aligns with reportIntervalSec (default 30s)
- Pushes are non-fatal — plugin continues if Monitor is unreachable
- Interval cleanup on gateway_stop
- Updated monitor-server-connector-plan.md with new architecture
2026-03-22 01:37:21 +00:00
zhi
27b8b74d39 Align plugin monitor_port config 2026-03-21 19:22:57 +00:00
zhi
78a61e0fb2 Integrate plugin with local monitor bridge 2026-03-21 16:07:01 +00:00
zhi
9f649e2b39 feat: rename plugin to harbor-forge, remove sidecar, add --install-cli
Major changes:
- Renamed plugin id from harborforge-monitor to harbor-forge (TODO 4.1)
- Removed sidecar server/ directory and spawn logic (TODO 4.2)
- Added monitorPort to plugin config schema (TODO 4.3)
- Added --install-cli flag to installer for building hf CLI (TODO 4.4)
- skills/hf/ only deployed when --install-cli is present (TODO 4.5)
- Plugin now serves telemetry data directly via tools
- Installer handles migration from old plugin name
- Bumped version to 0.2.0
2026-03-21 15:24:50 +00:00
zhi
040cde8cad feat(telemetry): report openclaw and plugin versions separately
- Report remote OpenClaw CLI version as openclaw_version
- Report harborforge-monitor plugin version as plugin_version
- Pass plugin version from plugin runtime to sidecar
- Read live config via api.pluginConfig/api.config helper
2026-03-20 07:23:18 +00:00
zhi
006784db63 refactor(plugin): read config via api.pluginConfig and api.config
- Mirror dirigent plugin registration pattern
- Read base config from api.pluginConfig
- Read live config from api.config.plugins.entries.harborforge-monitor.config
- Support gateway_start/gateway_stop lifecycle only
- Compile nested plugin/core files
2026-03-20 07:13:12 +00:00
zhi
de4ef87491 refactor(plugin): remove fallback sidecar autostart 2026-03-20 06:42:45 +00:00
zhi
55b17e35ea fix(plugin): use OpenClaw gateway_start/gateway_stop hooks 2026-03-20 06:36:20 +00:00
zhi
8ebc76931f fix(plugin): normalize OpenClaw plugin config shapes
- Accept flat config, nested entry.config, or missing config
- Treat plugin as enabled unless explicitly disabled
- Log resolved runtime config for gateway diagnostics
2026-03-20 06:27:46 +00:00
zhi
eb43434e48 fix(plugin): correct telemetry server path for installed plugin
- Resolve telemetry.mjs relative to installed plugin root
- Update installer messaging from challengeUuid to apiKey
- Document correct OpenClaw plugin entry config structure
2026-03-20 06:24:40 +00:00
zhi
0dc824549a feat: fix API Key authentication and payload alignment
- Update openclaw.plugin.json: replace challengeUuid with apiKey (optional)
- Fix tsconfig: use CommonJS module to avoid import.meta.url issues
- Fix plugin/index.ts: remove ESM-specific code, use __dirname
- Fix telemetry.mjs:
  - Add loadavg to os imports, remove require() call
  - Replace challengeUuid with apiKey in config
  - Update endpoint to heartbeat-v2
  - Add X-API-Key header when apiKey is configured
  - Fix payload field names: agents, load_avg (array), uptime_seconds
  - Change missing apiKey from error to warning
2026-03-19 18:20:29 +00:00
zhi
0debe835b4 feat: reorganize to standard OpenClaw plugin structure
New structure:
├── package.json                 # Root package
├── README.md                    # Documentation
├── plugin/                      # OpenClaw plugin
│   ├── openclaw.plugin.json     # Plugin manifest
│   ├── index.ts                 # Plugin entry (TypeScript)
│   ├── package.json
│   └── tsconfig.json
├── server/                      # Telemetry sidecar
│   └── telemetry.mjs
├── skills/                      # OpenClaw skills
└── scripts/
    └── install.mjs              # Installation script

Matches PaddedCell project structure.
Provides install.mjs with build/install/configure/uninstall commands.
2026-03-19 13:51:19 +00:00