@aiwg/cli 2026.10.5 → 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 +57 -6
- 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 +143 -14
- package/dist/src/artifacts/index-files.js +15 -4
- package/dist/src/artifacts/index-reader.js +44 -0
- package/dist/src/artifacts/index-refresh.js +114 -55
- package/dist/src/artifacts/index-status.js +20 -5
- 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 +1 -0
- 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 +10 -9
- 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/candidates.js +7 -6
- package/dist/src/sessions/contracts.js +63 -53
- package/dist/src/sessions/output-registration.js +11 -10
- package/dist/src/sessions/workspace-discovery.js +3 -4
- 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
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import {
|
|
1
|
+
import { randomUUID } from 'node:crypto';
|
|
2
2
|
import * as fs from 'node:fs';
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
4
|
import path from 'node:path';
|
|
@@ -7,13 +7,14 @@ import { findPackageRoot } from '../cli/find-package-root.js';
|
|
|
7
7
|
import { projectAiwgPath, projectControlPath } from '../config/project-artifacts.js';
|
|
8
8
|
import { getUserStateDir } from '../config/user-state.js';
|
|
9
9
|
import { resolveIndexWorkers } from './index-preparation.js';
|
|
10
|
-
import {
|
|
10
|
+
import { resolveFrameworkIndexRoot } from './framework-index-paths.js';
|
|
11
11
|
import { collectIndexStatus } from './index-status.js';
|
|
12
|
+
import { graphIndexDigest, indexAdapterRegistry, selectIndexAdapters, indexFreshnessSnapshot, indexAdapterDigest, recordIndexVerification } from './index-adapters.js';
|
|
12
13
|
import { getFortemiCoreSyncStatus, syncFortemiCoreIndex } from './fortemi-core-sync.js';
|
|
13
14
|
import { acquireDirectoryLock, DirectoryLockContentionError } from './prebuilt-build-lock.js';
|
|
14
15
|
import { resolveImportExclusions } from '../sessions/import-exclusions.js';
|
|
15
16
|
import { resolveImportLimits } from '../sessions/import-limits.js';
|
|
16
|
-
import {
|
|
17
|
+
import { GRAPH_CONFIGS, getGraphIndexDir, graphBuildOrder, loadWorkspaceGraphs, resolveGraphScanDir, } from './types.js';
|
|
17
18
|
function readJson(file, tolerateMalformed = true) {
|
|
18
19
|
try {
|
|
19
20
|
return JSON.parse(fs.readFileSync(file, 'utf8'));
|
|
@@ -29,14 +30,6 @@ function writeJson(file, value) {
|
|
|
29
30
|
fs.writeFileSync(temporary, `${JSON.stringify(value, null, 2)}\n`, { mode: 0o600 });
|
|
30
31
|
fs.renameSync(temporary, file);
|
|
31
32
|
}
|
|
32
|
-
/** The registry is process-global; reload it per workspace to avoid cross-project leakage. */
|
|
33
|
-
function loadWorkspaceGraphs(workspace) {
|
|
34
|
-
for (const name of Object.keys(GRAPH_CONFIGS))
|
|
35
|
-
delete GRAPH_CONFIGS[name];
|
|
36
|
-
Object.assign(GRAPH_CONFIGS, structuredClone(BUILTIN_GRAPH_CONFIGS));
|
|
37
|
-
loadUserGraphConfigs(workspace);
|
|
38
|
-
loadGlobalGraphConfigs();
|
|
39
|
-
}
|
|
40
33
|
function workspacePaths(options) {
|
|
41
34
|
const cwd = options.cwd ?? process.cwd();
|
|
42
35
|
const found = new Map();
|
|
@@ -124,33 +117,38 @@ function planWorkspaceRefresh(options, workspaces) {
|
|
|
124
117
|
loadWorkspaceGraphs(workspace);
|
|
125
118
|
const graphs = collectIndexStatus(workspace).graphs
|
|
126
119
|
.sort((a, b) => graphBuildOrder(a.name, GRAPH_CONFIGS[a.name]) - graphBuildOrder(b.name, GRAPH_CONFIGS[b.name]) || a.name.localeCompare(b.name));
|
|
127
|
-
|
|
120
|
+
const adapters = indexAdapterRegistry(workspace);
|
|
121
|
+
const selected = selectIndexAdapters(adapters, options.only);
|
|
122
|
+
const includes = (name) => selected.some(adapter => adapter.name === name);
|
|
123
|
+
if (!options.only || options.only === 'all' || options.only === 'graphs' || selected.some(adapter => adapter.group === 'graphs')) {
|
|
128
124
|
for (const graph of graphs) {
|
|
129
|
-
if (
|
|
125
|
+
if (selected.some(adapter => adapter.group === 'graphs' && adapter.graph === graph.name)
|
|
126
|
+
&& (graph.built || graph.defaultBuild || graph.origin === 'registered'
|
|
127
|
+
|| (options.only && options.only !== 'all' && options.only !== 'graphs'))) {
|
|
130
128
|
jobs.push({ kind: 'graph', workspace, graph: graph.name, status: 'planned', wallMs: 0 });
|
|
131
129
|
}
|
|
132
130
|
}
|
|
133
131
|
}
|
|
134
|
-
if (!options.only || options.only === 'caches') {
|
|
132
|
+
if (!options.only || options.only === 'all' || options.only === 'caches' || options.only?.startsWith('caches:')) {
|
|
135
133
|
for (const graph of graphs) {
|
|
136
134
|
// Refresh only local, opted-in caches; never create a new cache from a packaged prebuilt.
|
|
137
|
-
if (fs.existsSync(getFortemiCoreSyncStatus(workspace, graph.name).location)) {
|
|
135
|
+
if (includes(`caches:${graph.name}`) && fs.existsSync(getFortemiCoreSyncStatus(workspace, graph.name).location)) {
|
|
138
136
|
jobs.push({ kind: 'cache', workspace, graph: graph.name, status: 'planned', wallMs: 0 });
|
|
139
137
|
}
|
|
140
138
|
}
|
|
141
139
|
}
|
|
142
|
-
if ((
|
|
140
|
+
if (includes('sessions') && fs.existsSync(path.join(workspace, '.aiwg/sessions/catalog.sqlite'))) {
|
|
143
141
|
jobs.push({ kind: 'sessions', workspace, status: 'planned', wallMs: 0, noManifest: 0 });
|
|
144
142
|
}
|
|
145
143
|
for (const kind of ['runtime', 'issues']) {
|
|
146
|
-
if (
|
|
144
|
+
if (!includes(kind))
|
|
147
145
|
continue;
|
|
148
146
|
if (kind === 'issues' && !fs.existsSync(projectAiwgPath(workspace, 'issues')))
|
|
149
147
|
continue;
|
|
150
148
|
jobs.push({ kind, workspace, status: 'planned', wallMs: 0 });
|
|
151
149
|
}
|
|
152
150
|
}
|
|
153
|
-
if (!options.only || options.only === 'models') {
|
|
151
|
+
if (!options.only || options.only === 'all' || options.only === 'models') {
|
|
154
152
|
jobs.push({ kind: 'models', scope: 'host', status: 'planned', wallMs: 0 });
|
|
155
153
|
}
|
|
156
154
|
return jobs;
|
|
@@ -177,23 +175,6 @@ export async function refreshResourceGate(workspace, live) {
|
|
|
177
175
|
const result = preflight.evaluateDispatchGate(live ?? preflight.readLiveHostResources({ paths: [workspace] }), thresholds);
|
|
178
176
|
return { ok: result.ok, reason: result.failures.map((failure) => failure.reason).join('; ') || undefined };
|
|
179
177
|
}
|
|
180
|
-
async function graphFingerprint(workspace, graph) {
|
|
181
|
-
const files = await collectGraphIndexFiles(workspace, graph);
|
|
182
|
-
// Source import resolution also depends on the compiler/package configuration.
|
|
183
|
-
if (graph === 'source') {
|
|
184
|
-
for (const file of ['tsconfig.json', 'package.json']) {
|
|
185
|
-
if (fs.existsSync(path.join(workspace, file)))
|
|
186
|
-
files.push(path.join(workspace, file));
|
|
187
|
-
}
|
|
188
|
-
}
|
|
189
|
-
const stats = [...new Set(files)].sort().map(file => {
|
|
190
|
-
const stat = fs.statSync(file);
|
|
191
|
-
return [file, stat.mtimeMs, stat.ctimeMs, stat.size];
|
|
192
|
-
});
|
|
193
|
-
return createHash('sha256').update(JSON.stringify([
|
|
194
|
-
INDEX_VERSION, INDEX_EXTRACTOR_VERSION, GRAPH_CONFIGS[graph], resolveGraphBackendType(graph), stats,
|
|
195
|
-
])).digest('hex');
|
|
196
|
-
}
|
|
197
178
|
async function refreshWorkspaceRuntime(workspace, full, runtime) {
|
|
198
179
|
const directory = projectAiwgPath(workspace, 'smiths', 'toolsmith');
|
|
199
180
|
const output = path.join(directory, 'runtime.json');
|
|
@@ -237,34 +218,54 @@ async function refreshWorkspaceRuntime(workspace, full, runtime) {
|
|
|
237
218
|
async function executeJob(job, options, aliases, runtime) {
|
|
238
219
|
const workspace = job.workspace ?? process.env.HOME ?? homedir();
|
|
239
220
|
if (job.kind === 'graph') {
|
|
221
|
+
const graphStart = Date.now();
|
|
240
222
|
const graph = job.graph;
|
|
241
223
|
const config = GRAPH_CONFIGS[graph];
|
|
242
|
-
|
|
224
|
+
const sourceWorkspace = graph === 'framework' ? resolveFrameworkIndexRoot(workspace) : workspace;
|
|
225
|
+
if (!config.scanDirs.some(dir => fs.existsSync(resolveGraphScanDir(sourceWorkspace, dir)))) {
|
|
243
226
|
job.status = 'skipped';
|
|
244
227
|
job.reason = 'scan directories missing';
|
|
245
228
|
return;
|
|
246
229
|
}
|
|
247
230
|
const directory = getGraphIndexDir(workspace, graph);
|
|
248
231
|
const markerPath = path.join(directory, 'refresh-state.json');
|
|
232
|
+
const fingerprint = await graphIndexDigest(sourceWorkspace, graph);
|
|
249
233
|
const marker = readJson(markerPath);
|
|
250
234
|
const metadata = readJson(path.join(directory, 'metadata.json'));
|
|
251
|
-
const
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
235
|
+
const adapter = indexAdapterRegistry(workspace).find(item => item.name === graph);
|
|
236
|
+
if (!options.full && marker?.fingerprint === fingerprint && marker.builtAt === metadata?.builtAt
|
|
237
|
+
&& indexFreshnessSnapshot(adapter, workspace).pendingWork === 0) {
|
|
238
|
+
const release = await acquireDirectoryLock(`${directory}.build.lock`, {
|
|
239
|
+
timeoutMs: options.lockWaitMs ?? 0, reclaimDeadOwner: true,
|
|
240
|
+
});
|
|
241
|
+
try {
|
|
242
|
+
const current = await graphIndexDigest(sourceWorkspace, graph);
|
|
243
|
+
if (current === fingerprint && indexFreshnessSnapshot(adapter, workspace).pendingWork === 0) {
|
|
244
|
+
recordIndexVerification(adapter, workspace, { before: fingerprint, after: current, wallMs: Date.now() - graphStart });
|
|
245
|
+
job.status = 'skipped';
|
|
246
|
+
job.reason = 'unchanged';
|
|
247
|
+
return;
|
|
248
|
+
}
|
|
249
|
+
}
|
|
250
|
+
finally {
|
|
251
|
+
await release();
|
|
252
|
+
}
|
|
260
253
|
}
|
|
254
|
+
const beforeOutput = outputStamp(path.join(directory, 'metadata.json'));
|
|
261
255
|
const { buildIndex } = await import('./index-builder.js');
|
|
262
|
-
await buildIndex(
|
|
256
|
+
await buildIndex(sourceWorkspace, { graph, force: Boolean(options.full), explicit: false, quiet: true, workers: options.workers, lockWaitMs: options.lockWaitMs ?? 0,
|
|
263
257
|
onDiagnostic: message => (job.diagnostics ??= []).push(message) });
|
|
264
258
|
const built = readJson(path.join(directory, 'metadata.json'));
|
|
265
259
|
if (!built)
|
|
266
260
|
throw new Error(`graph did not produce metadata: ${graph}`);
|
|
267
|
-
|
|
261
|
+
const verification = readJson(path.join(directory, 'freshness.json'));
|
|
262
|
+
if (!options.full && beforeOutput && beforeOutput === outputStamp(path.join(directory, 'metadata.json'))) {
|
|
263
|
+
job.status = 'skipped';
|
|
264
|
+
job.reason = 'unchanged';
|
|
265
|
+
}
|
|
266
|
+
if (!verification?.pendingWork && verification?.lastVerifiedDigest === fingerprint) {
|
|
267
|
+
writeJson(markerPath, { fingerprint, builtAt: built.builtAt });
|
|
268
|
+
}
|
|
268
269
|
}
|
|
269
270
|
else if (job.kind === 'cache') {
|
|
270
271
|
const status = getFortemiCoreSyncStatus(workspace, job.graph);
|
|
@@ -333,7 +334,8 @@ async function executeJob(job, options, aliases, runtime) {
|
|
|
333
334
|
}
|
|
334
335
|
}
|
|
335
336
|
}
|
|
336
|
-
job.status
|
|
337
|
+
if (job.status !== 'skipped')
|
|
338
|
+
job.status = 'ok';
|
|
337
339
|
}
|
|
338
340
|
function outputStamp(file) {
|
|
339
341
|
try {
|
|
@@ -385,6 +387,17 @@ export async function refreshIndexes(options = {}, dependencies = {}) {
|
|
|
385
387
|
.reduce((total, receipt) => total + (receipt.totals.excluded ?? 0), 0), 0),
|
|
386
388
|
wallMs: Date.now() - start,
|
|
387
389
|
};
|
|
390
|
+
report.indices = [];
|
|
391
|
+
for (const workspace of workspaces.keys()) {
|
|
392
|
+
loadWorkspaceGraphs(workspace);
|
|
393
|
+
for (const adapter of selectIndexAdapters(indexAdapterRegistry(workspace), options.only)) {
|
|
394
|
+
report.indices.push({ ...indexFreshnessSnapshot(adapter, workspace), workspace });
|
|
395
|
+
}
|
|
396
|
+
}
|
|
397
|
+
if (!jobs.length && options.only && report.indices.length && report.indices.every(index => index.status === 'unsupported')) {
|
|
398
|
+
report.status = 'deferred';
|
|
399
|
+
report.reason = 'unsupported';
|
|
400
|
+
}
|
|
388
401
|
return report;
|
|
389
402
|
};
|
|
390
403
|
if (options.dryRun)
|
|
@@ -435,6 +448,8 @@ export async function refreshIndexes(options = {}, dependencies = {}) {
|
|
|
435
448
|
continue;
|
|
436
449
|
}
|
|
437
450
|
const jobStart = Date.now();
|
|
451
|
+
let adapter;
|
|
452
|
+
let beforeDigest;
|
|
438
453
|
try {
|
|
439
454
|
const gateWorkspace = job.workspace ?? workspaces.keys().next().value ?? options.cwd ?? process.cwd();
|
|
440
455
|
const gate = await (dependencies.gate ?? refreshResourceGate)(gateWorkspace);
|
|
@@ -447,6 +462,15 @@ export async function refreshIndexes(options = {}, dependencies = {}) {
|
|
|
447
462
|
}
|
|
448
463
|
if (job.workspace)
|
|
449
464
|
loadWorkspaceGraphs(job.workspace);
|
|
465
|
+
const workspace = job.workspace ?? options.cwd ?? process.cwd();
|
|
466
|
+
adapter = indexAdapterRegistry(workspace).find(item => item.name === (job.kind === 'graph' ? job.graph
|
|
467
|
+
: job.kind === 'cache' ? `caches:${job.graph}` : job.kind));
|
|
468
|
+
if (adapter?.supported && job.kind !== 'graph') {
|
|
469
|
+
try {
|
|
470
|
+
beforeDigest = await indexAdapterDigest(adapter, workspace);
|
|
471
|
+
}
|
|
472
|
+
catch { /* Owner reports unavailable dependencies. */ }
|
|
473
|
+
}
|
|
450
474
|
if (job.kind === 'cache' && jobs.some(other => other.kind === 'graph'
|
|
451
475
|
&& other.workspace === job.workspace && other.graph === job.graph && other.status === 'error')) {
|
|
452
476
|
job.status = 'skipped';
|
|
@@ -471,13 +495,52 @@ export async function refreshIndexes(options = {}, dependencies = {}) {
|
|
|
471
495
|
await executeJob(job, options, aliases, discoverRuntime);
|
|
472
496
|
}
|
|
473
497
|
catch (error) {
|
|
474
|
-
|
|
475
|
-
|
|
498
|
+
if (error instanceof DirectoryLockContentionError) {
|
|
499
|
+
job.status = 'deferred';
|
|
500
|
+
job.reason = 'lock-held';
|
|
501
|
+
report.status = 'deferred';
|
|
502
|
+
}
|
|
503
|
+
else {
|
|
504
|
+
job.status = 'error';
|
|
505
|
+
job.error = error instanceof Error ? error.message : String(error);
|
|
506
|
+
}
|
|
476
507
|
}
|
|
477
508
|
finally {
|
|
478
509
|
job.wallMs = Date.now() - jobStart;
|
|
510
|
+
if (adapter) {
|
|
511
|
+
const workspace = job.workspace ?? options.cwd ?? process.cwd();
|
|
512
|
+
if (adapter.supported && job.kind !== 'graph' && job.status !== 'deferred') {
|
|
513
|
+
try {
|
|
514
|
+
let after;
|
|
515
|
+
let probeError;
|
|
516
|
+
try {
|
|
517
|
+
after = await indexAdapterDigest(adapter, workspace);
|
|
518
|
+
}
|
|
519
|
+
catch (error) {
|
|
520
|
+
probeError = String(error);
|
|
521
|
+
}
|
|
522
|
+
if (job.kind === 'runtime' && job.status === 'ok')
|
|
523
|
+
beforeDigest = after;
|
|
524
|
+
const partial = job.reason && job.reason !== 'unchanged';
|
|
525
|
+
job.freshness = recordIndexVerification(adapter, workspace, { before: beforeDigest, after,
|
|
526
|
+
error: job.error ?? probeError, pendingWork: partial ? 1 : 0, wallMs: job.wallMs });
|
|
527
|
+
}
|
|
528
|
+
catch (error) {
|
|
529
|
+
job.freshness = { ...indexFreshnessSnapshot(adapter, workspace), status: 'degraded',
|
|
530
|
+
pendingWork: 1, lastError: String(error) };
|
|
531
|
+
}
|
|
532
|
+
}
|
|
533
|
+
else
|
|
534
|
+
job.freshness = indexFreshnessSnapshot(adapter, workspace);
|
|
535
|
+
if (job.freshness.pendingWork && !job.error && job.status !== 'deferred' && job.kind === 'graph'
|
|
536
|
+
&& job.reason !== 'scan directories missing') {
|
|
537
|
+
job.status = 'deferred';
|
|
538
|
+
job.reason = 'inputs changed during build';
|
|
539
|
+
report.status = 'deferred';
|
|
540
|
+
}
|
|
541
|
+
}
|
|
479
542
|
}
|
|
480
|
-
if (job.status !== 'error' && job.reason !== 'graph failed'
|
|
543
|
+
if (job.status !== 'error' && job.status !== 'deferred' && job.reason !== 'graph failed'
|
|
481
544
|
&& job.reason !== 'no authorized discovery manifest')
|
|
482
545
|
checkpoint.completed.push(key);
|
|
483
546
|
writeJson(checkpointPath, checkpoint);
|
|
@@ -534,10 +597,6 @@ export async function runIndexRefresh(args, cwd = process.cwd(), signal) {
|
|
|
534
597
|
else if (flag === '--exclude')
|
|
535
598
|
(options.exclude ??= []).push(value);
|
|
536
599
|
else if (flag === '--only') {
|
|
537
|
-
if (value !== 'graphs' && value !== 'sessions' && value !== 'caches'
|
|
538
|
-
&& value !== 'runtime' && value !== 'models' && value !== 'issues') {
|
|
539
|
-
throw new Error('--only must be graphs, sessions, caches, runtime, models, or issues');
|
|
540
|
-
}
|
|
541
600
|
options.only = value;
|
|
542
601
|
}
|
|
543
602
|
else {
|
|
@@ -18,8 +18,9 @@
|
|
|
18
18
|
*/
|
|
19
19
|
import * as fs from 'node:fs';
|
|
20
20
|
import * as path from 'node:path';
|
|
21
|
-
import { GRAPH_CONFIGS, BUILTIN_GRAPH_CONFIGS, getGraphIndexDir, getProjectIndexRoot,
|
|
21
|
+
import { GRAPH_CONFIGS, BUILTIN_GRAPH_CONFIGS, getGraphIndexDir, getProjectIndexRoot, loadWorkspaceGraphs, resolveGraphBackendType, } from './types.js';
|
|
22
22
|
import { getFortemiCoreSyncStatus, } from './fortemi-core-sync.js';
|
|
23
|
+
import { indexAdapterRegistry, indexFreshnessSnapshot, selectIndexAdapters } from './index-adapters.js';
|
|
23
24
|
function readBuiltMeta(indexDir) {
|
|
24
25
|
try {
|
|
25
26
|
const metaPath = path.join(indexDir, 'metadata.json');
|
|
@@ -42,12 +43,11 @@ function readBuiltMeta(indexDir) {
|
|
|
42
43
|
*
|
|
43
44
|
* @param nowMs - injectable clock for deterministic tests (defaults to Date.now()).
|
|
44
45
|
*/
|
|
45
|
-
export function collectIndexStatus(cwd, nowMs) {
|
|
46
|
+
export function collectIndexStatus(cwd, nowMs, only) {
|
|
46
47
|
// Populate the registry from module + operator config, collecting warnings
|
|
47
48
|
// instead of letting malformed defs vanish (#1624).
|
|
48
49
|
const warnings = [];
|
|
49
|
-
|
|
50
|
-
loadGlobalGraphConfigs(warnings);
|
|
50
|
+
loadWorkspaceGraphs(cwd, warnings);
|
|
51
51
|
const now = nowMs ?? Date.now();
|
|
52
52
|
const graphs = [];
|
|
53
53
|
for (const [name, config] of Object.entries(GRAPH_CONFIGS)) {
|
|
@@ -99,6 +99,10 @@ export function collectIndexStatus(cwd, nowMs) {
|
|
|
99
99
|
const built = graphs.filter((g) => g.built).length;
|
|
100
100
|
return {
|
|
101
101
|
graphs,
|
|
102
|
+
indices: selectIndexAdapters(indexAdapterRegistry(cwd), only).map(adapter => ({
|
|
103
|
+
...indexFreshnessSnapshot(adapter, cwd, now), identity: adapter.identity, backend: adapter.backend,
|
|
104
|
+
operation: adapter.operation, roots: adapter.roots(cwd), exclusions: adapter.exclusions, outputPaths: adapter.outputPaths,
|
|
105
|
+
})),
|
|
102
106
|
orphanIndexDirs,
|
|
103
107
|
warnings,
|
|
104
108
|
fortemiCore: getFortemiCoreSyncStatus(cwd),
|
|
@@ -111,9 +115,17 @@ export function collectIndexStatus(cwd, nowMs) {
|
|
|
111
115
|
},
|
|
112
116
|
};
|
|
113
117
|
}
|
|
118
|
+
/** Probe inputs through their owners; the legacy synchronous reader stays available. */
|
|
119
|
+
export async function probeIndexStatus(cwd, only, nowMs = Date.now()) {
|
|
120
|
+
const report = collectIndexStatus(cwd, nowMs, only);
|
|
121
|
+
const adapters = new Map(indexAdapterRegistry(cwd).map(adapter => [adapter.name, adapter]));
|
|
122
|
+
report.indices = await Promise.all(report.indices.map(async (index) => ({ ...index,
|
|
123
|
+
...await adapters.get(index.name).probe(cwd, nowMs) })));
|
|
124
|
+
return report;
|
|
125
|
+
}
|
|
114
126
|
/** Render `aiwg index status` (human table or JSON). */
|
|
115
127
|
export async function showIndexStatus(cwd, opts = {}) {
|
|
116
|
-
const report =
|
|
128
|
+
const report = await probeIndexStatus(cwd, opts.only);
|
|
117
129
|
if (opts.json) {
|
|
118
130
|
console.log(JSON.stringify(report, null, 2));
|
|
119
131
|
return;
|
|
@@ -182,6 +194,9 @@ export async function showIndexStatus(cwd, opts = {}) {
|
|
|
182
194
|
console.log(`⚠ ${missing} registered durable index(es) are not built. Run \`aiwg index build --all\`.`);
|
|
183
195
|
}
|
|
184
196
|
console.log('');
|
|
197
|
+
for (const index of report.indices) {
|
|
198
|
+
console.log(` ${index.name}: ${index.status} (target ${index.policy.targetStaleAfterMs}ms, pending ${index.pendingWork})${index.lastError ? `: ${index.lastError}` : ''}`);
|
|
199
|
+
}
|
|
185
200
|
console.log(`${report.summary.total} graph(s): ${report.summary.built} built, ${missing} missing, ` +
|
|
186
201
|
`${report.summary.orphans} orphan(s), ${report.summary.warnings} warning(s).`);
|
|
187
202
|
}
|