@borgee/agents-host 0.2.2 → 0.2.28

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 (84) hide show
  1. package/README.md +184 -21
  2. package/dist/agents-host-supervisor.d.ts +7 -5
  3. package/dist/agents-host-supervisor.js +24 -4
  4. package/dist/agents-host.d.ts +114 -15
  5. package/dist/agents-host.js +2712 -141
  6. package/dist/chat/chat-control-plane.d.ts +13 -2
  7. package/dist/chat/sdk-chat-control-plane.d.ts +14 -3
  8. package/dist/chat/sdk-chat-control-plane.js +54 -2
  9. package/dist/cli-args.d.ts +46 -5
  10. package/dist/cli-args.js +313 -32
  11. package/dist/cli.d.ts +9 -0
  12. package/dist/cli.js +112 -5
  13. package/dist/compatibility-gates.d.ts +39 -0
  14. package/dist/compatibility-gates.js +131 -0
  15. package/dist/config.d.ts +1 -0
  16. package/dist/config.js +23 -5
  17. package/dist/connections-state-store.d.ts +81 -0
  18. package/dist/connections-state-store.js +228 -0
  19. package/dist/context/attention.d.ts +12 -0
  20. package/dist/context/attention.js +137 -0
  21. package/dist/context/collaboration-capabilities-diagnostics.d.ts +3 -0
  22. package/dist/context/collaboration-capabilities-diagnostics.js +18 -0
  23. package/dist/context/collaboration-outcome.d.ts +2 -0
  24. package/dist/context/collaboration-outcome.js +26 -0
  25. package/dist/context/injection.d.ts +134 -0
  26. package/dist/context/injection.js +355 -0
  27. package/dist/context/prompt.d.ts +4 -1
  28. package/dist/context/prompt.js +231 -1
  29. package/dist/context/task-thread-collaboration.d.ts +6 -0
  30. package/dist/context/task-thread-collaboration.js +31 -0
  31. package/dist/context/turn-preparation.d.ts +9 -0
  32. package/dist/context/turn-preparation.js +135 -0
  33. package/dist/debug.d.ts +44 -0
  34. package/dist/debug.js +135 -0
  35. package/dist/gateway/localhost-gateway.d.ts +52 -0
  36. package/dist/gateway/localhost-gateway.js +857 -0
  37. package/dist/index.js +7 -5
  38. package/dist/local-config.d.ts +4 -1
  39. package/dist/local-config.js +24 -7
  40. package/dist/managed-daemon-log.d.ts +34 -0
  41. package/dist/managed-daemon-log.js +261 -0
  42. package/dist/managed-daemon.d.ts +220 -0
  43. package/dist/managed-daemon.js +1601 -0
  44. package/dist/policy/authorization-audit.d.ts +63 -0
  45. package/dist/policy/authorization-audit.js +94 -0
  46. package/dist/policy/copilot-permission.d.ts +15 -0
  47. package/dist/policy/copilot-permission.js +193 -0
  48. package/dist/policy/gateway-authorization.d.ts +42 -0
  49. package/dist/policy/gateway-authorization.js +162 -0
  50. package/dist/providers/awaiting-user.d.ts +12 -0
  51. package/dist/providers/awaiting-user.js +192 -0
  52. package/dist/providers/claude/adapter.d.ts +3 -1
  53. package/dist/providers/claude/adapter.js +8 -12
  54. package/dist/providers/claude/cli-client.d.ts +12 -5
  55. package/dist/providers/claude/cli-client.js +184 -37
  56. package/dist/providers/claude/session-store.d.ts +1 -0
  57. package/dist/providers/codex/adapter.d.ts +11 -0
  58. package/dist/providers/codex/adapter.js +19 -0
  59. package/dist/providers/codex/cli-client.d.ts +103 -0
  60. package/dist/providers/codex/cli-client.js +1133 -0
  61. package/dist/providers/codex/project-doc.d.ts +3 -0
  62. package/dist/providers/codex/project-doc.js +90 -0
  63. package/dist/providers/codex/session-store.d.ts +38 -0
  64. package/dist/providers/codex/session-store.js +150 -0
  65. package/dist/providers/copilot/adapter.d.ts +3 -1
  66. package/dist/providers/copilot/adapter.js +8 -12
  67. package/dist/providers/copilot/cli-client.d.ts +20 -2
  68. package/dist/providers/copilot/cli-client.js +251 -71
  69. package/dist/providers/copilot/session-store.d.ts +1 -0
  70. package/dist/providers/create-provider.d.ts +11 -2
  71. package/dist/providers/create-provider.js +131 -12
  72. package/dist/run.d.ts +1 -0
  73. package/dist/run.js +5 -2
  74. package/dist/state-paths.d.ts +14 -1
  75. package/dist/state-paths.js +87 -3
  76. package/dist/task-thread-resolution.d.ts +10 -0
  77. package/dist/task-thread-resolution.js +48 -0
  78. package/dist/types.d.ts +267 -1
  79. package/dist/visible-mentions.d.ts +3 -0
  80. package/dist/visible-mentions.js +15 -0
  81. package/package.json +19 -17
  82. package/skills/borgee-agent/SKILL.md +33 -0
  83. package/skills/borgee-agent/borgee-agent.mjs +473 -0
  84. package/skills/borgee-agent/borgee-agent.py +409 -0
@@ -1,10 +1,21 @@
1
- import type { ChannelMessageEvent, MeResponseUser, PostedMessage } from '../types.js';
1
+ import type { ChannelSummary, ChannelHistoryEntry, ChannelMessageEvent, CreateTaskInput, DirectoryUser, MeResponseUser, PostMessageInput, PostedMessage, ReadChannelHistoryInput, Task, UpdateTaskInput } from '../types.js';
2
2
  export interface ChatControlPlane {
3
3
  connect(onMessage: (message: ChannelMessageEvent) => void): Promise<void>;
4
4
  close(): Promise<void>;
5
- postMessage(channelId: string, content: string): Promise<PostedMessage>;
5
+ postMessage(input: PostMessageInput): Promise<PostedMessage>;
6
6
  editMessage(messageId: string, content: string): Promise<void>;
7
7
  deleteMessage(messageId: string): Promise<void>;
8
8
  startTyping(channelId: string): () => void;
9
9
  getMe(): Promise<MeResponseUser>;
10
+ listUsers(): Promise<DirectoryUser[]>;
11
+ listChannels(): Promise<ChannelSummary[]>;
12
+ readChannelHistory(input: ReadChannelHistoryInput): Promise<ChannelHistoryEntry[]>;
13
+ createTask(input: CreateTaskInput): Promise<Task>;
14
+ listTasks(input: {
15
+ channelId: string;
16
+ }): Promise<Task[]>;
17
+ getTask(input: {
18
+ taskId: string;
19
+ }): Promise<Task>;
20
+ updateTask(input: UpdateTaskInput): Promise<Task>;
10
21
  }
@@ -1,7 +1,7 @@
1
1
  import { type BorgeePluginClient, type BorgeePluginOptions, type InboundMessageEvent } from '@borgee/plugin-sdk';
2
- import type { ChannelMessageEvent, MeResponseUser, PostedMessage } from '../types.js';
2
+ import type { ChannelSummary, ChannelHistoryEntry, ChannelMessageEvent, CreateTaskInput, DirectoryUser, MeResponseUser, PostMessageInput, PostedMessage, ReadChannelHistoryInput, Task, UpdateTaskInput } from '../types.js';
3
3
  import type { ChatControlPlane } from './chat-control-plane.js';
4
- type PluginClientLike = Pick<BorgeePluginClient, 'agentId' | 'close' | 'connect' | 'deleteMessage' | 'editMessage' | 'getMe' | 'on' | 'sendMessage' | 'startTyping'>;
4
+ type PluginClientLike = Pick<BorgeePluginClient, 'agentId' | 'close' | 'connect' | 'createTask' | 'deleteMessage' | 'editMessage' | 'getMe' | 'getTask' | 'listChannels' | 'listTasks' | 'listUsers' | 'on' | 'readHistory' | 'sendMessage' | 'startTyping' | 'updateTask'>;
5
5
  type PluginClientFactory = (options: BorgeePluginOptions) => PluginClientLike;
6
6
  type SdkChatControlPlaneOptions = Pick<BorgeePluginOptions, 'cursorStore' | 'pluginId'>;
7
7
  /**
@@ -18,11 +18,22 @@ export declare class SdkChatControlPlane implements ChatControlPlane {
18
18
  constructor(baseUrl: string, apiKey: string, createClient?: PluginClientFactory, options?: SdkChatControlPlaneOptions);
19
19
  connect(onMessage: (message: ChannelMessageEvent) => void): Promise<void>;
20
20
  close(): Promise<void>;
21
- postMessage(channelId: string, content: string): Promise<PostedMessage>;
21
+ postMessage(input: PostMessageInput): Promise<PostedMessage>;
22
22
  editMessage(messageId: string, content: string): Promise<void>;
23
23
  deleteMessage(messageId: string): Promise<void>;
24
24
  startTyping(channelId: string): () => void;
25
25
  getMe(): Promise<MeResponseUser>;
26
+ listUsers(): Promise<DirectoryUser[]>;
27
+ readChannelHistory(input: ReadChannelHistoryInput): Promise<ChannelHistoryEntry[]>;
28
+ listChannels(): Promise<ChannelSummary[]>;
29
+ createTask(input: CreateTaskInput): Promise<Task>;
30
+ listTasks(input: {
31
+ channelId: string;
32
+ }): Promise<Task[]>;
33
+ getTask(input: {
34
+ taskId: string;
35
+ }): Promise<Task>;
36
+ updateTask(input: UpdateTaskInput): Promise<Task>;
26
37
  }
27
38
  export declare function mapInboundToChannelMessage(event: InboundMessageEvent): ChannelMessageEvent;
28
39
  export {};
@@ -47,8 +47,12 @@ export class SdkChatControlPlane {
47
47
  this.unsubscribe = null;
48
48
  await this.client.close();
49
49
  }
50
- async postMessage(channelId, content) {
51
- const sent = await this.client.sendMessage({ channelId, body: content });
50
+ async postMessage(input) {
51
+ const sent = await this.client.sendMessage({
52
+ channelId: input.channelId,
53
+ body: input.body,
54
+ replyToId: input.replyToId,
55
+ });
52
56
  return { messageId: sent.messageId };
53
57
  }
54
58
  async editMessage(messageId, content) {
@@ -72,10 +76,58 @@ export class SdkChatControlPlane {
72
76
  };
73
77
  return this.me;
74
78
  }
79
+ async listUsers() {
80
+ const users = await this.client.listUsers();
81
+ return users.map((user) => ({
82
+ id: user.id,
83
+ display_name: user.displayName,
84
+ kind: user.kind,
85
+ }));
86
+ }
87
+ async readChannelHistory(input) {
88
+ const messages = await this.client.readHistory({
89
+ channelId: input.channelId,
90
+ before: input.before,
91
+ after: input.after,
92
+ limit: input.limit,
93
+ });
94
+ return messages.map((message) => ({
95
+ id: message.id,
96
+ channelId: message.channelId,
97
+ authorId: message.authorId,
98
+ body: message.body,
99
+ contentType: message.contentType,
100
+ type: message.type,
101
+ replyToId: message.replyToId,
102
+ createdAt: message.createdAt,
103
+ editedAt: message.editedAt,
104
+ }));
105
+ }
106
+ async listChannels() {
107
+ const channels = await this.client.listChannels();
108
+ return channels.map((channel) => ({
109
+ id: channel.id,
110
+ name: channel.name,
111
+ kind: channel.kind,
112
+ }));
113
+ }
114
+ async createTask(input) {
115
+ return this.client.createTask(input);
116
+ }
117
+ async listTasks(input) {
118
+ return this.client.listTasks(input);
119
+ }
120
+ async getTask(input) {
121
+ return this.client.getTask(input);
122
+ }
123
+ async updateTask(input) {
124
+ return this.client.updateTask(input);
125
+ }
75
126
  }
76
127
  export function mapInboundToChannelMessage(event) {
77
128
  return {
78
129
  type: event.kind,
130
+ ...(event.message?.type != null ? { message_type: event.message.type } : {}),
79
131
  channel_id: event.channelId,
80
132
  channel_type: event.channelType,
81
133
  message_id: event.message?.id ?? event.messageId,
@@ -1,8 +1,9 @@
1
1
  /**
2
- * Maps single-agent `agents-host start` CLI flags to the env vars `config.ts`
3
- * reads. Keeping this as a plain lookup table (rather than duplicating
4
- * `loadConfigFromEnv`'s parsing logic) means the CLI and the env-var entry
5
- * point (`index.ts`) always agree on defaults/validation.
2
+ * Maps `agents-host start` / `agents-host start-managed` agent flags to the env
3
+ * vars `config.ts` reads. Keeping this as a plain lookup table (rather than
4
+ * duplicating `loadConfigFromEnv`'s parsing logic) means the CLI and the
5
+ * standalone env-var entry point (`index.ts`) always agree on
6
+ * defaults/validation.
6
7
  */
7
8
  export declare const CLI_FLAG_TO_ENV: Record<string, string>;
8
9
  export type ParsedStartArgs = ParsedSingleAgentStartArgs | ParsedLocalConfigStartArgs;
@@ -10,11 +11,18 @@ export interface ParsedSingleAgentStartArgs {
10
11
  mode: 'single-agent';
11
12
  serverUrl: string;
12
13
  apiKey: string;
14
+ debug: boolean;
15
+ env: Record<string, string>;
16
+ }
17
+ export interface ParsedManagedStartArgs {
18
+ serverUrl: string;
19
+ apiKey?: string;
13
20
  env: Record<string, string>;
14
21
  }
15
22
  export interface ParsedLocalConfigStartArgs {
16
23
  mode: 'local-config';
17
24
  configPath: string;
25
+ debug: boolean;
18
26
  }
19
27
  export interface ParsedValidateArgs {
20
28
  configPath: string;
@@ -35,11 +43,44 @@ export interface ParsedGenerateConfigFromStdinArgs {
35
43
  input: 'stdin';
36
44
  }
37
45
  export type ParsedGenerateConfigArgs = ParsedGenerateConfigFromArgvArgs | ParsedGenerateConfigFromStdinArgs;
46
+ export interface ParsedDaemonArgs {
47
+ rootPath: string;
48
+ debug: boolean;
49
+ }
50
+ export interface ParsedLogArgs {
51
+ serverUrl: string;
52
+ lines: number;
53
+ follow: boolean;
54
+ pathOnly: boolean;
55
+ }
56
+ export interface ParsedDescribeManagedArgs {
57
+ serverUrl: string;
58
+ }
59
+ export interface ParsedCleanupManagedArgs {
60
+ serverUrl: string;
61
+ purge: boolean;
62
+ }
63
+ export interface ParsedApplyManagedFromArgvArgs {
64
+ serverUrl: string;
65
+ input: 'argv';
66
+ specJson: string;
67
+ }
68
+ export interface ParsedApplyManagedFromStdinArgs {
69
+ serverUrl: string;
70
+ input: 'stdin';
71
+ }
72
+ export type ParsedApplyManagedArgs = ParsedApplyManagedFromArgvArgs | ParsedApplyManagedFromStdinArgs;
38
73
  export declare class CliUsageError extends Error {
39
74
  }
40
75
  export declare function parseStartArgs(argv: string[]): ParsedStartArgs;
76
+ export declare function parseManagedStartArgs(argv: string[]): ParsedManagedStartArgs;
41
77
  export declare function parseValidateArgs(argv: string[]): ParsedValidateArgs;
42
78
  export declare function parseDescribeArgs(argv: string[]): ParsedDescribeArgs;
43
79
  export declare function parsePrintLayoutArgs(argv: string[]): ParsedPrintLayoutArgs;
44
80
  export declare function parseGenerateConfigArgs(argv: string[]): ParsedGenerateConfigArgs;
45
- export declare const USAGE = "Usage:\n agents-host start <serverUrl> <apiKey> [options]\n agents-host start --config <path-to-host-config>\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\nSingle-agent options:\n --name <name> Display name (default: Assistant)\n --provider <claude|copilot> Runtime provider (default: claude)\n --claude-command <cmd> Local Claude CLI command (default: claude)\n --claude-args <args> Local Claude CLI args (default: --print)\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\nLocal-config mode:\n start --config <path> Start agents + supervisor + watchers from a host config file\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\n agents-host start --config ./agents-host.yaml\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";
81
+ export declare function parseDaemonArgs(argv: string[]): ParsedDaemonArgs;
82
+ export declare function parseLogArgs(argv: string[]): ParsedLogArgs;
83
+ export declare function parseDescribeManagedArgs(argv: string[]): ParsedDescribeManagedArgs;
84
+ export declare function parseCleanupManagedArgs(argv: string[]): ParsedCleanupManagedArgs;
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";
package/dist/cli-args.js CHANGED
@@ -1,26 +1,72 @@
1
1
  /**
2
- * Maps single-agent `agents-host start` CLI flags to the env vars `config.ts`
3
- * reads. Keeping this as a plain lookup table (rather than duplicating
4
- * `loadConfigFromEnv`'s parsing logic) means the CLI and the env-var entry
5
- * point (`index.ts`) always agree on defaults/validation.
2
+ * Maps `agents-host start` / `agents-host start-managed` agent flags to the env
3
+ * vars `config.ts` reads. Keeping this as a plain lookup table (rather than
4
+ * duplicating `loadConfigFromEnv`'s parsing logic) means the CLI and the
5
+ * standalone env-var entry point (`index.ts`) always agree on
6
+ * defaults/validation.
6
7
  */
7
8
  export const CLI_FLAG_TO_ENV = {
8
9
  name: 'BORGEE_AGENT_NAME',
9
10
  provider: 'RUNTIME_PROVIDER',
10
11
  'claude-command': 'CLAUDE_COMMAND',
11
12
  'claude-args': 'CLAUDE_ARGS',
13
+ 'codex-command': 'CODEX_COMMAND',
14
+ 'codex-args': 'CODEX_ARGS',
12
15
  'copilot-command': 'COPILOT_COMMAND',
13
16
  'copilot-args': 'COPILOT_ARGS',
14
17
  'copilot-session-ttl-minutes': 'COPILOT_SESSION_TTL_MINUTES',
15
18
  };
16
19
  const SINGLE_AGENT_FLAG_NAMES = new Set(Object.keys(CLI_FLAG_TO_ENV));
20
+ const FLAGS_ALLOWING_DASH_PREFIX_VALUE = new Set(['claude-args', 'codex-args', 'copilot-args']);
17
21
  export class CliUsageError extends Error {
18
22
  }
23
+ function parseSingleAgentPositionals(positionals) {
24
+ const [serverUrl, apiKey, ...extra] = positionals;
25
+ if (!serverUrl) {
26
+ throw new CliUsageError('Missing <serverUrl>');
27
+ }
28
+ if (!apiKey) {
29
+ throw new CliUsageError('Missing <apiKey>');
30
+ }
31
+ if (extra.length > 0) {
32
+ throw new CliUsageError(`Unexpected argument: ${extra[0]}`);
33
+ }
34
+ return { serverUrl, apiKey };
35
+ }
36
+ function readSingleAgentFlagValue(argv, index, flag) {
37
+ const value = argv[index + 1];
38
+ if (value === undefined ||
39
+ (value.startsWith('--') && !FLAGS_ALLOWING_DASH_PREFIX_VALUE.has(flag))) {
40
+ throw new CliUsageError(`Missing value for --${flag}`);
41
+ }
42
+ return value;
43
+ }
44
+ function applySingleAgentFlag(argv, index, env, seenSingleAgentFlags) {
45
+ const flag = argv[index]?.slice(2) ?? '';
46
+ const envKey = CLI_FLAG_TO_ENV[flag];
47
+ if (!envKey) {
48
+ throw new CliUsageError(`Unknown option: --${flag}`);
49
+ }
50
+ env[envKey] = readSingleAgentFlagValue(argv, index, flag);
51
+ seenSingleAgentFlags.add(flag);
52
+ return index + 1;
53
+ }
54
+ function parseNonNegativeInteger(value, flag) {
55
+ if (!/^\d+$/u.test(value)) {
56
+ throw new CliUsageError(`--${flag} must be a non-negative integer`);
57
+ }
58
+ const parsed = Number.parseInt(value, 10);
59
+ if (!Number.isSafeInteger(parsed)) {
60
+ throw new CliUsageError(`--${flag} must be a non-negative integer`);
61
+ }
62
+ return parsed;
63
+ }
19
64
  export function parseStartArgs(argv) {
20
65
  const positionals = [];
21
66
  const env = {};
22
67
  const seenSingleAgentFlags = new Set();
23
68
  let configPath;
69
+ let debug = false;
24
70
  for (let i = 0; i < argv.length; i++) {
25
71
  const arg = argv[i];
26
72
  if (!arg.startsWith('--')) {
@@ -28,25 +74,22 @@ export function parseStartArgs(argv) {
28
74
  continue;
29
75
  }
30
76
  const flag = arg.slice(2);
31
- const value = argv[i + 1];
32
- if (value === undefined || value.startsWith('--')) {
33
- throw new CliUsageError(`Missing value for --${flag}`);
77
+ if (flag === 'debug') {
78
+ if (debug) {
79
+ throw new CliUsageError('--debug may only be specified once');
80
+ }
81
+ debug = true;
82
+ continue;
34
83
  }
35
84
  if (flag === 'config') {
36
85
  if (configPath !== undefined) {
37
86
  throw new CliUsageError('--config may only be specified once');
38
87
  }
39
- configPath = value;
88
+ configPath = readSingleAgentFlagValue(argv, i, flag);
40
89
  i++;
41
90
  continue;
42
91
  }
43
- const envKey = CLI_FLAG_TO_ENV[flag];
44
- if (!envKey) {
45
- throw new CliUsageError(`Unknown option: --${flag}`);
46
- }
47
- env[envKey] = value;
48
- seenSingleAgentFlags.add(flag);
49
- i++;
92
+ i = applySingleAgentFlag(argv, i, env, seenSingleAgentFlags);
50
93
  }
51
94
  if (configPath !== undefined) {
52
95
  if (positionals.length > 0) {
@@ -58,25 +101,49 @@ export function parseStartArgs(argv) {
58
101
  return {
59
102
  mode: 'local-config',
60
103
  configPath,
104
+ debug,
61
105
  };
62
106
  }
63
- const [serverUrl, apiKey, ...extra] = positionals;
64
- if (!serverUrl) {
65
- throw new CliUsageError('Missing <serverUrl>');
66
- }
67
- if (!apiKey) {
68
- throw new CliUsageError('Missing <apiKey>');
69
- }
70
- if (extra.length > 0) {
71
- throw new CliUsageError(`Unexpected argument: ${extra[0]}`);
72
- }
107
+ const { serverUrl, apiKey } = parseSingleAgentPositionals(positionals);
73
108
  return {
74
109
  mode: 'single-agent',
75
110
  serverUrl,
76
111
  apiKey,
112
+ debug,
77
113
  env,
78
114
  };
79
115
  }
116
+ export function parseManagedStartArgs(argv) {
117
+ const positionals = [];
118
+ const env = {};
119
+ const seenSingleAgentFlags = new Set();
120
+ for (let i = 0; i < argv.length; i++) {
121
+ const arg = argv[i];
122
+ if (!arg.startsWith('--')) {
123
+ positionals.push(arg);
124
+ continue;
125
+ }
126
+ const flag = arg.slice(2);
127
+ if (flag === 'debug') {
128
+ throw new CliUsageError('start-managed does not support --debug; use foreground start for debug logging');
129
+ }
130
+ if (flag === 'config') {
131
+ throw new CliUsageError('start-managed does not support --config');
132
+ }
133
+ i = applySingleAgentFlag(argv, i, env, seenSingleAgentFlags);
134
+ }
135
+ if (positionals.length === 1) {
136
+ if (seenSingleAgentFlags.size > 0) {
137
+ throw new CliUsageError(`Cannot combine bare start-managed <serverUrl> resume with agent option --${[...seenSingleAgentFlags][0]}; provide <apiKey> to bootstrap or update an agent`);
138
+ }
139
+ return {
140
+ serverUrl: positionals[0],
141
+ env,
142
+ };
143
+ }
144
+ const { serverUrl, apiKey } = parseSingleAgentPositionals(positionals);
145
+ return { serverUrl, apiKey, env };
146
+ }
80
147
  export function parseValidateArgs(argv) {
81
148
  const positionals = [];
82
149
  let configPath;
@@ -218,27 +285,234 @@ export function parseGenerateConfigArgs(argv) {
218
285
  }
219
286
  return { rootPath, input: 'argv', specJson };
220
287
  }
288
+ export function parseDaemonArgs(argv) {
289
+ const positionals = [];
290
+ let rootPath;
291
+ let debug = false;
292
+ for (let i = 0; i < argv.length; i++) {
293
+ const arg = argv[i];
294
+ if (!arg.startsWith('--')) {
295
+ positionals.push(arg);
296
+ continue;
297
+ }
298
+ const flag = arg.slice(2);
299
+ if (flag === 'debug') {
300
+ if (debug) {
301
+ throw new CliUsageError('--debug may only be specified once');
302
+ }
303
+ debug = true;
304
+ continue;
305
+ }
306
+ if (flag === 'root') {
307
+ const value = argv[i + 1];
308
+ if (value === undefined || value.startsWith('--')) {
309
+ throw new CliUsageError('Missing value for --root');
310
+ }
311
+ if (rootPath !== undefined) {
312
+ throw new CliUsageError('--root may only be specified once');
313
+ }
314
+ rootPath = value;
315
+ i++;
316
+ continue;
317
+ }
318
+ throw new CliUsageError(`Unknown option: --${flag}`);
319
+ }
320
+ if (positionals.length > 0) {
321
+ throw new CliUsageError(`Unexpected argument: ${positionals[0]}`);
322
+ }
323
+ if (!rootPath) {
324
+ throw new CliUsageError('Missing required --root <dir>');
325
+ }
326
+ return { rootPath, debug };
327
+ }
328
+ export function parseLogArgs(argv) {
329
+ const positionals = [];
330
+ let lines = 100;
331
+ let follow = false;
332
+ let pathOnly = false;
333
+ let linesSpecified = false;
334
+ for (let i = 0; i < argv.length; i++) {
335
+ const arg = argv[i];
336
+ if (!arg.startsWith('--')) {
337
+ positionals.push(arg);
338
+ continue;
339
+ }
340
+ const flag = arg.slice(2);
341
+ if (flag === 'follow') {
342
+ if (follow) {
343
+ throw new CliUsageError('--follow may only be specified once');
344
+ }
345
+ follow = true;
346
+ continue;
347
+ }
348
+ if (flag === 'path') {
349
+ if (pathOnly) {
350
+ throw new CliUsageError('--path may only be specified once');
351
+ }
352
+ pathOnly = true;
353
+ continue;
354
+ }
355
+ if (flag === 'lines') {
356
+ if (linesSpecified) {
357
+ throw new CliUsageError('--lines may only be specified once');
358
+ }
359
+ const value = argv[i + 1];
360
+ if (value === undefined || value.startsWith('--')) {
361
+ throw new CliUsageError('Missing value for --lines');
362
+ }
363
+ lines = parseNonNegativeInteger(value, 'lines');
364
+ linesSpecified = true;
365
+ i++;
366
+ continue;
367
+ }
368
+ throw new CliUsageError(`Unknown option: --${flag}`);
369
+ }
370
+ const [serverUrl, ...extra] = positionals;
371
+ if (!serverUrl) {
372
+ throw new CliUsageError('Missing <serverUrl>');
373
+ }
374
+ if (extra.length > 0) {
375
+ throw new CliUsageError(`Unexpected argument: ${extra[0]}`);
376
+ }
377
+ if (pathOnly && (follow || linesSpecified)) {
378
+ throw new CliUsageError('--path cannot be combined with --follow or --lines');
379
+ }
380
+ return { serverUrl, lines, follow, pathOnly };
381
+ }
382
+ export function parseDescribeManagedArgs(argv) {
383
+ const [serverUrl, ...extra] = argv;
384
+ if (!serverUrl) {
385
+ throw new CliUsageError('Missing <serverUrl>');
386
+ }
387
+ if (serverUrl.startsWith('--')) {
388
+ throw new CliUsageError(`Unknown option: ${serverUrl}`);
389
+ }
390
+ if (extra.length > 0) {
391
+ throw new CliUsageError(`Unexpected argument: ${extra[0]}`);
392
+ }
393
+ return { serverUrl };
394
+ }
395
+ export function parseCleanupManagedArgs(argv) {
396
+ const positionals = [];
397
+ let purge = false;
398
+ for (let i = 0; i < argv.length; i++) {
399
+ const arg = argv[i];
400
+ if (!arg.startsWith('--')) {
401
+ positionals.push(arg);
402
+ continue;
403
+ }
404
+ const flag = arg.slice(2);
405
+ if (flag === 'purge') {
406
+ if (purge) {
407
+ throw new CliUsageError('--purge may only be specified once');
408
+ }
409
+ purge = true;
410
+ continue;
411
+ }
412
+ throw new CliUsageError(`Unknown option: --${flag}`);
413
+ }
414
+ const [serverUrl, ...extra] = positionals;
415
+ if (!serverUrl) {
416
+ throw new CliUsageError('Missing <serverUrl>');
417
+ }
418
+ if (extra.length > 0) {
419
+ throw new CliUsageError(`Unexpected argument: ${extra[0]}`);
420
+ }
421
+ return { serverUrl, purge };
422
+ }
423
+ export function parseApplyManagedArgs(argv) {
424
+ const positionals = [];
425
+ let specJson;
426
+ let stdin = false;
427
+ for (let i = 0; i < argv.length; i++) {
428
+ const arg = argv[i];
429
+ if (!arg.startsWith('--')) {
430
+ positionals.push(arg);
431
+ continue;
432
+ }
433
+ const flag = arg.slice(2);
434
+ if (flag === 'stdin') {
435
+ if (stdin) {
436
+ throw new CliUsageError('--stdin may only be specified once');
437
+ }
438
+ stdin = true;
439
+ continue;
440
+ }
441
+ if (flag === 'spec-json') {
442
+ const value = argv[i + 1];
443
+ if (value === undefined || value.startsWith('--')) {
444
+ throw new CliUsageError('Missing value for --spec-json');
445
+ }
446
+ if (specJson !== undefined) {
447
+ throw new CliUsageError('--spec-json may only be specified once');
448
+ }
449
+ specJson = value;
450
+ i++;
451
+ continue;
452
+ }
453
+ throw new CliUsageError(`Unknown option: --${flag}`);
454
+ }
455
+ const [serverUrl, ...extra] = positionals;
456
+ if (!serverUrl) {
457
+ throw new CliUsageError('Missing <serverUrl>');
458
+ }
459
+ if (extra.length > 0) {
460
+ throw new CliUsageError(`Unexpected argument: ${extra[0]}`);
461
+ }
462
+ if (stdin && specJson !== undefined) {
463
+ throw new CliUsageError('apply-managed accepts exactly one input source: --stdin or --spec-json');
464
+ }
465
+ if (stdin) {
466
+ return { serverUrl, input: 'stdin' };
467
+ }
468
+ if (!specJson) {
469
+ throw new CliUsageError('Missing required input: use --stdin or --spec-json <json>');
470
+ }
471
+ return { serverUrl, input: 'argv', specJson };
472
+ }
221
473
  export const USAGE = `Usage:
222
474
  agents-host start <serverUrl> <apiKey> [options]
223
- agents-host start --config <path-to-host-config>
475
+ agents-host start-managed <serverUrl>
476
+ agents-host start-managed <serverUrl> <apiKey> [agent-options]
477
+ agents-host describe-managed <serverUrl>
478
+ agents-host cleanup-managed <serverUrl> [--purge]
479
+ agents-host apply-managed <serverUrl> --stdin
480
+ agents-host apply-managed <serverUrl> --spec-json <json>
481
+ agents-host log <serverUrl> [--lines <n>] [--follow]
482
+ agents-host log <serverUrl> --path
483
+ agents-host start --config <path-to-host-config> [--debug]
224
484
  agents-host validate --config <path-to-host-config>
225
485
  agents-host describe --config <path-to-host-config>
226
486
  agents-host print-layout --root <dir>
227
487
  agents-host generate-config --root <dir> --stdin
228
488
  agents-host generate-config --root <dir> --spec-json <json>
229
489
 
230
- Single-agent options:
490
+ Foreground start options:
491
+ --debug Enable host/provider debug logs (or set AGENTS_HOST_DEBUG=1)
492
+
493
+ Single-agent agent options:
231
494
  --name <name> Display name (default: Assistant)
232
- --provider <claude|copilot> Runtime provider (default: claude)
495
+ --provider <claude|codex|copilot>
496
+ Runtime provider (default: claude)
233
497
  --claude-command <cmd> Local Claude CLI command (default: claude)
234
- --claude-args <args> Local Claude CLI args (default: --print)
498
+ --claude-args <args> Local Claude CLI args (default: --print --permission-mode bypassPermissions)
499
+ --codex-command <cmd> Local Codex ACP adapter command (default: codex-acp)
500
+ --codex-args <args> Local Codex ACP adapter args
235
501
  --copilot-command <cmd> Local Copilot CLI command (default: copilot)
236
502
  --copilot-args <args> Ignored by the Copilot ACP prototype
237
503
  --copilot-session-ttl-minutes <minutes>
238
504
  Idle session TTL for Copilot ACP sessions (default: 2880)
239
505
 
240
- Local-config mode:
506
+ Command summary:
507
+ start <serverUrl> <apiKey> Start one foreground hosted agent (legacy-compatible behavior)
241
508
  start --config <path> Start agents + supervisor + watchers from a host config file
509
+ start-managed <serverUrl> Restart or resume an existing per-serverUrl managed daemon
510
+ start-managed <serverUrl> <apiKey>
511
+ Upsert one agent into the per-serverUrl local daemon and exit after reconcile
512
+ describe-managed <serverUrl> Print managed-runtime spec JSON for machine callers
513
+ cleanup-managed <serverUrl> Stop one managed-runtime daemon locally; --purge also removes its runtime root
514
+ apply-managed <serverUrl> Apply one managed-runtime full-set spec for machine callers
515
+ log <serverUrl> Print the managed daemon log tail for one server runtime
242
516
  validate --config <path> Validate local-config files without starting agents or watchers
243
517
  describe --config <path> Print the current managed full-set spec as JSON
244
518
  print-layout --root <dir> Print the canonical default local-config layout as JSON
@@ -247,8 +521,15 @@ Local-config mode:
247
521
  Compatibility input; JSON is exposed in process arguments
248
522
 
249
523
  Examples:
250
- agents-host start https://borgee.example.com bgr_xxxxxxxx --provider copilot
251
- agents-host start --config ./agents-host.yaml
524
+ agents-host start https://borgee.example.com bgr_xxxxxxxx --provider copilot --debug
525
+ agents-host start-managed https://borgee.example.com
526
+ agents-host start-managed https://borgee.example.com bgr_xxxxxxxx --provider copilot
527
+ agents-host describe-managed https://borgee.example.com
528
+ agents-host cleanup-managed https://borgee.example.com --purge
529
+ 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
530
+ agents-host log https://borgee.example.com --lines 200 --follow
531
+ agents-host log https://borgee.example.com --path
532
+ agents-host start --config ./agents-host.yaml --debug
252
533
  agents-host validate --config ./agents-host.yaml
253
534
  agents-host describe --config ./agents-host.yaml
254
535
  agents-host print-layout --root ./runtime-root
package/dist/cli.d.ts CHANGED
@@ -1,14 +1,23 @@
1
1
  #!/usr/bin/env node
2
+ import { applyManagedSpec, bootstrapManagedDaemonStart, cleanupManagedRuntime, describeManagedSpec } from './managed-daemon.js';
3
+ import { runManagedDaemonLogCommand } from './managed-daemon-log.js';
2
4
  import { describeLocalConfig, generateLocalConfig, printLocalConfigLayout, runMain, validateLocalConfig } from './run.js';
3
5
  export interface CliDeps {
4
6
  env?: NodeJS.ProcessEnv;
5
7
  logger?: Pick<Console, 'error'>;
6
8
  runMain?: typeof runMain;
9
+ bootstrapManagedDaemonStart?: typeof bootstrapManagedDaemonStart;
10
+ startManagedDaemon?: (rootPath: string, debug: boolean) => Promise<void>;
7
11
  validateLocalConfig?: typeof validateLocalConfig;
8
12
  describeLocalConfig?: typeof describeLocalConfig;
9
13
  printLocalConfigLayout?: typeof printLocalConfigLayout;
10
14
  generateLocalConfig?: typeof generateLocalConfig;
11
15
  readStdin?: () => Promise<string>;
16
+ runManagedDaemonLogCommand?: typeof runManagedDaemonLogCommand;
17
+ describeManagedSpec?: typeof describeManagedSpec;
18
+ cleanupManagedRuntime?: typeof cleanupManagedRuntime;
19
+ applyManagedSpec?: typeof applyManagedSpec;
20
+ stdout?: Pick<Console, 'log'>;
12
21
  }
13
22
  interface CliEntrypointDeps {
14
23
  realpath?: (path: string) => string;