@aiwg/cli 2026.10.4 → 2026.10.6
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/agentic/code/addons/composition-engine/lib/runtime.mjs +1401 -0
- package/agentic/code/addons/composition-engine/lib/validator.mjs +513 -0
- package/agentic/code/addons/composition-engine/schemas/flow-graph.schema.json +372 -0
- package/agentic/code/providers/model-capabilities.v1.json +74 -50
- package/bin/aiwg.mjs +3 -1
- package/dist/src/artifacts/browser-export.js +1 -0
- package/dist/src/artifacts/citation-parser.js +8 -1
- package/dist/src/artifacts/cli.js +72 -9
- package/dist/src/artifacts/fortemi-core-query-adapter.js +2 -0
- package/dist/src/artifacts/fortemi-core-sync.js +26 -8
- package/dist/src/artifacts/graph-query.js +18 -8
- package/dist/src/artifacts/index-adapters.js +339 -0
- package/dist/src/artifacts/index-builder.js +146 -16
- package/dist/src/artifacts/index-files.js +15 -4
- package/dist/src/artifacts/index-preparation.js +91 -26
- package/dist/src/artifacts/index-reader.js +44 -0
- package/dist/src/artifacts/index-refresh.js +130 -56
- package/dist/src/artifacts/index-status.js +20 -5
- package/dist/src/artifacts/index-worker.mjs +9 -7
- package/dist/src/artifacts/memory-maintenance.js +503 -0
- package/dist/src/artifacts/prebuilt-relations.js +3 -1
- package/dist/src/artifacts/query-engine.js +263 -108
- package/dist/src/artifacts/relations-builder.js +2 -2
- package/dist/src/artifacts/source-graph.js +2 -2
- package/dist/src/artifacts/types.js +9 -1
- package/dist/src/cli/handlers/decision.js +19 -1
- package/dist/src/cli/handlers/guided-setup.js +470 -0
- package/dist/src/cli/handlers/help.js +2 -2
- package/dist/src/cli/handlers/housekeeper.js +1110 -0
- package/dist/src/cli/handlers/index.js +4 -2
- package/dist/src/cli/handlers/init.js +41 -6
- package/dist/src/cli/handlers/local-executor.js +5 -3
- package/dist/src/cli/handlers/mc.js +509 -53
- package/dist/src/cli/handlers/models.js +32 -2
- package/dist/src/cli/handlers/ralph-launcher.js +76 -4
- package/dist/src/cli/handlers/rules.js +1 -1
- package/dist/src/cli/handlers/script-runner.js +73 -2
- package/dist/src/cli/handlers/serve.js +5 -3
- package/dist/src/cli/handlers/sessions.js +40 -6
- package/dist/src/cli/handlers/setup.js +428 -1
- package/dist/src/cli/handlers/skill-lint.js +1 -1
- package/dist/src/cli/handlers/subcommands.js +118 -8
- package/dist/src/cli/handlers/use.js +279 -93
- package/dist/src/cli/handlers/workspace.js +3 -1
- package/dist/src/cli/prompt-utils.js +8 -0
- package/dist/src/cli/router.js +16 -1
- package/dist/src/config/aiwg-config.js +42 -0
- package/dist/src/config/cli.js +7 -3
- package/dist/src/config/decision-config.js +14 -1
- package/dist/src/config/native-sandbox-warnings.js +25 -0
- package/dist/src/contributors/validation.js +6 -5
- package/dist/src/decision/admission.js +7 -3
- package/dist/src/decision/benchmark.js +469 -0
- package/dist/src/decision/ledger.js +22 -3
- package/dist/src/decision/pricing.js +147 -0
- package/dist/src/decision/qualification/gate-evidence.js +18 -15
- package/dist/src/decision/qualification/load-staged.js +539 -0
- package/dist/src/decision/qualification/load.js +109 -33
- package/dist/src/decision/qualification/runner.js +5 -2
- package/dist/src/decision/review/service.js +6 -4
- package/dist/src/decision/review/validate.js +23 -2
- package/dist/src/decision/savings.js +8 -3
- package/dist/src/discovery/index.js +492 -0
- package/dist/src/discovery/interview.js +233 -0
- package/dist/src/discovery/plan-apply.js +571 -0
- package/dist/src/discovery/plan-store.js +171 -0
- package/dist/src/discovery/plan-types.js +2 -0
- package/dist/src/discovery/plan-validation.js +139 -0
- package/dist/src/discovery/types.js +2 -0
- package/dist/src/extensions/commands/definitions.js +49 -9
- package/dist/src/extensions/manifest.js +71 -44
- package/dist/src/extensions/project-local-discovery.js +1 -1
- package/dist/src/extensions/project-quickref.js +18 -17
- package/dist/src/extensions/validation.js +32 -29
- package/dist/src/housekeeper/daemon-config.js +148 -0
- package/dist/src/housekeeper/ipc.js +84 -0
- package/dist/src/housekeeper/lifecycle.js +148 -0
- package/dist/src/housekeeper/platform.js +35 -0
- package/dist/src/housekeeper/status.js +70 -0
- package/dist/src/housekeeper/units.js +114 -0
- package/dist/src/jobs/flow.js +22 -21
- package/dist/src/lint/rule-activation.js +20 -5
- package/dist/src/lint/runner.js +1 -1
- package/dist/src/mcp/cli.mjs +5 -6
- package/dist/src/mcp/config-file.mjs +6 -2
- package/dist/src/mcp/config-layers.mjs +23 -7
- package/dist/src/mcp/profiles.js +18 -31
- package/dist/src/mcp/profiles.mjs +18 -32
- package/dist/src/mcp/registry.js +7 -27
- package/dist/src/mcp/registry.mjs +7 -28
- package/dist/src/mcp/server.mjs +34 -1
- package/dist/src/mcp/tools/agentic-sandbox.mjs +8 -7
- package/dist/src/mcp/tools/command-run.mjs +3 -2
- package/dist/src/mcp/tools/decision.mjs +49 -48
- package/dist/src/mcp/tools/discovery.mjs +46 -21
- package/dist/src/mcp/tools/orchestration.mjs +22 -22
- package/dist/src/mcp/tools/subsystems.mjs +9 -8
- package/dist/src/mcp/tools/worker-invoke.mjs +17 -4
- package/dist/src/mcp/tools/writer-profiles.mjs +1 -1
- package/dist/src/memory/audit.js +719 -0
- package/dist/src/memory/canonical-context.js +392 -13
- package/dist/src/memory/canonical-maintenance.js +95 -0
- package/dist/src/memory/cli-result.js +22 -0
- package/dist/src/memory/cli.js +176 -0
- package/dist/src/memory/context-pack.js +57 -6
- package/dist/src/memory/cost.js +512 -0
- package/dist/src/memory/firewall-classification.d.mts +7 -0
- package/dist/src/memory/firewall-classification.mjs +32 -0
- package/dist/src/memory/index.js +8 -0
- package/dist/src/memory/line-maintenance.js +68 -0
- package/dist/src/memory/maintenance-cli.js +286 -0
- package/dist/src/memory/maintenance-contract.js +136 -0
- package/dist/src/memory/maintenance-index.js +18 -0
- package/dist/src/memory/maintenance-owner.js +2 -0
- package/dist/src/memory/maintenance-record.js +138 -0
- package/dist/src/memory/maintenance.js +254 -0
- package/dist/src/memory/provider-memory-adapter.js +154 -0
- package/dist/src/memory/recommend-cli.js +83 -0
- package/dist/src/memory/recommend.js +269 -0
- package/dist/src/memory/scheduled.js +81 -0
- package/dist/src/memory/taxonomy.js +44 -0
- package/dist/src/mission-protocol/codecs.js +19 -9
- package/dist/src/models/config-loader.js +11 -1
- package/dist/src/models/model-capabilities.v1.json +74 -50
- package/dist/src/models/provider-policy.js +125 -62
- package/dist/src/models/resolver.js +45 -8
- package/dist/src/models/worker-installation.d.mts +7 -0
- package/dist/src/models/worker-installation.mjs +169 -37
- package/dist/src/models/wrapper-route.js +1 -1
- package/dist/src/output-modes/registry.js +8 -7
- package/dist/src/plugin/metadata-validator.js +1 -1
- package/dist/src/providers/deploy-version.d.mts +1 -0
- package/dist/src/providers/deploy-version.mjs +17 -0
- package/dist/src/providers/provider-definitions.js +19 -16
- package/dist/src/providers/skill-ownership.d.mts +11 -2
- package/dist/src/providers/skill-ownership.mjs +35 -17
- package/dist/src/rules/activation.d.mts +11 -2
- package/dist/src/rules/activation.mjs +82 -6
- package/dist/src/rules/inventory.js +1 -1
- package/dist/src/rules/rule-frontmatter.schema.json +2 -0
- package/dist/src/schema/zod-validation.d.mts +6 -0
- package/dist/src/schema/zod-validation.mjs +50 -0
- package/dist/src/serve/executor-registry.js +297 -20
- package/dist/src/serve/executor-token.d.mts +1 -0
- package/dist/src/serve/executor-token.mjs +8 -0
- package/dist/src/serve/shared-host-scheduler.js +1102 -31
- package/dist/src/serve/worker-invocation.js +114 -15
- package/dist/src/sessions/adapters/claude.js +19 -18
- package/dist/src/sessions/adapters/codex.js +33 -19
- package/dist/src/sessions/adapters/copilot.js +14 -13
- package/dist/src/sessions/adapters/cursor.js +19 -18
- package/dist/src/sessions/adapters/deepseek-harness.js +9 -8
- package/dist/src/sessions/adapters/factory.js +11 -10
- package/dist/src/sessions/adapters/generic.js +32 -23
- package/dist/src/sessions/adapters/grokbot.js +35 -35
- package/dist/src/sessions/adapters/hermes.js +20 -19
- package/dist/src/sessions/adapters/muse.js +50 -49
- package/dist/src/sessions/adapters/omp.js +5 -4
- package/dist/src/sessions/adapters/openclaw.js +30 -29
- package/dist/src/sessions/adapters/opencode.js +26 -26
- package/dist/src/sessions/adapters/openhuman.js +24 -23
- package/dist/src/sessions/adapters/pi.js +5 -4
- package/dist/src/sessions/adapters/windsurf.js +8 -8
- package/dist/src/sessions/analytics.js +10 -9
- package/dist/src/sessions/batch-contracts.js +1 -1
- package/dist/src/sessions/batch-import.js +202 -2
- package/dist/src/sessions/candidates.js +7 -6
- package/dist/src/sessions/contracts.js +73 -54
- package/dist/src/sessions/coverage-preflight.js +26 -1
- package/dist/src/sessions/output-registration.js +11 -10
- package/dist/src/sessions/policy.js +18 -7
- package/dist/src/sessions/refresh.js +2 -3
- package/dist/src/sessions/repository.js +4 -2
- package/dist/src/sessions/workspace-discovery.js +92 -26
- package/dist/src/smiths/context-pipeline/aiwg-md.js +18 -1
- package/dist/src/smiths/context-pipeline/claude-hook.js +42 -6
- package/dist/src/smiths/context-pipeline/parallelism-section.js +72 -5
- package/dist/src/smiths/context-pipeline/workspace-context.js +106 -10
- package/dist/src/update/checker.d.mts +4 -0
- package/dist/src/update/checker.mjs +14 -0
- package/dist/src/writing/exemplar-selection.js +6 -6
- package/dist/src/writing/voice-evaluation.js +24 -23
- package/dist/src/writing/writer-migration.js +14 -13
- package/dist/src/writing/writer-profile.js +19 -18
- package/dist/src/writing/writing-brief.js +18 -17
- package/dist/src/writing/writing-receipt.js +47 -46
- package/package.json +5 -2
- package/schemas/decision/DecisionReview.schema.json +78 -1
- package/schemas/mission-v1.schema.json +3 -0
- package/tools/agents/deploy-agents.mjs +67 -39
- package/tools/agents/providers/antigravity.mjs +6 -1
- package/tools/agents/providers/base.mjs +19 -13
- package/tools/agents/providers/claude.mjs +1 -1
- package/tools/agents/providers/codex.mjs +50 -56
- package/tools/agents/providers/copilot.mjs +8 -2
- package/tools/agents/providers/cursor.mjs +1 -1
- package/tools/agents/providers/deepseek-harness.mjs +1 -1
- package/tools/agents/providers/factory.mjs +7 -1
- package/tools/agents/providers/grok-build.mjs +18 -2
- package/tools/agents/providers/grokbot.mjs +1 -1
- package/tools/agents/providers/hermes.mjs +7 -13
- package/tools/agents/providers/muse-hooks.mjs +21 -14
- package/tools/agents/providers/muse.mjs +7 -2
- package/tools/agents/providers/omp.mjs +28 -4
- package/tools/agents/providers/opencode.mjs +14 -5
- package/tools/agents/providers/openhuman.mjs +1 -1
- package/tools/agents/providers/pi.mjs +1 -1
- package/tools/agents/providers/provider-prepare-coordinator.mjs +29 -9
- package/tools/agents/providers/rule-delivery.mjs +263 -71
- package/tools/agents/providers/windsurf.mjs +7 -0
- package/tools/cli/workspace-status.mjs +5 -0
- package/tools/commands/deploy-prompts-codex.mjs +11 -8
- package/tools/ralph-external/lib/codex-adapter.mjs +6 -2
- package/tools/ralph-external/lib/muse-adapter.mjs +12 -2
- package/tools/ralph-external/lib/worker-health.mjs +1 -1
- package/tools/ralph-external/lib/worker-isolation.mjs +65 -9
- package/tools/ralph-external/process-monitor.mjs +7 -4
- package/tools/ralph-external/session-launcher.mjs +280 -32
- package/tools/skills/deploy-skills-codex.mjs +11 -7
- package/vscode-extension/schemas/aiwg.config.v1.json +11 -1
|
@@ -0,0 +1,171 @@
|
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
|
+
import { mkdir, open, readFile, rename, rm, stat } from 'node:fs/promises';
|
|
3
|
+
import { dirname, join } from 'node:path';
|
|
4
|
+
import { isDeepStrictEqual } from 'node:util';
|
|
5
|
+
import { resolveProjectAiwgDir, resolveProjectAiwgDirForWrite } from '../config/project-artifacts-runtime.mjs';
|
|
6
|
+
import { SETUP_PLAN_SCHEMA_VERSION } from './plan-types.js';
|
|
7
|
+
import { assertPlanRedacted, planIdSchema, validateSetupPlan } from './plan-validation.js';
|
|
8
|
+
function checkedId(id) {
|
|
9
|
+
assertPlanRedacted(id);
|
|
10
|
+
if (!planIdSchema.safeParse(id).success)
|
|
11
|
+
throw new Error('Setup plan ID must be 1-120 letters, digits, underscores, or hyphens, starting with a letter or digit.');
|
|
12
|
+
return id;
|
|
13
|
+
}
|
|
14
|
+
/** Explicit compatibility seam: pre-release v0 lacked receipts and updatedAt. Never migrate on disk during read. */
|
|
15
|
+
export function migrateSetupPlan(input) {
|
|
16
|
+
if (!input || typeof input !== 'object' || Array.isArray(input))
|
|
17
|
+
throw new Error('Setup plan must be a versioned JSON object.');
|
|
18
|
+
const value = input;
|
|
19
|
+
const version = value.schemaVersion;
|
|
20
|
+
if (typeof version !== 'number' || !Number.isSafeInteger(version) || version < 0) {
|
|
21
|
+
throw new Error('Setup plan schemaVersion must be a non-negative integer.');
|
|
22
|
+
}
|
|
23
|
+
if (version > SETUP_PLAN_SCHEMA_VERSION) {
|
|
24
|
+
throw new Error(`Setup plan schemaVersion ${version} is newer than supported version ${SETUP_PLAN_SCHEMA_VERSION}; upgrade AIWG before resuming.`);
|
|
25
|
+
}
|
|
26
|
+
switch (version) {
|
|
27
|
+
case 0:
|
|
28
|
+
return validateSetupPlan({ ...value, schemaVersion: SETUP_PLAN_SCHEMA_VERSION,
|
|
29
|
+
updatedAt: value.updatedAt === undefined ? value.createdAt : value.updatedAt,
|
|
30
|
+
receipts: value.receipts === undefined ? [] : value.receipts });
|
|
31
|
+
case SETUP_PLAN_SCHEMA_VERSION:
|
|
32
|
+
return validateSetupPlan(value);
|
|
33
|
+
default:
|
|
34
|
+
throw new Error('No migration exists for this setup plan schemaVersion.');
|
|
35
|
+
}
|
|
36
|
+
}
|
|
37
|
+
/** One resolved artifact root owns the entire plan, including receipts for other workspaces. */
|
|
38
|
+
export async function writeSetupPlan(projectDir, input, env) {
|
|
39
|
+
// Scan the serialized snapshot too: toJSON/getters cannot introduce an unscanned write.
|
|
40
|
+
assertPlanRedacted(input);
|
|
41
|
+
let snapshot;
|
|
42
|
+
try {
|
|
43
|
+
snapshot = JSON.parse(JSON.stringify(input));
|
|
44
|
+
}
|
|
45
|
+
catch {
|
|
46
|
+
throw new Error('Setup plan must contain serializable JSON values.');
|
|
47
|
+
}
|
|
48
|
+
const plan = validateSetupPlan(snapshot);
|
|
49
|
+
const id = checkedId(plan.id);
|
|
50
|
+
const root = resolveProjectAiwgDirForWrite(projectDir, env);
|
|
51
|
+
const destination = join(root, 'setup', 'plans', `${id}.json`);
|
|
52
|
+
const temporary = join(dirname(destination), `.${id}.${randomUUID()}.tmp`);
|
|
53
|
+
try {
|
|
54
|
+
await mkdir(dirname(destination), { recursive: true, mode: 0o700 });
|
|
55
|
+
const file = await open(temporary, 'wx', 0o600);
|
|
56
|
+
try {
|
|
57
|
+
await file.writeFile(JSON.stringify(plan, null, 2) + '\n', 'utf8');
|
|
58
|
+
await file.sync();
|
|
59
|
+
}
|
|
60
|
+
finally {
|
|
61
|
+
await file.close();
|
|
62
|
+
}
|
|
63
|
+
await rename(temporary, destination);
|
|
64
|
+
}
|
|
65
|
+
catch (error) {
|
|
66
|
+
// The error code names the cause (EACCES, ENOSPC, ENOENT) without echoing plan data.
|
|
67
|
+
const code = error?.code;
|
|
68
|
+
throw new Error(`Cannot write setup plan under the resolved artifact root${code ? ` (${code})` : ''}. Check that the corpus is attached and writable; no fallback was used.`);
|
|
69
|
+
}
|
|
70
|
+
finally {
|
|
71
|
+
await rm(temporary, { force: true }).catch(() => { });
|
|
72
|
+
}
|
|
73
|
+
return destination;
|
|
74
|
+
}
|
|
75
|
+
export async function readSetupPlan(projectDir, id, env) {
|
|
76
|
+
checkedId(id);
|
|
77
|
+
const root = resolveProjectAiwgDir(projectDir, env);
|
|
78
|
+
try {
|
|
79
|
+
if (!(await stat(root)).isDirectory())
|
|
80
|
+
throw new Error();
|
|
81
|
+
}
|
|
82
|
+
catch {
|
|
83
|
+
throw new Error('Resolved AIWG artifact root is unavailable. Reconnect or attach the corpus before reading setup plans; no fallback was used.');
|
|
84
|
+
}
|
|
85
|
+
let content;
|
|
86
|
+
try {
|
|
87
|
+
content = await readFile(join(root, 'setup', 'plans', `${id}.json`), 'utf8');
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
throw new Error('Cannot read setup plan from the resolved artifact root. Check the plan ID and file permissions; no fallback was used.');
|
|
91
|
+
}
|
|
92
|
+
let parsed;
|
|
93
|
+
try {
|
|
94
|
+
parsed = JSON.parse(content);
|
|
95
|
+
}
|
|
96
|
+
catch {
|
|
97
|
+
throw new Error('Setup plan is not valid JSON. Restore the plan from a valid copy.');
|
|
98
|
+
}
|
|
99
|
+
const plan = migrateSetupPlan(parsed);
|
|
100
|
+
if (plan.id !== id)
|
|
101
|
+
throw new Error('Setup plan ID does not match its filename.');
|
|
102
|
+
return plan;
|
|
103
|
+
}
|
|
104
|
+
/** Failed and skipped actions remain eligible. The apply slice decides retry/skip policy. */
|
|
105
|
+
export function remainingPlanActions(plan) {
|
|
106
|
+
return plan.actions.filter(action => !plan.receipts.some(receipt => receipt.workspace === action.workspace &&
|
|
107
|
+
Object.hasOwn(receipt.actions, action.id) && receipt.actions[action.id].status === 'applied'));
|
|
108
|
+
}
|
|
109
|
+
/** Presence counts, including false, null, and default/discovered answers. Never fill/overwrite answers here. */
|
|
110
|
+
export function unansweredPlanChoices(plan) {
|
|
111
|
+
return plan.unresolvedChoices.filter(choice => !Object.hasOwn(plan.answers, choice.questionId));
|
|
112
|
+
}
|
|
113
|
+
function observedPaths(project) {
|
|
114
|
+
return [project.root, project.packageManifest, ...project.packageRoots,
|
|
115
|
+
project.aiwg.directory ? join(project.root, '.aiwg') : null, project.aiwg.configFile,
|
|
116
|
+
project.aiwg.contextFile, ...project.providerFiles.map(file => file.path)].filter((path) => path !== null);
|
|
117
|
+
}
|
|
118
|
+
function factValue(inventory, fact) {
|
|
119
|
+
if (fact.kind === 'tool')
|
|
120
|
+
return inventory.tools.find(tool => tool.executable === fact.executable)?.[fact.field];
|
|
121
|
+
const root = fact.kind === 'project' ? fact.root : fact.workspace;
|
|
122
|
+
const project = inventory.projects.find(entry => entry.root === root);
|
|
123
|
+
if (fact.kind === 'project')
|
|
124
|
+
return project?.[fact.field];
|
|
125
|
+
if (project && observedPaths(project).includes(fact.path))
|
|
126
|
+
return true;
|
|
127
|
+
// Missing observations in a partial inventory cannot establish absence.
|
|
128
|
+
if (inventory.stats.truncated || inventory.diagnostics.some(d => ['inaccessible', 'symlink-skipped', 'outside-root'].includes(d.code)))
|
|
129
|
+
return undefined;
|
|
130
|
+
return false;
|
|
131
|
+
}
|
|
132
|
+
/** Successful config owners establish these paths as present for subsequent actions. */
|
|
133
|
+
function createdByAppliedConfig(plan, fact) {
|
|
134
|
+
if (fact.kind !== 'path' || ![join(fact.workspace, '.aiwg'), join(fact.workspace, '.aiwg', 'aiwg.config')].includes(fact.path))
|
|
135
|
+
return false;
|
|
136
|
+
return plan.actions.some(action => action.workspace === fact.workspace &&
|
|
137
|
+
['write-project-config', 'configure-worker-dispatch', 'record-decline'].includes(action.kind) &&
|
|
138
|
+
plan.receipts.some(receipt => receipt.workspace === action.workspace && receipt.actions[action.id]?.status === 'applied'));
|
|
139
|
+
}
|
|
140
|
+
/** Pure comparison of local observations. Does not inspect paths, execute tools, or authorize apply. */
|
|
141
|
+
export function revalidateSetupPlan(plan, fresh) {
|
|
142
|
+
return plan.actions.flatMap(action => {
|
|
143
|
+
const changes = action.dependsOn.flatMap(fact => {
|
|
144
|
+
const before = createdByAppliedConfig(plan, fact) ? true : factValue(plan.inventory, fact);
|
|
145
|
+
const after = factValue(fresh, fact);
|
|
146
|
+
let reason;
|
|
147
|
+
if (before === undefined || after === undefined || before === 'unknown' || after === 'unknown')
|
|
148
|
+
reason = 'unobserved';
|
|
149
|
+
if (fact.kind === 'tool') {
|
|
150
|
+
const tool = fresh.tools.find(entry => entry.executable === fact.executable);
|
|
151
|
+
if (!tool || tool.installed === 'unknown')
|
|
152
|
+
reason = 'unobserved';
|
|
153
|
+
else if (tool.installed === 'no')
|
|
154
|
+
reason = 'tool-not-installed';
|
|
155
|
+
else if (fact.field === 'version' && (before === null || after === null))
|
|
156
|
+
reason = 'unobserved';
|
|
157
|
+
else if (fact.field === 'version' && !isDeepStrictEqual(before, after))
|
|
158
|
+
reason = 'version-changed';
|
|
159
|
+
}
|
|
160
|
+
if (fact.kind === 'project' && before !== undefined && after === undefined && !fresh.stats.truncated &&
|
|
161
|
+
!fresh.diagnostics.some(d => d.path === fact.root && d.code === 'inaccessible'))
|
|
162
|
+
reason = 'path-missing';
|
|
163
|
+
if (!reason && !isDeepStrictEqual(before, after)) {
|
|
164
|
+
reason = fact.kind === 'path' && after === false ? 'path-missing' : 'fact-changed';
|
|
165
|
+
}
|
|
166
|
+
return reason ? [{ fact, reason, before: before, after: after }] : [];
|
|
167
|
+
});
|
|
168
|
+
return changes.length ? [{ actionId: action.id, workspace: action.workspace, changes }] : [];
|
|
169
|
+
});
|
|
170
|
+
}
|
|
171
|
+
//# sourceMappingURL=plan-store.js.map
|
|
@@ -0,0 +1,139 @@
|
|
|
1
|
+
import { z } from 'zod';
|
|
2
|
+
import { dateTime, number } from '../schema/zod-validation.mjs';
|
|
3
|
+
import { redactText } from '../governance/redaction.js';
|
|
4
|
+
import { SETUP_PLAN_SCHEMA_VERSION } from './plan-types.js';
|
|
5
|
+
const text = z.string().min(1);
|
|
6
|
+
const timestamp = dateTime({ offset: true });
|
|
7
|
+
const observation = z.enum(['yes', 'no', 'unknown']);
|
|
8
|
+
export const planIdSchema = text.max(120).regex(/^[a-zA-Z0-9][a-zA-Z0-9_-]*$/);
|
|
9
|
+
const referenceSchema = z.strictObject({
|
|
10
|
+
kind: z.literal('credential-ref'), source: z.enum(['env', 'file', 'stdin-at-apply']), name: text,
|
|
11
|
+
});
|
|
12
|
+
const valueSchema = z.lazy(() => z.union([
|
|
13
|
+
z.string(), z.number().finite(), z.boolean(), z.null(), z.array(valueSchema), z.record(z.string(), valueSchema),
|
|
14
|
+
]));
|
|
15
|
+
const projectSchema = z.strictObject({
|
|
16
|
+
root: text, sources: z.array(z.enum(['workspace', 'registry', 'selected'])),
|
|
17
|
+
vcs: z.enum(['git', 'worktree', 'none', 'unknown']), layout: z.enum(['project', 'package', 'monorepo', 'ambiguous']),
|
|
18
|
+
packageManifest: text.nullable(), workspacePatterns: z.array(z.string()), packageRoots: z.array(text),
|
|
19
|
+
aiwg: z.strictObject({ directory: z.boolean(), configFile: text.nullable(), contextFile: text.nullable() }),
|
|
20
|
+
providerFiles: z.array(z.strictObject({ provider: text, path: text, kind: z.enum(['config', 'context', 'artifacts']) })),
|
|
21
|
+
});
|
|
22
|
+
const toolSchema = z.strictObject({
|
|
23
|
+
executable: text, path: text.nullable(), installed: observation, configured: observation,
|
|
24
|
+
authenticated: observation, qualified: observation, version: text.nullable(), evidence: z.array(z.string()),
|
|
25
|
+
});
|
|
26
|
+
const inventorySchema = z.strictObject({
|
|
27
|
+
projects: z.array(projectSchema), tools: z.array(toolSchema),
|
|
28
|
+
diagnostics: z.array(z.strictObject({
|
|
29
|
+
code: z.enum(['depth-limit', 'entry-limit', 'time-limit', 'file-limit', 'inaccessible', 'invalid-metadata',
|
|
30
|
+
'symlink-skipped', 'outside-root', 'ambiguous', 'excluded', 'home-scan-refused']),
|
|
31
|
+
path: z.string(), message: z.string(),
|
|
32
|
+
})),
|
|
33
|
+
limits: z.strictObject({ maxDepth: number().check(z.gte(0)).meta({ type: 'number', minimum: 0 }), maxEntries: number().check(z.gte(0)).meta({ type: 'number', minimum: 0 }),
|
|
34
|
+
timeBudgetMs: number().check(z.gte(0)).meta({ type: 'number', minimum: 0 }), maxFileBytes: number().check(z.gte(0)).meta({ type: 'number', minimum: 0 }) }),
|
|
35
|
+
stats: z.strictObject({ entriesInspected: number().check(z.gte(0)).meta({ type: 'number', minimum: 0 }), elapsedMs: number().check(z.gte(0)).meta({ type: 'number', minimum: 0 }), truncated: z.boolean() }),
|
|
36
|
+
});
|
|
37
|
+
const factSchema = z.discriminatedUnion('kind', [
|
|
38
|
+
z.strictObject({ kind: z.literal('project'), root: text, field: projectSchema.keyof() }),
|
|
39
|
+
z.strictObject({ kind: z.literal('tool'), executable: text, field: toolSchema.keyof() }),
|
|
40
|
+
z.strictObject({ kind: z.literal('path'), workspace: text, path: text }),
|
|
41
|
+
]);
|
|
42
|
+
const planSchema = z.strictObject({
|
|
43
|
+
schemaVersion: z.literal(SETUP_PLAN_SCHEMA_VERSION), id: planIdSchema, inventoryId: text,
|
|
44
|
+
createdAt: timestamp, updatedAt: timestamp,
|
|
45
|
+
answers: z.record(z.string(), z.strictObject({ value: valueSchema,
|
|
46
|
+
source: z.enum(['explicit-flag', 'existing-setting', 'interview', 'default', 'discovered']), answeredAt: timestamp })),
|
|
47
|
+
recommendations: z.array(z.strictObject({ questionId: text, value: valueSchema, reason: text })),
|
|
48
|
+
unresolvedChoices: z.array(z.strictObject({ questionId: text,
|
|
49
|
+
options: z.array(z.strictObject({ label: text, value: valueSchema })).min(1),
|
|
50
|
+
default: valueSchema, whyItMatters: text, deferredAt: timestamp.optional() })),
|
|
51
|
+
actions: z.array(z.strictObject({ id: text, workspace: text, provider: text, scope: z.enum(['project', 'user']),
|
|
52
|
+
kind: text, dependsOn: z.array(factSchema) })),
|
|
53
|
+
receipts: z.array(z.strictObject({ workspace: text, actions: z.record(z.string(), z.strictObject({
|
|
54
|
+
status: z.enum(['applied', 'failed', 'skipped']), startedAt: timestamp, completedAt: timestamp,
|
|
55
|
+
message: z.string().optional(),
|
|
56
|
+
})) })),
|
|
57
|
+
inventory: inventorySchema,
|
|
58
|
+
});
|
|
59
|
+
const sensitiveKey = /(?:password|passwd|token|secret|api[_-]?key|credential|authorization|cookie|private[_-]?key|connection[_-]?string)/i;
|
|
60
|
+
const secretError = () => new Error('Setup plan contains secret-looking material; use a credential-ref (env, file, or stdin-at-apply).');
|
|
61
|
+
/** Scan the exact JSON snapshot, including keys and free-form evidence/messages. Never echo rejected values. */
|
|
62
|
+
export function assertPlanRedacted(input) {
|
|
63
|
+
let nodes = 0;
|
|
64
|
+
const scanText = (value) => {
|
|
65
|
+
const result = redactText(value, { organizationPatterns: [
|
|
66
|
+
{ id: 'jwt', pattern: '\\beyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]{8,}\\b' },
|
|
67
|
+
{ id: 'extra-token', pattern: '\\b(?:aiwg_(?:at|rt)_|npm_|hf_|xai-|AIza)[A-Za-z0-9_-]{8,}\\b' },
|
|
68
|
+
] });
|
|
69
|
+
if (result.sensitivity !== 'none')
|
|
70
|
+
throw secretError();
|
|
71
|
+
// Scan disjoint runs rather than retrying lookaheads at every word boundary.
|
|
72
|
+
for (const candidate of value.match(/[A-Za-z0-9_+=-]{32,}/g) ?? []) {
|
|
73
|
+
if (/[a-z]/.test(candidate) && /[A-Z]/.test(candidate) && /[0-9]/.test(candidate))
|
|
74
|
+
throw secretError();
|
|
75
|
+
}
|
|
76
|
+
};
|
|
77
|
+
const isReference = (value) => referenceSchema.safeParse(value).success;
|
|
78
|
+
const visit = (value, depth, answerMap = false) => {
|
|
79
|
+
if (++nodes > 100_000 || depth > 64)
|
|
80
|
+
throw new Error('Setup plan exceeds redaction structure limits.');
|
|
81
|
+
if (typeof value === 'string')
|
|
82
|
+
scanText(value);
|
|
83
|
+
if (!value || typeof value !== 'object')
|
|
84
|
+
return;
|
|
85
|
+
if (Array.isArray(value)) {
|
|
86
|
+
for (const item of value)
|
|
87
|
+
visit(item, depth + 1);
|
|
88
|
+
return;
|
|
89
|
+
}
|
|
90
|
+
const object = value;
|
|
91
|
+
if (object.kind === 'credential-ref' && !isReference(object))
|
|
92
|
+
throw secretError();
|
|
93
|
+
// Answers and recommendations can carry sensitive question IDs as data.
|
|
94
|
+
if (typeof object.questionId === 'string' && sensitiveKey.test(object.questionId)) {
|
|
95
|
+
const values = [object.value, object.default,
|
|
96
|
+
...(Array.isArray(object.options) ? object.options.map(option => option?.value) : [])];
|
|
97
|
+
if (values.some(candidate => candidate !== undefined && candidate !== null && !isReference(candidate)))
|
|
98
|
+
throw secretError();
|
|
99
|
+
}
|
|
100
|
+
for (const [key, child] of Object.entries(object)) {
|
|
101
|
+
scanText(key);
|
|
102
|
+
if (sensitiveKey.test(key) && child !== null && child !== undefined && !isReference(child)) {
|
|
103
|
+
// A sensitive answer ID may wrap a reference with source/timestamp metadata.
|
|
104
|
+
const answer = child && typeof child === 'object' ? child : null;
|
|
105
|
+
if (!answerMap || !answer || !Object.hasOwn(answer, 'value') ||
|
|
106
|
+
(answer.value !== null && !isReference(answer.value)))
|
|
107
|
+
throw secretError();
|
|
108
|
+
}
|
|
109
|
+
visit(child, depth + 1, depth === 0 && key === 'answers');
|
|
110
|
+
}
|
|
111
|
+
};
|
|
112
|
+
visit(input, 0);
|
|
113
|
+
}
|
|
114
|
+
export function validateSetupPlan(input) {
|
|
115
|
+
assertPlanRedacted(input);
|
|
116
|
+
const parsed = planSchema.safeParse(input);
|
|
117
|
+
// Zod errors can include credential-bearing keys/values: keep diagnostics structural.
|
|
118
|
+
if (!parsed.success)
|
|
119
|
+
throw new Error('Invalid setup plan v1 shape; check required fields, timestamps, and action dependencies.');
|
|
120
|
+
const plan = parsed.data;
|
|
121
|
+
const ids = new Set(plan.actions.map(action => action.id));
|
|
122
|
+
if (ids.size !== plan.actions.length)
|
|
123
|
+
throw new Error('Setup plan action IDs must be unique.');
|
|
124
|
+
if (new Set(plan.receipts.map(receipt => receipt.workspace)).size !== plan.receipts.length) {
|
|
125
|
+
throw new Error('Setup plan workspace receipts must be unique.');
|
|
126
|
+
}
|
|
127
|
+
for (const receipt of plan.receipts)
|
|
128
|
+
for (const [id, result] of Object.entries(receipt.actions)) {
|
|
129
|
+
if (!plan.actions.some(action => action.id === id && action.workspace === receipt.workspace)) {
|
|
130
|
+
throw new Error('Setup plan receipt must refer to an action in the same workspace.');
|
|
131
|
+
}
|
|
132
|
+
if (Date.parse(result.completedAt) < Date.parse(result.startedAt))
|
|
133
|
+
throw new Error('Setup plan receipt timestamps are out of order.');
|
|
134
|
+
}
|
|
135
|
+
if (Date.parse(plan.updatedAt) < Date.parse(plan.createdAt))
|
|
136
|
+
throw new Error('Setup plan timestamps are out of order.');
|
|
137
|
+
return plan;
|
|
138
|
+
}
|
|
139
|
+
//# sourceMappingURL=plan-validation.js.map
|
|
@@ -687,6 +687,7 @@ export const initCommand = {
|
|
|
687
687
|
triggerPhrases: ['init project', 'setup project config', 'configure providers'],
|
|
688
688
|
commandHint: {
|
|
689
689
|
template: 'utility',
|
|
690
|
+
argumentHint: '[--scope project|user] [--intent code|docs|ops|mixed] [--credential <provider>=env:NAME|file:PATH|stdin] [--jev enable|decline|defer]',
|
|
690
691
|
allowedTools: ['Read', 'Write'],
|
|
691
692
|
},
|
|
692
693
|
},
|
|
@@ -718,7 +719,7 @@ export const setupCommand = {
|
|
|
718
719
|
],
|
|
719
720
|
commandHint: {
|
|
720
721
|
template: 'utility',
|
|
721
|
-
argumentHint: 'project [--yes] [--dry-run] [--target <dir>]',
|
|
722
|
+
argumentHint: 'project [--yes] [--dry-run] [--review] [--apply] [--plan <id>] [--target <dir>] [--scope project|user] [--workspace <root>] [--monorepo root|package] [--package <root>] [--scan-roots <dir>] [--intent code|docs|ops|mixed] [--credential <provider>=env:NAME|file:PATH|stdin] [--jev enable|decline|defer]',
|
|
722
723
|
allowedTools: ['Read', 'Write', 'Bash'],
|
|
723
724
|
},
|
|
724
725
|
},
|
|
@@ -1647,14 +1648,14 @@ export const discoverCommand = {
|
|
|
1647
1648
|
},
|
|
1648
1649
|
};
|
|
1649
1650
|
// Show: companion to `discover`. Where `discover` ranks candidates,
|
|
1650
|
-
// `show`
|
|
1651
|
+
// `show` returns a metadata card with explicit section/body drill-ins. This
|
|
1651
1652
|
// closes the loop so consumers never need to navigate AIWG's storage
|
|
1652
1653
|
// paths themselves — the CLI is the access point.
|
|
1653
1654
|
export const showCommand = {
|
|
1654
1655
|
id: 'show',
|
|
1655
1656
|
type: 'skill',
|
|
1656
1657
|
name: 'Show',
|
|
1657
|
-
description: '
|
|
1658
|
+
description: 'Show an AIWG artifact metadata card; use --section or --body for content',
|
|
1658
1659
|
version: '1.0.0',
|
|
1659
1660
|
capabilities: ['cli', 'discovery', 'read', 'capability', 'skills'],
|
|
1660
1661
|
keywords: ['show', 'cat', 'read skill', 'print skill', 'get skill content', 'aiwg show'],
|
|
@@ -1678,7 +1679,7 @@ export const showCommand = {
|
|
|
1678
1679
|
],
|
|
1679
1680
|
commandHint: {
|
|
1680
1681
|
template: 'utility',
|
|
1681
|
-
argumentHint: '<type> <name> [--json] [--first] [--resource-source local|web|auto] [--aiwg-version <version|range|digest|channel>] [--offline] # type: skill | agent | command | rule',
|
|
1682
|
+
argumentHint: '<type> <name> [--body] [--section <heading>] [--rules] [--resources] [--json] [--first] [--resource-source local|web|auto] [--aiwg-version <version|range|digest|channel>] [--offline] # type: skill | agent | command | rule',
|
|
1682
1683
|
allowedTools: ['Read'],
|
|
1683
1684
|
},
|
|
1684
1685
|
},
|
|
@@ -3177,6 +3178,39 @@ export const daemonInitCommand = {
|
|
|
3177
3178
|
},
|
|
3178
3179
|
},
|
|
3179
3180
|
};
|
|
3181
|
+
export const housekeeperCommand = {
|
|
3182
|
+
id: 'housekeeper',
|
|
3183
|
+
type: 'skill',
|
|
3184
|
+
name: 'Housekeeper',
|
|
3185
|
+
description: 'Deterministic maintenance daemon: start/stop/status/run-once, jobs, watch roots, autostart units',
|
|
3186
|
+
version: '1.0.0',
|
|
3187
|
+
capabilities: ['cli', 'daemon', 'maintenance', 'scheduler'],
|
|
3188
|
+
keywords: ['housekeeper', 'daemon', 'maintenance', 'schedule', 'run-once', 'autostart'],
|
|
3189
|
+
category: 'daemon',
|
|
3190
|
+
platforms: {
|
|
3191
|
+
claude: 'full',
|
|
3192
|
+
generic: 'full',
|
|
3193
|
+
},
|
|
3194
|
+
deployment: {
|
|
3195
|
+
pathTemplate: '.{platform}/commands/{id}.md',
|
|
3196
|
+
core: false,
|
|
3197
|
+
},
|
|
3198
|
+
metadata: {
|
|
3199
|
+
type: 'skill',
|
|
3200
|
+
triggerPhrases: ['housekeeper', 'housekeeper status', 'housekeeper start', 'maintenance daemon'],
|
|
3201
|
+
commandHint: {
|
|
3202
|
+
template: 'utility',
|
|
3203
|
+
argumentHint: '<start|stop|status|run-once|job|watch|install|uninstall> [options]',
|
|
3204
|
+
allowedTools: ['Bash', 'Read', 'Write'],
|
|
3205
|
+
executionSteps: [
|
|
3206
|
+
'Parse subcommand and flags',
|
|
3207
|
+
'Start/stop/query the housekeeper-profile daemon or edit its config',
|
|
3208
|
+
'Run one job without a daemon (run-once) or write autostart units (install)',
|
|
3209
|
+
'Display result',
|
|
3210
|
+
],
|
|
3211
|
+
},
|
|
3212
|
+
},
|
|
3213
|
+
};
|
|
3180
3214
|
// Config Commands
|
|
3181
3215
|
export const configCommand = {
|
|
3182
3216
|
id: 'config',
|
|
@@ -3341,7 +3375,7 @@ export const memoryCommand = {
|
|
|
3341
3375
|
id: 'memory',
|
|
3342
3376
|
type: 'skill',
|
|
3343
3377
|
name: 'Memory',
|
|
3344
|
-
description: '
|
|
3378
|
+
description: 'Read-only memory audit/cost/recommend/verify, reviewed plan/apply/restore, storage and project memory registry commands',
|
|
3345
3379
|
version: '1.0.0',
|
|
3346
3380
|
capabilities: ['cli', 'memory', 'semantic-memory', 'storage', 'pkm', 'project-memory', 'user-registry'],
|
|
3347
3381
|
keywords: ['memory', 'semantic-memory', 'project-memory', 'registry', 'reflections', 'pages'],
|
|
@@ -3359,11 +3393,16 @@ export const memoryCommand = {
|
|
|
3359
3393
|
triggerPhrases: ['where is memory', 'memory path', 'list memory', 'project memory', 'aiwg memory'],
|
|
3360
3394
|
commandHint: {
|
|
3361
3395
|
template: 'utility',
|
|
3362
|
-
argumentHint: '<path|list|get|put|delete|append-log|project> [options]',
|
|
3396
|
+
argumentHint: '<audit|cost|recommend|plan|apply|verify|restore|path|list|get|put|delete|append-log|project> [options]',
|
|
3363
3397
|
allowedTools: ['Bash', 'Read'],
|
|
3364
3398
|
executionSteps: [
|
|
3365
3399
|
'Parse subcommand and arguments',
|
|
3366
|
-
'
|
|
3400
|
+
'For audit, parse --scope global|project|provider, --provider <id>, --json, --cost strictly; default to workspace and perform a bounded read-only inventory',
|
|
3401
|
+
'For cost, run the same read-only inventory through the resident-cost view (--demote, --startup-measurement, --usage only read; nothing is written)',
|
|
3402
|
+
'For recommend and verify, run read-only reports; verify --plan checks existing owner receipts, retained history and published end states without refresh',
|
|
3403
|
+
'For plan/apply/restore, show project targeting, diff, owner review and next-session limits; mutation requires exact reviewed owner plans',
|
|
3404
|
+
'Use maintenance exit codes 0 success, 1 findings, 2 usage, 3 stale or failed',
|
|
3405
|
+
'Resolve storage adapter for storage operations only',
|
|
3367
3406
|
'Read/write/list/delete/append-log via the adapter or manage project-memory mappings',
|
|
3368
3407
|
'Print result',
|
|
3369
3408
|
],
|
|
@@ -3755,7 +3794,7 @@ export const rlmCacheCommand = {
|
|
|
3755
3794
|
* - SDLC Orchestration (1): sdlc-accelerate
|
|
3756
3795
|
* - Index (1): index
|
|
3757
3796
|
* - Reproducibility (4): execution-mode, snapshot, checkpoint, reproducibility-validate
|
|
3758
|
-
* - Daemon (
|
|
3797
|
+
* - Daemon (3): behavior, daemon-init, housekeeper
|
|
3759
3798
|
* - Config (1): config
|
|
3760
3799
|
* - Ops (1): ops
|
|
3761
3800
|
* - Agentic Tools (5): chunk, fanout, rlm-prep, rlm-search, rlm-status
|
|
@@ -3886,9 +3925,10 @@ export const commandDefinitions = [
|
|
|
3886
3925
|
snapshotCommand,
|
|
3887
3926
|
checkpointCommand,
|
|
3888
3927
|
reproducibilityValidateCommand,
|
|
3889
|
-
// Daemon (
|
|
3928
|
+
// Daemon (3)
|
|
3890
3929
|
behaviorCommand,
|
|
3891
3930
|
daemonInitCommand,
|
|
3931
|
+
housekeeperCommand,
|
|
3892
3932
|
// Config (1)
|
|
3893
3933
|
configCommand,
|
|
3894
3934
|
// Ops (1)
|