blun-king-cli 9.1.486 → 9.1.488
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/LIESMICH.txt +26 -7
- package/README.md +14 -3
- package/agent-spine-plugin/.claude-plugin/marketplace.json +20 -0
- package/agent-spine-plugin/.claude-plugin/plugin.json +14 -0
- package/agent-spine-plugin/.codex-plugin/plugin.json +34 -0
- package/agent-spine-plugin/.mcp.json +8 -0
- package/agent-spine-plugin/CHANGELOG.md +277 -0
- package/agent-spine-plugin/LICENSE +186 -0
- package/agent-spine-plugin/README.md +342 -0
- package/agent-spine-plugin/assets/agentspine-banner.svg +32 -0
- package/agent-spine-plugin/bin/agentspine-mcp.js +4 -0
- package/agent-spine-plugin/bin/agentspine.js +7 -0
- package/agent-spine-plugin/blun.plugin.json +33 -0
- package/agent-spine-plugin/docs/acceptance.md +61 -0
- package/agent-spine-plugin/docs/architecture.md +183 -0
- package/agent-spine-plugin/docs/attention.md +121 -0
- package/agent-spine-plugin/docs/automatic-continuity.md +79 -0
- package/agent-spine-plugin/docs/channel-runtime.md +92 -0
- package/agent-spine-plugin/docs/coordination.md +138 -0
- package/agent-spine-plugin/docs/feed-transport.md +99 -0
- package/agent-spine-plugin/docs/gateway-runtime.md +109 -0
- package/agent-spine-plugin/docs/harness-reference.md +45 -0
- package/agent-spine-plugin/docs/host-integration.md +129 -0
- package/agent-spine-plugin/docs/https-transport.md +116 -0
- package/agent-spine-plugin/docs/learning.md +98 -0
- package/agent-spine-plugin/docs/object-transport.md +93 -0
- package/agent-spine-plugin/docs/peer-transport.md +88 -0
- package/agent-spine-plugin/docs/preservation-contract.md +53 -0
- package/agent-spine-plugin/docs/quality-gates.md +50 -0
- package/agent-spine-plugin/docs/relationships.md +67 -0
- package/agent-spine-plugin/docs/releasing.md +83 -0
- package/agent-spine-plugin/docs/roadmap.md +307 -0
- package/agent-spine-plugin/docs/selfstarter.md +88 -0
- package/agent-spine-plugin/docs/session-briefing.md +74 -0
- package/agent-spine-plugin/docs/shared-memory.md +259 -0
- package/agent-spine-plugin/docs/source-roots.md +86 -0
- package/agent-spine-plugin/docs/sqlite-transport.md +76 -0
- package/agent-spine-plugin/hooks/hooks.json +95 -0
- package/agent-spine-plugin/hooks/version.json +5 -0
- package/agent-spine-plugin/package.json +69 -0
- package/agent-spine-plugin/scripts/check-hosts.js +193 -0
- package/agent-spine-plugin/scripts/check-install.js +551 -0
- package/agent-spine-plugin/scripts/check-syntax.js +29 -0
- package/agent-spine-plugin/scripts/github-actions.js +11 -0
- package/agent-spine-plugin/scripts/release-check.js +127 -0
- package/agent-spine-plugin/scripts/run-acceptance.js +19 -0
- package/agent-spine-plugin/scripts/run-checks.js +46 -0
- package/agent-spine-plugin/scripts/run-tests-hermetic.js +73 -0
- package/agent-spine-plugin/skill/SKILL.md +76 -0
- package/agent-spine-plugin/skills/agent-spine/SKILL.md +84 -0
- package/agent-spine-plugin/spine-example/1-identity.md +12 -0
- package/agent-spine-plugin/spine-example/2-voice.md +6 -0
- package/agent-spine-plugin/spine-example/3-conduct.md +8 -0
- package/agent-spine-plugin/spine-example/4-history.md +4 -0
- package/agent-spine-plugin/src/cli.js +950 -0
- package/agent-spine-plugin/src/hook.js +646 -0
- package/agent-spine-plugin/src/index.js +84 -0
- package/agent-spine-plugin/src/lib/acceptance.js +294 -0
- package/agent-spine-plugin/src/lib/attention.js +755 -0
- package/agent-spine-plugin/src/lib/audit.js +308 -0
- package/agent-spine-plugin/src/lib/authentication.js +513 -0
- package/agent-spine-plugin/src/lib/briefing.js +305 -0
- package/agent-spine-plugin/src/lib/catalog.js +142 -0
- package/agent-spine-plugin/src/lib/channel-runtime.js +665 -0
- package/agent-spine-plugin/src/lib/context.js +154 -0
- package/agent-spine-plugin/src/lib/continuity.js +333 -0
- package/agent-spine-plugin/src/lib/coordination.js +577 -0
- package/agent-spine-plugin/src/lib/documents.js +199 -0
- package/agent-spine-plugin/src/lib/feed-transport.js +497 -0
- package/agent-spine-plugin/src/lib/filesystem-retry.js +27 -0
- package/agent-spine-plugin/src/lib/gateway-runtime.js +760 -0
- package/agent-spine-plugin/src/lib/graph.js +284 -0
- package/agent-spine-plugin/src/lib/https-transport.js +392 -0
- package/agent-spine-plugin/src/lib/indexed-memory-offline.js +40 -0
- package/agent-spine-plugin/src/lib/indexed-memory.js +281 -0
- package/agent-spine-plugin/src/lib/learning.js +645 -0
- package/agent-spine-plugin/src/lib/object-transport.js +206 -0
- package/agent-spine-plugin/src/lib/paths.js +60 -0
- package/agent-spine-plugin/src/lib/peer-transport.js +283 -0
- package/agent-spine-plugin/src/lib/persona-runtime.js +503 -0
- package/agent-spine-plugin/src/lib/runtime.js +13 -0
- package/agent-spine-plugin/src/lib/selfstarter.js +819 -0
- package/agent-spine-plugin/src/lib/sharing.js +969 -0
- package/agent-spine-plugin/src/lib/source-roots.js +451 -0
- package/agent-spine-plugin/src/lib/sqlite-transport.js +501 -0
- package/agent-spine-plugin/src/lib/telegram-adapter.js +119 -0
- package/agent-spine-plugin/src/lib/voice-runtime.js +39 -0
- package/agent-spine-plugin/src/mcp.js +526 -0
- package/agent-spine-plugin/src/version.js +1 -0
- package/agent-spine-plugin/src/worker.js +178 -0
- package/bin/identity-context-policy.cjs +51 -1
- package/bin/launcher-runtime.js +9 -1
- package/bin/plugin-bootstrap.js +68 -27
- package/bin/turn-thinking-policy.cjs +5 -4
- package/bin/turn-tool-performance-policy.cjs +15 -2
- package/blun.mjs +96 -31
- package/package.json +2 -1
|
@@ -0,0 +1,950 @@
|
|
|
1
|
+
import { fileURLToPath } from "node:url";
|
|
2
|
+
import { scanAndSave, verifyCatalog } from "./lib/catalog.js";
|
|
3
|
+
import { readDocument, resolveContext } from "./lib/context.js";
|
|
4
|
+
import { sessionBriefing } from "./lib/briefing.js";
|
|
5
|
+
import { runAudit } from "./lib/audit.js";
|
|
6
|
+
import {
|
|
7
|
+
attentionContext, configureAttention, deleteAttention, loadAttention,
|
|
8
|
+
recordActivity, resolveAttention, upsertAttention
|
|
9
|
+
} from "./lib/attention.js";
|
|
10
|
+
import {
|
|
11
|
+
addLearningEvidence, configureLearning, deleteLearning, evaluateLearning,
|
|
12
|
+
learningContext, loadLearning, proposeLearning, reviewLearning, rollbackLearning
|
|
13
|
+
} from "./lib/learning.js";
|
|
14
|
+
import { configureContinuity, loadContinuity, purgeContinuity } from "./lib/continuity.js";
|
|
15
|
+
import {
|
|
16
|
+
checkDelegation, createTask, deleteTask, grantDelegation, loadDelegationPolicy,
|
|
17
|
+
revokeDelegation, taskContext, updateTask
|
|
18
|
+
} from "./lib/coordination.js";
|
|
19
|
+
import {
|
|
20
|
+
cancelJob, deleteJob, grantExecution, loadExecutionPolicy, registerJob,
|
|
21
|
+
revokeExecution, selfstarterContext
|
|
22
|
+
} from "./lib/selfstarter.js";
|
|
23
|
+
import {
|
|
24
|
+
channelRuntimeContext, grantChannelBinding, loadChannelPolicy, revokeChannelBinding
|
|
25
|
+
} from "./lib/channel-runtime.js";
|
|
26
|
+
import { personaContext, syncPersonaRosterFromEnvironment } from "./lib/persona-runtime.js";
|
|
27
|
+
import { assignGoal, gatewayContext, setGatewayControl } from "./lib/gateway-runtime.js";
|
|
28
|
+
import {
|
|
29
|
+
configureSharing, deleteShared, initDirectoryAdapter, publishLearning, pullShared,
|
|
30
|
+
reviewShared, rollbackShared, sharedContext, sharedInbox
|
|
31
|
+
} from "./lib/sharing.js";
|
|
32
|
+
import {
|
|
33
|
+
generateSigningIdentity, listSigningIdentities, revokeTrustedSigner,
|
|
34
|
+
trustedSignerContext, trustSigner
|
|
35
|
+
} from "./lib/authentication.js";
|
|
36
|
+
import { exportHttpsSnapshot, pullHttpsSnapshot } from "./lib/https-transport.js";
|
|
37
|
+
import { publishHttpsSnapshot } from "./lib/object-transport.js";
|
|
38
|
+
import { loadHttpsFeedState, publishHttpsFeed, pullHttpsFeed } from "./lib/feed-transport.js";
|
|
39
|
+
import { pullPeerCommand, servePeerOnce } from "./lib/peer-transport.js";
|
|
40
|
+
import {
|
|
41
|
+
initSqliteAdapter, inspectSqliteAdapter, publishSqliteSnapshot, pullSqliteSnapshot
|
|
42
|
+
} from "./lib/sqlite-transport.js";
|
|
43
|
+
import {
|
|
44
|
+
annotateDocument, linkDocuments, linkEntities,
|
|
45
|
+
relationshipContext, upsertEntity
|
|
46
|
+
} from "./lib/graph.js";
|
|
47
|
+
import { checkHosts } from "../scripts/check-hosts.js";
|
|
48
|
+
import { renderAcceptanceReport, runVisibleAcceptance } from "./lib/acceptance.js";
|
|
49
|
+
import {
|
|
50
|
+
bindSourceRoot, inspectSourceRegistry, purgeSourceBinding, resolveHostSourceCatalog,
|
|
51
|
+
rollbackSourceBinding
|
|
52
|
+
} from "./lib/source-roots.js";
|
|
53
|
+
import { VERSION } from "./version.js";
|
|
54
|
+
import { isMainModule } from "./lib/runtime.js";
|
|
55
|
+
import { scanIndexedMemoryOrphans } from "./lib/indexed-memory-offline.js";
|
|
56
|
+
|
|
57
|
+
function parse(argv) {
|
|
58
|
+
const [command = "help", ...rest] = argv;
|
|
59
|
+
const flags = {};
|
|
60
|
+
const positional = [];
|
|
61
|
+
for (let index = 0; index < rest.length; index += 1) {
|
|
62
|
+
const token = rest[index];
|
|
63
|
+
if (!token.startsWith("--")) {
|
|
64
|
+
positional.push(token);
|
|
65
|
+
continue;
|
|
66
|
+
}
|
|
67
|
+
const [name, inline] = token.slice(2).split("=", 2);
|
|
68
|
+
if (inline !== undefined) flags[name] = inline;
|
|
69
|
+
else if (rest[index + 1] && !rest[index + 1].startsWith("--")) flags[name] = rest[++index];
|
|
70
|
+
else flags[name] = true;
|
|
71
|
+
}
|
|
72
|
+
return { command, flags, positional };
|
|
73
|
+
}
|
|
74
|
+
|
|
75
|
+
function output(value, json = false) {
|
|
76
|
+
if (json) {
|
|
77
|
+
process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
78
|
+
return;
|
|
79
|
+
}
|
|
80
|
+
if (typeof value === "string") process.stdout.write(`${value}\n`);
|
|
81
|
+
else process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
|
|
82
|
+
}
|
|
83
|
+
|
|
84
|
+
function booleanFlag(value, fallback = false) {
|
|
85
|
+
if (value === undefined) return fallback;
|
|
86
|
+
if (value === true || value === "true" || value === "1") return true;
|
|
87
|
+
if (value === false || value === "false" || value === "0") return false;
|
|
88
|
+
throw new Error(`expected boolean flag, received: ${value}`);
|
|
89
|
+
}
|
|
90
|
+
|
|
91
|
+
function help() {
|
|
92
|
+
return `AgentSpine ${VERSION}
|
|
93
|
+
|
|
94
|
+
Usage:
|
|
95
|
+
agentspine scan [root] [--json]
|
|
96
|
+
agentspine context [root] [--cwd path] [--host codex|claude|generic] [--max-bytes n] [--json]
|
|
97
|
+
agentspine briefing [root] [--host codex|claude|generic] [--entity id] [--group id] [--project id] [--current-task id] [--include-private] [--max-bytes n] [--allow-attention] [--no-source-content]
|
|
98
|
+
agentspine read <relative-path> [--root path] [--offset n] [--length n] [--json]
|
|
99
|
+
agentspine verify [root] [--json]
|
|
100
|
+
agentspine link <from.md> <to.md> --relation related [--reason text] [--confidence 0.8]
|
|
101
|
+
agentspine annotate <path.md> --layer soul [--reason text] [--confidence 0.8]
|
|
102
|
+
agentspine entity <id> --kind person [--name text] [--privacy private]
|
|
103
|
+
agentspine relate <from> <to> --relation works-with [--privacy private]
|
|
104
|
+
agentspine relationships <entity-id> [--group id] [--include-private] [--json]
|
|
105
|
+
agentspine attention [root] [--group id] [--include-private] [--focus-active] [--mark-presented]
|
|
106
|
+
agentspine attention-events [root] [--include-history]
|
|
107
|
+
agentspine attention-add [id] --kind promise --summary text [--entity id] [--group id] [--due date]
|
|
108
|
+
agentspine attention-resolve <id> [--status completed|dismissed|open]
|
|
109
|
+
agentspine attention-touch <entity-id> [--kind interaction] [--at date]
|
|
110
|
+
agentspine attention-delete <signal-id>
|
|
111
|
+
agentspine attention-event-delete <event-id>
|
|
112
|
+
agentspine attention-purge <entity-id>
|
|
113
|
+
agentspine attention-config [root] [--enabled true|false] [--quiet-start 22 --quiet-end 7 --utc-offset 120]
|
|
114
|
+
agentspine learn-propose [id] --kind preference --claim text --evidence text
|
|
115
|
+
agentspine learn-evidence <id> --summary text [--type interaction] [--source path.md]
|
|
116
|
+
agentspine learn-review <id> --decision accept|reject --reason text [--confirmed-by-user]
|
|
117
|
+
agentspine learn-context [root] [--group id] [--include-private] [--kind preference,goal]
|
|
118
|
+
agentspine learn-evaluate [root]
|
|
119
|
+
agentspine learn-rollback <id> --reason text
|
|
120
|
+
agentspine learn-delete <id>
|
|
121
|
+
agentspine learn-config [root] [--auto-promote true|false] [--min-confidence 0.85]
|
|
122
|
+
agentspine continuity-config [root] [--enabled true|false] [--entity id] [--project id] [--confirm-local-opt-in]
|
|
123
|
+
agentspine continuity-status [root]
|
|
124
|
+
agentspine continuity-purge <entity-id> [--root path] --confirm-local-purge
|
|
125
|
+
agentspine source-status --host claude|codex [--cwd path]
|
|
126
|
+
agentspine doctor --host claude [--cwd path] [--offline-memory-orphans]
|
|
127
|
+
agentspine source-bind <state-root> --host all|claude|codex --scope state-user --project path --host-home path --confirm-local-binding
|
|
128
|
+
agentspine source-rollback <binding-id> --confirm-local-binding
|
|
129
|
+
agentspine source-purge <binding-id> --confirm-local-binding
|
|
130
|
+
agentspine delegation-grant <actor-id> --actions assign,manage --targets agent:id --reason text [--confirm-local-policy]
|
|
131
|
+
agentspine delegation-revoke <grant-id> --reason text [--confirm-local-policy]
|
|
132
|
+
agentspine delegation-check <actor-id> --action assign [--target agent:id]
|
|
133
|
+
agentspine delegation-policy [root]
|
|
134
|
+
agentspine task-create [id] --actor id --title text [--assignee id] [--kind task|open-thread|handoff] [--privacy private|shared|group]
|
|
135
|
+
agentspine task-update <id> --actor id [--status in-progress] [--assignee id|--unassign]
|
|
136
|
+
agentspine tasks [root] [--assignee id] [--project id] [--include-private] [--group id]
|
|
137
|
+
agentspine task-delete <id> [--confirm-local-policy]
|
|
138
|
+
agentspine execution-grant <job-id> --actor id --task task:id --target id --project project:id --host claude|codex --capabilities tool:Write --reason text [--expires date] --confirm-local-execution
|
|
139
|
+
agentspine execution-revoke <grant-id> --reason text --confirm-local-execution
|
|
140
|
+
agentspine execution-policy [root]
|
|
141
|
+
agentspine job-register <job-id> --grant grant:id [--max-retries 3] [--lease-seconds 120] --confirm-local-execution
|
|
142
|
+
agentspine jobs [root] [--actor id] [--project id] [--task id] [--include-terminal]
|
|
143
|
+
agentspine job-cancel <job-id> --reason text --confirm-local-execution
|
|
144
|
+
agentspine job-delete <job-id> --confirm-local-execution
|
|
145
|
+
agentspine channel-bind <binding-id> --provider telegram --tenant id --account id --chat id --senders id,id --agent agent:id --project project:id --session key --secret-env VARIABLE [--outbound-secret-env VARIABLE] --confirm-local-channel
|
|
146
|
+
agentspine channel-revoke <binding-id> --reason text --confirm-local-channel
|
|
147
|
+
agentspine channel-policy [root]
|
|
148
|
+
agentspine channel-events [root] [--agent id] [--project id] [--group id] [--provider telegram] [--include-terminal]
|
|
149
|
+
agentspine persona-sync [root] --roster absolute-path --confirm-local-persona
|
|
150
|
+
agentspine personas [root] [--persona id] [--group id] [--include-inactive]
|
|
151
|
+
agentspine goal-assign <goal-id> --agent id --owner id --project id --success text --next-step text [--group id] [--deadline date] --confirm-local-goal
|
|
152
|
+
agentspine gateway-control [root] [--enabled true|false] [--kill-switch true|false] --confirm-local-gateway
|
|
153
|
+
agentspine gateway-status [root] [--agent id]
|
|
154
|
+
agentspine share-keygen <signer-id> [--public-out signer.json] [--rotate] [--confirm-local-share]
|
|
155
|
+
agentspine share-signers [root]
|
|
156
|
+
agentspine share-trust <signer.json> [--root path] [--confirm-local-share]
|
|
157
|
+
agentspine share-trust-revoke <key-id> --reason text [--root path] [--confirm-local-share]
|
|
158
|
+
agentspine share-trust-list [root] [--include-revoked]
|
|
159
|
+
agentspine share-init <directory> --scope team:id [--adapter adapter:id] [--signer signer:id] [--confirm-local-share]
|
|
160
|
+
agentspine share-publish <directory> --learning id [--id shared:id] [--signer signer:id] [--supersedes shared:id] [--confirm-local-share]
|
|
161
|
+
agentspine share-pull <directory> [--root path] [--require-authenticated]
|
|
162
|
+
agentspine share-snapshot-export <directory> --out snapshot.json [--id snapshot:id] [--confirm-local-share]
|
|
163
|
+
agentspine share-https-publish <directory> --base https://store.example/spine [--id snapshot:id] [--token-env VARIABLE] [--timeout-ms 10000] [--allow-private-network] --confirm-local-share
|
|
164
|
+
agentspine share-https-pull <https-url> [--token-env VARIABLE] [--timeout-ms 10000] [--allow-private-network --confirm-local-share]
|
|
165
|
+
agentspine share-feed-publish <directory> --base https://store.example/spine --feed team:id --signer signer:id [--id snapshot:id] [--token-env VARIABLE] --confirm-local-share
|
|
166
|
+
agentspine share-feed-pull --base https://store.example/spine --feed team:id [--root path] [--token-env VARIABLE] [--allow-private-network --confirm-local-share]
|
|
167
|
+
agentspine share-feed-state [root]
|
|
168
|
+
agentspine share-peer-serve <directory> --root path --signer signer:id [--timeout-ms 10000] --confirm-local-share
|
|
169
|
+
agentspine share-peer-pull --root path --command-json '["ssh","host","agentspine",…]' [--timeout-ms 10000] [--max-bytes n] --confirm-local-share
|
|
170
|
+
agentspine share-sqlite-init <directory> --database path --confirm-local-share
|
|
171
|
+
agentspine share-sqlite-publish <directory> --database path [--id snapshot:id] --confirm-local-share
|
|
172
|
+
agentspine share-sqlite-inspect --database path [--root path]
|
|
173
|
+
agentspine share-sqlite-pull --database path [--root path]
|
|
174
|
+
agentspine share-inbox [root] [--status pending|accepted|rejected|superseded|rolled-back]
|
|
175
|
+
agentspine share-review <id> --decision accept|reject --reason text [--confirmed-by-user]
|
|
176
|
+
agentspine share-context [root] [--scope team:id] [--group group:id] [--kind preference,goal]
|
|
177
|
+
agentspine share-rollback <id> --reason text
|
|
178
|
+
agentspine share-delete <id> [--confirm-local-share]
|
|
179
|
+
agentspine share-config [root] --max-items 12
|
|
180
|
+
agentspine audit [root] [--json]
|
|
181
|
+
agentspine acceptance [--json]
|
|
182
|
+
agentspine doctor [--json]
|
|
183
|
+
agentspine mcp
|
|
184
|
+
|
|
185
|
+
AgentSpine reads existing Markdown in place. It never rewrites source documents.`;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
export async function run(argv = process.argv.slice(2)) {
|
|
189
|
+
const { command, flags, positional } = parse(argv);
|
|
190
|
+
const json = Boolean(flags.json);
|
|
191
|
+
if (command === "help" || command === "--help" || command === "-h") return output(help());
|
|
192
|
+
if (command === "version" || command === "--version" || command === "-v") return output(VERSION);
|
|
193
|
+
|
|
194
|
+
if (command === "acceptance") {
|
|
195
|
+
if (positional.length || Object.keys(flags).some((name) => name !== "json")) {
|
|
196
|
+
throw new Error("acceptance supports only --json");
|
|
197
|
+
}
|
|
198
|
+
const report = await runVisibleAcceptance();
|
|
199
|
+
if (json) return output(report, true);
|
|
200
|
+
process.stdout.write(renderAcceptanceReport(report));
|
|
201
|
+
return;
|
|
202
|
+
}
|
|
203
|
+
|
|
204
|
+
if (command === "scan") {
|
|
205
|
+
const result = await scanAndSave(positional[0] || process.cwd());
|
|
206
|
+
return output(json ? result : {
|
|
207
|
+
root: result.catalog.root,
|
|
208
|
+
catalog: result.catalogPath,
|
|
209
|
+
documents: result.catalog.summary.total,
|
|
210
|
+
protected: result.catalog.summary.protected,
|
|
211
|
+
layers: result.catalog.summary.byLayer
|
|
212
|
+
}, json);
|
|
213
|
+
}
|
|
214
|
+
|
|
215
|
+
if (command === "context") {
|
|
216
|
+
const root = positional[0] || process.cwd();
|
|
217
|
+
const result = await resolveContext({
|
|
218
|
+
root,
|
|
219
|
+
cwd: flags.cwd || root,
|
|
220
|
+
host: flags.host || "generic",
|
|
221
|
+
maxBytes: Number(flags["max-bytes"] || 65536),
|
|
222
|
+
includeContent: flags["no-content"] !== true
|
|
223
|
+
});
|
|
224
|
+
return output(result, json);
|
|
225
|
+
}
|
|
226
|
+
|
|
227
|
+
if (command === "briefing") {
|
|
228
|
+
const root = positional[0] || process.cwd();
|
|
229
|
+
return output(await sessionBriefing({
|
|
230
|
+
root, cwd: flags.cwd || root, host: flags.host || "generic",
|
|
231
|
+
entityId: flags.entity || null, groupId: flags.group || null,
|
|
232
|
+
projectId: flags.project || null, currentTaskId: flags["current-task"] || null,
|
|
233
|
+
includePrivate: booleanFlag(flags["include-private"]),
|
|
234
|
+
focusActive: !booleanFlag(flags["allow-attention"]),
|
|
235
|
+
includeSourceContent: !booleanFlag(flags["no-source-content"]),
|
|
236
|
+
maxBytes: Number(flags["max-bytes"] ?? 16384)
|
|
237
|
+
}), json);
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
if (command === "read") {
|
|
241
|
+
const result = await readDocument({
|
|
242
|
+
root: flags.root || process.cwd(),
|
|
243
|
+
path: positional[0],
|
|
244
|
+
offset: Number(flags.offset || 0),
|
|
245
|
+
length: Number(flags.length || 65536)
|
|
246
|
+
});
|
|
247
|
+
return output(json ? result : result.content, json);
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
if (command === "verify") {
|
|
251
|
+
const result = await verifyCatalog(positional[0] || process.cwd());
|
|
252
|
+
output(result, json);
|
|
253
|
+
if (!result.ok) process.exitCode = 1;
|
|
254
|
+
return;
|
|
255
|
+
}
|
|
256
|
+
|
|
257
|
+
if (command === "link") {
|
|
258
|
+
const result = await linkDocuments({
|
|
259
|
+
root: flags.root || process.cwd(), from: positional[0], to: positional[1],
|
|
260
|
+
relation: flags.relation || "related", reason: flags.reason || "",
|
|
261
|
+
confidence: Number(flags.confidence ?? 0.5)
|
|
262
|
+
});
|
|
263
|
+
return output(result, json);
|
|
264
|
+
}
|
|
265
|
+
|
|
266
|
+
if (command === "annotate") {
|
|
267
|
+
const result = await annotateDocument({
|
|
268
|
+
root: flags.root || process.cwd(), path: positional[0], layer: flags.layer,
|
|
269
|
+
reason: flags.reason || "", confidence: Number(flags.confidence ?? 0.5)
|
|
270
|
+
});
|
|
271
|
+
return output(result, json);
|
|
272
|
+
}
|
|
273
|
+
|
|
274
|
+
if (command === "entity") {
|
|
275
|
+
const result = await upsertEntity({
|
|
276
|
+
root: flags.root || process.cwd(), id: positional[0], kind: flags.kind,
|
|
277
|
+
displayName: flags.name || "", confidence: Number(flags.confidence ?? 0.5),
|
|
278
|
+
privacy: flags.privacy || "private"
|
|
279
|
+
});
|
|
280
|
+
return output(result, json);
|
|
281
|
+
}
|
|
282
|
+
|
|
283
|
+
if (command === "relate") {
|
|
284
|
+
const result = await linkEntities({
|
|
285
|
+
root: flags.root || process.cwd(), from: positional[0], to: positional[1],
|
|
286
|
+
relation: flags.relation || "related", reason: flags.reason || "",
|
|
287
|
+
confidence: Number(flags.confidence ?? 0.5), privacy: flags.privacy || "private"
|
|
288
|
+
});
|
|
289
|
+
return output(result, json);
|
|
290
|
+
}
|
|
291
|
+
|
|
292
|
+
if (command === "relationships") {
|
|
293
|
+
return output(await relationshipContext({
|
|
294
|
+
root: flags.root || process.cwd(), entityId: positional[0],
|
|
295
|
+
includePrivate: Boolean(flags["include-private"]), groupId: flags.group || null
|
|
296
|
+
}), json);
|
|
297
|
+
}
|
|
298
|
+
|
|
299
|
+
if (command === "attention") {
|
|
300
|
+
return output(await attentionContext({
|
|
301
|
+
root: positional[0] || process.cwd(),
|
|
302
|
+
includePrivate: booleanFlag(flags["include-private"]),
|
|
303
|
+
focusActive: booleanFlag(flags["focus-active"]),
|
|
304
|
+
markPresented: booleanFlag(flags["mark-presented"]),
|
|
305
|
+
entityId: flags.entity || null,
|
|
306
|
+
groupId: flags.group || null,
|
|
307
|
+
projectId: flags.project || null,
|
|
308
|
+
currentTaskId: flags.task || null,
|
|
309
|
+
maxItems: flags["max-items"] === undefined ? null : Number(flags["max-items"])
|
|
310
|
+
}), json);
|
|
311
|
+
}
|
|
312
|
+
|
|
313
|
+
if (command === "attention-events") {
|
|
314
|
+
const { attention, attentionPath } = await loadAttention(positional[0] || process.cwd());
|
|
315
|
+
return output({
|
|
316
|
+
schema: "agentspine.attention-events/v1", attentionPath,
|
|
317
|
+
events: attention.events,
|
|
318
|
+
receipts: attention.receipts,
|
|
319
|
+
history: booleanFlag(flags["include-history"]) ? attention.history.filter((item) => item.kind === "attention-event") : [],
|
|
320
|
+
authority: "context-only"
|
|
321
|
+
}, json);
|
|
322
|
+
}
|
|
323
|
+
|
|
324
|
+
if (command === "attention-add") {
|
|
325
|
+
return output(await upsertAttention({
|
|
326
|
+
root: flags.root || process.cwd(), id: positional[0], kind: flags.kind,
|
|
327
|
+
summary: flags.summary, entityId: flags.entity || null, dueAt: flags.due || null,
|
|
328
|
+
priority: Number(flags.priority ?? 50), privacy: flags.privacy || "private",
|
|
329
|
+
groupId: flags.group || null,
|
|
330
|
+
sourceDocument: flags.source || null, confidence: Number(flags.confidence ?? 0.5)
|
|
331
|
+
}), json);
|
|
332
|
+
}
|
|
333
|
+
|
|
334
|
+
if (command === "attention-resolve") {
|
|
335
|
+
return output(await resolveAttention({
|
|
336
|
+
root: flags.root || process.cwd(), id: positional[0], status: flags.status || "completed"
|
|
337
|
+
}), json);
|
|
338
|
+
}
|
|
339
|
+
|
|
340
|
+
if (command === "attention-touch") {
|
|
341
|
+
return output(await recordActivity({
|
|
342
|
+
root: flags.root || process.cwd(), entityId: positional[0], kind: flags.kind || "interaction",
|
|
343
|
+
at: flags.at || new Date(), privacy: flags.privacy || "private", groupId: flags.group || null
|
|
344
|
+
}), json);
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
if (command === "attention-delete") {
|
|
348
|
+
return output(await deleteAttention({ root: flags.root || process.cwd(), signalId: positional[0] }), json);
|
|
349
|
+
}
|
|
350
|
+
|
|
351
|
+
if (command === "attention-event-delete") {
|
|
352
|
+
return output(await deleteAttention({ root: flags.root || process.cwd(), eventId: positional[0] }), json);
|
|
353
|
+
}
|
|
354
|
+
|
|
355
|
+
if (command === "attention-purge") {
|
|
356
|
+
return output(await deleteAttention({ root: flags.root || process.cwd(), entityId: positional[0] }), json);
|
|
357
|
+
}
|
|
358
|
+
|
|
359
|
+
if (command === "attention-config") {
|
|
360
|
+
const root = positional[0] || process.cwd();
|
|
361
|
+
const config = {};
|
|
362
|
+
if (flags.enabled !== undefined) config.enabled = booleanFlag(flags.enabled);
|
|
363
|
+
if (flags["min-interval-hours"] !== undefined) config.minIntervalHours = Number(flags["min-interval-hours"]);
|
|
364
|
+
if (flags["silence-days"] !== undefined) config.entitySilenceDays = Number(flags["silence-days"]);
|
|
365
|
+
if (flags["heartbeat-stale-minutes"] !== undefined) config.heartbeatStaleMinutes = Number(flags["heartbeat-stale-minutes"]);
|
|
366
|
+
if (flags["max-items"] !== undefined) config.maxItems = Number(flags["max-items"]);
|
|
367
|
+
if (flags["quiet-off"] !== undefined) config.quietHours = null;
|
|
368
|
+
else if (flags["quiet-start"] !== undefined || flags["quiet-end"] !== undefined) {
|
|
369
|
+
config.quietHours = {
|
|
370
|
+
start: Number(flags["quiet-start"]), end: Number(flags["quiet-end"]),
|
|
371
|
+
utcOffsetMinutes: Number(flags["utc-offset"] ?? 0)
|
|
372
|
+
};
|
|
373
|
+
}
|
|
374
|
+
if (!Object.keys(config).length) return output((await loadAttention(root)).attention.config, json);
|
|
375
|
+
return output(await configureAttention({ root, config }), json);
|
|
376
|
+
}
|
|
377
|
+
|
|
378
|
+
if (command === "learn-propose") {
|
|
379
|
+
return output(await proposeLearning({
|
|
380
|
+
root: flags.root || process.cwd(), id: positional[0], kind: flags.kind,
|
|
381
|
+
claim: flags.claim, subjectId: flags.subject || null, privacy: flags.privacy || "private",
|
|
382
|
+
groupId: flags.group || null, supersedesId: flags.supersedes || null,
|
|
383
|
+
evidence: {
|
|
384
|
+
id: flags["evidence-id"], type: flags["evidence-type"] || "user-statement",
|
|
385
|
+
summary: flags.evidence, sourceDocument: flags.source || null,
|
|
386
|
+
confidence: Number(flags.confidence ?? 0.5), observedAt: flags.at
|
|
387
|
+
}
|
|
388
|
+
}), json);
|
|
389
|
+
}
|
|
390
|
+
|
|
391
|
+
if (command === "learn-evidence") {
|
|
392
|
+
return output(await addLearningEvidence({
|
|
393
|
+
root: flags.root || process.cwd(), id: positional[0],
|
|
394
|
+
evidence: {
|
|
395
|
+
id: flags["evidence-id"], type: flags.type || "interaction", summary: flags.summary,
|
|
396
|
+
sourceDocument: flags.source || null, confidence: Number(flags.confidence ?? 0.5), observedAt: flags.at
|
|
397
|
+
}
|
|
398
|
+
}), json);
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
if (command === "learn-review") {
|
|
402
|
+
return output(await reviewLearning({
|
|
403
|
+
root: flags.root || process.cwd(), id: positional[0], decision: flags.decision,
|
|
404
|
+
reason: flags.reason, confirmedByUser: booleanFlag(flags["confirmed-by-user"])
|
|
405
|
+
}), json);
|
|
406
|
+
}
|
|
407
|
+
|
|
408
|
+
if (command === "learn-context") {
|
|
409
|
+
return output(await learningContext({
|
|
410
|
+
root: positional[0] || process.cwd(), includePrivate: booleanFlag(flags["include-private"]),
|
|
411
|
+
groupId: flags.group || null,
|
|
412
|
+
kinds: flags.kind ? String(flags.kind).split(",").filter(Boolean) : null,
|
|
413
|
+
subjectIds: flags.subject ? String(flags.subject).split(",").filter(Boolean) : null,
|
|
414
|
+
maxItems: flags["max-items"] === undefined ? null : Number(flags["max-items"])
|
|
415
|
+
}), json);
|
|
416
|
+
}
|
|
417
|
+
|
|
418
|
+
if (command === "learn-evaluate") {
|
|
419
|
+
return output(await evaluateLearning({ root: positional[0] || process.cwd() }), json);
|
|
420
|
+
}
|
|
421
|
+
|
|
422
|
+
if (command === "learn-rollback") {
|
|
423
|
+
return output(await rollbackLearning({
|
|
424
|
+
root: flags.root || process.cwd(), id: positional[0], reason: flags.reason
|
|
425
|
+
}), json);
|
|
426
|
+
}
|
|
427
|
+
|
|
428
|
+
if (command === "learn-delete") {
|
|
429
|
+
return output(await deleteLearning({ root: flags.root || process.cwd(), id: positional[0] }), json);
|
|
430
|
+
}
|
|
431
|
+
|
|
432
|
+
if (command === "learn-config") {
|
|
433
|
+
const root = positional[0] || process.cwd();
|
|
434
|
+
const config = {};
|
|
435
|
+
if (flags["auto-promote"] !== undefined) config.autoPromote = booleanFlag(flags["auto-promote"]);
|
|
436
|
+
if (flags["min-confidence"] !== undefined) config.minConfidence = Number(flags["min-confidence"]);
|
|
437
|
+
if (flags["min-evidence"] !== undefined) config.minEvidence = Number(flags["min-evidence"]);
|
|
438
|
+
if (flags["max-items"] !== undefined) config.maxContextItems = Number(flags["max-items"]);
|
|
439
|
+
if (!Object.keys(config).length) return output((await loadLearning(root)).learning.config, json);
|
|
440
|
+
return output(await configureLearning({ root, config }), json);
|
|
441
|
+
}
|
|
442
|
+
|
|
443
|
+
if (command === "continuity-config") {
|
|
444
|
+
const root = positional[0] || process.cwd();
|
|
445
|
+
const config = {};
|
|
446
|
+
if (flags.enabled !== undefined) config.enabled = booleanFlag(flags.enabled);
|
|
447
|
+
if (flags.entity !== undefined) config.defaultEntityId = flags.entity === "none" ? null : flags.entity;
|
|
448
|
+
if (flags.project !== undefined) config.defaultProjectId = flags.project === "none" ? null : flags.project;
|
|
449
|
+
if (flags["min-confidence"] !== undefined) config.minConfidence = Number(flags["min-confidence"]);
|
|
450
|
+
if (flags["min-directness"] !== undefined) config.minDirectness = Number(flags["min-directness"]);
|
|
451
|
+
if (flags["min-evidence"] !== undefined) config.minEvidence = Number(flags["min-evidence"]);
|
|
452
|
+
if (flags["max-prompt-bytes"] !== undefined) config.maxPromptBytes = Number(flags["max-prompt-bytes"]);
|
|
453
|
+
if (flags["max-briefing-bytes"] !== undefined) config.maxBriefingBytes = Number(flags["max-briefing-bytes"]);
|
|
454
|
+
if (!Object.keys(config).length) return output((await loadContinuity(root)).continuity.config, json);
|
|
455
|
+
return output(await configureContinuity({
|
|
456
|
+
root, config,
|
|
457
|
+
confirmation: booleanFlag(flags["confirm-local-opt-in"]) ? "local-user-opt-in" : null
|
|
458
|
+
}), json);
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
if (command === "continuity-status") {
|
|
462
|
+
const { continuity, continuityPath } = await loadContinuity(positional[0] || process.cwd());
|
|
463
|
+
return output({
|
|
464
|
+
schema: continuity.schema, config: continuity.config,
|
|
465
|
+
signals: continuity.signals.length, history: continuity.history.length,
|
|
466
|
+
continuityPath, authority: "context-only"
|
|
467
|
+
}, json);
|
|
468
|
+
}
|
|
469
|
+
|
|
470
|
+
if (command === "continuity-purge") {
|
|
471
|
+
return output(await purgeContinuity({
|
|
472
|
+
root: flags.root || process.cwd(), subjectId: positional[0],
|
|
473
|
+
confirmation: booleanFlag(flags["confirm-local-purge"]) ? "local-user-confirmed" : null
|
|
474
|
+
}), json);
|
|
475
|
+
}
|
|
476
|
+
|
|
477
|
+
if (command === "source-status") {
|
|
478
|
+
const host = flags.host || process.env.AGENTSPINE_HOST;
|
|
479
|
+
if (!["claude", "codex"].includes(host)) throw new Error("source-status requires --host claude or --host codex");
|
|
480
|
+
const resolved = await resolveHostSourceCatalog({ host, cwd: flags.cwd || process.cwd() });
|
|
481
|
+
const registry = await inspectSourceRegistry();
|
|
482
|
+
return output({ diagnostics: resolved.diagnostics, sources: resolved.catalog.documents.map((item) => ({
|
|
483
|
+
id: item.relativePath, scope: item.sourceScope, binding: item.sourceBinding, sha256: item.sha256,
|
|
484
|
+
bytes: item.bytes, authority: item.authority
|
|
485
|
+
})), bindings: registry.registry.bindings, authority: "context-only" }, json);
|
|
486
|
+
}
|
|
487
|
+
|
|
488
|
+
if (command === "source-bind") {
|
|
489
|
+
return output(await bindSourceRoot({
|
|
490
|
+
host: flags.host, hostHome: flags["host-home"] || process.env.CLAUDE_CONFIG_DIR || process.env.CODEX_HOME || process.cwd(),
|
|
491
|
+
projectRoot: flags.project || process.cwd(), sourceRoot: positional[0], scope: flags.scope || "state-user",
|
|
492
|
+
confirmation: booleanFlag(flags["confirm-local-binding"]) ? "local-user-confirmed" : null
|
|
493
|
+
}), json);
|
|
494
|
+
}
|
|
495
|
+
|
|
496
|
+
if (command === "source-rollback") {
|
|
497
|
+
return output(await rollbackSourceBinding({ id: positional[0],
|
|
498
|
+
confirmation: booleanFlag(flags["confirm-local-binding"]) ? "local-user-confirmed" : null }), json);
|
|
499
|
+
}
|
|
500
|
+
|
|
501
|
+
if (command === "source-purge") {
|
|
502
|
+
return output(await purgeSourceBinding({ id: positional[0],
|
|
503
|
+
confirmation: booleanFlag(flags["confirm-local-binding"]) ? "local-user-confirmed" : null }), json);
|
|
504
|
+
}
|
|
505
|
+
|
|
506
|
+
if (command === "delegation-grant") {
|
|
507
|
+
return output(await grantDelegation({
|
|
508
|
+
root: flags.root || process.cwd(), actorId: positional[0],
|
|
509
|
+
id: flags.id, actions: String(flags.actions || "").split(",").filter(Boolean),
|
|
510
|
+
targetIds: String(flags.targets || "*").split(",").filter(Boolean), reason: flags.reason,
|
|
511
|
+
confirmation: booleanFlag(flags["confirm-local-policy"]) ? "local-owner-confirmed" : null
|
|
512
|
+
}), json);
|
|
513
|
+
}
|
|
514
|
+
|
|
515
|
+
if (command === "delegation-revoke") {
|
|
516
|
+
return output(await revokeDelegation({
|
|
517
|
+
root: flags.root || process.cwd(), id: positional[0], reason: flags.reason,
|
|
518
|
+
confirmation: booleanFlag(flags["confirm-local-policy"]) ? "local-owner-confirmed" : null
|
|
519
|
+
}), json);
|
|
520
|
+
}
|
|
521
|
+
|
|
522
|
+
if (command === "delegation-check") {
|
|
523
|
+
return output(await checkDelegation({
|
|
524
|
+
root: flags.root || process.cwd(), actorId: positional[0], action: flags.action,
|
|
525
|
+
targetId: flags.target || null
|
|
526
|
+
}), json);
|
|
527
|
+
}
|
|
528
|
+
|
|
529
|
+
if (command === "delegation-policy") {
|
|
530
|
+
return output((await loadDelegationPolicy(positional[0] || process.cwd())).policy, json);
|
|
531
|
+
}
|
|
532
|
+
|
|
533
|
+
if (command === "task-create") {
|
|
534
|
+
return output(await createTask({
|
|
535
|
+
root: flags.root || process.cwd(), id: positional[0], actorId: flags.actor,
|
|
536
|
+
assigneeId: flags.assignee || null, kind: flags.kind || "task", title: flags.title,
|
|
537
|
+
summary: flags.summary || null, projectId: flags.project || null,
|
|
538
|
+
privacy: flags.privacy || "private", groupId: flags.group || null,
|
|
539
|
+
priority: Number(flags.priority ?? 50), dueAt: flags.due || null
|
|
540
|
+
}), json);
|
|
541
|
+
}
|
|
542
|
+
|
|
543
|
+
if (command === "task-update") {
|
|
544
|
+
const patch = {};
|
|
545
|
+
if (flags.status !== undefined) patch.status = flags.status;
|
|
546
|
+
if (flags.assignee !== undefined) patch.assigneeId = flags.assignee;
|
|
547
|
+
if (flags.unassign !== undefined) patch.assigneeId = null;
|
|
548
|
+
if (flags.title !== undefined) patch.title = flags.title;
|
|
549
|
+
if (flags.summary !== undefined) patch.summary = flags.summary;
|
|
550
|
+
if (flags.priority !== undefined) patch.priority = Number(flags.priority);
|
|
551
|
+
if (flags.due !== undefined) patch.dueAt = flags.due;
|
|
552
|
+
if (flags["clear-due"] !== undefined) patch.dueAt = null;
|
|
553
|
+
if (flags.note !== undefined) patch.note = flags.note;
|
|
554
|
+
return output(await updateTask({
|
|
555
|
+
root: flags.root || process.cwd(), id: positional[0], actorId: flags.actor, patch
|
|
556
|
+
}), json);
|
|
557
|
+
}
|
|
558
|
+
|
|
559
|
+
if (command === "tasks") {
|
|
560
|
+
return output(await taskContext({
|
|
561
|
+
root: positional[0] || process.cwd(), includePrivate: booleanFlag(flags["include-private"]),
|
|
562
|
+
groupId: flags.group || null, actorId: flags.actor || null, assigneeId: flags.assignee || null,
|
|
563
|
+
projectId: flags.project || null, includeClosed: booleanFlag(flags.closed),
|
|
564
|
+
maxItems: Number(flags["max-items"] ?? 20)
|
|
565
|
+
}), json);
|
|
566
|
+
}
|
|
567
|
+
|
|
568
|
+
if (command === "task-delete") {
|
|
569
|
+
return output(await deleteTask({
|
|
570
|
+
root: flags.root || process.cwd(), id: positional[0],
|
|
571
|
+
confirmation: booleanFlag(flags["confirm-local-policy"]) ? "local-owner-confirmed" : null
|
|
572
|
+
}), json);
|
|
573
|
+
}
|
|
574
|
+
|
|
575
|
+
if (command === "execution-grant") {
|
|
576
|
+
return output(await grantExecution({
|
|
577
|
+
root: flags.root || process.cwd(), id: flags.id, jobId: positional[0], actorId: flags.actor,
|
|
578
|
+
taskId: flags.task, targetId: flags.target, projectId: flags.project, groupId: flags.group || null,
|
|
579
|
+
host: flags.host, capabilities: String(flags.capabilities || "").split(",").filter(Boolean),
|
|
580
|
+
reason: flags.reason, expiresAt: flags.expires || null,
|
|
581
|
+
confirmation: booleanFlag(flags["confirm-local-execution"]) ? "local-owner-confirmed" : null
|
|
582
|
+
}), json);
|
|
583
|
+
}
|
|
584
|
+
|
|
585
|
+
if (command === "execution-revoke") {
|
|
586
|
+
return output(await revokeExecution({
|
|
587
|
+
root: flags.root || process.cwd(), id: positional[0], reason: flags.reason,
|
|
588
|
+
confirmation: booleanFlag(flags["confirm-local-execution"]) ? "local-owner-confirmed" : null
|
|
589
|
+
}), json);
|
|
590
|
+
}
|
|
591
|
+
|
|
592
|
+
if (command === "execution-policy") {
|
|
593
|
+
return output((await loadExecutionPolicy(positional[0] || process.cwd())).policy, json);
|
|
594
|
+
}
|
|
595
|
+
|
|
596
|
+
if (command === "job-register") {
|
|
597
|
+
return output(await registerJob({
|
|
598
|
+
root: flags.root || process.cwd(), id: positional[0], grantId: flags.grant,
|
|
599
|
+
maxRetries: Number(flags["max-retries"] ?? 3), leaseSeconds: Number(flags["lease-seconds"] ?? 120),
|
|
600
|
+
baseRetrySeconds: Number(flags["retry-seconds"] ?? 5),
|
|
601
|
+
confirmation: booleanFlag(flags["confirm-local-execution"]) ? "local-owner-confirmed" : null
|
|
602
|
+
}), json);
|
|
603
|
+
}
|
|
604
|
+
|
|
605
|
+
if (command === "jobs") {
|
|
606
|
+
return output(await selfstarterContext({
|
|
607
|
+
root: positional[0] || process.cwd(), actorId: flags.actor || null,
|
|
608
|
+
projectId: flags.project || null, taskId: flags.task || null,
|
|
609
|
+
includeTerminal: booleanFlag(flags["include-terminal"])
|
|
610
|
+
}), json);
|
|
611
|
+
}
|
|
612
|
+
|
|
613
|
+
if (command === "job-cancel") {
|
|
614
|
+
return output(await cancelJob({
|
|
615
|
+
root: flags.root || process.cwd(), id: positional[0], reason: flags.reason,
|
|
616
|
+
confirmation: booleanFlag(flags["confirm-local-execution"]) ? "local-owner-confirmed" : null
|
|
617
|
+
}), json);
|
|
618
|
+
}
|
|
619
|
+
|
|
620
|
+
if (command === "job-delete") {
|
|
621
|
+
return output(await deleteJob({
|
|
622
|
+
root: flags.root || process.cwd(), id: positional[0],
|
|
623
|
+
confirmation: booleanFlag(flags["confirm-local-execution"]) ? "local-owner-confirmed" : null
|
|
624
|
+
}), json);
|
|
625
|
+
}
|
|
626
|
+
|
|
627
|
+
if (command === "channel-bind") {
|
|
628
|
+
return output(await grantChannelBinding({
|
|
629
|
+
root: flags.root || process.cwd(), id: positional[0], provider: flags.provider,
|
|
630
|
+
tenantId: flags.tenant, accountId: flags.account, chatId: flags.chat,
|
|
631
|
+
threadId: flags.thread || null,
|
|
632
|
+
senderIds: String(flags.senders || "").split(",").filter(Boolean),
|
|
633
|
+
agentId: flags.agent, projectId: flags.project, groupId: flags.group || null,
|
|
634
|
+
sessionKey: flags.session, secretEnv: flags["secret-env"], outboundSecretEnv: flags["outbound-secret-env"] || null,
|
|
635
|
+
capabilities: String(flags.capabilities || "receive,reply").split(",").filter(Boolean),
|
|
636
|
+
confirmation: booleanFlag(flags["confirm-local-channel"]) ? "local-owner-confirmed" : null
|
|
637
|
+
}), json);
|
|
638
|
+
}
|
|
639
|
+
|
|
640
|
+
if (command === "channel-revoke") {
|
|
641
|
+
return output(await revokeChannelBinding({
|
|
642
|
+
root: flags.root || process.cwd(), id: positional[0], reason: flags.reason,
|
|
643
|
+
confirmation: booleanFlag(flags["confirm-local-channel"]) ? "local-owner-confirmed" : null
|
|
644
|
+
}), json);
|
|
645
|
+
}
|
|
646
|
+
|
|
647
|
+
if (command === "channel-policy") {
|
|
648
|
+
return output((await loadChannelPolicy(positional[0] || process.cwd())).policy, json);
|
|
649
|
+
}
|
|
650
|
+
|
|
651
|
+
if (command === "channel-events") {
|
|
652
|
+
return output(await channelRuntimeContext({
|
|
653
|
+
root: positional[0] || process.cwd(), agentId: flags.agent || null,
|
|
654
|
+
projectId: flags.project || null,
|
|
655
|
+
...(flags.group !== undefined ? { groupId: flags.group || null } : {}),
|
|
656
|
+
provider: flags.provider || null,
|
|
657
|
+
includeTerminal: booleanFlag(flags["include-terminal"]),
|
|
658
|
+
maxItems: Number(flags["max-items"] ?? 20)
|
|
659
|
+
}), json);
|
|
660
|
+
}
|
|
661
|
+
|
|
662
|
+
if (command === "persona-sync") {
|
|
663
|
+
if (!booleanFlag(flags["confirm-local-persona"])) throw new Error("persona synchronization requires --confirm-local-persona");
|
|
664
|
+
return output(await syncPersonaRosterFromEnvironment({
|
|
665
|
+
root: positional[0] || process.cwd(), env: { ...process.env, AGENTSPINE_PERSONA_ROSTER_FILE: flags.roster }
|
|
666
|
+
}), json);
|
|
667
|
+
}
|
|
668
|
+
|
|
669
|
+
if (command === "personas") {
|
|
670
|
+
return output(await personaContext({
|
|
671
|
+
root: positional[0] || process.cwd(), personaId: flags.persona || null,
|
|
672
|
+
...(flags.group !== undefined ? { groupId: flags.group || null } : {}),
|
|
673
|
+
includeInactive: booleanFlag(flags["include-inactive"])
|
|
674
|
+
}), json);
|
|
675
|
+
}
|
|
676
|
+
|
|
677
|
+
if (command === "goal-assign") {
|
|
678
|
+
return output(await assignGoal({
|
|
679
|
+
root: flags.root || process.cwd(), goalId: positional[0], agentId: flags.agent,
|
|
680
|
+
ownerSubjectId: flags.owner, projectId: flags.project, groupId: flags.group || null,
|
|
681
|
+
priority: Number(flags.priority ?? 70), successCriterion: flags.success,
|
|
682
|
+
nextSafeStep: flags["next-step"], deadline: flags.deadline || null,
|
|
683
|
+
confirmation: booleanFlag(flags["confirm-local-goal"]) ? "local-owner-confirmed" : null
|
|
684
|
+
}), json);
|
|
685
|
+
}
|
|
686
|
+
|
|
687
|
+
if (command === "gateway-control") {
|
|
688
|
+
return output(await setGatewayControl({
|
|
689
|
+
root: positional[0] || process.cwd(),
|
|
690
|
+
...(flags.enabled !== undefined ? { enabled: booleanFlag(flags.enabled) } : {}),
|
|
691
|
+
...(flags["kill-switch"] !== undefined ? { killSwitch: booleanFlag(flags["kill-switch"]) } : {}),
|
|
692
|
+
confirmation: booleanFlag(flags["confirm-local-gateway"]) ? "local-owner-confirmed" : null
|
|
693
|
+
}), json);
|
|
694
|
+
}
|
|
695
|
+
|
|
696
|
+
if (command === "gateway-status") {
|
|
697
|
+
return output(await gatewayContext({ root: positional[0] || process.cwd(), agentId: flags.agent || null }), json);
|
|
698
|
+
}
|
|
699
|
+
|
|
700
|
+
if (command === "share-init") {
|
|
701
|
+
return output(await initDirectoryAdapter({
|
|
702
|
+
root: flags.root || process.cwd(), directory: positional[0], scopeId: flags.scope,
|
|
703
|
+
adapterId: flags.adapter, signerId: flags.signer || null,
|
|
704
|
+
confirmation: booleanFlag(flags["confirm-local-share"]) ? "local-share-confirmed" : null
|
|
705
|
+
}), json);
|
|
706
|
+
}
|
|
707
|
+
|
|
708
|
+
if (command === "share-keygen") {
|
|
709
|
+
return output(await generateSigningIdentity({
|
|
710
|
+
root: flags.root || process.cwd(), signerId: positional[0], rotate: booleanFlag(flags.rotate),
|
|
711
|
+
publicOut: flags["public-out"] || null,
|
|
712
|
+
confirmation: booleanFlag(flags["confirm-local-share"]) ? "local-share-confirmed" : null
|
|
713
|
+
}), json);
|
|
714
|
+
}
|
|
715
|
+
|
|
716
|
+
if (command === "share-signers") {
|
|
717
|
+
return output(await listSigningIdentities({ root: positional[0] || process.cwd() }), json);
|
|
718
|
+
}
|
|
719
|
+
|
|
720
|
+
if (command === "share-trust") {
|
|
721
|
+
return output(await trustSigner({
|
|
722
|
+
root: flags.root || process.cwd(), publicIdentityPath: positional[0],
|
|
723
|
+
confirmation: booleanFlag(flags["confirm-local-share"]) ? "local-share-confirmed" : null
|
|
724
|
+
}), json);
|
|
725
|
+
}
|
|
726
|
+
|
|
727
|
+
if (command === "share-trust-revoke") {
|
|
728
|
+
return output(await revokeTrustedSigner({
|
|
729
|
+
root: flags.root || process.cwd(), keyId: positional[0], reason: flags.reason,
|
|
730
|
+
confirmation: booleanFlag(flags["confirm-local-share"]) ? "local-share-confirmed" : null
|
|
731
|
+
}), json);
|
|
732
|
+
}
|
|
733
|
+
|
|
734
|
+
if (command === "share-trust-list") {
|
|
735
|
+
return output(await trustedSignerContext({
|
|
736
|
+
root: positional[0] || process.cwd(), includeRevoked: booleanFlag(flags["include-revoked"])
|
|
737
|
+
}), json);
|
|
738
|
+
}
|
|
739
|
+
|
|
740
|
+
if (command === "share-publish") {
|
|
741
|
+
return output(await publishLearning({
|
|
742
|
+
root: flags.root || process.cwd(), directory: positional[0], learningId: flags.learning,
|
|
743
|
+
eventId: flags.id, supersedesEventId: flags.supersedes || null, signerId: flags.signer || null,
|
|
744
|
+
confirmation: booleanFlag(flags["confirm-local-share"]) ? "local-share-confirmed" : null
|
|
745
|
+
}), json);
|
|
746
|
+
}
|
|
747
|
+
|
|
748
|
+
if (command === "share-pull") {
|
|
749
|
+
return output(await pullShared({
|
|
750
|
+
root: flags.root || process.cwd(), directory: positional[0],
|
|
751
|
+
requireAuthenticated: booleanFlag(flags["require-authenticated"])
|
|
752
|
+
}), json);
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
if (command === "share-snapshot-export") {
|
|
756
|
+
return output(await exportHttpsSnapshot({
|
|
757
|
+
root: flags.root || process.cwd(), directory: positional[0], output: flags.out,
|
|
758
|
+
snapshotId: flags.id,
|
|
759
|
+
confirmation: booleanFlag(flags["confirm-local-share"]) ? "local-share-confirmed" : null
|
|
760
|
+
}), json);
|
|
761
|
+
}
|
|
762
|
+
|
|
763
|
+
if (command === "share-https-publish") {
|
|
764
|
+
return output(await publishHttpsSnapshot({
|
|
765
|
+
root: flags.root || process.cwd(), directory: positional[0], baseUrl: flags.base,
|
|
766
|
+
snapshotId: flags.id, tokenEnv: flags["token-env"] || null,
|
|
767
|
+
timeoutMs: Number(flags["timeout-ms"] ?? 10000),
|
|
768
|
+
allowPrivateNetwork: booleanFlag(flags["allow-private-network"]),
|
|
769
|
+
confirmation: booleanFlag(flags["confirm-local-share"]) ? "local-share-confirmed" : null
|
|
770
|
+
}), json);
|
|
771
|
+
}
|
|
772
|
+
|
|
773
|
+
if (command === "share-https-pull") {
|
|
774
|
+
return output(await pullHttpsSnapshot({
|
|
775
|
+
root: flags.root || process.cwd(), url: positional[0], tokenEnv: flags["token-env"] || null,
|
|
776
|
+
timeoutMs: Number(flags["timeout-ms"] ?? 10000),
|
|
777
|
+
allowPrivateNetwork: booleanFlag(flags["allow-private-network"]),
|
|
778
|
+
confirmation: booleanFlag(flags["confirm-local-share"]) ? "local-share-confirmed" : null
|
|
779
|
+
}), json);
|
|
780
|
+
}
|
|
781
|
+
|
|
782
|
+
if (command === "share-feed-publish") {
|
|
783
|
+
return output(await publishHttpsFeed({
|
|
784
|
+
root: flags.root || process.cwd(), directory: positional[0], baseUrl: flags.base,
|
|
785
|
+
feedId: flags.feed, signerId: flags.signer, snapshotId: flags.id,
|
|
786
|
+
tokenEnv: flags["token-env"] || null, timeoutMs: Number(flags["timeout-ms"] ?? 10000),
|
|
787
|
+
allowPrivateNetwork: booleanFlag(flags["allow-private-network"]),
|
|
788
|
+
confirmation: booleanFlag(flags["confirm-local-share"]) ? "local-share-confirmed" : null
|
|
789
|
+
}), json);
|
|
790
|
+
}
|
|
791
|
+
|
|
792
|
+
if (command === "share-feed-pull") {
|
|
793
|
+
return output(await pullHttpsFeed({
|
|
794
|
+
root: flags.root || process.cwd(), baseUrl: flags.base, feedId: flags.feed,
|
|
795
|
+
tokenEnv: flags["token-env"] || null, timeoutMs: Number(flags["timeout-ms"] ?? 10000),
|
|
796
|
+
allowPrivateNetwork: booleanFlag(flags["allow-private-network"]),
|
|
797
|
+
confirmation: booleanFlag(flags["confirm-local-share"]) ? "local-share-confirmed" : null
|
|
798
|
+
}), json);
|
|
799
|
+
}
|
|
800
|
+
|
|
801
|
+
if (command === "share-feed-state") {
|
|
802
|
+
return output(await loadHttpsFeedState(positional[0] || process.cwd()), json);
|
|
803
|
+
}
|
|
804
|
+
|
|
805
|
+
if (command === "share-peer-serve") {
|
|
806
|
+
await servePeerOnce({
|
|
807
|
+
root: flags.root || process.cwd(), directory: positional[0], signerId: flags.signer,
|
|
808
|
+
input: process.stdin, output: process.stdout,
|
|
809
|
+
timeoutMs: Number(flags["timeout-ms"] ?? 10000),
|
|
810
|
+
confirmation: booleanFlag(flags["confirm-local-share"]) ? "local-share-confirmed" : null
|
|
811
|
+
});
|
|
812
|
+
return;
|
|
813
|
+
}
|
|
814
|
+
|
|
815
|
+
if (command === "share-peer-pull") {
|
|
816
|
+
return output(await pullPeerCommand({
|
|
817
|
+
root: flags.root || process.cwd(), commandJson: flags["command-json"],
|
|
818
|
+
timeoutMs: Number(flags["timeout-ms"] ?? 10000),
|
|
819
|
+
maxBytes: Number(flags["max-bytes"] ?? 22 * 1024 * 1024),
|
|
820
|
+
confirmation: booleanFlag(flags["confirm-local-share"]) ? "local-share-confirmed" : null
|
|
821
|
+
}), json);
|
|
822
|
+
}
|
|
823
|
+
|
|
824
|
+
if (command === "share-sqlite-init") {
|
|
825
|
+
return output(await initSqliteAdapter({
|
|
826
|
+
root: flags.root || process.cwd(), directory: positional[0], database: flags.database,
|
|
827
|
+
confirmation: booleanFlag(flags["confirm-local-share"]) ? "local-share-confirmed" : null
|
|
828
|
+
}), json);
|
|
829
|
+
}
|
|
830
|
+
|
|
831
|
+
if (command === "share-sqlite-publish") {
|
|
832
|
+
return output(await publishSqliteSnapshot({
|
|
833
|
+
root: flags.root || process.cwd(), directory: positional[0], database: flags.database,
|
|
834
|
+
snapshotId: flags.id,
|
|
835
|
+
confirmation: booleanFlag(flags["confirm-local-share"]) ? "local-share-confirmed" : null
|
|
836
|
+
}), json);
|
|
837
|
+
}
|
|
838
|
+
|
|
839
|
+
if (command === "share-sqlite-inspect") {
|
|
840
|
+
return output(await inspectSqliteAdapter({
|
|
841
|
+
root: flags.root || process.cwd(), database: flags.database
|
|
842
|
+
}), json);
|
|
843
|
+
}
|
|
844
|
+
|
|
845
|
+
if (command === "share-sqlite-pull") {
|
|
846
|
+
return output(await pullSqliteSnapshot({
|
|
847
|
+
root: flags.root || process.cwd(), database: flags.database
|
|
848
|
+
}), json);
|
|
849
|
+
}
|
|
850
|
+
|
|
851
|
+
if (command === "share-inbox") {
|
|
852
|
+
return output(await sharedInbox({ root: positional[0] || process.cwd(), status: flags.status || "pending" }), json);
|
|
853
|
+
}
|
|
854
|
+
|
|
855
|
+
if (command === "share-review") {
|
|
856
|
+
return output(await reviewShared({
|
|
857
|
+
root: flags.root || process.cwd(), id: positional[0], decision: flags.decision,
|
|
858
|
+
reason: flags.reason, confirmedByUser: booleanFlag(flags["confirmed-by-user"])
|
|
859
|
+
}), json);
|
|
860
|
+
}
|
|
861
|
+
|
|
862
|
+
if (command === "share-context") {
|
|
863
|
+
return output(await sharedContext({
|
|
864
|
+
root: positional[0] || process.cwd(), scopeId: flags.scope || null, groupId: flags.group || null,
|
|
865
|
+
includePrivate: booleanFlag(flags["include-private"]),
|
|
866
|
+
kinds: flags.kind ? String(flags.kind).split(",").filter(Boolean) : null,
|
|
867
|
+
subjectIds: flags.subject ? String(flags.subject).split(",").filter(Boolean) : null,
|
|
868
|
+
maxItems: flags["max-items"] === undefined ? null : Number(flags["max-items"])
|
|
869
|
+
}), json);
|
|
870
|
+
}
|
|
871
|
+
|
|
872
|
+
if (command === "share-rollback") {
|
|
873
|
+
return output(await rollbackShared({
|
|
874
|
+
root: flags.root || process.cwd(), id: positional[0], reason: flags.reason
|
|
875
|
+
}), json);
|
|
876
|
+
}
|
|
877
|
+
|
|
878
|
+
if (command === "share-delete") {
|
|
879
|
+
return output(await deleteShared({
|
|
880
|
+
root: flags.root || process.cwd(), id: positional[0],
|
|
881
|
+
confirmation: booleanFlag(flags["confirm-local-share"]) ? "local-share-confirmed" : null
|
|
882
|
+
}), json);
|
|
883
|
+
}
|
|
884
|
+
|
|
885
|
+
if (command === "share-config") {
|
|
886
|
+
return output(await configureSharing({
|
|
887
|
+
root: positional[0] || process.cwd(), maxContextItems: Number(flags["max-items"])
|
|
888
|
+
}), json);
|
|
889
|
+
}
|
|
890
|
+
|
|
891
|
+
if (command === "doctor") {
|
|
892
|
+
let hostIntegration;
|
|
893
|
+
try {
|
|
894
|
+
hostIntegration = await checkHosts(fileURLToPath(new URL("..", import.meta.url)));
|
|
895
|
+
} catch (error) {
|
|
896
|
+
hostIntegration = { ok: false, error: error.message };
|
|
897
|
+
}
|
|
898
|
+
let sourceResolution = null;
|
|
899
|
+
let orphanScan = null;
|
|
900
|
+
const sourceHost = flags.host || process.env.AGENTSPINE_HOST;
|
|
901
|
+
if (["claude", "codex"].includes(sourceHost)) {
|
|
902
|
+
try {
|
|
903
|
+
const resolved = await resolveHostSourceCatalog({ host: sourceHost, cwd: flags.cwd || process.cwd() });
|
|
904
|
+
sourceResolution = resolved.diagnostics;
|
|
905
|
+
if (booleanFlag(flags["offline-memory-orphans"])) {
|
|
906
|
+
if (sourceHost !== "claude" || !resolved.memoryRoot) throw new Error("offline memory orphan scan requires a resolved Claude project-memory root");
|
|
907
|
+
orphanScan = await scanIndexedMemoryOrphans(resolved.memoryRoot);
|
|
908
|
+
}
|
|
909
|
+
}
|
|
910
|
+
catch (error) { sourceResolution = { status: "failed-closed", reason: error.message }; }
|
|
911
|
+
}
|
|
912
|
+
const result = {
|
|
913
|
+
ok: Number(process.versions.node.split(".")[0]) >= 20 && hostIntegration.ok
|
|
914
|
+
&& (!sourceResolution || sourceResolution.status === "loaded"),
|
|
915
|
+
version: VERSION,
|
|
916
|
+
node: process.versions.node,
|
|
917
|
+
platform: process.platform,
|
|
918
|
+
preservationMode: "read-only-source-overlay",
|
|
919
|
+
stateDirectory: process.env.AGENTSPINE_STATE_DIR || "platform-default",
|
|
920
|
+
hostIntegration,
|
|
921
|
+
sourceResolution,
|
|
922
|
+
orphanScan
|
|
923
|
+
};
|
|
924
|
+
output(result, json);
|
|
925
|
+
if (!result.ok) process.exitCode = 1;
|
|
926
|
+
return;
|
|
927
|
+
}
|
|
928
|
+
|
|
929
|
+
if (command === "audit") {
|
|
930
|
+
const result = await runAudit(positional[0] || process.cwd(), { host: flags.host || process.env.AGENTSPINE_HOST || null });
|
|
931
|
+
output(result, json);
|
|
932
|
+
if (!result.ok) process.exitCode = 1;
|
|
933
|
+
return;
|
|
934
|
+
}
|
|
935
|
+
|
|
936
|
+
if (command === "mcp") {
|
|
937
|
+
const { startMcpServer } = await import("./mcp.js");
|
|
938
|
+
startMcpServer();
|
|
939
|
+
return;
|
|
940
|
+
}
|
|
941
|
+
|
|
942
|
+
throw new Error(`Unknown command: ${command}`);
|
|
943
|
+
}
|
|
944
|
+
|
|
945
|
+
if (isMainModule(import.meta.url)) {
|
|
946
|
+
run().catch((error) => {
|
|
947
|
+
process.stderr.write(`AgentSpine: ${error.message}\n`);
|
|
948
|
+
process.exitCode = 1;
|
|
949
|
+
});
|
|
950
|
+
}
|