@borgee/agents-host 0.2.31 → 0.2.33
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.
- package/README.md +64 -0
- package/dist/chat/sdk-chat-control-plane.d.ts +1 -1
- package/dist/chat/sdk-chat-control-plane.js +1 -1
- package/dist/cli-args.d.ts +3 -1
- package/dist/cli-args.js +16 -0
- package/dist/cli.d.ts +4 -0
- package/dist/cli.js +12 -1
- package/dist/context/prompt.js +1 -1
- package/dist/durable-cursor-store.d.ts +1 -1
- package/dist/durable-cursor-store.js +1 -1
- package/dist/gateway/localhost-gateway.js +30 -2
- package/dist/index.js +4 -1
- package/dist/plugin-sdk.js +5131 -0
- package/dist/plugin-sdk.js.map +7 -0
- package/dist/policy/authorization-audit.d.ts +1 -0
- package/dist/policy/gateway-authorization.d.ts +1 -1
- package/dist/policy/gateway-authorization.js +27 -4
- package/dist/state-paths.d.ts +5 -0
- package/dist/state-paths.js +12 -0
- package/dist/update/package-installation.d.ts +52 -0
- package/dist/update/package-installation.js +90 -0
- package/dist/update/package-manager.d.ts +33 -0
- package/dist/update/package-manager.js +137 -0
- package/dist/update/semantic-version.d.ts +7 -0
- package/dist/update/semantic-version.js +76 -0
- package/dist/update/update-command.d.ts +9 -0
- package/dist/update/update-command.js +55 -0
- package/dist/update/update-notice.d.ts +39 -0
- package/dist/update/update-notice.js +161 -0
- package/package.json +8 -5
- package/skills/borgee-agent/SKILL.md +5 -3
- package/skills/borgee-agent/borgee-agent.mjs +54 -21
- package/skills/borgee-agent/borgee-agent.py +53 -26
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
|
|
@@ -232,6 +233,7 @@ 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
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. |
|
|
@@ -506,6 +508,68 @@ There is no separate transcript/history store on our side. Claude, Codex, and
|
|
|
506
508
|
Copilot only persist the native session ids they should try to resume later;
|
|
507
509
|
cross-host continuity still does not exist in this runtime.
|
|
508
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
|
+
|
|
509
573
|
## Testing
|
|
510
574
|
|
|
511
575
|
```bash
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { type BorgeePluginClient, type BorgeePluginOptions, type InboundMessageEvent } from '
|
|
1
|
+
import { type BorgeePluginClient, type BorgeePluginOptions, type InboundMessageEvent } from '../plugin-sdk.js';
|
|
2
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
4
|
type PluginClientLike = Pick<BorgeePluginClient, 'agentId' | 'close' | 'connect' | 'createTask' | 'deleteMessage' | 'editMessage' | 'getMe' | 'getTask' | 'listChannels' | 'listTasks' | 'listUsers' | 'on' | 'readHistory' | 'sendMessage' | 'startTyping' | 'updateTask'>;
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { createBorgeePlugin, } from '
|
|
1
|
+
import { createBorgeePlugin, } from '../plugin-sdk.js';
|
|
2
2
|
/**
|
|
3
3
|
* Thin adapter over `@borgee/plugin-sdk` (the same BPP/`/ws/plugin` SDK used by
|
|
4
4
|
* the OpenClaw plugin) that implements the minimal `ChatControlPlane` surface
|
package/dist/cli-args.d.ts
CHANGED
|
@@ -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
|
-
|
|
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)
|
|
@@ -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() {
|
package/dist/context/prompt.js
CHANGED
|
@@ -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') {
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { existsSync } from 'node:fs';
|
|
2
2
|
import { createServer } from 'node:http';
|
|
3
3
|
import { randomUUID } from 'node:crypto';
|
|
4
|
-
import { BorgeeError, PermissionDeniedError } from '
|
|
4
|
+
import { BorgeeError, PermissionDeniedError } from '../plugin-sdk.js';
|
|
5
5
|
import { SqliteConnectionsStateStore } from '../connections-state-store.js';
|
|
6
6
|
import { evaluateGatewayAuthorization, } from '../policy/gateway-authorization.js';
|
|
7
7
|
import { resolveConnectionsStatePath } from '../state-paths.js';
|
|
@@ -505,6 +505,33 @@ class LoopbackLocalhostGatewayController {
|
|
|
505
505
|
this.recordAudit('authorized', 200, decision.path, request.method ?? 'GET', decision.binding);
|
|
506
506
|
return;
|
|
507
507
|
}
|
|
508
|
+
case 'task-history': {
|
|
509
|
+
// The thread this reads is the one the server recorded on the task: thread_id is
|
|
510
|
+
// written once by task creation and is not part of the task update whitelist, so no
|
|
511
|
+
// client can repoint an in-scope task at another channel's messages after the check.
|
|
512
|
+
const task = await this.loadAuthorizedTask(binding.channelId, decision.route);
|
|
513
|
+
if (!task.threadId) {
|
|
514
|
+
this.sendJson(response, 404, { error: 'not_found' });
|
|
515
|
+
this.recordAudit('not-found', 404, decision.path, request.method ?? 'GET', decision.binding);
|
|
516
|
+
return;
|
|
517
|
+
}
|
|
518
|
+
const url = new URL(request.url ?? '/', baseUrl);
|
|
519
|
+
const limit = clampHistoryLimit(url.searchParams.get('limit'));
|
|
520
|
+
const before = parseOptionalInteger(url.searchParams.get('before'));
|
|
521
|
+
const after = parseOptionalInteger(url.searchParams.get('after'));
|
|
522
|
+
const messages = await this.controlPlane.readChannelHistory({
|
|
523
|
+
channelId: task.threadId,
|
|
524
|
+
before,
|
|
525
|
+
after,
|
|
526
|
+
limit,
|
|
527
|
+
});
|
|
528
|
+
this.sendJson(response, 200, { messages });
|
|
529
|
+
// Presence of `readChannelId` is the cross-channel disclosure signal, so it is
|
|
530
|
+
// stamped only when the thread really is another channel; a task read from inside
|
|
531
|
+
// its own thread would otherwise imply a disclosure that never happened.
|
|
532
|
+
this.recordAudit('authorized', 200, decision.path, request.method ?? 'GET', decision.binding, task.threadId === binding.channelId ? undefined : { readChannelId: task.threadId });
|
|
533
|
+
return;
|
|
534
|
+
}
|
|
508
535
|
case 'users': {
|
|
509
536
|
if (!binding.payload?.localhostGateway?.collaboration?.enabled) {
|
|
510
537
|
this.sendJson(response, 404, { error: 'not_found' });
|
|
@@ -604,7 +631,7 @@ class LoopbackLocalhostGatewayController {
|
|
|
604
631
|
response.setHeader('content-type', 'application/json; charset=utf-8');
|
|
605
632
|
response.end(`${JSON.stringify(payload)}\n`);
|
|
606
633
|
}
|
|
607
|
-
recordAudit(reason, status, path, method, binding) {
|
|
634
|
+
recordAudit(reason, status, path, method, binding, readTarget) {
|
|
608
635
|
if (!this.policyAuditGateEnabled) {
|
|
609
636
|
return;
|
|
610
637
|
}
|
|
@@ -616,6 +643,7 @@ class LoopbackLocalhostGatewayController {
|
|
|
616
643
|
reason,
|
|
617
644
|
agentId: binding?.agentId,
|
|
618
645
|
channelId: binding?.channelId,
|
|
646
|
+
...readTarget,
|
|
619
647
|
method,
|
|
620
648
|
path,
|
|
621
649
|
status,
|
package/dist/index.js
CHANGED
|
@@ -1,11 +1,14 @@
|
|
|
1
1
|
import { resolveAgentsHostDebugMode } from './debug.js';
|
|
2
2
|
import { runMain } from './run.js';
|
|
3
|
+
import { emitUpdateNotice } from './update/update-notice.js';
|
|
3
4
|
// Plain env-var entry point (`pnpm dev` / `pnpm start`) for the standalone
|
|
4
5
|
// single-agent process. For the CLI entry point that accepts foreground
|
|
5
6
|
// `agents-host start <serverUrl> <apiKey> ...` and opt-in
|
|
6
7
|
// `agents-host start-managed <serverUrl>` / `agents-host start-managed <serverUrl> <apiKey> ...`,
|
|
7
8
|
// see cli.ts.
|
|
8
|
-
|
|
9
|
+
emitUpdateNotice({ env: process.env })
|
|
10
|
+
.then(() => runMain({ debug: resolveAgentsHostDebugMode(false, process.env) }))
|
|
11
|
+
.catch((error) => {
|
|
9
12
|
console.error('[agents-host] fatal error:', error);
|
|
10
13
|
process.exitCode = 1;
|
|
11
14
|
});
|