@borgee/agents-host 0.2.29 → 0.2.32

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (38) hide show
  1. package/README.md +82 -27
  2. package/dist/agents-host.d.ts +1 -1
  3. package/dist/agents-host.js +45 -18
  4. package/dist/cli-args.d.ts +3 -1
  5. package/dist/cli-args.js +18 -2
  6. package/dist/cli.d.ts +4 -0
  7. package/dist/cli.js +12 -1
  8. package/dist/compatibility-gates.js +4 -1
  9. package/dist/config.d.ts +8 -0
  10. package/dist/config.js +51 -13
  11. package/dist/context/prompt.js +1 -1
  12. package/dist/gateway/localhost-gateway.js +34 -2
  13. package/dist/index.js +4 -1
  14. package/dist/local-config.js +20 -1
  15. package/dist/managed-daemon.js +20 -6
  16. package/dist/policy/authorization-audit.d.ts +1 -0
  17. package/dist/policy/gateway-authorization.d.ts +1 -1
  18. package/dist/policy/gateway-authorization.js +27 -4
  19. package/dist/providers/claude/cli-client.d.ts +55 -16
  20. package/dist/providers/claude/cli-client.js +811 -345
  21. package/dist/providers/create-provider.js +8 -13
  22. package/dist/state-paths.d.ts +5 -0
  23. package/dist/state-paths.js +12 -0
  24. package/dist/types.d.ts +1 -0
  25. package/dist/update/package-installation.d.ts +52 -0
  26. package/dist/update/package-installation.js +90 -0
  27. package/dist/update/package-manager.d.ts +33 -0
  28. package/dist/update/package-manager.js +137 -0
  29. package/dist/update/semantic-version.d.ts +7 -0
  30. package/dist/update/semantic-version.js +76 -0
  31. package/dist/update/update-command.d.ts +9 -0
  32. package/dist/update/update-command.js +55 -0
  33. package/dist/update/update-notice.d.ts +39 -0
  34. package/dist/update/update-notice.js +161 -0
  35. package/package.json +5 -2
  36. package/skills/borgee-agent/SKILL.md +5 -3
  37. package/skills/borgee-agent/borgee-agent.mjs +56 -22
  38. package/skills/borgee-agent/borgee-agent.py +56 -27
package/README.md CHANGED
@@ -63,6 +63,7 @@ agents-host describe --config <path-to-host-config>
63
63
  agents-host print-layout --root <dir>
64
64
  agents-host generate-config --root <dir> --stdin
65
65
  agents-host generate-config --root <dir> --spec-json <json>
66
+ agents-host update
66
67
  ```
67
68
 
68
69
  ## Standalone env mode
@@ -84,7 +85,7 @@ Codex now ships on the same default hosted-provider surface as Claude and Copilo
84
85
 
85
86
  The current shipped internal compatibility surface resolves gates in this order:
86
87
 
87
- 1. start from the shipped defaults: `claude-provider-v2`, `copilot-provider-v2`, `codex-provider`, `managed-runtime-convergence`, and `policy-audit-enforcement`
88
+ 1. start from the shipped defaults: `copilot-provider-v2`, `codex-provider`, `managed-runtime-convergence`, and `policy-audit-enforcement`
88
89
  2. add any explicit entries from `AGENTS_HOST_INTERNAL_COMPATIBILITY_GATES`
89
90
  3. subtract any explicit entries from `AGENTS_HOST_INTERNAL_DISABLED_COMPATIBILITY_GATES`
90
91
 
@@ -98,7 +99,7 @@ Legacy managed roots created before `managed-runtime-settings.json` existed need
98
99
  Rollback and hardening controls stay explicit:
99
100
 
100
101
  - `AGENTS_HOST_INTERNAL_DISABLED_COMPATIBILITY_GATES=<comma-list>` disables shipped gates for rollback
101
- - `AGENTS_HOST_INTERNAL_PROVIDER_IMPLEMENTATIONS=claude:v1,copilot:v1` forces Claude and/or Copilot back to the v1 adapters while their v2 gates stay enabled
102
+ - `AGENTS_HOST_INTERNAL_PROVIDER_IMPLEMENTATIONS=copilot:v1` forces Copilot back to the v1 adapter while its v2 gate stays enabled; stale `claude:v1|v2` entries are tolerated as no-ops for compatibility
102
103
  - `AGENTS_HOST_INTERNAL_POLICY_MODE=enforce` hardens the shipped `policy-audit-enforcement` gate beyond its default `audit-only` mode
103
104
 
104
105
  Or with the CLI:
@@ -232,9 +233,10 @@ Notes:
232
233
  | `BORGEE_BASE_URL` | positional `<serverUrl>` | yes | — | Borgee server base URL |
233
234
  | `BORGEE_AGENT_API_KEY` | positional `<apiKey>` | yes | — | Agent API key from the web UI |
234
235
  | `AGENTS_HOST_DEBUG` | `--debug` | no | off | Extra host/provider lifecycle logs. Set `AGENTS_HOST_DEBUG=1` to enable without the CLI flag. |
236
+ | `AGENTS_HOST_DISABLE_UPDATE_CHECK` | — | no | off | Set to `1` to skip the advisory startup update check. |
235
237
  | `BORGEE_AGENT_NAME` | `--name` | no | `Assistant` | Display name used in prompts |
236
238
  | `RUNTIME_PROVIDER` | `--provider` | no | `claude` | `claude`, `copilot`, or `codex` |
237
- | `CLAUDE_COMMAND` / `CLAUDE_ARGS` | `--claude-command` / `--claude-args` | no | `claude` / `--print --permission-mode bypassPermissions` | Local Claude CLI command + args |
239
+ | `CLAUDE_COMMAND` / `CLAUDE_ARGS` | `--claude-command` / `--claude-args` | no | `claude-agent-acp` / empty | Local Claude ACP adapter command + args. The shipped bundled `claude-agent-acp` path requires empty `CLAUDE_ARGS`; non-empty args are only valid when `CLAUDE_COMMAND` points at a custom ACP adapter command. Legacy `claude --print --permission-mode bypassPermissions` is tolerated as a compatibility alias. |
238
240
  | `CODEX_COMMAND` / `CODEX_ARGS` | `--codex-command` / `--codex-args` | no | `codex-acp` / empty | Local Codex ACP adapter command + args. The default launch resolves the bundled `@agentclientprotocol/codex-acp` entrypoint. |
239
241
  | `COPILOT_COMMAND` / `COPILOT_ARGS` | `--copilot-command` / `--copilot-args` | no | `copilot` / parsed but ignored by ACP runtime | Local Copilot CLI command. The persistent Copilot ACP prototype always launches `copilot --acp`. |
240
242
  | `COPILOT_SESSION_TTL_MINUTES` | `--copilot-session-ttl-minutes` | no | `2880` | Idle TTL for per-channel Copilot ACP sessions |
@@ -317,8 +319,8 @@ The spec shape is:
317
319
  "host": {
318
320
  "borgeeBaseUrl": "https://borgee.example.com",
319
321
  "defaults": {
320
- "claudeCommand": "claude",
321
- "claudeArgs": ["--print", "--permission-mode", "bypassPermissions"],
322
+ "claudeCommand": "claude-agent-acp",
323
+ "claudeArgs": [],
322
324
  "codexCommand": "codex-acp",
323
325
  "codexArgs": [],
324
326
  "copilotCommand": "copilot",
@@ -384,11 +386,8 @@ paths are also allowed.
384
386
  borgeeBaseUrl: https://borgee.example.com
385
387
  agentsDir: ./agents
386
388
  defaults:
387
- claudeCommand: claude
388
- claudeArgs:
389
- - --print
390
- - --permission-mode
391
- - bypassPermissions
389
+ claudeCommand: claude-agent-acp
390
+ claudeArgs: []
392
391
  codexCommand: codex-acp
393
392
  codexArgs: []
394
393
  copilotCommand: copilot
@@ -424,12 +423,6 @@ name: Support Bot
424
423
  apiKey: bgr_support_xxxxxxxx
425
424
  provider: claude
426
425
  enabled: true
427
- claudeArgs:
428
- - --print
429
- - --permission-mode
430
- - bypassPermissions
431
- - --model
432
- - sonnet
433
426
  ```
434
427
 
435
428
  Agent config fields:
@@ -439,6 +432,7 @@ Agent config fields:
439
432
  - `apiKey` (**required**)
440
433
  - `provider` (**required**): `claude`, `copilot`, or `codex` (roll back Codex only with `AGENTS_HOST_INTERNAL_DISABLED_COMPATIBILITY_GATES=codex-provider`)
441
434
  - `enabled` (optional, default `true`)
435
+ - `claudeCommand` / `claudeArgs` (optional): leave unset to use the shipped bundled `claude-agent-acp` path. On that bundled path `claudeArgs` must stay empty. Non-empty `claudeArgs` are only supported when `claudeCommand` points at a custom ACP adapter command.
442
436
  - optional overrides for `claudeCommand`, `claudeArgs`, `codexCommand`,
443
437
  `codexArgs`, `copilotCommand`, `copilotArgs`, and
444
438
  `copilotSessionTtlMinutes`
@@ -478,10 +472,16 @@ successfully applied snapshot running.
478
472
  Each Borgee channel is mapped 1:1 to a provider-native session while it stays
479
473
  active:
480
474
 
481
- - **Claude**: first turn for a channel uses `--session-id <uuid>`; every turn
482
- after uses `-r/--resume <uuid>`. The host persists the channel→session map in
483
- its state root, serializes cross-channel map rewrites, and retries once with a
484
- fresh session immediately if Claude reports a stale `--resume` target.
475
+ - **Claude**: one persistent `@agentclientprotocol/claude-agent-acp` subprocess
476
+ is shared by a single `AgentsHost`, with one ACP session per Borgee channel.
477
+ Same-channel turns are serialized; different channels keep isolated ACP
478
+ sessions. Ordinary threads keep the shared runtime workspace cwd, while
479
+ eligible `task_assignment` threads switch the real ACP session cwd to that
480
+ same hidden local task-scoped workspace. The host persists the
481
+ channel→ACP-session map in its state root, restores same-host continuity with
482
+ ACP `session/resume` when available, retries stale restores with a fresh
483
+ session immediately, and injects the per-channel local context paths through
484
+ Claude ACP `_meta.systemPrompt.append`.
485
485
  - **Codex**: one persistent `@agentclientprotocol/codex-acp` subprocess is
486
486
  shared by a single `AgentsHost`, with one ACP session per Borgee channel. When
487
487
  the current turn has a materialized channel context payload, Codex refreshes a
@@ -504,17 +504,72 @@ active:
504
504
  state root and restores same-host continuity with ACP `session/resume` when
505
505
  available, otherwise `session/load` plus local replay cleanup on runtimes
506
506
  that advertise only load support.
507
- - **Claude**: Claude still keeps one provider-native session mapping per Borgee
508
- channel, but unlike the ACP-backed adapters it spawns a fresh CLI process for
509
- each turn. Ordinary threads inherit the host runtime cwd; eligible
510
- `task_assignment` threads run the CLI process with the hidden local
511
- task-scoped workspace as the process cwd, again without implying that the
512
- target repository is already checked out there.
513
-
514
507
  There is no separate transcript/history store on our side. Claude, Codex, and
515
508
  Copilot only persist the native session ids they should try to resume later;
516
509
  cross-host continuity still does not exist in this runtime.
517
510
 
511
+ ## Staying up to date
512
+
513
+ `agents-host update` reinstalls the published package:
514
+
515
+ ```bash
516
+ agents-host update
517
+ ```
518
+
519
+ It takes no options. The latest published release is resolved with `npm view`,
520
+ and the package is reinstalled with the manager that owns the current global
521
+ install (`npm install -g`, `pnpm add -g`, `yarn global add`, or `bun add -g`).
522
+ When the installed version is already at or ahead of the latest release it says
523
+ so and does nothing.
524
+
525
+ The command only acts on a **global** install. It refuses a source checkout
526
+ (update that with git) and a project-local dependency (update it through the
527
+ consuming project's manifest); rewriting either behind their owner's back is not
528
+ this command's call. Which of the three it is comes from asking each installed
529
+ manager where it puts global installs — `npm root -g`, `pnpm root -g`,
530
+ `yarn global dir`, `bun pm bin -g` — and seeing which answer contains this
531
+ package, so relocated roots (`YARN_GLOBAL_FOLDER`, `BUN_INSTALL`, Windows
532
+ `%LOCALAPPDATA%\Yarn\Data`) and pnpm's virtual store all classify correctly.
533
+
534
+ `npm` has to be on `PATH` for the version lookup even when another manager owns
535
+ the install; it ships with Node, and all four managers read the same registry.
536
+ Going through npm rather than querying the registry directly is what makes
537
+ `.npmrc` discovery, scoped auth tokens, proxies, custom CAs, and retries work,
538
+ so private and mirrored registries need no extra configuration here.
539
+
540
+ ### Startup update check
541
+
542
+ Every user-facing startup path — the env-var entrypoint, `start`, `start --config`,
543
+ and both `start-managed` forms — checks for a newer published release first and
544
+ prints an advisory notice on stderr:
545
+
546
+ ```text
547
+ [agents-host] update available: 0.2.31 -> 0.3.0
548
+ [agents-host] run `agents-host update` to install it
549
+ ```
550
+
551
+ The check cannot hold startup back:
552
+
553
+ - source checkouts are skipped from the package path alone, so `pnpm dev` never
554
+ nags and never spawns a package manager
555
+ - the answer is cached for six hours in `~/.borgee/agents-host/update-check.json`
556
+ (mode `0600`), so repeated `start-managed` upserts do not re-query the registry
557
+ - a failed lookup is cached the same way, so an unreachable registry costs the
558
+ deadline once per six hours rather than on every start
559
+ - the lookup owns a five-second deadline and **kills** the `npm` child when it
560
+ passes, which bounds the wait even when the hang is inside DNS resolution
561
+ - which manager owns the install is only asked once there is a notice to word,
562
+ so a start with nothing to report never pays for it
563
+ - every failure — offline machine, unreachable registry, unreadable cache — is
564
+ silent; `AGENTS_HOST_DEBUG=1` prints the reason
565
+ - `AGENTS_HOST_DISABLE_UPDATE_CHECK=1` turns the check off
566
+ - machine-oriented commands (`describe-managed`, `apply-managed`, `describe`,
567
+ `print-layout`, `generate-config`, `log`) never run it
568
+
569
+ A cached start still runs one local `npm config get registry`, measured at about
570
+ 100ms, because the cached answer is only valid for the registry it came from and
571
+ npm is the only thing that knows which registry `.npmrc` resolves to.
572
+
518
573
  ## Testing
519
574
 
520
575
  ```bash
@@ -128,7 +128,7 @@ export declare class AgentsHost {
128
128
  private resolveVisibleTurnBody;
129
129
  private shouldRelayProtocolReply;
130
130
  private normalizeMessage;
131
- private markAssignedTaskInProgress;
131
+ private resolveTaskAssignmentDelivery;
132
132
  private ensureSelfAgentId;
133
133
  private classifyAuthor;
134
134
  private refreshParticipantDirectory;
@@ -527,6 +527,11 @@ export class AgentsHost {
527
527
  if (!normalized) {
528
528
  return;
529
529
  }
530
+ const effective = await this.resolveTaskAssignmentDelivery(msg, normalized);
531
+ if (!effective) {
532
+ return;
533
+ }
534
+ msg = effective;
530
535
  let taskThreadContext = { state: 'inactive' };
531
536
  let attentionSnapshot;
532
537
  if (this.attentionFollowSemanticsEnabled
@@ -542,9 +547,6 @@ export class AgentsHost {
542
547
  }
543
548
  }
544
549
  }
545
- if (msg.message_type === 'task_assignment') {
546
- await this.markAssignedTaskInProgress(msg.channel_id, normalized.content);
547
- }
548
550
  await this.runUngatedTurn(msg, normalized.authorId, normalized.content, taskThreadContext, attentionSnapshot);
549
551
  }
550
552
  async handleCollaborationMessage(msg) {
@@ -552,9 +554,11 @@ export class AgentsHost {
552
554
  if (!normalized) {
553
555
  return;
554
556
  }
555
- if (msg.message_type === 'task_assignment') {
556
- await this.markAssignedTaskInProgress(msg.channel_id, normalized.content);
557
+ const effective = await this.resolveTaskAssignmentDelivery(msg, normalized);
558
+ if (!effective) {
559
+ return;
557
560
  }
561
+ msg = effective;
558
562
  const channelState = this.ensureCollaborationChannelState(msg.channel_id);
559
563
  await this.ensureProtocolStateLoaded(msg.channel_id, channelState);
560
564
  await this.ensureAttentionSnapshotLoaded(msg.channel_id, channelState);
@@ -2640,28 +2644,51 @@ export class AgentsHost {
2640
2644
  content,
2641
2645
  };
2642
2646
  }
2643
- async markAssignedTaskInProgress(threadId, content) {
2647
+ // Only a task assigned to this agent drives a task-assignment turn: it keeps the message a
2648
+ // task_assignment (and best-effort flips an open task to in_progress). An unassigned or
2649
+ // other-assigned task_assignment degrades to an ordinary message, and this agent's own echo of
2650
+ // it drops, so the creator never auto-starts work it was not assigned.
2651
+ async resolveTaskAssignmentDelivery(msg, normalized) {
2652
+ if (msg.message_type !== 'task_assignment') {
2653
+ return msg;
2654
+ }
2655
+ const selfAgentId = await this.ensureSelfAgentId();
2656
+ let task;
2644
2657
  try {
2645
- const selfAgentId = await this.ensureSelfAgentId();
2646
- const task = await waitForTaskForThread(this.borgee, threadId, {
2647
- preferredTaskId: extractTaskIdFromTaskAssignmentContent(content),
2658
+ task = await waitForTaskForThread(this.borgee, msg.channel_id, {
2659
+ preferredTaskId: extractTaskIdFromTaskAssignmentContent(normalized.content),
2648
2660
  attempts: 10,
2649
2661
  delayMs: 250,
2650
2662
  });
2651
- if (!task || task.status !== 'open' || task.assigneeId !== selfAgentId) {
2652
- return;
2653
- }
2654
- await this.borgee.updateTask({
2655
- taskId: task.id,
2656
- status: 'in_progress',
2657
- });
2658
2663
  }
2659
2664
  catch (error) {
2660
- this.logger.debugError('best-effort task auto-start failed', {
2661
- channelId: threadId,
2665
+ this.logger.debugError('task-assignment resolution failed', {
2666
+ channelId: msg.channel_id,
2662
2667
  error,
2663
2668
  });
2669
+ task = null;
2670
+ }
2671
+ if (task && task.assigneeId === selfAgentId) {
2672
+ if (task.status === 'open') {
2673
+ try {
2674
+ await this.borgee.updateTask({
2675
+ taskId: task.id,
2676
+ status: 'in_progress',
2677
+ });
2678
+ }
2679
+ catch (error) {
2680
+ this.logger.debugError('best-effort task auto-start failed', {
2681
+ channelId: msg.channel_id,
2682
+ error,
2683
+ });
2684
+ }
2685
+ }
2686
+ return msg;
2687
+ }
2688
+ if (normalized.authorId === selfAgentId) {
2689
+ return null;
2664
2690
  }
2691
+ return { ...msg, message_type: 'default' };
2665
2692
  }
2666
2693
  async ensureSelfAgentId() {
2667
2694
  if (this.selfAgentId) {
@@ -83,4 +83,6 @@ export declare function parseLogArgs(argv: string[]): ParsedLogArgs;
83
83
  export declare function parseDescribeManagedArgs(argv: string[]): ParsedDescribeManagedArgs;
84
84
  export declare function parseCleanupManagedArgs(argv: string[]): ParsedCleanupManagedArgs;
85
85
  export declare function parseApplyManagedArgs(argv: string[]): ParsedApplyManagedArgs;
86
- export declare const USAGE = "Usage:\n agents-host start <serverUrl> <apiKey> [options]\n agents-host start-managed <serverUrl>\n agents-host start-managed <serverUrl> <apiKey> [agent-options]\n agents-host describe-managed <serverUrl>\n agents-host cleanup-managed <serverUrl> [--purge]\n agents-host apply-managed <serverUrl> --stdin\n agents-host apply-managed <serverUrl> --spec-json <json>\n agents-host log <serverUrl> [--lines <n>] [--follow]\n agents-host log <serverUrl> --path\n agents-host start --config <path-to-host-config> [--debug]\n agents-host validate --config <path-to-host-config>\n agents-host describe --config <path-to-host-config>\n agents-host print-layout --root <dir>\n agents-host generate-config --root <dir> --stdin\n agents-host generate-config --root <dir> --spec-json <json>\n\nForeground start options:\n --debug Enable host/provider debug logs (or set AGENTS_HOST_DEBUG=1)\n\nSingle-agent agent options:\n --name <name> Display name (default: Assistant)\n --provider <claude|codex|copilot>\n Runtime provider (default: claude)\n --claude-command <cmd> Local Claude CLI command (default: claude)\n --claude-args <args> Local Claude CLI args (default: --print --permission-mode bypassPermissions)\n --codex-command <cmd> Local Codex ACP adapter command (default: codex-acp)\n --codex-args <args> Local Codex ACP adapter args\n --copilot-command <cmd> Local Copilot CLI command (default: copilot)\n --copilot-args <args> Ignored by the Copilot ACP prototype\n --copilot-session-ttl-minutes <minutes>\n Idle session TTL for Copilot ACP sessions (default: 2880)\n\nCommand summary:\n start <serverUrl> <apiKey> Start one foreground hosted agent (legacy-compatible behavior)\n start --config <path> Start agents + supervisor + watchers from a host config file\n start-managed <serverUrl> Restart or resume an existing per-serverUrl managed daemon\n start-managed <serverUrl> <apiKey>\n Upsert one agent into the per-serverUrl local daemon and exit after reconcile\n describe-managed <serverUrl> Print managed-runtime spec JSON for machine callers\n cleanup-managed <serverUrl> Stop one managed-runtime daemon locally; --purge also removes its runtime root\n apply-managed <serverUrl> Apply one managed-runtime full-set spec for machine callers\n log <serverUrl> Print the managed daemon log tail for one server runtime\n validate --config <path> Validate local-config files without starting agents or watchers\n describe --config <path> Print the current managed full-set spec as JSON\n print-layout --root <dir> Print the canonical default local-config layout as JSON\n generate-config --root <dir> --stdin Materialize canonical local-config files from stdin\n generate-config --root <dir> --spec-json <json>\n Compatibility input; JSON is exposed in process arguments\n\nExamples:\n agents-host start https://borgee.example.com bgr_xxxxxxxx --provider copilot --debug\n agents-host start-managed https://borgee.example.com\n agents-host start-managed https://borgee.example.com bgr_xxxxxxxx --provider copilot\n agents-host describe-managed https://borgee.example.com\n agents-host cleanup-managed https://borgee.example.com --purge\n printf '%s' '{\"host\":{\"borgeeBaseUrl\":\"https://borgee.example.com\"},\"agents\":[{\"key\":\"cp1\",\"name\":\"Copilot\",\"apiKey\":\"bgr_xxx\",\"provider\":\"copilot\"}]}' | agents-host apply-managed https://borgee.example.com --stdin\n agents-host log https://borgee.example.com --lines 200 --follow\n agents-host log https://borgee.example.com --path\n agents-host start --config ./agents-host.yaml --debug\n agents-host validate --config ./agents-host.yaml\n agents-host describe --config ./agents-host.yaml\n agents-host print-layout --root ./runtime-root\n printf '%s' '{\"host\":{\"borgeeBaseUrl\":\"https://borgee.example.com\"},\"agents\":[{\"key\":\"cp1\",\"name\":\"Copilot\",\"apiKey\":\"bgr_xxx\",\"provider\":\"copilot\"}]}' | agents-host generate-config --root ./runtime-root --stdin\n";
86
+ /** `update` always installs the latest published release; it takes no options. */
87
+ export declare function assertNoUpdateArgs(argv: string[]): void;
88
+ export declare const USAGE = "Usage:\n agents-host start <serverUrl> <apiKey> [options]\n agents-host start-managed <serverUrl>\n agents-host start-managed <serverUrl> <apiKey> [agent-options]\n agents-host describe-managed <serverUrl>\n agents-host cleanup-managed <serverUrl> [--purge]\n agents-host apply-managed <serverUrl> --stdin\n agents-host apply-managed <serverUrl> --spec-json <json>\n agents-host log <serverUrl> [--lines <n>] [--follow]\n agents-host log <serverUrl> --path\n agents-host start --config <path-to-host-config> [--debug]\n agents-host validate --config <path-to-host-config>\n agents-host describe --config <path-to-host-config>\n agents-host print-layout --root <dir>\n agents-host generate-config --root <dir> --stdin\n agents-host generate-config --root <dir> --spec-json <json>\n agents-host update\n\nForeground start options:\n --debug Enable host/provider debug logs (or set AGENTS_HOST_DEBUG=1)\n\nSingle-agent agent options:\n --name <name> Display name (default: Assistant)\n --provider <claude|codex|copilot>\n Runtime provider (default: claude)\n --claude-command <cmd> Local Claude ACP adapter command (default: claude-agent-acp)\n --claude-args <args> Local Claude ACP adapter args (empty on the shipped bundled path)\n --codex-command <cmd> Local Codex ACP adapter command (default: codex-acp)\n --codex-args <args> Local Codex ACP adapter args\n --copilot-command <cmd> Local Copilot CLI command (default: copilot)\n --copilot-args <args> Ignored by the Copilot ACP prototype\n --copilot-session-ttl-minutes <minutes>\n Idle session TTL for Copilot ACP sessions (default: 2880)\n\nCommand summary:\n start <serverUrl> <apiKey> Start one foreground hosted agent (legacy-compatible behavior)\n start --config <path> Start agents + supervisor + watchers from a host config file\n start-managed <serverUrl> Restart or resume an existing per-serverUrl managed daemon\n start-managed <serverUrl> <apiKey>\n Upsert one agent into the per-serverUrl local daemon and exit after reconcile\n describe-managed <serverUrl> Print managed-runtime spec JSON for machine callers\n cleanup-managed <serverUrl> Stop one managed-runtime daemon locally; --purge also removes its runtime root\n apply-managed <serverUrl> Apply one managed-runtime full-set spec for machine callers\n log <serverUrl> Print the managed daemon log tail for one server runtime\n validate --config <path> Validate local-config files without starting agents or watchers\n describe --config <path> Print the current managed full-set spec as JSON\n print-layout --root <dir> Print the canonical default local-config layout as JSON\n generate-config --root <dir> --stdin Materialize canonical local-config files from stdin\n generate-config --root <dir> --spec-json <json>\n Compatibility input; JSON is exposed in process arguments\n update Update the globally installed @borgee/agents-host to the latest release\n\nStartup update check:\n Startup commands print an advisory notice on stderr when a newer release is published.\n Set AGENTS_HOST_DISABLE_UPDATE_CHECK=1 to turn that check off.\n\nExamples:\n agents-host start https://borgee.example.com bgr_xxxxxxxx --provider copilot --debug\n agents-host start-managed https://borgee.example.com\n agents-host start-managed https://borgee.example.com bgr_xxxxxxxx --provider copilot\n agents-host describe-managed https://borgee.example.com\n agents-host cleanup-managed https://borgee.example.com --purge\n printf '%s' '{\"host\":{\"borgeeBaseUrl\":\"https://borgee.example.com\"},\"agents\":[{\"key\":\"cp1\",\"name\":\"Copilot\",\"apiKey\":\"bgr_xxx\",\"provider\":\"copilot\"}]}' | agents-host apply-managed https://borgee.example.com --stdin\n agents-host log https://borgee.example.com --lines 200 --follow\n agents-host log https://borgee.example.com --path\n agents-host start --config ./agents-host.yaml --debug\n agents-host validate --config ./agents-host.yaml\n agents-host describe --config ./agents-host.yaml\n agents-host print-layout --root ./runtime-root\n printf '%s' '{\"host\":{\"borgeeBaseUrl\":\"https://borgee.example.com\"},\"agents\":[{\"key\":\"cp1\",\"name\":\"Copilot\",\"apiKey\":\"bgr_xxx\",\"provider\":\"copilot\"}]}' | agents-host generate-config --root ./runtime-root --stdin\n agents-host update\n";
package/dist/cli-args.js CHANGED
@@ -470,6 +470,15 @@ export function parseApplyManagedArgs(argv) {
470
470
  }
471
471
  return { serverUrl, input: 'argv', specJson };
472
472
  }
473
+ /** `update` always installs the latest published release; it takes no options. */
474
+ export function assertNoUpdateArgs(argv) {
475
+ const [unexpected] = argv;
476
+ if (unexpected !== undefined) {
477
+ throw new CliUsageError(unexpected.startsWith('--')
478
+ ? `Unknown option: ${unexpected}`
479
+ : `Unexpected argument: ${unexpected}`);
480
+ }
481
+ }
473
482
  export const USAGE = `Usage:
474
483
  agents-host start <serverUrl> <apiKey> [options]
475
484
  agents-host start-managed <serverUrl>
@@ -486,6 +495,7 @@ export const USAGE = `Usage:
486
495
  agents-host print-layout --root <dir>
487
496
  agents-host generate-config --root <dir> --stdin
488
497
  agents-host generate-config --root <dir> --spec-json <json>
498
+ agents-host update
489
499
 
490
500
  Foreground start options:
491
501
  --debug Enable host/provider debug logs (or set AGENTS_HOST_DEBUG=1)
@@ -494,8 +504,8 @@ Single-agent agent options:
494
504
  --name <name> Display name (default: Assistant)
495
505
  --provider <claude|codex|copilot>
496
506
  Runtime provider (default: claude)
497
- --claude-command <cmd> Local Claude CLI command (default: claude)
498
- --claude-args <args> Local Claude CLI args (default: --print --permission-mode bypassPermissions)
507
+ --claude-command <cmd> Local Claude ACP adapter command (default: claude-agent-acp)
508
+ --claude-args <args> Local Claude ACP adapter args (empty on the shipped bundled path)
499
509
  --codex-command <cmd> Local Codex ACP adapter command (default: codex-acp)
500
510
  --codex-args <args> Local Codex ACP adapter args
501
511
  --copilot-command <cmd> Local Copilot CLI command (default: copilot)
@@ -519,6 +529,11 @@ Command summary:
519
529
  generate-config --root <dir> --stdin Materialize canonical local-config files from stdin
520
530
  generate-config --root <dir> --spec-json <json>
521
531
  Compatibility input; JSON is exposed in process arguments
532
+ update Update the globally installed @borgee/agents-host to the latest release
533
+
534
+ Startup update check:
535
+ Startup commands print an advisory notice on stderr when a newer release is published.
536
+ Set AGENTS_HOST_DISABLE_UPDATE_CHECK=1 to turn that check off.
522
537
 
523
538
  Examples:
524
539
  agents-host start https://borgee.example.com bgr_xxxxxxxx --provider copilot --debug
@@ -534,4 +549,5 @@ Examples:
534
549
  agents-host describe --config ./agents-host.yaml
535
550
  agents-host print-layout --root ./runtime-root
536
551
  printf '%s' '{"host":{"borgeeBaseUrl":"https://borgee.example.com"},"agents":[{"key":"cp1","name":"Copilot","apiKey":"bgr_xxx","provider":"copilot"}]}' | agents-host generate-config --root ./runtime-root --stdin
552
+ agents-host update
537
553
  `;
package/dist/cli.d.ts CHANGED
@@ -2,6 +2,8 @@
2
2
  import { applyManagedSpec, bootstrapManagedDaemonStart, cleanupManagedRuntime, describeManagedSpec } from './managed-daemon.js';
3
3
  import { runManagedDaemonLogCommand } from './managed-daemon-log.js';
4
4
  import { describeLocalConfig, generateLocalConfig, printLocalConfigLayout, runMain, validateLocalConfig } from './run.js';
5
+ import { runUpdateCommand } from './update/update-command.js';
6
+ import { emitUpdateNotice } from './update/update-notice.js';
5
7
  export interface CliDeps {
6
8
  env?: NodeJS.ProcessEnv;
7
9
  logger?: Pick<Console, 'error'>;
@@ -17,6 +19,8 @@ export interface CliDeps {
17
19
  describeManagedSpec?: typeof describeManagedSpec;
18
20
  cleanupManagedRuntime?: typeof cleanupManagedRuntime;
19
21
  applyManagedSpec?: typeof applyManagedSpec;
22
+ runUpdateCommand?: typeof runUpdateCommand;
23
+ emitUpdateNotice?: typeof emitUpdateNotice;
20
24
  stdout?: Pick<Console, 'log'>;
21
25
  }
22
26
  interface CliEntrypointDeps {
package/dist/cli.js CHANGED
@@ -2,11 +2,13 @@
2
2
  import { realpathSync } from 'node:fs';
3
3
  import { dirname, resolve } from 'node:path';
4
4
  import { fileURLToPath } from 'node:url';
5
- import { CliUsageError, parseApplyManagedArgs, parseDaemonArgs, parseDescribeArgs, parseDescribeManagedArgs, parseCleanupManagedArgs, parseGenerateConfigArgs, parseLogArgs, parseManagedStartArgs, parsePrintLayoutArgs, parseStartArgs, parseValidateArgs, USAGE, } from './cli-args.js';
5
+ import { assertNoUpdateArgs, CliUsageError, parseApplyManagedArgs, parseDaemonArgs, parseDescribeArgs, parseDescribeManagedArgs, parseCleanupManagedArgs, parseGenerateConfigArgs, parseLogArgs, parseManagedStartArgs, parsePrintLayoutArgs, parseStartArgs, parseValidateArgs, USAGE, } from './cli-args.js';
6
6
  import { resolveAgentsHostDebugMode } from './debug.js';
7
7
  import { applyManagedSpec, bootstrapManagedDaemonStart, cleanupManagedRuntime, describeManagedSpec, ManagedAgentsHostDaemon, } from './managed-daemon.js';
8
8
  import { runManagedDaemonLogCommand } from './managed-daemon-log.js';
9
9
  import { describeLocalConfig, generateLocalConfig, printLocalConfigLayout, runMain, validateLocalConfig, } from './run.js';
10
+ import { runUpdateCommand } from './update/update-command.js';
11
+ import { emitUpdateNotice } from './update/update-notice.js';
10
12
  function formatErrorMessage(error) {
11
13
  if (error instanceof Error) {
12
14
  return error.message;
@@ -46,9 +48,12 @@ export async function dispatchCli(argv, deps = {}) {
46
48
  });
47
49
  const readStdin = deps.readStdin ?? readAllStdin;
48
50
  const stdout = deps.stdout ?? console;
51
+ const runUpdateCommandImpl = deps.runUpdateCommand ?? runUpdateCommand;
52
+ const emitUpdateNoticeImpl = deps.emitUpdateNotice ?? emitUpdateNotice;
49
53
  if (command === 'start') {
50
54
  const parsed = parseStartArgs(rest);
51
55
  const debug = resolveAgentsHostDebugMode(parsed.debug, env);
56
+ await emitUpdateNoticeImpl({ env });
52
57
  if (parsed.mode === 'single-agent') {
53
58
  env.BORGEE_BASE_URL = parsed.serverUrl;
54
59
  env.BORGEE_AGENT_API_KEY = parsed.apiKey;
@@ -67,6 +72,7 @@ export async function dispatchCli(argv, deps = {}) {
67
72
  if (resolveAgentsHostDebugMode(false, env)) {
68
73
  throw new CliUsageError('start-managed does not support debug mode; use foreground start or start --config --debug instead');
69
74
  }
75
+ await emitUpdateNoticeImpl({ env });
70
76
  if (parsed.apiKey === undefined) {
71
77
  await bootstrapManagedDaemonStartImpl({
72
78
  serverUrl: parsed.serverUrl,
@@ -165,6 +171,11 @@ export async function dispatchCli(argv, deps = {}) {
165
171
  await startManagedDaemonImpl(parsed.rootPath, parsed.debug);
166
172
  return;
167
173
  }
174
+ if (command === 'update') {
175
+ assertNoUpdateArgs(rest);
176
+ await runUpdateCommandImpl();
177
+ return;
178
+ }
168
179
  throw new CliUsageError(`Unknown command: ${command}`);
169
180
  }
170
181
  async function readAllStdin() {
@@ -21,7 +21,6 @@ export const INTERNAL_PROVIDER_IMPLEMENTATIONS_ENV = 'AGENTS_HOST_INTERNAL_PROVI
21
21
  export const MANAGED_RUNTIME_SETTINGS_SCHEMA_VERSION = 1;
22
22
  const VALID_PROVIDER_IMPLEMENTATION_ENTRIES = '"claude:v1", "claude:v2", "copilot:v1", or "copilot:v2"';
23
23
  export const DEFAULT_INTERNAL_COMPATIBILITY_GATES = Object.freeze([
24
- CLAUDE_PROVIDER_V2_COMPATIBILITY_GATE,
25
24
  COLLABORATION_CAPABILITIES_DIAGNOSTICS_COMPATIBILITY_GATE,
26
25
  COLLABORATION_OUTCOME_MODEL_COMPATIBILITY_GATE,
27
26
  CONNECTIONS_STATE_LAYER_COMPATIBILITY_GATE,
@@ -118,11 +117,15 @@ export function resolveManagedRuntimeProviderImplementationOverrides(env = proce
118
117
  const enabledGates = new Set(compatibilityGates);
119
118
  return normalizeInternalProviderImplementationOverrides(env[INTERNAL_PROVIDER_IMPLEMENTATIONS_ENV]).filter((assignment) => {
120
119
  const [provider] = assignment.split(':');
120
+ if (provider === 'claude') {
121
+ return false;
122
+ }
121
123
  return enabledGates.has(PROVIDER_IMPLEMENTATION_COMPATIBILITY_GATES[provider]);
122
124
  });
123
125
  }
124
126
  export function resolveManagedRuntimeCompatibilityGates(env = process.env) {
125
127
  const compatibilityGates = new Set(resolveInternalCompatibilityGates(env));
128
+ compatibilityGates.delete(CLAUDE_PROVIDER_V2_COMPATIBILITY_GATE);
126
129
  const explicitlyEnabledGates = parseCompatibilityGates(env[COMPATIBILITY_GATES_ENV]);
127
130
  if (compatibilityGates.has(MANAGED_RUNTIME_CONVERGENCE_COMPATIBILITY_GATE)) {
128
131
  compatibilityGates.add(CONNECTIONS_STATE_LAYER_COMPATIBILITY_GATE);
package/dist/config.d.ts CHANGED
@@ -1,6 +1,9 @@
1
1
  import type { AgentsHostConfig, ProviderCommandConfig, ProviderKind } from './types.js';
2
2
  export declare const MAX_COPILOT_SESSION_TTL_MINUTES: number;
3
3
  export declare const DEFAULT_COPILOT_SESSION_TTL_MINUTES: number;
4
+ export declare const DEFAULT_CLAUDE_COMMAND = "claude-agent-acp";
5
+ export declare const LEGACY_CLAUDE_COMMAND = "claude";
6
+ export declare const LEGACY_CLAUDE_ONE_SHOT_ARGS: readonly ["--print", "--permission-mode", "bypassPermissions"];
4
7
  export declare const DEFAULT_PROVIDER_COMMAND_CONFIG: ProviderCommandConfig;
5
8
  export declare function requireNonEmptyString(value: unknown, message: string): string;
6
9
  export declare function optionalNonEmptyString(value: unknown, fieldName: string, sourceLabel: string): string | undefined;
@@ -9,5 +12,10 @@ export declare function optionalStringArray(value: unknown, fieldName: string, s
9
12
  export declare function parseCopilotSessionTtlMinutesValue(value: unknown, sourceLabel: string): number;
10
13
  export declare function resolveProvider(rawValue: string, sourceLabel: string): ProviderKind;
11
14
  export declare function assertProviderCompatibility(provider: ProviderKind, sourceLabel: string, env?: NodeJS.ProcessEnv): void;
15
+ export declare function isLegacyClaudeCompatibilityAlias(command: string, args: string[]): boolean;
16
+ export declare function isLegacyClaudeBinaryCommand(command: string): boolean;
17
+ export declare function hasLegacyClaudeOneShotArgs(args: string[]): boolean;
18
+ export declare function assertClaudeCommandCompatibility(command: string, args: string[], sourceLabel: string): void;
19
+ export declare function assertProviderCommandCompatibility(provider: ProviderKind, config: Pick<ProviderCommandConfig, 'claudeCommand' | 'claudeArgs'>, sourceLabel: string): void;
12
20
  export declare function resolveProviderCommandConfig(overrides?: Partial<ProviderCommandConfig>): ProviderCommandConfig;
13
21
  export declare function loadConfigFromEnv(env?: NodeJS.ProcessEnv): AgentsHostConfig;
package/dist/config.js CHANGED
@@ -1,11 +1,15 @@
1
+ import { basename } from 'node:path';
1
2
  import { resolveSingleAgentStateRoot } from './state-paths.js';
2
3
  import { CODEX_PROVIDER_COMPATIBILITY_GATE, resolveInternalCompatibilityGates, } from './compatibility-gates.js';
3
4
  const MAX_TIMER_DELAY_MS = 2_147_483_647;
4
5
  export const MAX_COPILOT_SESSION_TTL_MINUTES = MAX_TIMER_DELAY_MS / 60_000;
5
6
  export const DEFAULT_COPILOT_SESSION_TTL_MINUTES = 2 * 24 * 60;
7
+ export const DEFAULT_CLAUDE_COMMAND = 'claude-agent-acp';
8
+ export const LEGACY_CLAUDE_COMMAND = 'claude';
9
+ export const LEGACY_CLAUDE_ONE_SHOT_ARGS = ['--print', '--permission-mode', 'bypassPermissions'];
6
10
  export const DEFAULT_PROVIDER_COMMAND_CONFIG = {
7
- claudeCommand: 'claude',
8
- claudeArgs: ['--print', '--permission-mode', 'bypassPermissions'],
11
+ claudeCommand: DEFAULT_CLAUDE_COMMAND,
12
+ claudeArgs: [],
9
13
  codexCommand: 'codex-acp',
10
14
  codexArgs: [],
11
15
  copilotCommand: 'copilot',
@@ -74,6 +78,38 @@ export function assertProviderCompatibility(provider, sourceLabel, env = process
74
78
  throw new Error(`${sourceLabel}: provider "codex" requires the shipped ${CODEX_PROVIDER_COMPATIBILITY_GATE} path to remain enabled`);
75
79
  }
76
80
  }
81
+ export function isLegacyClaudeCompatibilityAlias(command, args) {
82
+ if (command !== LEGACY_CLAUDE_COMMAND || args.length !== LEGACY_CLAUDE_ONE_SHOT_ARGS.length) {
83
+ return false;
84
+ }
85
+ return args.every((arg, index) => arg === LEGACY_CLAUDE_ONE_SHOT_ARGS[index]);
86
+ }
87
+ export function isLegacyClaudeBinaryCommand(command) {
88
+ return basename(command) === LEGACY_CLAUDE_COMMAND;
89
+ }
90
+ export function hasLegacyClaudeOneShotArgs(args) {
91
+ return (args.length === LEGACY_CLAUDE_ONE_SHOT_ARGS.length
92
+ && args.every((arg, index) => arg === LEGACY_CLAUDE_ONE_SHOT_ARGS[index]));
93
+ }
94
+ export function assertClaudeCommandCompatibility(command, args, sourceLabel) {
95
+ if (command === DEFAULT_CLAUDE_COMMAND) {
96
+ if (args.length > 0) {
97
+ throw new Error(`Invalid Claude config in ${sourceLabel}: the shipped ${DEFAULT_CLAUDE_COMMAND} path does not accept CLAUDE_ARGS/claudeArgs. Leave them empty or point claudeCommand/CLAUDE_COMMAND at a custom ACP adapter command instead.`);
98
+ }
99
+ return;
100
+ }
101
+ if (isLegacyClaudeBinaryCommand(command)) {
102
+ if (isLegacyClaudeCompatibilityAlias(command, args)) {
103
+ return;
104
+ }
105
+ throw new Error(`Invalid Claude config in ${sourceLabel}: raw "${LEGACY_CLAUDE_COMMAND}" commands no longer speak ACP directly. Use the shipped ${DEFAULT_CLAUDE_COMMAND} default, keep only the exact legacy compatibility alias "${LEGACY_CLAUDE_COMMAND} ${LEGACY_CLAUDE_ONE_SHOT_ARGS.join(' ')}", or point claudeCommand/CLAUDE_COMMAND at a real ACP adapter command.`);
106
+ }
107
+ }
108
+ export function assertProviderCommandCompatibility(provider, config, sourceLabel) {
109
+ if (provider === 'claude') {
110
+ assertClaudeCommandCompatibility(config.claudeCommand, config.claudeArgs, sourceLabel);
111
+ }
112
+ }
77
113
  export function resolveProviderCommandConfig(overrides = {}) {
78
114
  return {
79
115
  claudeCommand: overrides.claudeCommand ?? DEFAULT_PROVIDER_COMMAND_CONFIG.claudeCommand,
@@ -89,20 +125,22 @@ export function loadConfigFromEnv(env = process.env) {
89
125
  const provider = resolveProvider(envOr('RUNTIME_PROVIDER', 'claude', env), 'Unsupported RUNTIME_PROVIDER');
90
126
  assertProviderCompatibility(provider, 'Unsupported RUNTIME_PROVIDER', env);
91
127
  const agentApiKey = requireEnv('BORGEE_AGENT_API_KEY', env);
128
+ const providerConfig = resolveProviderCommandConfig({
129
+ claudeCommand: envOr('CLAUDE_COMMAND', DEFAULT_PROVIDER_COMMAND_CONFIG.claudeCommand, env),
130
+ claudeArgs: parseArgs(envOr('CLAUDE_ARGS', DEFAULT_PROVIDER_COMMAND_CONFIG.claudeArgs.join(' '), env)),
131
+ codexCommand: envOr('CODEX_COMMAND', DEFAULT_PROVIDER_COMMAND_CONFIG.codexCommand, env),
132
+ codexArgs: parseArgs(envOr('CODEX_ARGS', DEFAULT_PROVIDER_COMMAND_CONFIG.codexArgs.join(' '), env)),
133
+ copilotCommand: envOr('COPILOT_COMMAND', DEFAULT_PROVIDER_COMMAND_CONFIG.copilotCommand, env),
134
+ copilotArgs: parseArgs(envOr('COPILOT_ARGS', DEFAULT_PROVIDER_COMMAND_CONFIG.copilotArgs.join(' '), env)),
135
+ copilotSessionTtlMinutes: env.COPILOT_SESSION_TTL_MINUTES && env.COPILOT_SESSION_TTL_MINUTES.trim().length > 0
136
+ ? parseCopilotSessionTtlMinutesValue(env.COPILOT_SESSION_TTL_MINUTES, 'environment variable COPILOT_SESSION_TTL_MINUTES')
137
+ : DEFAULT_PROVIDER_COMMAND_CONFIG.copilotSessionTtlMinutes,
138
+ });
139
+ assertProviderCommandCompatibility(provider, providerConfig, 'environment variables');
92
140
  return {
93
141
  borgeeBaseUrl: requireEnv('BORGEE_BASE_URL', env),
94
142
  stateRootDir: resolveSingleAgentStateRoot(env, undefined, agentApiKey),
95
- ...resolveProviderCommandConfig({
96
- claudeCommand: envOr('CLAUDE_COMMAND', DEFAULT_PROVIDER_COMMAND_CONFIG.claudeCommand, env),
97
- claudeArgs: parseArgs(envOr('CLAUDE_ARGS', DEFAULT_PROVIDER_COMMAND_CONFIG.claudeArgs.join(' '), env)),
98
- codexCommand: envOr('CODEX_COMMAND', DEFAULT_PROVIDER_COMMAND_CONFIG.codexCommand, env),
99
- codexArgs: parseArgs(envOr('CODEX_ARGS', DEFAULT_PROVIDER_COMMAND_CONFIG.codexArgs.join(' '), env)),
100
- copilotCommand: envOr('COPILOT_COMMAND', DEFAULT_PROVIDER_COMMAND_CONFIG.copilotCommand, env),
101
- copilotArgs: parseArgs(envOr('COPILOT_ARGS', DEFAULT_PROVIDER_COMMAND_CONFIG.copilotArgs.join(' '), env)),
102
- copilotSessionTtlMinutes: env.COPILOT_SESSION_TTL_MINUTES && env.COPILOT_SESSION_TTL_MINUTES.trim().length > 0
103
- ? parseCopilotSessionTtlMinutesValue(env.COPILOT_SESSION_TTL_MINUTES, 'environment variable COPILOT_SESSION_TTL_MINUTES')
104
- : DEFAULT_PROVIDER_COMMAND_CONFIG.copilotSessionTtlMinutes,
105
- }),
143
+ ...providerConfig,
106
144
  agent: {
107
145
  agentApiKey,
108
146
  agentName: envOr('BORGEE_AGENT_NAME', 'Assistant', env),
@@ -48,7 +48,7 @@ function buildLocalhostGatewayPromptLines(context) {
48
48
  lines.push('Task-collection commands remain disabled inside this task thread; use the parent channel for create/list task operations.', `Node get current thread task: node ${context.skillRuntime.nodeCliPath} --context ${context.channelContextPayloadPath} --auth-path ${context.gatewayAuthPath} --get-task`, `Node update current thread task: node ${context.skillRuntime.nodeCliPath} --context ${context.channelContextPayloadPath} --auth-path ${context.gatewayAuthPath} --update-task [--status "<status>"] [--assignee-id "<assignee-id>"] [--title "<title>"]`, `Python get current thread task: python3 ${context.skillRuntime.pythonCliPath} --context ${context.channelContextPayloadPath} --auth-path ${context.gatewayAuthPath} --get-task`, `Python update current thread task: python3 ${context.skillRuntime.pythonCliPath} --context ${context.channelContextPayloadPath} --auth-path ${context.gatewayAuthPath} --update-task [--status "<status>"] [--assignee-id "<assignee-id>"] [--title "<title>"]`);
49
49
  }
50
50
  else {
51
- lines.push(`Node create task: node ${context.skillRuntime.nodeCliPath} --context ${context.channelContextPayloadPath} --auth-path ${context.gatewayAuthPath} --create-task --title "<title>" [--description "<description>"] [--assignee-id "<assignee-id>"]`, `Node list tasks: node ${context.skillRuntime.nodeCliPath} --context ${context.channelContextPayloadPath} --auth-path ${context.gatewayAuthPath} --list-tasks`, `Node get task: node ${context.skillRuntime.nodeCliPath} --context ${context.channelContextPayloadPath} --auth-path ${context.gatewayAuthPath} --get-task --task-id "<task-id>"`, `Node update task: node ${context.skillRuntime.nodeCliPath} --context ${context.channelContextPayloadPath} --auth-path ${context.gatewayAuthPath} --update-task --task-id "<task-id>" [--status "<status>"] [--assignee-id "<assignee-id>"] [--title "<title>"]`, `Python create task: python3 ${context.skillRuntime.pythonCliPath} --context ${context.channelContextPayloadPath} --auth-path ${context.gatewayAuthPath} --create-task --title "<title>" [--description "<description>"] [--assignee-id "<assignee-id>"]`, `Python list tasks: python3 ${context.skillRuntime.pythonCliPath} --context ${context.channelContextPayloadPath} --auth-path ${context.gatewayAuthPath} --list-tasks`, `Python get task: python3 ${context.skillRuntime.pythonCliPath} --context ${context.channelContextPayloadPath} --auth-path ${context.gatewayAuthPath} --get-task --task-id "<task-id>"`, `Python update task: python3 ${context.skillRuntime.pythonCliPath} --context ${context.channelContextPayloadPath} --auth-path ${context.gatewayAuthPath} --update-task --task-id "<task-id>" [--status "<status>"] [--assignee-id "<assignee-id>"] [--title "<title>"]`);
51
+ lines.push(`Node create task: node ${context.skillRuntime.nodeCliPath} --context ${context.channelContextPayloadPath} --auth-path ${context.gatewayAuthPath} --create-task --title "<title>" [--description "<description>"] [--assignee-id "<assignee-id>"]`, `Node list tasks: node ${context.skillRuntime.nodeCliPath} --context ${context.channelContextPayloadPath} --auth-path ${context.gatewayAuthPath} --list-tasks`, `Node get task: node ${context.skillRuntime.nodeCliPath} --context ${context.channelContextPayloadPath} --auth-path ${context.gatewayAuthPath} --get-task --task-id "<task-id>"`, `Node read task thread history: node ${context.skillRuntime.nodeCliPath} --context ${context.channelContextPayloadPath} --auth-path ${context.gatewayAuthPath} --read-task-history --task-id "<task-id>" --limit 20`, `Node update task: node ${context.skillRuntime.nodeCliPath} --context ${context.channelContextPayloadPath} --auth-path ${context.gatewayAuthPath} --update-task --task-id "<task-id>" [--status "<status>"] [--assignee-id "<assignee-id>"] [--title "<title>"]`, `Python create task: python3 ${context.skillRuntime.pythonCliPath} --context ${context.channelContextPayloadPath} --auth-path ${context.gatewayAuthPath} --create-task --title "<title>" [--description "<description>"] [--assignee-id "<assignee-id>"]`, `Python list tasks: python3 ${context.skillRuntime.pythonCliPath} --context ${context.channelContextPayloadPath} --auth-path ${context.gatewayAuthPath} --list-tasks`, `Python get task: python3 ${context.skillRuntime.pythonCliPath} --context ${context.channelContextPayloadPath} --auth-path ${context.gatewayAuthPath} --get-task --task-id "<task-id>"`, `Python read task thread history: python3 ${context.skillRuntime.pythonCliPath} --context ${context.channelContextPayloadPath} --auth-path ${context.gatewayAuthPath} --read-task-history --task-id "<task-id>" --limit 20`, `Python update task: python3 ${context.skillRuntime.pythonCliPath} --context ${context.channelContextPayloadPath} --auth-path ${context.gatewayAuthPath} --update-task --task-id "<task-id>" [--status "<status>"] [--assignee-id "<assignee-id>"] [--title "<title>"]`);
52
52
  }
53
53
  if (context.localhostGateway.collaboration?.enabled &&
54
54
  (context.collaborationTurnMode ?? 'ordinary') === 'ordinary') {