@tt-a1i/hive 1.4.4 → 1.6.0
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/CHANGELOG.md +47 -0
- package/README.en.md +21 -0
- package/README.md +16 -0
- package/assets/qq-group.jpg +0 -0
- package/dist/bin/team.cmd +1 -0
- package/dist/src/cli/hive-update.d.ts +45 -17
- package/dist/src/cli/hive-update.js +63 -25
- package/dist/src/cli/hive.d.ts +25 -0
- package/dist/src/cli/hive.js +41 -3
- package/dist/src/cli/team.d.ts +1 -0
- package/dist/src/cli/team.js +216 -3
- package/dist/src/server/agent-command-resolver.js +3 -19
- package/dist/src/server/agent-manager-support.d.ts +2 -2
- package/dist/src/server/agent-manager-support.js +98 -24
- package/dist/src/server/agent-run-starter.d.ts +6 -1
- package/dist/src/server/agent-run-starter.js +9 -2
- package/dist/src/server/agent-run-store.d.ts +1 -1
- package/dist/src/server/agent-runtime-close.d.ts +1 -0
- package/dist/src/server/agent-runtime-close.js +25 -1
- package/dist/src/server/agent-runtime-contract.d.ts +12 -1
- package/dist/src/server/agent-runtime-stop-run.d.ts +1 -1
- package/dist/src/server/agent-runtime-stop-run.js +4 -1
- package/dist/src/server/agent-runtime.d.ts +2 -1
- package/dist/src/server/agent-runtime.js +14 -3
- package/dist/src/server/agent-startup-instructions.d.ts +7 -1
- package/dist/src/server/agent-startup-instructions.js +17 -9
- package/dist/src/server/agent-stdin-dispatcher.d.ts +25 -5
- package/dist/src/server/agent-stdin-dispatcher.js +141 -40
- package/dist/src/server/cron-util.d.ts +7 -0
- package/dist/src/server/cron-util.js +19 -0
- package/dist/src/server/dispatch-ledger-store.d.ts +22 -0
- package/dist/src/server/dispatch-ledger-store.js +51 -3
- package/dist/src/server/env-sync-message.js +9 -9
- package/dist/src/server/feature-flags.d.ts +42 -0
- package/dist/src/server/feature-flags.js +24 -0
- package/dist/src/server/fs-pick-folder.js +4 -0
- package/dist/src/server/fs-sandbox.js +36 -7
- package/dist/src/server/hive-team-guidance.d.ts +12 -6
- package/dist/src/server/hive-team-guidance.js +253 -71
- package/dist/src/server/live-run-registry.d.ts +1 -0
- package/dist/src/server/live-run-registry.js +1 -1
- package/dist/src/server/open-target-commands.js +5 -6
- package/dist/src/server/orchestrator-autostart.d.ts +12 -0
- package/dist/src/server/orchestrator-autostart.js +15 -13
- package/dist/src/server/path-canonicalization.d.ts +3 -0
- package/dist/src/server/path-canonicalization.js +29 -0
- package/dist/src/server/platform-path.d.ts +3 -0
- package/dist/src/server/platform-path.js +13 -0
- package/dist/src/server/post-start-input-writer.d.ts +1 -1
- package/dist/src/server/post-start-input-writer.js +110 -13
- package/dist/src/server/preset-launch-support.d.ts +1 -1
- package/dist/src/server/preset-launch-support.js +33 -2
- package/dist/src/server/recovery-summary.d.ts +5 -1
- package/dist/src/server/recovery-summary.js +18 -17
- package/dist/src/server/report-outbox-store.d.ts +36 -0
- package/dist/src/server/report-outbox-store.js +33 -0
- package/dist/src/server/restart-policy-support.d.ts +5 -1
- package/dist/src/server/restart-policy-support.js +9 -1
- package/dist/src/server/restart-policy.d.ts +6 -2
- package/dist/src/server/restart-policy.js +51 -31
- package/dist/src/server/role-template-store.d.ts +1 -0
- package/dist/src/server/role-template-store.js +11 -1
- package/dist/src/server/route-types.d.ts +43 -0
- package/dist/src/server/routes-runtime.js +2 -1
- package/dist/src/server/routes-settings.js +76 -0
- package/dist/src/server/routes-tasks.js +23 -0
- package/dist/src/server/routes-team.js +211 -1
- package/dist/src/server/routes-workflow-schedules.d.ts +2 -0
- package/dist/src/server/routes-workflow-schedules.js +58 -0
- package/dist/src/server/routes-workflows.d.ts +2 -0
- package/dist/src/server/routes-workflows.js +83 -0
- package/dist/src/server/routes-workspaces.js +5 -0
- package/dist/src/server/routes.js +4 -0
- package/dist/src/server/runtime-restart-policy.d.ts +3 -1
- package/dist/src/server/runtime-restart-policy.js +2 -1
- package/dist/src/server/runtime-store-contract.d.ts +125 -0
- package/dist/src/server/runtime-store-contract.js +1 -0
- package/dist/src/server/runtime-store-helpers.d.ts +11 -0
- package/dist/src/server/runtime-store-helpers.js +106 -2
- package/dist/src/server/runtime-store-workflows.d.ts +6 -0
- package/dist/src/server/runtime-store-workflows.js +108 -0
- package/dist/src/server/runtime-store.d.ts +3 -72
- package/dist/src/server/runtime-store.js +71 -4
- package/dist/src/server/session-capture-codex.d.ts +3 -3
- package/dist/src/server/session-capture-codex.js +9 -7
- package/dist/src/server/session-capture-gemini.d.ts +1 -1
- package/dist/src/server/session-capture-gemini.js +6 -3
- package/dist/src/server/settings-store.d.ts +3 -0
- package/dist/src/server/settings-store.js +1 -0
- package/dist/src/server/sqlite-schema-v19.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v19.js +17 -0
- package/dist/src/server/sqlite-schema-v20.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v20.js +20 -0
- package/dist/src/server/sqlite-schema-v21.d.ts +2 -0
- package/dist/src/server/sqlite-schema-v21.js +20 -0
- package/dist/src/server/sqlite-schema.d.ts +1 -1
- package/dist/src/server/sqlite-schema.js +110 -1
- package/dist/src/server/system-message.d.ts +7 -0
- package/dist/src/server/system-message.js +8 -1
- package/dist/src/server/task-deps.d.ts +32 -0
- package/dist/src/server/task-deps.js +40 -0
- package/dist/src/server/tasks-file-watcher.d.ts +12 -1
- package/dist/src/server/tasks-file-watcher.js +128 -23
- package/dist/src/server/tasks-file.d.ts +3 -1
- package/dist/src/server/tasks-file.js +33 -9
- package/dist/src/server/tasks-websocket-server.js +13 -14
- package/dist/src/server/team-authz.d.ts +1 -1
- package/dist/src/server/team-authz.js +10 -1
- package/dist/src/server/team-autostaff.d.ts +16 -0
- package/dist/src/server/team-autostaff.js +16 -0
- package/dist/src/server/team-list-serializer.d.ts +1 -1
- package/dist/src/server/team-list-serializer.js +3 -1
- package/dist/src/server/team-operations.d.ts +21 -1
- package/dist/src/server/team-operations.js +183 -16
- package/dist/src/server/terminal-protocol.js +9 -3
- package/dist/src/server/terminal-stream-hub.js +16 -10
- package/dist/src/server/terminal-ws-server.js +10 -8
- package/dist/src/server/webhook-notifier.d.ts +34 -0
- package/dist/src/server/webhook-notifier.js +47 -0
- package/dist/src/server/websocket-upgrade-safety.d.ts +10 -0
- package/dist/src/server/websocket-upgrade-safety.js +35 -0
- package/dist/src/server/windows-command-line.d.ts +3 -0
- package/dist/src/server/windows-command-line.js +9 -0
- package/dist/src/server/windows-filename.d.ts +2 -0
- package/dist/src/server/windows-filename.js +33 -0
- package/dist/src/server/workflow-cli-policy.d.ts +60 -0
- package/dist/src/server/workflow-cli-policy.js +110 -0
- package/dist/src/server/workflow-dispatch-awaiter.d.ts +12 -0
- package/dist/src/server/workflow-dispatch-awaiter.js +80 -0
- package/dist/src/server/workflow-feature.d.ts +15 -0
- package/dist/src/server/workflow-feature.js +15 -0
- package/dist/src/server/workflow-http-serializers.d.ts +64 -0
- package/dist/src/server/workflow-http-serializers.js +58 -0
- package/dist/src/server/workflow-output-schema.d.ts +18 -0
- package/dist/src/server/workflow-output-schema.js +41 -0
- package/dist/src/server/workflow-run-log-store.d.ts +19 -0
- package/dist/src/server/workflow-run-log-store.js +45 -0
- package/dist/src/server/workflow-run-store.d.ts +50 -0
- package/dist/src/server/workflow-run-store.js +103 -0
- package/dist/src/server/workflow-runner.d.ts +147 -0
- package/dist/src/server/workflow-runner.js +411 -0
- package/dist/src/server/workflow-schedule-create.d.ts +14 -0
- package/dist/src/server/workflow-schedule-create.js +41 -0
- package/dist/src/server/workflow-schedule-store.d.ts +43 -0
- package/dist/src/server/workflow-schedule-store.js +112 -0
- package/dist/src/server/workflow-scheduler.d.ts +36 -0
- package/dist/src/server/workflow-scheduler.js +97 -0
- package/dist/src/server/workflow-script-loader.d.ts +34 -0
- package/dist/src/server/workflow-script-loader.js +106 -0
- package/dist/src/server/workspace-path-validation.js +16 -4
- package/dist/src/server/workspace-shell-runtime.d.ts +5 -0
- package/dist/src/server/workspace-shell-runtime.js +24 -2
- package/dist/src/server/workspace-store-contract.d.ts +4 -1
- package/dist/src/server/workspace-store-hydration.js +23 -7
- package/dist/src/server/workspace-store-mutations.js +2 -5
- package/dist/src/server/workspace-store-support.d.ts +4 -0
- package/dist/src/server/workspace-store-support.js +13 -1
- package/dist/src/server/workspace-store.js +38 -4
- package/dist/src/shared/types.d.ts +16 -1
- package/package.json +4 -2
- package/web/dist/assets/{AddWorkerDialog-DeZhTQLi.js → AddWorkerDialog-CGbaxu0T.js} +2 -2
- package/web/dist/assets/AddWorkspaceDialog-CNgExu6b.js +1 -0
- package/web/dist/assets/{FirstRunWizard-B5wLcat5.js → FirstRunWizard-DxGApUNc.js} +1 -1
- package/web/dist/assets/{MarketplaceDrawer-BC0eBOEW.js → MarketplaceDrawer-Bk6cpukn.js} +1 -1
- package/web/dist/assets/WhatsNewDialog-CSGzk-2U.js +1 -0
- package/web/dist/assets/WorkerModal-i2F3n3nZ.js +1 -0
- package/web/dist/assets/WorkspaceTaskDrawer-C_Ta_K13.js +1 -0
- package/web/dist/assets/WorkspaceTerminalPanels-VdDxtrQF.js +1 -0
- package/web/dist/assets/index-5zh61jMg.css +1 -0
- package/web/dist/assets/index-CAgGM6nb.js +75 -0
- package/web/dist/assets/path-join-7MR1s7b1.js +1 -0
- package/web/dist/index.html +2 -2
- package/web/dist/sw.js +1 -1
- package/web/dist/assets/AddWorkspaceDialog-DDpXNEKf.js +0 -1
- package/web/dist/assets/WorkerModal-BwMHq-Bi.js +0 -1
- package/web/dist/assets/WorkspaceTaskDrawer-CxvT4nqs.js +0 -1
- package/web/dist/assets/WorkspaceTerminalPanels-CvibsPSd.js +0 -1
- package/web/dist/assets/index-BEsTmfrO.css +0 -1
- package/web/dist/assets/index-Ddb7bDN5.js +0 -75
- package/web/dist/assets/path-join-S7qkXQtP.js +0 -1
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { FEATURE_FLAGS_ALL_OFF } from './feature-flags.js';
|
|
2
|
+
import { DEFAULT_WORKFLOW_CLI_POLICY } from './workflow-cli-policy.js';
|
|
1
3
|
/**
|
|
2
4
|
* Tail reminder appended to every message that flows INTO the orchestrator
|
|
3
5
|
* (worker reports, worker status updates, user chat input). Re-anchors the
|
|
@@ -10,12 +12,25 @@
|
|
|
10
12
|
* banner noise after a few occurrences, but `<...-system-reminder>` tags
|
|
11
13
|
* mirror the out-of-band envelope LLMs are trained to attend to; placement
|
|
12
14
|
* at the tail (right before the agent's reply turn) maximizes recency
|
|
13
|
-
* weighting; phrasing as a
|
|
14
|
-
*
|
|
15
|
+
* weighting; phrasing as a short action menu is more actionable than abstract
|
|
16
|
+
* identity restatement. Kept deliberately SHORT — the full command syntax and
|
|
17
|
+
* the workflow DSL live in `.hive/PROTOCOL.md`, which agents re-read on demand.
|
|
18
|
+
* A long banner on every turn is itself the noise this envelope exists to beat.
|
|
15
19
|
*/
|
|
16
|
-
export const
|
|
17
|
-
'You are the Hive Orchestrator. Reply
|
|
18
|
-
|
|
20
|
+
export const buildOrchestratorReminderTail = ({ workflowsEnabled }) => {
|
|
21
|
+
const body = 'You are the Hive Orchestrator. Reply with one of: ' +
|
|
22
|
+
'(a) `team send "<worker-name>" "<task>"` to dispatch — run `team list` first if the roster may have changed since your last view (Hive does not push membership changes; stale names fail). ' +
|
|
23
|
+
'If no worker fits or the roster is empty, `team spawn <role> [--cli claude|codex|opencode|gemini]` to create one (add `--ephemeral` for a one-shot), then dispatch; do not ask the user to add workers. ' +
|
|
24
|
+
'(b) `team cancel --dispatch <id> "<reason>"` to close an obsolete dispatch. ' +
|
|
25
|
+
(workflowsEnabled
|
|
26
|
+
? '(c) `team workflow run --stdin` to fan out across 3+ workers or run a staged review→fix — never a loop of `team send` (no barrier, no UI group, no stop button). (d) plain text to the user. '
|
|
27
|
+
: '(c) plain text to the user. ') +
|
|
28
|
+
`Do not use your CLI's own subagent${workflowsEnabled ? ' / workflow' : ''} tools — they run inside your CLI, bypass Hive, and never reach the UI or \`team list\`. ` +
|
|
29
|
+
(workflowsEnabled
|
|
30
|
+
? 'Full command syntax and the workflow DSL: re-read `.hive/PROTOCOL.md`.'
|
|
31
|
+
: 'Full command syntax: re-read `.hive/PROTOCOL.md`.');
|
|
32
|
+
return `<hive-system-reminder>\n${body}\n</hive-system-reminder>`;
|
|
33
|
+
};
|
|
19
34
|
/**
|
|
20
35
|
* Tail reminder appended to dispatches sent TO a worker. Reinforces the
|
|
21
36
|
* worker identity (so the agent does not regress into its normal CLI
|
|
@@ -23,80 +38,247 @@ export const ORCHESTRATOR_REMINDER_TAIL = '<hive-system-reminder>\n' +
|
|
|
23
38
|
* with dispatch_id pre-bound.
|
|
24
39
|
*/
|
|
25
40
|
export const buildWorkerReminderTail = (dispatchId) => '<hive-system-reminder>\n' +
|
|
26
|
-
`You are a Hive Worker. Do not launch nested CLI subagents
|
|
41
|
+
`You are a Hive Worker. Do not launch nested CLI subagents — finish the task yourself. When the task is done, blocked, or has failed, report with: \`team report "<result>" --dispatch ${dispatchId}\` (or \`team report --stdin --dispatch ${dispatchId}\` for long bodies).\n` +
|
|
27
42
|
'</hive-system-reminder>';
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
'
|
|
37
|
-
'`team list`
|
|
43
|
+
/**
|
|
44
|
+
* Core, always-on orchestrator rules. Injected at startup, on crash recovery,
|
|
45
|
+
* and on restart env-sync. Deliberately free of multi-line code skeletons —
|
|
46
|
+
* those are reference material that lives in `.hive/PROTOCOL.md` (see
|
|
47
|
+
* WORKFLOW_DSL_REFERENCE) so the recovery / env-sync paths re-anchor identity
|
|
48
|
+
* and dispatch discipline without re-injecting a wall of example JS.
|
|
49
|
+
*/
|
|
50
|
+
const CORE_ORCHESTRATOR_RULES = [
|
|
51
|
+
'A Hive worker is a real CLI agent shown as a card on the right — NOT a subagent of your own CLI.',
|
|
52
|
+
'Dispatch against the current roster: re-run `team list` before a `team send` whenever a user reply or one of your own dispatches/cancels has happened since your last list. Hive never pushes membership changes, so do not dispatch from a remembered roster — a renamed or removed worker fails.',
|
|
53
|
+
'Small, low-risk tasks you can finish in a couple of minutes: do them yourself; do not dispatch for the sake of form. Reach for `team send` when the work needs parallelism, long execution, independent review/test, a dedicated role, or the user explicitly asked for a worker.',
|
|
54
|
+
'If exactly one worker is available, dispatch to it directly with `team send <worker-name> "<task>"` — do not bounce the choice back to the user.',
|
|
55
|
+
'When the user says "have a worker do X", dispatch it with `team send <worker-name> "<task>"`.',
|
|
56
|
+
'If the roster is empty or lacks the role the task needs, build the team yourself: `team spawn <role> [--name <n>] [--cli claude|codex|opencode|gemini]`, then immediately dispatch. Do not stop to ask the user to add members — that call is yours.',
|
|
57
|
+
'`team spawn` is PERSISTENT by default (a normal member that stays in the workspace); add `--ephemeral` for a one-shot worker that auto-dismisses after its first `team report`. Rule of thumb: will you reuse this role in the next 10 minutes? Yes → persistent; no → `--ephemeral`.',
|
|
58
|
+
'When the user cancels or changes direction on an open dispatch, close it explicitly with `team cancel --dispatch <id> "<reason>"` — do not just say "cancel" in prose.',
|
|
59
|
+
'Each `team send` opens a SEPARATE dispatch with its own pending count and its own required report — it is not a way to tack context onto a dispatch already in flight. Send the same worker twice and it owes you TWO reports; one report closes only one dispatch (the one its `--dispatch <id>` names, or the oldest open one if the flag is omitted), so the other stays open and the worker is pinned on `working`. To change or extend an in-flight task, `team cancel --dispatch <id> "<reason>"` the stale dispatch and re-send the whole task, or wait for the worker to report and dispatch the follow-up after.',
|
|
60
|
+
"Never substitute your CLI's own subagent / workflow tools (e.g. Task / Explore / Workflow / Agent) for Hive workers or Hive workflows — they run inside your CLI process, bypass Hive's PTY fleet, never appear in the UI or `team list`, and the stop button cannot reach them.",
|
|
61
|
+
'In `team list`, `last_pty_line` is raw terminal output (stdout / help / control-sequence noise), NOT a worker\'s report. A real report arrives only as an injected "report from @<name>" / "status from @<name>" system message — treat only those as replies.',
|
|
62
|
+
];
|
|
63
|
+
/**
|
|
64
|
+
* Workflow-authoring rule — only injected when the experimental workflow
|
|
65
|
+
* feature is ENABLED. When workflows are off the orchestrator is never told
|
|
66
|
+
* to reach for `team workflow`, which keeps its always-on prompt lean and
|
|
67
|
+
* avoids it firing a command the runtime will reject.
|
|
68
|
+
*/
|
|
69
|
+
const WORKFLOW_ORCHESTRATOR_RULES = [
|
|
70
|
+
'Choosing to use a workflow is YOUR call, judged from the task\'s shape — the user describes what they want in plain language and will not (and need not) ask for a "workflow" by name. When a task fans out across 3+ workers, needs a staged review→fix, or loops until results converge, author the workflow script yourself from the task and fire it with ONE `team workflow run --stdin` — decide this on your own, do not wait to be told, and do not approximate it with a loop of `team send` (no barrier, no UI grouping, no stop button). The DSL and ready-made patterns are in `.hive/PROTOCOL.md`.',
|
|
71
|
+
];
|
|
72
|
+
/**
|
|
73
|
+
* Auto-staff rule — only injected when the experimental auto-staff feature is
|
|
74
|
+
* ENABLED (ON by default). Grants + encourages the orchestrator to size the
|
|
75
|
+
* team to the task instead of adding workers one at a time. The shared-FS +
|
|
76
|
+
* ephemeral notes are operating instructions (Hive gives every worker the same
|
|
77
|
+
* workspace root with no per-worker isolation), not optional caution: without
|
|
78
|
+
* them parallel coders overwrite each other.
|
|
79
|
+
*
|
|
80
|
+
* The text adapts to whether workflows are ALSO on: there is no batch `team
|
|
81
|
+
* spawn` syntax (one command per member), so it says exactly that; and when
|
|
82
|
+
* workflows are available it defers one-shot batch fan-out to `team workflow
|
|
83
|
+
* run` so the two experiments don't give the orchestrator competing advice.
|
|
84
|
+
*/
|
|
85
|
+
const buildAutostaffRule = (workflowsEnabled) => 'You may size the team to the task instead of adding workers one at a time: judge what mix of roles runs it fastest (e.g. a couple of coders plus a reviewer and a tester) and issue the individual `team spawn <role> --ephemeral` commands you need up front — one command per member (there is no batch form), this call is yours, do not ask the user. Match the count to the work: more agents is not faster once they would collide or sit idle. CRITICAL: all workers share the same workspace files with NO per-worker isolation, so split the work so no two agents touch the same files/modules. Use `--ephemeral` so this task-scoped staff auto-dismiss after reporting and do not pile up.' +
|
|
86
|
+
(workflowsEnabled
|
|
87
|
+
? ' When the work is a one-shot fan-out across 3+ workers or a staged review→fix that runs to completion, prefer `team workflow run` (barrier, phase tree, stop button) over a batch of `team spawn`; reserve up-front staffing for a standing team you direct interactively across several turns.'
|
|
88
|
+
: '');
|
|
89
|
+
const orchestratorRules = ({ workflowsEnabled, autostaffEnabled, }) => [
|
|
90
|
+
...CORE_ORCHESTRATOR_RULES,
|
|
91
|
+
...(workflowsEnabled ? WORKFLOW_ORCHESTRATOR_RULES : []),
|
|
92
|
+
...(autostaffEnabled ? [buildAutostaffRule(workflowsEnabled)] : []),
|
|
38
93
|
];
|
|
39
94
|
const WORKER_RULES = [
|
|
40
|
-
'
|
|
41
|
-
|
|
42
|
-
'
|
|
43
|
-
'
|
|
44
|
-
'`team --help`
|
|
45
|
-
'`team report` / `team status`
|
|
95
|
+
'You are a real CLI worker shown as a card on the right in Hive — not a subagent of your own CLI.',
|
|
96
|
+
"Do not call `team send`, and do not launch your own CLI's subagent tools to do the work for you — finish it yourself.",
|
|
97
|
+
'When an assigned task is done, blocked, or has failed, you MUST report to the Orchestrator with `team report`.',
|
|
98
|
+
'When you have no active dispatch and only want to report readiness, environment, or status, use `team status "<state>"`.',
|
|
99
|
+
'`team --help` only prints command syntax — it is NOT a way to report; its output never reaches the Orchestrator. You still owe a real `team report` / `team status` afterward.',
|
|
100
|
+
'If `team report` / `team status` errors, it also prints USAGE — fix the arguments per USAGE and retry; do not use `team --help` as a stand-in for reporting.',
|
|
46
101
|
];
|
|
47
|
-
export const getHiveTeamRules = (agent) => agent.role === 'orchestrator' ?
|
|
102
|
+
export const getHiveTeamRules = (agent, flags = FEATURE_FLAGS_ALL_OFF) => (agent.role === 'orchestrator' ? orchestratorRules(flags) : WORKER_RULES);
|
|
48
103
|
const renderRules = (rules) => rules.map((line) => `- ${line}`).join('\n');
|
|
104
|
+
/**
|
|
105
|
+
* The workflow DSL teaching: agent()/parallel()/pipeline() semantics, the
|
|
106
|
+
* agent() opts surface, runnable skeletons, and the canonical patterns. This
|
|
107
|
+
* is REFERENCE material — it lives only in `.hive/PROTOCOL.md`, never in the
|
|
108
|
+
* per-message reminder or the recovery/env-sync injections, so the always-on
|
|
109
|
+
* paths stay lean. The orchestrator is pointed here by the core rules and the
|
|
110
|
+
* reminder tail whenever it needs to author a `team workflow run`.
|
|
111
|
+
*/
|
|
112
|
+
const WORKFLOW_DSL_REFERENCE = `## Workflow DSL (\`team workflow run --stdin\`)
|
|
113
|
+
|
|
114
|
+
Use a workflow when a task fans out beyond a single dispatch: 3+ parallel
|
|
115
|
+
workers, a staged review→fix, or a loop until results converge. The DSL mirrors
|
|
116
|
+
Claude Code's Workflow tool, but every \`agent()\` runs on Hive's PTY fleet — a
|
|
117
|
+
real CLI process — not an in-CLI API subagent. \`team workflow run\` is the only
|
|
118
|
+
entry into the Hive runtime; never use your CLI's own Workflow/Agent tool.
|
|
119
|
+
|
|
120
|
+
Host functions injected into the script: \`agent(prompt, opts)\`,
|
|
121
|
+
\`parallel(thunks)\`, \`pipeline(items, ...stages)\`, \`phase(title)\`,
|
|
122
|
+
\`log(msg)\`, plus the \`args\` global.
|
|
123
|
+
|
|
124
|
+
\`agent(prompt, opts)\` opts: \`{ agentType?: "coder"|"reviewer"|"tester"|"custom"|<custom-role-name>, cli?: "claude"|"codex"|"opencode"|"gemini", model?: string, outputSchema?: object, label?: string, timeoutMs?: number }\` — other fields are silently ignored. \`agentType\` also accepts the name of a workspace custom role template (case-insensitive); a typo throws rather than silently falling back to coder. \`model\` is passed through to the worker launch config (\`--model <id>\`), so a 100-way fan-out can use a cheap model and the synthesizer a strong one. \`outputSchema\` makes \`agent()\` resolve to a parsed object instead of a string: the worker is told to end its report with a fenced \`\`\`json block whose keys match the schema. On a parse miss it falls back to \`{ text: "<raw report>" }\`, so ALWAYS treat a missing field as the SAFE default (never assume success). The worker auto-dismisses when its \`agent()\` call resolves — you never dismiss it.
|
|
125
|
+
|
|
126
|
+
\`parallel()\` takes an array of THUNKS (\`() => agent(...)\`), NOT already-started promises: \`parallel([agent(...), agent(...)])\` degrades to unordered concurrency counted as a single step (a no-op grouping), because the promises already started at construction time. \`pipeline(items, ...stages)\` stages are also functions, shape \`(prev, item, i) => agent(...)\`.
|
|
127
|
+
|
|
128
|
+
\`log("...")\` writes one narrator line — stored in the DB, shown when the run row is expanded in the Drawer, and its last 8 lines are spliced into the completion reminder sent back to you. Use it for a readable progress summary, e.g. \`log('Discovered 47 endpoints')\`.
|
|
129
|
+
|
|
130
|
+
Runtime limits: each run defaults to at most 1000 \`agent()\` calls and 60 minutes wall-clock; the concurrency cap is \`min(16, cores-2)\` and parallel/pipeline queue against it automatically. Override in \`meta\`, e.g. \`meta = { name, description, maxAgentCalls: 50, maxDurationMs }\`.
|
|
131
|
+
|
|
132
|
+
\`meta\` must be a pure literal (no variables). Scripts are JS, not TS (type annotations error). The body may use top-level \`await\` and a trailing \`return\`.
|
|
133
|
+
|
|
134
|
+
Minimal script (heredoc into \`--stdin\`):
|
|
135
|
+
\`\`\`
|
|
136
|
+
export const meta = { name: 'review-changes', description: 'review + tests' }
|
|
137
|
+
phase('Find')
|
|
138
|
+
const issues = await agent('Run \`git diff\` and list any potential bugs.', { agentType: 'reviewer', label: 'review' })
|
|
139
|
+
phase('Verify')
|
|
140
|
+
const tests = await agent(\`Write tests for: \${issues}\`, { agentType: 'tester', label: 'verify' })
|
|
141
|
+
return { issues, tests }
|
|
142
|
+
\`\`\`
|
|
143
|
+
|
|
144
|
+
Parallel fan-out + multi-vendor mix (Hive's signature — several CLIs in one run):
|
|
145
|
+
\`\`\`
|
|
146
|
+
export const meta = { name: 'parallel-audit', description: 'audit N files in parallel' }
|
|
147
|
+
const files = ['src/a.ts', 'src/b.ts', 'src/c.ts']
|
|
148
|
+
phase('Audit')
|
|
149
|
+
const reports = await parallel(files.map((f) => () => agent(\`Audit \${f} for security bugs.\`, { agentType: 'reviewer', cli: 'codex', label: \`audit:\${f}\` })))
|
|
150
|
+
phase('Synthesize')
|
|
151
|
+
return await agent(\`Synthesize: \${reports.filter(Boolean).join('\\n---\\n')}\`, { agentType: 'reviewer', cli: 'claude', label: 'synth' })
|
|
152
|
+
\`\`\`
|
|
153
|
+
|
|
154
|
+
Passing args (so a saved script is reusable instead of hard-coding values):
|
|
155
|
+
\`\`\`
|
|
156
|
+
team workflow run --stdin --args '["src/a.ts","src/b.ts"]' <<'EOF'
|
|
157
|
+
export const meta = { name: 'audit', description: 'd' }
|
|
158
|
+
phase('Audit')
|
|
159
|
+
return await parallel(args.map((f) => () => agent(\`Audit \${f}\`)))
|
|
160
|
+
EOF
|
|
161
|
+
\`\`\`
|
|
162
|
+
\`--args\` takes JSON (\`'{"q":1}'\`, \`'["a","b"]'\`, \`'"plain"'\`); omitted → \`args\` is \`undefined\`.
|
|
163
|
+
|
|
164
|
+
Patterns worth knowing:
|
|
165
|
+
- **loop-until-dry** — stop after K empty rounds; more robust than \`while (count < N)\`, which stalls on the hard-to-find tail:
|
|
166
|
+
\`\`\`
|
|
167
|
+
const seen = new Set(), confirmed = []
|
|
168
|
+
let dry = 0
|
|
169
|
+
while (dry < 2) {
|
|
170
|
+
const found = await agent('Find any potential bugs not in: ' + [...seen].join(', '))
|
|
171
|
+
const fresh = found.split('\\n').filter((b) => b.trim() && !seen.has(b))
|
|
172
|
+
if (!fresh.length) { dry++; continue }
|
|
173
|
+
dry = 0
|
|
174
|
+
fresh.forEach((b) => { seen.add(b); confirmed.push(b) })
|
|
175
|
+
}
|
|
176
|
+
return confirmed
|
|
177
|
+
\`\`\`
|
|
178
|
+
- **judge panel** — N independent verifiers per finding; majority confirms. \`outputSchema\` makes each vote a typed object instead of fragile yes/no string-matching. Note the safe default: a parse miss has no \`refuted\` key, so \`v.refuted === false\` is false → the finding stays refuted and a malformed reply can never flip it to "confirmed":
|
|
179
|
+
\`\`\`
|
|
180
|
+
phase('Verify')
|
|
181
|
+
const votes = await parallel([
|
|
182
|
+
() => agent(\`Try to REFUTE: \${claim}. Default refuted=true if uncertain.\`, { outputSchema: { refuted: 'boolean' } }),
|
|
183
|
+
() => agent(\`Independently judge: \${claim}.\`, { outputSchema: { refuted: 'boolean' } }),
|
|
184
|
+
() => agent(\`Repro test: \${claim}. Did it reproduce?\`, { outputSchema: { refuted: 'boolean' } }),
|
|
185
|
+
])
|
|
186
|
+
// Only an explicit refuted:false counts as "survived"; missing/unparseable stays safely refuted.
|
|
187
|
+
const real = votes.filter((v) => v && v.refuted === false).length >= 2
|
|
188
|
+
\`\`\`
|
|
189
|
+
- **pipeline** — multi-item, multi-stage, no barrier between stages (item A can be in stage 3 while item B is in stage 1); wall-clock = slowest single item, not sum-of-slowest-per-stage. Each stage gets \`(prevResult, originalItem, index)\`; a stage that throws drops that item to null and skips its remaining stages.
|
|
190
|
+
|
|
191
|
+
On completion Hive injects \`<hive-system-reminder>Hive workflow ... finished: status=...</hive-system-reminder>\` carrying each step's short report; synthesize that back to the user. Full per-agent transcripts: \`team workflow show <run-id>\`.`;
|
|
49
192
|
/**
|
|
50
193
|
* Workspace-local protocol cheat sheet written to `.hive/PROTOCOL.md`. Agents
|
|
51
194
|
* are explicitly trained to look at project root markdown when confused, so
|
|
52
195
|
* keeping a single canonical doc next to `.hive/tasks.md` doubles as a
|
|
53
196
|
* "cat-recover" path when both the startup prompt and the in-message
|
|
54
|
-
* reminders fail to anchor.
|
|
197
|
+
* reminders fail to anchor. This is also the single home of the full command
|
|
198
|
+
* syntax and the workflow DSL reference — the always-on injections only carry
|
|
199
|
+
* the lean core rules and point here.
|
|
55
200
|
*/
|
|
56
|
-
export const buildProtocolDoc = () =>
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
201
|
+
export const buildProtocolDoc = (cliPolicy = DEFAULT_WORKFLOW_CLI_POLICY, flags = FEATURE_FLAGS_ALL_OFF) => {
|
|
202
|
+
const { workflowsEnabled } = flags;
|
|
203
|
+
// The `team workflow …` subcommands + the DSL reference + the per-workspace
|
|
204
|
+
// CLI-policy section only appear when the experimental workflow feature is
|
|
205
|
+
// ON. While off, the orchestrator's canonical reference never mentions
|
|
206
|
+
// workflows (leaner prompt) and never points at a command the runtime rejects.
|
|
207
|
+
const workflowCliCommands = workflowsEnabled
|
|
208
|
+
? [
|
|
209
|
+
"- `team workflow run --stdin` — fire a multi-agent workflow; pass JS source via stdin. Add `--args '<JSON>'` to set the script's `args` global.",
|
|
210
|
+
'- `team workflow run --inline "<source>"` — same, single-arg form',
|
|
211
|
+
'- `team workflow stop <run-id>` — cancel a running workflow',
|
|
212
|
+
'- `team workflow show <run-id>` — full per-agent transcript (status, phase, label, prompt, full reportText) — use this when the truncated completion reminder is not enough',
|
|
213
|
+
'- `team workflow schedule --cron "<5-field cron>" --name <n> --stdin` — register a RECURRING run; pass the same JS source you would give `run`. The source is persisted so cron can fire it with no orchestrator present. The UI can pause / delete schedules but never create them — scheduling is your job.',
|
|
214
|
+
]
|
|
215
|
+
: [];
|
|
216
|
+
const workflowSections = workflowsEnabled
|
|
217
|
+
? [
|
|
218
|
+
WORKFLOW_DSL_REFERENCE,
|
|
219
|
+
'',
|
|
220
|
+
'## Workflow agent CLIs (this workspace)',
|
|
221
|
+
'',
|
|
222
|
+
'When a workflow `agent()` omits `cli` it launches a worker on the default',
|
|
223
|
+
'CLI below; an explicit `cli:` must be one of the allowed CLIs or the run',
|
|
224
|
+
'fails with a clear error. (Custom role templates keep their own configured',
|
|
225
|
+
'CLI and are exempt from the allowlist.)',
|
|
226
|
+
'',
|
|
227
|
+
`- Default CLI when \`cli\` is omitted: **${cliPolicy.default}**`,
|
|
228
|
+
`- Allowed CLIs for \`cli\`: ${cliPolicy.allowed.join(', ')}`,
|
|
229
|
+
'',
|
|
230
|
+
]
|
|
231
|
+
: [];
|
|
232
|
+
return [
|
|
233
|
+
'# Hive Team Protocol',
|
|
234
|
+
'',
|
|
235
|
+
'This file is auto-generated by Hive on every workspace open. If you',
|
|
236
|
+
'(the agent) lost context after `/compact` or an internal summarization,',
|
|
237
|
+
're-read `.hive/PROTOCOL.md` (POSIX: `cat`, Windows cmd: `type`, PowerShell:',
|
|
238
|
+
'`Get-Content`) to re-anchor.',
|
|
239
|
+
'',
|
|
240
|
+
'## You are running inside Hive',
|
|
241
|
+
'',
|
|
242
|
+
'Hive is a multi-CLI-agent workbench. Each agent in this workspace is a',
|
|
243
|
+
'real CLI process (Claude Code / Codex / OpenCode / Gemini). All',
|
|
244
|
+
'inter-agent communication goes through the `team` CLI binary on your',
|
|
245
|
+
'PATH.',
|
|
246
|
+
'',
|
|
247
|
+
'## Roles',
|
|
248
|
+
'',
|
|
249
|
+
'- **Orchestrator** — talks to the user, plans tasks, dispatches to workers',
|
|
250
|
+
'- **Worker** (Coder / Reviewer / Tester / custom) — executes one assigned task and reports back',
|
|
251
|
+
'',
|
|
252
|
+
'## `team` CLI — orchestrator',
|
|
253
|
+
'',
|
|
254
|
+
'- `team list` — show workspace members and their status',
|
|
255
|
+
'- `team send "<worker-name>" "<task>"` — dispatch to a worker by name (never id)',
|
|
256
|
+
'- `team spawn <role> [--name <name>] [--cli claude|codex|opencode|gemini]` — create a PERSISTENT member when none fits (or when the roster is empty)',
|
|
257
|
+
'- `team spawn <role> --ephemeral [other-flags]` — create a one-shot worker that auto-dismisses after its first `team report`',
|
|
258
|
+
'- `team dismiss <worker-name>` — remove an ephemeral worker you spawned',
|
|
259
|
+
'- `team cancel --dispatch <id> "<reason>"` — cancel an obsolete open dispatch',
|
|
260
|
+
...workflowCliCommands,
|
|
261
|
+
'',
|
|
262
|
+
'## `team` CLI — worker',
|
|
263
|
+
'',
|
|
264
|
+
'- `team report "<result>" --dispatch <id>` — report task outcome',
|
|
265
|
+
'- `team report --stdin --dispatch <id>` — same, body from stdin (pipe content in via your shell — POSIX heredoc, `type file |`, or whatever your environment supports)',
|
|
266
|
+
'- `team status "<state>"` — update orchestrator when no dispatch is active',
|
|
267
|
+
'',
|
|
268
|
+
'## Orchestrator rules',
|
|
269
|
+
'',
|
|
270
|
+
renderRules(orchestratorRules(flags)),
|
|
271
|
+
'',
|
|
272
|
+
'## Worker rules',
|
|
273
|
+
'',
|
|
274
|
+
renderRules(WORKER_RULES),
|
|
275
|
+
'',
|
|
276
|
+
...workflowSections,
|
|
277
|
+
'## In-message reminders',
|
|
278
|
+
'',
|
|
279
|
+
'Every message you receive in this workspace ends with a short',
|
|
280
|
+
'`<hive-system-reminder>` block carrying the minimum syntax you need',
|
|
281
|
+
'right now. If something is missing from that block, re-read this file.',
|
|
282
|
+
'',
|
|
283
|
+
].join('\n');
|
|
284
|
+
};
|
|
@@ -11,7 +11,7 @@ export const createLiveRunRegistry = () => {
|
|
|
11
11
|
const promise = new Promise((nextResolve) => {
|
|
12
12
|
resolve = nextResolve;
|
|
13
13
|
});
|
|
14
|
-
runExitPromises.set(runId, { promise, resolve });
|
|
14
|
+
runExitPromises.set(runId, { promise, resolve, runId });
|
|
15
15
|
},
|
|
16
16
|
deleteExitEntry(runId) {
|
|
17
17
|
runExitPromises.delete(runId);
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { execFile } from 'node:child_process';
|
|
2
2
|
import { getDefaultOpenTargetIdForPlatform, getEffectiveOpenTargetId, isOpenTargetId, } from '../shared/open-targets.js';
|
|
3
|
+
import { buildCmdCallCommand } from './windows-command-line.js';
|
|
3
4
|
export { getEffectiveOpenTargetId, isOpenTargetId, isOpenTargetSupported, OPEN_TARGET_IDS_BY_PLATFORM, } from '../shared/open-targets.js';
|
|
4
5
|
export const resolveOpenTargetPlatform = (platform) => {
|
|
5
6
|
if (platform === 'darwin')
|
|
@@ -50,15 +51,13 @@ const linuxAttempts = (targetId, path) => {
|
|
|
50
51
|
* PATHEXT and cannot launch `.cmd` files directly, so a bare `code` argv
|
|
51
52
|
* returns ENOENT even when VSCode is installed.
|
|
52
53
|
*
|
|
53
|
-
* `cmd.exe /d /s /c` parses the trailing command line.
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
* fire because the command line starts with the binary name (e.g. `code`),
|
|
57
|
-
* not a `"`.
|
|
54
|
+
* `cmd.exe /d /s /c` parses the trailing command line. Build that command
|
|
55
|
+
* with cmd-aware escaping instead of separate argv entries so path metachars
|
|
56
|
+
* (`&`, `|`, `%`, etc.) remain data rather than syntax.
|
|
58
57
|
*/
|
|
59
58
|
const cmdExeShimAttempt = (bin, path) => ({
|
|
60
59
|
command: 'cmd.exe',
|
|
61
|
-
args: ['/d', '/s', '/c', bin, path],
|
|
60
|
+
args: ['/d', '/s', '/c', buildCmdCallCommand(bin, [path])],
|
|
62
61
|
});
|
|
63
62
|
const windowsAttempts = (targetId, path) => {
|
|
64
63
|
switch (targetId) {
|
|
@@ -18,6 +18,18 @@ export interface OrchestratorStartResult {
|
|
|
18
18
|
error: string | null;
|
|
19
19
|
run_id: string | null;
|
|
20
20
|
}
|
|
21
|
+
/**
|
|
22
|
+
* Translate an early-exit terminal state to a human-friendly error string.
|
|
23
|
+
*
|
|
24
|
+
* Two cases land here:
|
|
25
|
+
* - exit 127 (POSIX) / 9009 (Windows cmd.exe): shell saying "command not
|
|
26
|
+
* found" — the most common real case when the configured CLI is missing,
|
|
27
|
+
* because node-pty does NOT throw sync ENOENT for missing binaries; it
|
|
28
|
+
* spawns successfully and the child dies via onExit.
|
|
29
|
+
* - any other non-zero exit: surface the raw code so we don't lie about the
|
|
30
|
+
* cause.
|
|
31
|
+
*/
|
|
32
|
+
export declare const formatEarlyExitError: (command: string, exitCode: number | null) => string;
|
|
21
33
|
/**
|
|
22
34
|
* Wraps `store.startAgent` so spawn failures never bubble up: callers always
|
|
23
35
|
* receive a structured result. The HTTP layer uses this to keep workspace
|
|
@@ -1,15 +1,17 @@
|
|
|
1
1
|
import { getStartupCommandExecutable } from './startup-command-parser.js';
|
|
2
2
|
// SETTLE_WAIT_MS: how long we wait before declaring autostart "ok". Must be
|
|
3
3
|
// long enough to observe an early exit when the child shell prints
|
|
4
|
-
// "command not found" then dies with exit 127 (
|
|
5
|
-
// 800ms balances reliability vs the perceived
|
|
4
|
+
// "command not found" then dies with exit 127 (POSIX) or 9009 (Windows)
|
|
5
|
+
// — typically <100ms in practice. 800ms balances reliability vs the perceived
|
|
6
|
+
// workspace-create latency cost.
|
|
6
7
|
const SETTLE_WAIT_MS = 800;
|
|
7
8
|
const POLL_INTERVAL_MS = 25;
|
|
8
|
-
// Shells emit exit code
|
|
9
|
-
// node-pty does NOT raise a synchronous spawn error for that
|
|
10
|
-
// just dies almost immediately via onExit. We translate that to
|
|
11
|
-
// string as the sync-ENOENT path so the user gets one consistent
|
|
12
|
-
|
|
9
|
+
// Shells emit a "command not found" exit code when the requested binary is
|
|
10
|
+
// missing on PATH. node-pty does NOT raise a synchronous spawn error for that
|
|
11
|
+
// case — the PTY just dies almost immediately via onExit. We translate that to
|
|
12
|
+
// the same UX string as the sync-ENOENT path so the user gets one consistent
|
|
13
|
+
// message. POSIX shells use 127; Windows cmd.exe uses 9009.
|
|
14
|
+
const COMMAND_NOT_FOUND_EXIT_CODES = new Set([127, 9009]);
|
|
13
15
|
const sleep = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
|
|
14
16
|
const isErrnoException = (error) => error instanceof Error && typeof error.code === 'string';
|
|
15
17
|
/**
|
|
@@ -28,15 +30,15 @@ const formatStartError = (error, command) => {
|
|
|
28
30
|
* Translate an early-exit terminal state to a human-friendly error string.
|
|
29
31
|
*
|
|
30
32
|
* Two cases land here:
|
|
31
|
-
* - exit 127: shell saying "command not
|
|
32
|
-
*
|
|
33
|
-
*
|
|
34
|
-
* onExit
|
|
33
|
+
* - exit 127 (POSIX) / 9009 (Windows cmd.exe): shell saying "command not
|
|
34
|
+
* found" — the most common real case when the configured CLI is missing,
|
|
35
|
+
* because node-pty does NOT throw sync ENOENT for missing binaries; it
|
|
36
|
+
* spawns successfully and the child dies via onExit.
|
|
35
37
|
* - any other non-zero exit: surface the raw code so we don't lie about the
|
|
36
38
|
* cause.
|
|
37
39
|
*/
|
|
38
|
-
const formatEarlyExitError = (command, exitCode) => {
|
|
39
|
-
if (exitCode
|
|
40
|
+
export const formatEarlyExitError = (command, exitCode) => {
|
|
41
|
+
if (exitCode !== null && COMMAND_NOT_FOUND_EXIT_CODES.has(exitCode)) {
|
|
40
42
|
return `${command} CLI not found in PATH`;
|
|
41
43
|
}
|
|
42
44
|
return `${command} failed to start (exit ${exitCode ?? 'null'})`;
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare const realpathNative: (path: string) => string;
|
|
2
|
+
export declare const normalizeFilesystemIdentity: (path: string, platform?: NodeJS.Platform) => string;
|
|
3
|
+
export declare const sameFilesystemPath: (left: string, right: string, platform?: NodeJS.Platform) => boolean;
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
import { realpathSync } from 'node:fs';
|
|
2
|
+
import { posix, resolve, win32 } from 'node:path';
|
|
3
|
+
export const realpathNative = (path) => {
|
|
4
|
+
try {
|
|
5
|
+
return realpathSync.native(path);
|
|
6
|
+
}
|
|
7
|
+
catch (error) {
|
|
8
|
+
if (error?.code === 'ENOSYS')
|
|
9
|
+
return realpathSync(path);
|
|
10
|
+
throw error;
|
|
11
|
+
}
|
|
12
|
+
};
|
|
13
|
+
export const normalizeFilesystemIdentity = (path, platform = process.platform) => {
|
|
14
|
+
const resolveForPlatform = platform === 'win32' ? win32.resolve : posix.resolve;
|
|
15
|
+
let resolved;
|
|
16
|
+
if (platform === process.platform) {
|
|
17
|
+
try {
|
|
18
|
+
resolved = realpathNative(path);
|
|
19
|
+
}
|
|
20
|
+
catch {
|
|
21
|
+
resolved = resolve(path);
|
|
22
|
+
}
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
resolved = resolveForPlatform(path);
|
|
26
|
+
}
|
|
27
|
+
return platform === 'win32' ? resolved.toLowerCase() : resolved;
|
|
28
|
+
};
|
|
29
|
+
export const sameFilesystemPath = (left, right, platform = process.platform) => normalizeFilesystemIdentity(left, platform) === normalizeFilesystemIdentity(right, platform);
|
|
@@ -0,0 +1,3 @@
|
|
|
1
|
+
export declare const arePathsEqual: (left: string, right: string, platform?: NodeJS.Platform) => boolean;
|
|
2
|
+
export declare const containsPathMarker: (haystack: string, marker: string, platform?: NodeJS.Platform) => boolean;
|
|
3
|
+
export declare const indexOfPathMarker: (haystack: string, marker: string, platform?: NodeJS.Platform) => number;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
const toForwardSlashes = (path) => path.replace(/\\/g, '/');
|
|
2
|
+
const normalizeForWin32 = (path) => toForwardSlashes(path).toLowerCase();
|
|
3
|
+
export const arePathsEqual = (left, right, platform = process.platform) => {
|
|
4
|
+
if (platform === 'win32')
|
|
5
|
+
return normalizeForWin32(left) === normalizeForWin32(right);
|
|
6
|
+
return left === right;
|
|
7
|
+
};
|
|
8
|
+
export const containsPathMarker = (haystack, marker, platform = process.platform) => indexOfPathMarker(haystack, marker, platform) !== -1;
|
|
9
|
+
export const indexOfPathMarker = (haystack, marker, platform = process.platform) => {
|
|
10
|
+
if (platform === 'win32')
|
|
11
|
+
return toForwardSlashes(haystack).indexOf(marker);
|
|
12
|
+
return haystack.indexOf(marker);
|
|
13
|
+
};
|
|
@@ -3,4 +3,4 @@ export declare const toBracketedPasteSubmission: (text: string) => string;
|
|
|
3
3
|
export declare const isInteractiveAgentCommand: (command: string) => boolean;
|
|
4
4
|
export declare const hasInteractivePromptReady: (output: string, command?: string) => boolean;
|
|
5
5
|
export declare const hasBracketedPasteAcknowledgement: (output: string, baselineLength: number) => boolean;
|
|
6
|
-
export declare const createPostStartInputWriter: (agentManager: AgentManager, command: string) => ((runId: string, text: string) => void);
|
|
6
|
+
export declare const createPostStartInputWriter: (agentManager: AgentManager, command: string) => ((runId: string, text: string) => Promise<void>);
|