@0dai-dev/cli 4.3.6 → 4.3.7
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +12 -11
- package/bin/0dai.js +127 -30
- package/lib/ai/manifest/mcp-exposure-contract.json +121 -0
- package/lib/ai/meta/manifest/mcp-tool-tiers.json +435 -0
- package/lib/ai/registry/mcp-catalog.json +98 -0
- package/lib/commands/auth.js +2 -1
- package/lib/commands/compliance.js +1 -1
- package/lib/commands/doctor.js +506 -12
- package/lib/commands/experience.js +40 -5
- package/lib/commands/feedback.js +157 -15
- package/lib/commands/gh.js +26 -0
- package/lib/commands/graph.js +9 -4
- package/lib/commands/heatmap.js +1 -1
- package/lib/commands/init.js +209 -27
- package/lib/commands/mcp.js +111 -33
- package/lib/commands/models.js +138 -41
- package/lib/commands/provider.js +30 -59
- package/lib/commands/quota.js +1 -1
- package/lib/commands/receipt.js +1 -1
- package/lib/commands/run.js +14 -6
- package/lib/commands/runner.js +31 -1
- package/lib/commands/status.js +38 -10
- package/lib/commands/swarm.js +130 -12
- package/lib/commands/update.js +184 -38
- package/lib/commands/usage.js +1 -1
- package/lib/commands/validate.js +32 -3
- package/lib/commands/vault.js +43 -8
- package/lib/python/__init__.py +0 -0
- package/lib/python/agent_quotas.py +525 -0
- package/lib/python/anomaly_alert.py +397 -0
- package/lib/python/anti_pattern_detector.py +799 -0
- package/lib/python/auth.py +443 -0
- package/lib/python/capi_profile_guard.py +477 -0
- package/lib/python/compliance_report.py +581 -0
- package/lib/python/drift_detector.py +388 -0
- package/lib/python/experience_pipeline.py +1130 -0
- package/lib/python/graph.py +19 -0
- package/lib/python/graph_core.py +293 -0
- package/lib/python/graph_io.py +179 -0
- package/lib/python/graph_legacy.py +2052 -0
- package/lib/python/graph_legacy_helpers.py +221 -0
- package/lib/python/graph_outcomes_core.py +85 -0
- package/lib/python/graph_queries.py +171 -0
- package/lib/python/graph_slice.py +198 -0
- package/lib/python/graph_slicer.py +576 -0
- package/lib/python/graph_slicer_cli.py +60 -0
- package/lib/python/graph_validation.py +64 -0
- package/lib/python/heatmap.py +934 -0
- package/lib/python/json_utils.py +193 -0
- package/lib/python/mcp_exposure_check.py +247 -0
- package/lib/python/model_router.py +1434 -0
- package/lib/python/project_manager.py +621 -0
- package/lib/python/provider_profiles.py +1618 -0
- package/lib/python/provider_registry.py +1211 -0
- package/lib/python/provider_registry_cli.py +125 -0
- package/lib/python/receipt_png.py +727 -0
- package/lib/python/structural_memory.py +325 -0
- package/lib/python/swarm_cost.py +177 -0
- package/lib/python/usage_ledger.py +569 -0
- package/lib/scripts/mcp_tier_config.py +240 -0
- package/lib/shared.js +95 -12
- package/lib/tui/index.mjs +35174 -0
- package/lib/utils/activation_telemetry.js +1 -4
- package/lib/utils/constants.js +7 -1
- package/lib/utils/identity.js +184 -0
- package/lib/utils/mcp-auth.js +81 -15
- package/lib/utils/plan.js +1 -1
- package/lib/vault/index.js +19 -3
- package/lib/vault/storage.js +21 -2
- package/lib/wizard.js +5 -2
- package/package.json +9 -3
- package/scripts/build-python-bundle.js +106 -0
- package/scripts/build-tui.js +14 -1
- package/scripts/harvest_experience.py +523 -0
- package/scripts/postinstall.js +15 -9
package/README.md
CHANGED
|
@@ -43,39 +43,36 @@ Daily (regular work):
|
|
|
43
43
|
0dai run <goal> # split a backlog item into agent tasks [--dry-run] [--dry-cost] [--agent claude|codex|gemini]
|
|
44
44
|
0dai swarm status # show queued, active, and done tasks
|
|
45
45
|
0dai swarm add # queue one task [--task '...' --to agent]
|
|
46
|
-
0dai swarm
|
|
46
|
+
0dai swarm pick # pick one queued task [--agent codex]
|
|
47
|
+
0dai swarm-run # repo-checkout helper: add, dispatch, and wait for one swarm task as JSON
|
|
47
48
|
0dai harvest # convert experience events into candidate lessons
|
|
48
49
|
0dai watch # live task monitor [--interval N]
|
|
49
50
|
0dai reflect # session reflection: delivered, delegation, blockers
|
|
50
|
-
0dai standup # morning voice briefing about overnight agent work
|
|
51
|
-
0dai feedback push
|
|
51
|
+
0dai standup # repo-checkout helper: morning voice briefing about overnight agent work
|
|
52
|
+
0dai feedback push --target . # send feedback to 0dai
|
|
52
53
|
0dai feedback retry # retry queued feedback after a failed push
|
|
53
|
-
0dai persona-simulate "topic" # focus-group report and optional issue drafts
|
|
54
54
|
```
|
|
55
55
|
|
|
56
56
|
Pro / advanced:
|
|
57
57
|
|
|
58
58
|
```bash
|
|
59
59
|
0dai init-existing # existing-repo setup alias for init
|
|
60
|
-
0dai project bind # bind repository to your 0dai account [--json]
|
|
60
|
+
0dai project bind # bind repository to your 0dai account [--name NAME] [--json]
|
|
61
61
|
0dai project status # local project binding and health [--json]
|
|
62
62
|
0dai graph push # upload local graph (Pro: edges, Free: nodes)
|
|
63
63
|
0dai graph pull # download server graph and merge locally
|
|
64
64
|
0dai graph status # local graph stats and sync state
|
|
65
|
-
0dai ci # portable CI pipelines and AI-MQ [list|plan|mq-status]
|
|
66
65
|
0dai heatmap # repo treemap: LOC × agent-edit intensity
|
|
67
66
|
0dai session save # save session for roaming
|
|
68
|
-
0dai provider #
|
|
67
|
+
0dai provider # provider profiles and local BYOK registry [status|list|switch|clear]
|
|
69
68
|
0dai models # model ratings (--fast/--balanced/--deep/--available)
|
|
70
69
|
0dai quota # agent subscription usage [--refresh] [--json]
|
|
71
70
|
0dai usage # local token, task, and USD ledger [status|daily|monthly]
|
|
72
71
|
0dai workspace # tmux workspace sessions (init|up|status)
|
|
73
|
-
0dai
|
|
74
|
-
0dai report # privacy-safe project reports (preview|push|status)
|
|
72
|
+
0dai report # repo-checkout helper: privacy-safe project reports (preview|push|status)
|
|
75
73
|
0dai compliance # SOC2/ISO evidence and ADR audit-trail export
|
|
76
|
-
0dai experience # structured experience events (list|stats|sync|warnings|dismiss)
|
|
74
|
+
0dai experience # structured experience events (list|stats|record-json|sync|warnings|dismiss)
|
|
77
75
|
0dai receipt # session receipt PNG [--last|--active|--session ID]
|
|
78
|
-
0dai boneyard # weekly digest of worst agent moves [--week YYYY-WW|current]
|
|
79
76
|
0dai gh branch-protection # GitHub branch protection [print|apply|install]
|
|
80
77
|
0dai import claude-code-agents # import .claude/agents/*.md as personas [--dry-run]
|
|
81
78
|
0dai auth logout # remove credentials
|
|
@@ -100,6 +97,10 @@ Global flags: `--target PATH`, `--version`, `--help`, `--json`, `--quiet`. See `
|
|
|
100
97
|
|
|
101
98
|
Your source code is never sent. Only file names and package/build manifests.
|
|
102
99
|
|
|
100
|
+
## Privacy
|
|
101
|
+
|
|
102
|
+
Local activation and experience records stay on your machine: `ai/meta/telemetry/activation.jsonl`, `ai/experience/`, and the generated `ai/` layer/project agent configs are local files. Server-side activation sends one `free_tier_activated` event when you run `0dai activate free` unless telemetry is opted out. See https://0dai.dev/legal/privacy.
|
|
103
|
+
|
|
103
104
|
## Why 0dai, not just Cursor or Copilot?
|
|
104
105
|
|
|
105
106
|
Cursor and Copilot are editors. They help inside one coding session. 0dai writes a project layer that Claude Code, Codex, OpenCode, Gemini, and Aider can all read. The point is not another autocomplete box; it is one manifest, one set of agent roles, one task queue, and one health check for the repo.
|
package/bin/0dai.js
CHANGED
|
@@ -26,7 +26,7 @@ if ((earlyParsed.args[0] || "help") === "swarm-run") {
|
|
|
26
26
|
}
|
|
27
27
|
|
|
28
28
|
const shared = require("../lib/shared");
|
|
29
|
-
const { T, R, D, log, VERSION, fs, path, spawnSync, findRepoScript, checkVersion } = shared;
|
|
29
|
+
const { T, R, D, log, VERSION, fs, path, spawnSync, findRepoScript, repoScriptCandidates, checkVersion } = shared;
|
|
30
30
|
|
|
31
31
|
/**
|
|
32
32
|
* Hot-path Go binary fallback (issue #2424).
|
|
@@ -130,7 +130,10 @@ function tryGoHotPath(cmdName, target, argv) {
|
|
|
130
130
|
if (!bin) return false;
|
|
131
131
|
if (!goBinaryCompatible(bin)) return false;
|
|
132
132
|
const forwarded = [cmdName, "--target", target, ...argv];
|
|
133
|
-
const res = spawnSync(bin, forwarded, {
|
|
133
|
+
const res = spawnSync(bin, forwarded, {
|
|
134
|
+
stdio: "inherit",
|
|
135
|
+
env: { ...process.env, ODAI_NODE_PTY_PROBE_DIR: path.join(__dirname, "..") },
|
|
136
|
+
});
|
|
134
137
|
if (res.error) return false;
|
|
135
138
|
if (typeof res.status === "number") process.exit(res.status);
|
|
136
139
|
process.exit(0);
|
|
@@ -157,7 +160,7 @@ const { cmdAudit } = require("../lib/commands/audit");
|
|
|
157
160
|
const { cmdExport } = require("../lib/commands/export");
|
|
158
161
|
const { cmdMcp } = require("../lib/commands/mcp");
|
|
159
162
|
const { cmdVault } = require("../lib/commands/vault");
|
|
160
|
-
const { cmdDoctor } = require("../lib/commands/doctor");
|
|
163
|
+
const { cmdDoctor, collectLayerVersionFreshness } = require("../lib/commands/doctor");
|
|
161
164
|
const { cmdValidate } = require("../lib/commands/validate");
|
|
162
165
|
const { cmdUpdate } = require("../lib/commands/update");
|
|
163
166
|
const { cmdUpgrade } = require("../lib/commands/upgrade");
|
|
@@ -221,40 +224,38 @@ function printHelp() {
|
|
|
221
224
|
console.log(" run <goal> Split a backlog item into agent tasks [--dry-run] [--dry-cost] [--max-cost N] [--agent claude|codex|gemini] [--provider X]");
|
|
222
225
|
console.log(" swarm status Show queued, active, and done tasks");
|
|
223
226
|
console.log(" swarm add Queue one task for an agent [--task '...' --to agent]");
|
|
224
|
-
console.log(" swarm
|
|
227
|
+
console.log(" swarm pick Pick one queued task for this agent [--agent codex]");
|
|
228
|
+
console.log(" swarm-run Repo-checkout helper: add, dispatch, and wait for one swarm task as JSON");
|
|
225
229
|
console.log(" harvest Convert experience events into candidate lessons");
|
|
226
230
|
console.log(" watch Live task monitor: queue, active, recently done [--interval N]");
|
|
227
231
|
console.log(" reflect Session reflection: delivered, delegation rate, blockers");
|
|
228
|
-
console.log(" standup
|
|
232
|
+
console.log(" standup Repo-checkout helper: morning voice briefing about overnight agent work");
|
|
229
233
|
console.log(" feedback push Send feedback to 0dai");
|
|
234
|
+
console.log(" feedback submit Send one feedback report file [--file ai/feedback/codex-report.json]");
|
|
230
235
|
console.log(" feedback retry Retry queued feedback after a failed push");
|
|
231
236
|
console.log("");
|
|
232
237
|
console.log("Pro / advanced:");
|
|
233
238
|
console.log(" init-existing Legacy alias for init (older docs / scripted bootstraps); use 'init' [--minimal] [--dry-run]");
|
|
234
|
-
console.log(" project bind Bind current repository to your 0dai account [--json]");
|
|
239
|
+
console.log(" project bind Bind current repository to your 0dai account [--name NAME] [--json]");
|
|
235
240
|
console.log(" project status Show local project binding and health state [--json]");
|
|
236
241
|
console.log(" graph push Upload local graph to server (Pro: edges, Free: nodes)");
|
|
237
242
|
console.log(" graph pull Download server graph and merge locally");
|
|
238
243
|
console.log(" graph status Show local graph stats and sync state");
|
|
239
|
-
console.log(" ci Plan portable 0dai CI pipelines and inspect AI-MQ [list|plan|mq-status] [--json]");
|
|
240
244
|
console.log(" mcp MCP server, tools, and health [list|catalog|doctor|call] [--json]");
|
|
241
245
|
console.log(" vault Local age-encrypted secrets vault [init|add|get] [--json]");
|
|
242
246
|
console.log(" heatmap Repo treemap: LOC x agent-edit intensity");
|
|
243
247
|
console.log(" session save Save session for roaming");
|
|
244
|
-
console.log(" provider Local provider profiles
|
|
248
|
+
console.log(" provider Local provider profiles and BYOK registry [status|list|switch|clear]");
|
|
245
249
|
console.log(" models Show model ratings (--fast/--balanced/--deep/--available)");
|
|
246
250
|
console.log(" models recommend Ledger-ranked model pick for a task type [--task TYPE] [--goal '...'] [--json]");
|
|
247
251
|
console.log(" quota Agent subscription usage table [--refresh] [--json]");
|
|
248
252
|
console.log(" usage Local token, task, and USD usage ledger [status|daily|monthly]");
|
|
249
253
|
console.log(" workspace Manage tmux workspace sessions (init|up|status)");
|
|
250
|
-
console.log("
|
|
251
|
-
console.log(" report Privacy-safe project reports (preview|push|status)");
|
|
254
|
+
console.log(" report Repo-checkout helper: privacy-safe project reports (preview|push|status)");
|
|
252
255
|
console.log(" trust Pre-run blast-radius: protected paths, authority matrix, egress [--json]");
|
|
253
256
|
console.log(" compliance SOC2/ISO evidence and ADR audit-trail export");
|
|
254
|
-
console.log(" experience Structured experience events (list|stats|sync|warnings|dismiss)");
|
|
255
|
-
console.log(" persona-simulate Produce a focus-group report and optional issue drafts");
|
|
257
|
+
console.log(" experience Structured experience events (list|stats|record-json|sync|warnings|dismiss)");
|
|
256
258
|
console.log(" receipt Render a 1200×630 session receipt PNG [--last|--active|--session ID]");
|
|
257
|
-
console.log(" boneyard Weekly digest of worst agent moves [--week YYYY-WW|current]");
|
|
258
259
|
console.log(" gh branch-protection [print|apply|install] Manage generated GitHub branch protection");
|
|
259
260
|
console.log(" import claude-code-agents Import .claude/agents/*.md as 0dai personas [--source DIR] [--target DIR] [--dry-run]");
|
|
260
261
|
console.log(" auth logout Remove credentials");
|
|
@@ -270,29 +271,105 @@ function printHelp() {
|
|
|
270
271
|
console.log("https://0dai.dev");
|
|
271
272
|
}
|
|
272
273
|
|
|
274
|
+
function explainMissingHarvestHelper(target, args) {
|
|
275
|
+
const candidates = repoScriptCandidates(target, "harvest_experience.py");
|
|
276
|
+
if (args.includes("--json")) {
|
|
277
|
+
console.log(JSON.stringify({
|
|
278
|
+
error: "harvest_helper_unavailable",
|
|
279
|
+
helper: "harvest_experience.py",
|
|
280
|
+
target,
|
|
281
|
+
looked_in: candidates,
|
|
282
|
+
fallback_inputs: [
|
|
283
|
+
"ai/experience/events/*.json",
|
|
284
|
+
"ai/experience/events/*.jsonl",
|
|
285
|
+
"ai/experience/outbox/*.json",
|
|
286
|
+
"ai/experience/outbox/*.jsonl",
|
|
287
|
+
],
|
|
288
|
+
required_fallback_fields: [
|
|
289
|
+
"schema",
|
|
290
|
+
"event_id",
|
|
291
|
+
"timestamp",
|
|
292
|
+
"event_type",
|
|
293
|
+
"tool",
|
|
294
|
+
"task_type",
|
|
295
|
+
"summary",
|
|
296
|
+
"paths",
|
|
297
|
+
"ci_passed",
|
|
298
|
+
"source",
|
|
299
|
+
],
|
|
300
|
+
}, null, 2));
|
|
301
|
+
return;
|
|
302
|
+
}
|
|
303
|
+
|
|
304
|
+
log("harvest helper unavailable");
|
|
305
|
+
if (!args.includes("--explain")) return;
|
|
306
|
+
|
|
307
|
+
console.log(` ${D}looked for scripts/harvest_experience.py at:${R}`);
|
|
308
|
+
for (const candidate of candidates) {
|
|
309
|
+
console.log(` - ${candidate}`);
|
|
310
|
+
}
|
|
311
|
+
console.log(` ${D}fallback event inputs:${R}`);
|
|
312
|
+
console.log(" - ai/experience/events/*.json");
|
|
313
|
+
console.log(" - ai/experience/events/*.jsonl");
|
|
314
|
+
console.log(" - ai/experience/outbox/*.json");
|
|
315
|
+
console.log(" - ai/experience/outbox/*.jsonl");
|
|
316
|
+
console.log(` ${D}fallback schema fields:${R}`);
|
|
317
|
+
console.log(" schema, event_id, timestamp, event_type, tool, task_type, summary, paths, ci_passed, source");
|
|
318
|
+
}
|
|
319
|
+
|
|
273
320
|
const SYNC_ALLOWED_FLAGS = new Set([
|
|
321
|
+
"--check",
|
|
274
322
|
"--dry-run",
|
|
275
323
|
"--yes",
|
|
276
324
|
"-y",
|
|
277
325
|
"--quiet",
|
|
278
326
|
"-q",
|
|
279
327
|
"--force",
|
|
328
|
+
"--force-template-reset",
|
|
280
329
|
"--no-diff",
|
|
281
330
|
"--no-mcp-auth",
|
|
282
331
|
"--skip-link-check",
|
|
283
332
|
"--strict-links",
|
|
284
333
|
]);
|
|
285
334
|
|
|
335
|
+
function printInitHelp(commandName = "init") {
|
|
336
|
+
console.log(`\n ${T}0dai ${commandName}${R} — Create or refresh the managed ai/ layer\n`);
|
|
337
|
+
console.log("Usage:");
|
|
338
|
+
console.log(` 0dai ${commandName} [--local] [--minimal] [--dry-run] [--no-wizard] [--auth-code CODE] [--code LICENSE] [--no-mcp-auth] [--mcp-host HOST] [--reset] [--target PATH]`);
|
|
339
|
+
console.log("");
|
|
340
|
+
console.log("Options:");
|
|
341
|
+
console.log(" --local Generate the ai/ layer offline without signing in");
|
|
342
|
+
console.log(" --minimal Generate the smallest starter layer");
|
|
343
|
+
console.log(" --dry-run Preview init changes without writing them");
|
|
344
|
+
console.log(" --no-wizard Skip the interactive first-run wizard");
|
|
345
|
+
console.log(" --auth-code Exchange a browser/device auth code before init");
|
|
346
|
+
console.log(" --code Redeem an activation/license code before init");
|
|
347
|
+
console.log(" --no-mcp-auth Skip MCP cloud-token bootstrap during init");
|
|
348
|
+
console.log(" --mcp-host Use a custom MCP cloud host");
|
|
349
|
+
console.log(" --reset Overwrite managed MCP entries during bootstrap");
|
|
350
|
+
console.log(" --target PATH Run init against another project path");
|
|
351
|
+
console.log("");
|
|
352
|
+
}
|
|
353
|
+
|
|
354
|
+
function handleInitHelp(args) {
|
|
355
|
+
const initArgs = args.slice(1);
|
|
356
|
+
if (!initArgs.includes("--help") && !initArgs.includes("-h")) return false;
|
|
357
|
+
printInitHelp(args[0] || "init");
|
|
358
|
+
return true;
|
|
359
|
+
}
|
|
360
|
+
|
|
286
361
|
function printSyncHelp() {
|
|
287
362
|
console.log(`\n ${T}0dai sync${R} — Update the managed ai/ layer\n`);
|
|
288
363
|
console.log("Usage:");
|
|
289
|
-
console.log(" 0dai sync [--dry-run] [--yes|-y] [--quiet|-q] [--force] [--no-diff] [--no-mcp-auth] [--target PATH]");
|
|
364
|
+
console.log(" 0dai sync [--check] [--dry-run] [--yes|-y] [--quiet|-q] [--force] [--force-template-reset] [--no-diff] [--no-mcp-auth] [--target PATH]");
|
|
290
365
|
console.log("");
|
|
291
366
|
console.log("Options:");
|
|
367
|
+
console.log(" --check CI-friendly alias for --dry-run --quiet");
|
|
292
368
|
console.log(" --dry-run Preview managed file changes without writing them");
|
|
293
369
|
console.log(" --yes, -y Apply changes without an interactive confirmation prompt");
|
|
294
370
|
console.log(" --quiet, -q Reduce non-essential output");
|
|
295
371
|
console.log(" --force Also overwrite native config files from managed ai/ sources");
|
|
372
|
+
console.log(" --force-template-reset Allow replacing project-owned roadmap/manifest state");
|
|
296
373
|
console.log(" --no-diff Hide unified diff output in previews/prompts");
|
|
297
374
|
console.log(" --no-mcp-auth Skip MCP cloud-token bootstrap during sync");
|
|
298
375
|
console.log(" --skip-link-check Skip the SPEC-028 doc cross-link scan after sync");
|
|
@@ -318,6 +395,24 @@ function handleSyncHelpOrInvalidArgs(args) {
|
|
|
318
395
|
return false;
|
|
319
396
|
}
|
|
320
397
|
|
|
398
|
+
function printActivateHelp() {
|
|
399
|
+
console.log(`\n ${T}0dai activate${R} — Claim or inspect a 0dai activation\n`);
|
|
400
|
+
console.log("Usage:");
|
|
401
|
+
console.log(" 0dai activate [free|status|code <CODE>] [--target PATH]");
|
|
402
|
+
console.log("");
|
|
403
|
+
console.log("Privacy:");
|
|
404
|
+
console.log(" Local files stay local; 'activate free' sends one free_tier_activated event unless telemetry is opted out.");
|
|
405
|
+
console.log(" https://0dai.dev/legal/privacy");
|
|
406
|
+
console.log("");
|
|
407
|
+
}
|
|
408
|
+
|
|
409
|
+
function handleActivateHelp(args) {
|
|
410
|
+
const activateArgs = args.slice(1);
|
|
411
|
+
if (!activateArgs.includes("--help") && !activateArgs.includes("-h")) return false;
|
|
412
|
+
printActivateHelp();
|
|
413
|
+
return true;
|
|
414
|
+
}
|
|
415
|
+
|
|
321
416
|
async function main() {
|
|
322
417
|
const { args, target } = parseTargetAndArgs(process.argv.slice(2), process.cwd());
|
|
323
418
|
|
|
@@ -333,8 +428,18 @@ async function main() {
|
|
|
333
428
|
return;
|
|
334
429
|
}
|
|
335
430
|
|
|
336
|
-
|
|
337
|
-
|
|
431
|
+
if ((cmd === "init" || cmd === "init-existing") && handleInitHelp(args)) {
|
|
432
|
+
return;
|
|
433
|
+
}
|
|
434
|
+
|
|
435
|
+
if (cmd === "activate" && handleActivateHelp(args)) {
|
|
436
|
+
return;
|
|
437
|
+
}
|
|
438
|
+
|
|
439
|
+
// Non-blocking version check (runs in background, once per day). Skip
|
|
440
|
+
// machine-readable commands so update network I/O never holds JSON output
|
|
441
|
+
// open or pollutes stdout.
|
|
442
|
+
if (!args.includes("--json") && cmd !== "init" && cmd !== "init-existing") checkVersion();
|
|
338
443
|
|
|
339
444
|
// Track first run for time-to-init telemetry
|
|
340
445
|
try { require("../lib/onboarding").trackFirstRun(target); } catch {}
|
|
@@ -359,6 +464,7 @@ async function main() {
|
|
|
359
464
|
case "watch": cmdWatch(target, args.slice(1)); break;
|
|
360
465
|
case "audit": cmdAudit(target); break;
|
|
361
466
|
case "export": await cmdExport(target, args); break;
|
|
467
|
+
case "vault": cmdVault(target, args[1], args.slice(2)); break;
|
|
362
468
|
case "security": {
|
|
363
469
|
const subSec = args[1] || "";
|
|
364
470
|
if (subSec === "install-hook") {
|
|
@@ -399,24 +505,15 @@ async function main() {
|
|
|
399
505
|
const driftMode = args.includes("--drift");
|
|
400
506
|
// Go fast-path covers only the base read-only doctor (no --drift, no
|
|
401
507
|
// network). Anything else falls through to the full Node implementation.
|
|
402
|
-
|
|
508
|
+
const layerFreshness = collectLayerVersionFreshness(target);
|
|
509
|
+
if (!driftMode && layerFreshness.status !== "stale") {
|
|
403
510
|
tryGoHotPath("doctor", target, args.slice(1));
|
|
404
511
|
}
|
|
405
512
|
cmdDoctor(target, { drift: driftMode, json: args.includes("--json") });
|
|
406
|
-
if (args.includes("--drift")) {
|
|
407
|
-
const ds = findRepoScript(target, "drift_detector.py");
|
|
408
|
-
console.log("\n drift report:");
|
|
409
|
-
if (ds) {
|
|
410
|
-
const result = spawnSync("python3", [ds, "report", "--target", target], { stdio: "inherit" });
|
|
411
|
-
if (typeof result.status === "number" && result.status !== 0) process.exit(result.status);
|
|
412
|
-
} else {
|
|
413
|
-
console.log(` ${D}drift detector unavailable in this environment${R}`);
|
|
414
|
-
}
|
|
415
|
-
}
|
|
416
513
|
break;
|
|
417
514
|
}
|
|
418
515
|
case "drift": {
|
|
419
|
-
const ds =
|
|
516
|
+
const ds = shared.resolvePythonScript(target, "drift_detector.py");
|
|
420
517
|
if (!ds) { log("drift detector unavailable"); break; }
|
|
421
518
|
if (sub === "accept" && args[2]) {
|
|
422
519
|
spawnSync("python3", [ds, "accept", args[2], "--target", target], { stdio: "inherit" });
|
|
@@ -441,7 +538,7 @@ async function main() {
|
|
|
441
538
|
case "project":
|
|
442
539
|
if (sub === "status") cmdStatus(target, { json: args.includes("--json") });
|
|
443
540
|
else if (sub === "bind") await cmdProjectBind(target, args.slice(2));
|
|
444
|
-
else console.log("Usage: 0dai project [bind [--json]|status [--json]] [--target PATH]");
|
|
541
|
+
else console.log("Usage: 0dai project [bind [--name NAME] [--json]|status [--json]] [--target PATH]");
|
|
445
542
|
break;
|
|
446
543
|
case "auth":
|
|
447
544
|
if (sub === "login") await cmdAuthLogin(args.slice(2));
|
|
@@ -479,7 +576,7 @@ async function main() {
|
|
|
479
576
|
case "feedback": await cmdFeedback(target, sub, args); break;
|
|
480
577
|
case "harvest": {
|
|
481
578
|
const harvestScript = findRepoScript(target, "harvest_experience.py");
|
|
482
|
-
if (!harvestScript) {
|
|
579
|
+
if (!harvestScript) { explainMissingHarvestHelper(target, args); break; }
|
|
483
580
|
const result = spawnSync("python3", [harvestScript, "--target", target, ...args.slice(1)], { stdio: "inherit", timeout: 15000 });
|
|
484
581
|
if (typeof result.status === "number" && result.status !== 0) process.exit(result.status);
|
|
485
582
|
break;
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
{
|
|
2
|
+
"schema_version": 1,
|
|
3
|
+
"updated_at": "2026-05-28",
|
|
4
|
+
"purpose": "Expected MCP exposure contract for agent runtimes. Health checks compare observed tool names against this manifest and scripts/mcp_tier_config.py.",
|
|
5
|
+
"project_server": {
|
|
6
|
+
"name": "0dai",
|
|
7
|
+
"config_path": ".mcp.json",
|
|
8
|
+
"tool_count_source": "scripts/mcp_tier_config.py",
|
|
9
|
+
"expected_tool_count": 113
|
|
10
|
+
},
|
|
11
|
+
"normalization": {
|
|
12
|
+
"accepted_examples": [
|
|
13
|
+
"memory_search",
|
|
14
|
+
"mcp__0dai__memory_search",
|
|
15
|
+
"mcp__0dai_internal__.memory_search",
|
|
16
|
+
"mcp__0dai_internal__memory_search"
|
|
17
|
+
],
|
|
18
|
+
"rule": "Compare by canonical tool basename after MCP namespace prefixes."
|
|
19
|
+
},
|
|
20
|
+
"agents": {
|
|
21
|
+
"default": {
|
|
22
|
+
"required": [
|
|
23
|
+
"memory_search",
|
|
24
|
+
"get_project_health",
|
|
25
|
+
"get_codebase_map",
|
|
26
|
+
"record_experience"
|
|
27
|
+
],
|
|
28
|
+
"recommended": [
|
|
29
|
+
"get_anomaly_taxonomy",
|
|
30
|
+
"get_anomaly_events",
|
|
31
|
+
"get_anomaly_summary",
|
|
32
|
+
"memory_add",
|
|
33
|
+
"memory_inject",
|
|
34
|
+
"search_experience",
|
|
35
|
+
"get_project_graph",
|
|
36
|
+
"get_specs",
|
|
37
|
+
"get_session",
|
|
38
|
+
"save_session",
|
|
39
|
+
"get_wal"
|
|
40
|
+
]
|
|
41
|
+
},
|
|
42
|
+
"codex": {
|
|
43
|
+
"inherits": "default",
|
|
44
|
+
"required": [
|
|
45
|
+
"memory_search",
|
|
46
|
+
"get_project_health",
|
|
47
|
+
"get_codebase_map",
|
|
48
|
+
"record_experience"
|
|
49
|
+
],
|
|
50
|
+
"recommended": [
|
|
51
|
+
"get_anomaly_taxonomy",
|
|
52
|
+
"get_anomaly_events",
|
|
53
|
+
"get_anomaly_summary",
|
|
54
|
+
"record_anomaly",
|
|
55
|
+
"memory_add",
|
|
56
|
+
"memory_inject",
|
|
57
|
+
"search_experience",
|
|
58
|
+
"get_project_graph",
|
|
59
|
+
"get_specs",
|
|
60
|
+
"get_session",
|
|
61
|
+
"save_session",
|
|
62
|
+
"swarm_delegate",
|
|
63
|
+
"watch_tasks",
|
|
64
|
+
"get_portfolio",
|
|
65
|
+
"get_wal"
|
|
66
|
+
]
|
|
67
|
+
},
|
|
68
|
+
"claude": {
|
|
69
|
+
"inherits": "default",
|
|
70
|
+
"required": [
|
|
71
|
+
"memory_search",
|
|
72
|
+
"get_project_health",
|
|
73
|
+
"get_codebase_map",
|
|
74
|
+
"record_experience",
|
|
75
|
+
"get_session",
|
|
76
|
+
"save_session"
|
|
77
|
+
],
|
|
78
|
+
"recommended": [
|
|
79
|
+
"get_anomaly_taxonomy",
|
|
80
|
+
"get_anomaly_events",
|
|
81
|
+
"get_anomaly_summary",
|
|
82
|
+
"record_anomaly",
|
|
83
|
+
"memory_add",
|
|
84
|
+
"memory_inject",
|
|
85
|
+
"search_experience",
|
|
86
|
+
"swarm_delegate",
|
|
87
|
+
"watch_tasks",
|
|
88
|
+
"get_portfolio",
|
|
89
|
+
"gh_label_create",
|
|
90
|
+
"gh_issue_edit_body"
|
|
91
|
+
]
|
|
92
|
+
},
|
|
93
|
+
"pool": {
|
|
94
|
+
"inherits": "default",
|
|
95
|
+
"required": [
|
|
96
|
+
"memory_search",
|
|
97
|
+
"get_project_health",
|
|
98
|
+
"get_codebase_map",
|
|
99
|
+
"record_experience",
|
|
100
|
+
"watch_tasks"
|
|
101
|
+
],
|
|
102
|
+
"recommended": [
|
|
103
|
+
"get_anomaly_taxonomy",
|
|
104
|
+
"get_anomaly_events",
|
|
105
|
+
"get_anomaly_summary",
|
|
106
|
+
"memory_add",
|
|
107
|
+
"search_experience",
|
|
108
|
+
"swarm_delegate",
|
|
109
|
+
"run_task",
|
|
110
|
+
"get_swarm_status",
|
|
111
|
+
"save_session"
|
|
112
|
+
]
|
|
113
|
+
}
|
|
114
|
+
},
|
|
115
|
+
"statuses": {
|
|
116
|
+
"green": "All required and recommended tools for the agent were observed.",
|
|
117
|
+
"yellow": "Required tools were observed, but recommended tools or full server count evidence is missing.",
|
|
118
|
+
"red": "One or more required tools are missing from the observed runtime.",
|
|
119
|
+
"unknown": "No observed tool evidence was supplied by the runtime."
|
|
120
|
+
}
|
|
121
|
+
}
|