@aiwg/cli 2026.10.3 → 2026.10.5
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 +2 -2
- package/agentic/code/providers/model-capabilities.v1.json +96 -4
- package/bin/aiwg.mjs +50 -27
- package/dist/src/agents/grounding/knowledge-base.js +54 -6
- package/dist/src/artifacts/browser-export.js +6 -0
- package/dist/src/artifacts/checksum-manifest.js +1 -0
- package/dist/src/artifacts/citation-parser.js +173 -92
- package/dist/src/artifacts/citation-table-schema.js +59 -0
- package/dist/src/artifacts/cli.js +69 -18
- package/dist/src/artifacts/corpus-tools/snapshot.js +1 -1
- package/dist/src/artifacts/corpus-tools/vision-extract.js +2 -0
- package/dist/src/artifacts/corpus-views/ref-parser.js +3 -1
- package/dist/src/artifacts/corpus-views/renderers.js +3 -3
- package/dist/src/artifacts/discovery-eval.js +6 -4
- package/dist/src/artifacts/fortemi-core-query-adapter.js +36 -3
- package/dist/src/artifacts/fortemi-core-sync.js +166 -40
- package/dist/src/artifacts/framework-capabilities.js +171 -0
- package/dist/src/artifacts/framework-index-paths.js +73 -0
- package/dist/src/artifacts/framework-source-digest.js +75 -0
- package/dist/src/artifacts/index-builder.js +286 -131
- package/dist/src/artifacts/index-files.js +132 -18
- package/dist/src/artifacts/index-preparation.js +130 -0
- package/dist/src/artifacts/index-refresh.js +591 -0
- package/dist/src/artifacts/index-worker.mjs +11 -0
- package/dist/src/artifacts/prebuilt-build-lock.js +47 -4
- package/dist/src/artifacts/prebuilt-deployment.js +46 -0
- package/dist/src/artifacts/prebuilt-relations.js +80 -0
- package/dist/src/artifacts/query-engine.js +410 -88
- package/dist/src/artifacts/relations-builder.js +168 -0
- package/dist/src/artifacts/relations.js +148 -0
- package/dist/src/artifacts/stats.js +5 -2
- package/dist/src/artifacts/types.js +30 -10
- package/dist/src/artifacts/watcher.js +1 -1
- package/dist/src/auth/credential-store.js +2 -1
- package/dist/src/catalog/cli.d.mts +5 -0
- package/dist/src/channel/manager.d.mts +20 -0
- package/dist/src/channel/manager.mjs +19 -2
- package/dist/src/cli/command-log.js +2 -3
- package/dist/src/cli/handlers/artifacts.js +3 -0
- package/dist/src/cli/handlers/auth.js +3 -0
- package/dist/src/cli/handlers/decision.js +19 -12
- package/dist/src/cli/handlers/diagnose.js +4 -3
- package/dist/src/cli/handlers/effect.js +4 -2
- package/dist/src/cli/handlers/evidence.js +3 -0
- package/dist/src/cli/handlers/help.js +1 -0
- package/dist/src/cli/handlers/index.js +3 -1
- package/dist/src/cli/handlers/init.js +4 -1
- package/dist/src/cli/handlers/lint.js +5 -0
- package/dist/src/cli/handlers/models.js +104 -8
- package/dist/src/cli/handlers/ralph-launcher.js +2 -0
- package/dist/src/cli/handlers/refresh.js +12 -0
- package/dist/src/cli/handlers/resource-versions.js +3 -0
- package/dist/src/cli/handlers/rules.js +195 -0
- package/dist/src/cli/handlers/run.js +4 -0
- package/dist/src/cli/handlers/runtime-info.js +1 -2
- package/dist/src/cli/handlers/script-runner.js +3 -2
- package/dist/src/cli/handlers/session.js +19 -9
- package/dist/src/cli/handlers/sessions.js +137 -43
- package/dist/src/cli/handlers/setup-manifest.js +39 -44
- package/dist/src/cli/handlers/setup.js +41 -0
- package/dist/src/cli/handlers/steward.js +11 -0
- package/dist/src/cli/handlers/subcommands.js +57 -2
- package/dist/src/cli/handlers/uhp.js +3 -0
- package/dist/src/cli/handlers/use.js +294 -55
- package/dist/src/cli/handlers/utilities.js +26 -10
- package/dist/src/cli/handlers/version.js +8 -0
- package/dist/src/cli/router.js +15 -1
- package/dist/src/cli/services/deployment-verification.js +19 -9
- package/dist/src/cli/services/provider-prepare-coordinator.js +24 -0
- package/dist/src/cli/skill-usage.js +2 -3
- package/dist/src/config/aiwg-config.js +87 -37
- package/dist/src/config/cli.js +111 -5
- package/dist/src/config/decision-config.js +106 -0
- package/dist/src/config/dispatch-thresholds-runtime.d.mts +8 -0
- package/dist/src/config/gitignore.js +50 -0
- package/dist/src/config/index-graph-overrides.js +36 -0
- package/dist/src/config/project-artifacts-health.d.mts +37 -0
- package/dist/src/config/project-artifacts-runtime.d.mts +16 -0
- package/dist/src/config/user-config-dir.d.mts +9 -0
- package/dist/src/config/user-config.js +2 -1
- package/dist/src/config/user-registry.js +23 -15
- package/dist/src/config/user-state.js +7 -0
- package/dist/src/decision/ask.js +203 -43
- package/dist/src/decision/context-live-qualification.js +2 -2
- package/dist/src/decision/driver.js +13 -8
- package/dist/src/decision/ensemble/aggregate.js +23 -10
- package/dist/src/decision/ensemble-study/multifact-study.js +6 -2
- package/dist/src/decision/entry.js +2 -15
- package/dist/src/decision/graph-live-qualification.js +1 -1
- package/dist/src/decision/graph-run.js +9 -0
- package/dist/src/decision/heldout/collector.js +5 -13
- package/dist/src/decision/heldout/contract.js +30 -7
- package/dist/src/decision/jev-credentials.js +15 -1
- package/dist/src/decision/ledger.js +131 -28
- package/dist/src/decision/offload-activation.js +137 -0
- package/dist/src/decision/offload.js +550 -0
- package/dist/src/decision/qualification/load.js +4 -6
- package/dist/src/decision/savings.js +28 -0
- package/dist/src/effects/types.js +5 -1
- package/dist/src/effects/verifiers/git.js +2 -1
- package/dist/src/effects/verifiers/tracker.js +26 -14
- package/dist/src/extensions/commands/definitions.js +19 -0
- package/dist/src/extensions/project-local-remove.js +36 -1
- package/dist/src/gates/providers/loader.js +61 -17
- package/dist/src/installation/manager-command.d.mts +18 -0
- package/dist/src/installation/manager-command.mjs +14 -2
- package/dist/src/installation/manager.d.mts +49 -0
- package/dist/src/installation/manager.mjs +78 -3
- package/dist/src/issues/cli.js +4 -4
- package/dist/src/issues/local.js +24 -5
- package/dist/src/jobs/runner.js +1 -1
- package/dist/src/lint/cli.js +27 -1
- package/dist/src/lint/loader.js +2 -1
- package/dist/src/lint/reporters.js +25 -1
- package/dist/src/lint/rule-activation.js +43 -0
- package/dist/src/lint/runner.js +137 -62
- package/dist/src/mcp/adapters/codex-runtime.js +7 -1
- package/dist/src/mcp/claude-install.d.mts +4 -0
- package/dist/src/mcp/claude-install.mjs +41 -0
- package/dist/src/mcp/cli.d.mts +1 -0
- package/dist/src/mcp/cli.mjs +36 -11
- package/dist/src/mcp/config-file.d.mts +28 -0
- package/dist/src/mcp/config-layers.d.mts +36 -0
- package/dist/src/mcp/credentials.d.mts +51 -0
- package/dist/src/mcp/grok-build-config.d.mts +6 -0
- package/dist/src/mcp/grok-build-config.mjs +1 -1
- package/dist/src/mcp/helpers.mjs +3 -2
- package/dist/src/mcp/muse-native-config.d.mts +13 -0
- package/dist/src/mcp/muse-native-config.mjs +1 -0
- package/dist/src/mcp/omp-config.d.mts +4 -0
- package/dist/src/mcp/registry.js +3 -93
- package/dist/src/mcp/registry.mjs +3 -87
- package/dist/src/mcp/server-config.d.mts +3 -0
- package/dist/src/mcp/server-config.mjs +89 -0
- package/dist/src/mcp/server.mjs +37 -375
- package/dist/src/mcp/test-simple.mjs +2 -1
- package/dist/src/mcp/toml-editor.d.mts +4 -0
- package/dist/src/mcp/toml-string.d.mts +1 -0
- package/dist/src/mcp/toml-strip-mcp.d.mts +1 -0
- package/dist/src/mcp/tool-filters.d.mts +46 -0
- package/dist/src/mcp/tools/decision.mjs +12 -11
- package/dist/src/mcp/tools/discovery.mjs +62 -55
- package/dist/src/mcp/tools/orchestration.mjs +12 -2
- package/dist/src/mcp/tools/worker-invoke.mjs +1340 -23
- package/dist/src/mcp/tools/worker-shell-control.mjs +52 -21
- package/dist/src/mcp/tools/worker-stdin-runtime.mjs +3 -3
- package/dist/src/mission-protocol/codecs.js +8 -0
- package/dist/src/models/config-loader.js +7 -2
- package/dist/src/models/model-capabilities.v1.json +96 -4
- package/dist/src/models/model-discovery.js +76 -11
- package/dist/src/models/provider-policy.js +101 -7
- package/dist/src/models/qualification-digest.d.mts +2 -0
- package/dist/src/models/resolver.js +12 -10
- package/dist/src/models/worker-direct-readiness.js +65 -44
- package/dist/src/models/worker-dispatch-offer.js +3 -3
- package/dist/src/models/worker-health-readiness.js +16 -3
- package/dist/src/models/worker-installation.d.mts +39 -0
- package/dist/src/models/worker-installation.mjs +135 -28
- package/dist/src/process/bounded-child-process.d.mts +84 -0
- package/dist/src/process/bounded-child-process.mjs +43 -0
- package/dist/src/process/cli-command.d.mts +16 -0
- package/dist/src/process/signal-child.d.mts +6 -0
- package/dist/src/process/signal-child.mjs +7 -0
- package/dist/src/providers/deployed-skill-roots.js +20 -0
- package/dist/src/providers/grok-build-acp.js +3 -2
- package/dist/src/providers/grok-build-headless.js +12 -4
- package/dist/src/providers/grok-build-inspect.js +1 -0
- package/dist/src/providers/omp-agent.d.mts +8 -0
- package/dist/src/providers/omp-diagnostics.d.mts +1 -0
- package/dist/src/providers/omp-paths.d.mts +13 -0
- package/dist/src/providers/skill-ownership.d.mts +9 -0
- package/dist/src/providers/skill-ownership.mjs +88 -0
- package/dist/src/rules/activation.d.mts +21 -0
- package/dist/src/rules/activation.mjs +62 -0
- package/dist/src/rules/inline-budget.d.mts +26 -0
- package/dist/src/rules/inline-budget.mjs +66 -0
- package/dist/src/rules/inventory.js +129 -0
- package/dist/src/rules/pin-state.js +73 -0
- package/dist/src/rules/pins.d.mts +14 -0
- package/dist/src/rules/pins.mjs +112 -0
- package/dist/src/rules/rule-frontmatter.schema.json +197 -0
- package/dist/src/serve/mission-conductor.js +38 -12
- package/dist/src/serve/worker-invocation.js +30 -10
- package/dist/src/serve/worker-stdin-frame.d.mts +10 -0
- package/dist/src/sessions/adapter-registry.js +23 -19
- package/dist/src/sessions/adapters/claude.js +39 -54
- package/dist/src/sessions/adapters/codex.js +95 -67
- package/dist/src/sessions/adapters/copilot.js +4 -4
- package/dist/src/sessions/adapters/cursor.js +40 -57
- package/dist/src/sessions/adapters/deepseek-harness.js +15 -12
- package/dist/src/sessions/adapters/factory.js +31 -27
- package/dist/src/sessions/adapters/generic.js +10 -10
- package/dist/src/sessions/adapters/grok-build.js +11 -11
- package/dist/src/sessions/adapters/grokbot.js +24 -13
- package/dist/src/sessions/adapters/hermes.js +27 -29
- package/dist/src/sessions/adapters/muse-workspace-scan.js +31 -11
- package/dist/src/sessions/adapters/muse.js +150 -93
- package/dist/src/sessions/adapters/omp.js +28 -14
- package/dist/src/sessions/adapters/openclaw.js +89 -79
- package/dist/src/sessions/adapters/opencode.js +27 -24
- package/dist/src/sessions/adapters/openhuman.js +18 -60
- package/dist/src/sessions/adapters/pi.js +29 -14
- package/dist/src/sessions/adapters/warp.js +3 -3
- package/dist/src/sessions/adapters/windsurf.js +19 -48
- package/dist/src/sessions/batch-contracts.js +16 -8
- package/dist/src/sessions/batch-import.js +252 -12
- package/dist/src/sessions/contracts.js +50 -3
- package/dist/src/sessions/coverage-preflight.js +27 -2
- package/dist/src/sessions/export-plan.js +4 -3
- package/dist/src/sessions/import-exclusions.js +72 -0
- package/dist/src/sessions/import-lease.js +34 -18
- package/dist/src/sessions/import-limits.js +37 -0
- package/dist/src/sessions/importer.js +60 -38
- package/dist/src/sessions/lifecycle.js +45 -0
- package/dist/src/sessions/policy.js +145 -26
- package/dist/src/sessions/readers.js +106 -53
- package/dist/src/sessions/refresh.js +105 -0
- package/dist/src/sessions/repository.js +151 -54
- package/dist/src/sessions/workspace-discovery.js +292 -60
- package/dist/src/sessions/workspace-matching.js +107 -0
- package/dist/src/skills/importer.js +1 -0
- package/dist/src/smiths/context-pipeline/aiwg-md.js +11 -0
- package/dist/src/smiths/context-pipeline/claude-hook.js +3 -26
- package/dist/src/smiths/context-pipeline/finalization.js +6 -5
- package/dist/src/smiths/context-pipeline/generator.js +21 -4
- package/dist/src/smiths/context-pipeline/parallelism-section.js +7 -15
- package/dist/src/smiths/mcpsmith/generator.js +1 -1
- package/dist/src/smiths/toolsmith/runtime-discovery.d.mts +10 -0
- package/dist/src/smiths/toolsmith/runtime-discovery.mjs +76 -18
- package/dist/src/storage/backends/fs.js +18 -76
- package/dist/src/storage/backends/obsidian.js +1 -0
- package/dist/src/tracker/forge-http.js +2 -1
- package/dist/src/update/checker.d.mts +2 -0
- package/dist/src/update/service.d.mts +22 -0
- package/dist/src/utils/contained-filesystem.d.mts +37 -0
- package/dist/src/utils/contained-filesystem.mjs +683 -0
- package/dist/src/utils/temporary-directory.js +36 -0
- package/dist/src/writing/example-generator.js +1 -1
- package/package.json +15 -2
- package/schemas/models/model-catalog.v1.schema.json +1 -1
- package/schemas/models/provider-model-capabilities.v1.schema.json +6 -0
- package/tools/_resolve-impl.mjs +13 -15
- package/tools/agents/deploy-agents.mjs +49 -21
- package/tools/agents/providers/base.mjs +104 -134
- package/tools/agents/providers/claude.mjs +8 -24
- package/tools/agents/providers/codex.mjs +18 -11
- package/tools/agents/providers/cursor.mjs +19 -18
- package/tools/agents/providers/grok-build.mjs +3 -1
- package/tools/agents/providers/hermes.mjs +57 -47
- package/tools/agents/providers/openclaw.mjs +9 -4
- package/tools/agents/providers/pi.mjs +5 -0
- package/tools/agents/providers/provider-prepare-channel.mjs +5 -0
- package/tools/agents/providers/provider-prepare-coordinator.mjs +247 -0
- package/tools/agents/providers/provider-prepare-worker.mjs +84 -0
- package/tools/agents/providers/rule-delivery.mjs +1270 -0
- package/tools/agents/providers/warp.mjs +20 -26
- package/tools/cli/decision-offload-report.mjs +40 -0
- package/tools/cli/workspace-status.mjs +862 -0
- package/tools/plugin/package-plugins.mjs +186 -8
- package/tools/plugin/plugin-links.mjs +114 -0
- package/tools/providers/antigravity-transport.mjs +3 -1
- package/tools/providers/deepseek-harness-transport.mjs +6 -4
- package/tools/providers/omp-transport.mjs +4 -2
- package/tools/ralph-external/lib/consecutive-failure-circuit-breaker.mjs +1748 -0
- package/tools/ralph-external/lib/launcher-recovery-evidence.mjs +55 -0
- package/tools/ralph-external/lib/omp-adapter.mjs +1 -1
- package/tools/ralph-external/lib/pi-adapter.mjs +0 -4
- package/tools/ralph-external/lib/provider-adapter.mjs +59 -1
- package/tools/ralph-external/lib/recovery-probe.mjs +72 -0
- package/tools/ralph-external/lib/session-environment.mjs +28 -0
- package/tools/ralph-external/lib/systemd-client.mjs +49 -0
- package/tools/ralph-external/lib/worker-health.mjs +1 -1
- package/tools/ralph-external/lib/worker-isolation.mjs +717 -0
- package/tools/ralph-external/lib/worker-overflow.mjs +50 -0
- package/tools/ralph-external/process-monitor.mjs +1017 -0
- package/tools/ralph-external/session-launcher.mjs +5057 -0
- package/tools/scripts/resource-preflight.mjs +541 -0
- package/tools/skills/deploy-skills-codex.mjs +2 -1
- package/vscode-extension/schemas/aiwg.config.v1.json +1194 -231
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
/** Framework build projection. Kept separate so lookup processes import only relations.ts. */
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { createHash } from 'node:crypto';
|
|
5
|
+
import { INDEX_EXTRACTOR_VERSION } from './types.js';
|
|
6
|
+
import { recordTypeForEntry, stableRecordId } from './browser-export.js';
|
|
7
|
+
import { resolveRuleBindingTarget } from './query-engine.js';
|
|
8
|
+
import { Minimatch } from 'minimatch';
|
|
9
|
+
import { FRAMEWORK_RELATIONS_REVISION } from './framework-source-digest.js';
|
|
10
|
+
import { writeIndexFile } from './index-reader.js';
|
|
11
|
+
import { RELATIONS_SCHEMA, RELATIONS_VERSION, RULE_TIERS, emptyRuleStats, } from './relations.js';
|
|
12
|
+
const TARGET_TYPES = new Set(['skill', 'agent', 'flow', 'command']);
|
|
13
|
+
const BINDING_TYPES = { skills: 'skill', agents: 'agent', flows: 'flow' };
|
|
14
|
+
export function relationId(entry) {
|
|
15
|
+
return stableRecordId(recordTypeForEntry(entry, 'v2'), entry.path);
|
|
16
|
+
}
|
|
17
|
+
function slug(entry) {
|
|
18
|
+
const normalized = entry.path.replace(/\\/g, '/');
|
|
19
|
+
const file = path.posix.basename(normalized);
|
|
20
|
+
return /^(SKILL|AGENT|FLOW|COMMAND|RULE|BEHAVIOR)\.md$/i.test(file)
|
|
21
|
+
? path.posix.basename(path.posix.dirname(normalized)) : file.replace(/\.[^.]+$/, '');
|
|
22
|
+
}
|
|
23
|
+
/** Same source bundle boundary as the framework graph (nested extensions retain their owner). */
|
|
24
|
+
function owner(entry) {
|
|
25
|
+
const match = entry.path.replace(/\\/g, '/').match(/(?:^|\/)agentic\/code\/(frameworks|addons|extensions)\/([^/]+)\//);
|
|
26
|
+
if (!match)
|
|
27
|
+
return null; // Top-level behaviors are unowned, not fabricated bundles.
|
|
28
|
+
const kind = { frameworks: 'framework', addons: 'addon', extensions: 'extension' }[match[1]];
|
|
29
|
+
return { id: `${kind}:${match[2]}`, kind };
|
|
30
|
+
}
|
|
31
|
+
/** Only rule/action sources affect this projection; no full metadata serialization or file rereads. */
|
|
32
|
+
export function relationsFingerprint(entries) {
|
|
33
|
+
const sources = entries.filter(entry => TARGET_TYPES.has(entry.type) || ['rule', 'behavior'].includes(entry.type))
|
|
34
|
+
.map(entry => [entry.path, entry.checksum]).sort((a, b) => a[0].localeCompare(b[0]));
|
|
35
|
+
return { version: RELATIONS_VERSION, sources: `sha256:${createHash('sha256').update(JSON.stringify({ projectionVersion: FRAMEWORK_RELATIONS_REVISION, extractorVersion: INDEX_EXTRACTOR_VERSION, sources })).digest('hex')}` };
|
|
36
|
+
}
|
|
37
|
+
function statsFor(ids, index) {
|
|
38
|
+
const stats = emptyRuleStats();
|
|
39
|
+
for (const id of ids) {
|
|
40
|
+
const rule = index.rules[id];
|
|
41
|
+
const enforcement = rule.enforcement ?? 'unknown';
|
|
42
|
+
const activation = rule.activation ?? 'unknown';
|
|
43
|
+
stats.by_enforcement[enforcement] = (stats.by_enforcement[enforcement] ?? 0) + 1;
|
|
44
|
+
stats.by_activation[activation] = (stats.by_activation[activation] ?? 0) + 1;
|
|
45
|
+
if (enforcement === 'critical' || enforcement === 'high')
|
|
46
|
+
stats.required_checks++;
|
|
47
|
+
}
|
|
48
|
+
return stats;
|
|
49
|
+
}
|
|
50
|
+
export function buildRelations(entries) {
|
|
51
|
+
const index = {
|
|
52
|
+
$schema: RELATIONS_SCHEMA, version: RELATIONS_VERSION, generatedAt: '1970-01-01T00:00:00.000Z',
|
|
53
|
+
fingerprint: relationsFingerprint(entries), artifacts: {}, rules: {}, targets: {}, capabilities: {}, aliases: { targets: {}, rules: {} },
|
|
54
|
+
};
|
|
55
|
+
for (const entry of [...entries].sort((a, b) => a.path.localeCompare(b.path))) {
|
|
56
|
+
if (!TARGET_TYPES.has(entry.type) && !['rule', 'behavior'].includes(entry.type))
|
|
57
|
+
continue;
|
|
58
|
+
const { path: sourcePath, type, name, title, kernel, script, governedPaths } = entry;
|
|
59
|
+
index.artifacts[relationId(entry)] = { path: sourcePath, type, title, ...(name ? { name } : {}), ...(kernel ? { kernel } : {}), ...(script ? { script } : {}), ...(governedPaths ? { governedPaths } : {}) };
|
|
60
|
+
}
|
|
61
|
+
const rules = entries.filter(entry => entry.type === 'rule' || entry.type === 'behavior')
|
|
62
|
+
.sort((a, b) => (a.name ?? a.path).localeCompare(b.name ?? b.path) || a.path.localeCompare(b.path));
|
|
63
|
+
const targets = entries.filter(entry => TARGET_TYPES.has(entry.type)).sort((a, b) => a.path.localeCompare(b.path));
|
|
64
|
+
for (const rule of rules) {
|
|
65
|
+
const id = relationId(rule);
|
|
66
|
+
const capability = owner(rule);
|
|
67
|
+
index.rules[id] = {
|
|
68
|
+
name: rule.name ?? slug(rule), path: rule.path, type: rule.type,
|
|
69
|
+
activation: rule.activation ?? null, enforcement: rule.ruleEnforcement ?? null,
|
|
70
|
+
summary: rule.ruleSummary ?? '', capability: capability?.id ?? null,
|
|
71
|
+
...(rule.rulePaths ? { paths: rule.rulePaths } : {}),
|
|
72
|
+
...(rule.triggers?.length ? { triggers: rule.triggers } : {}),
|
|
73
|
+
...(rule.bound_to ? { bound_to: rule.bound_to } : {}), targets: [],
|
|
74
|
+
};
|
|
75
|
+
for (const alias of new Set([rule.name, slug(rule), rule.path].filter((value) => !!value))) {
|
|
76
|
+
(index.aliases.rules[alias] ??= []).push(id);
|
|
77
|
+
}
|
|
78
|
+
if (capability) {
|
|
79
|
+
const owned = index.capabilities[capability.id] ??= {
|
|
80
|
+
kind: capability.kind, rules_by_tier: { critical: [], high: [], medium: [], low: [] },
|
|
81
|
+
};
|
|
82
|
+
const tier = RULE_TIERS.find(tier => tier === rule.ruleEnforcement);
|
|
83
|
+
if (tier)
|
|
84
|
+
owned.rules_by_tier[tier].push(id);
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
const compiled = rules.map(rule => ({ rule, bindings: Object.fromEntries(Object.entries(rule.bound_to ?? {}).map(([key, patterns]) => [key, patterns.map(pattern => ({ pattern, matcher: new Minimatch(pattern, { nonegate: true, nocomment: true }) }))])) }));
|
|
88
|
+
const aliases = new Map();
|
|
89
|
+
for (const target of targets)
|
|
90
|
+
for (const alias of new Set([target.name, slug(target), relationId(target)].filter((value) => !!value))) {
|
|
91
|
+
const key = `${target.type}:${alias}`;
|
|
92
|
+
const group = aliases.get(key) ?? { type: target.type, alias, entries: [] };
|
|
93
|
+
group.entries.push(target);
|
|
94
|
+
aliases.set(key, group);
|
|
95
|
+
}
|
|
96
|
+
for (const target of targets) {
|
|
97
|
+
const key = `${target.type}:${relationId(target)}`;
|
|
98
|
+
// Preserve show's tolerant alias/glob matching, including behavior contracts.
|
|
99
|
+
const normalized = target.path.replace(/\\/g, '/');
|
|
100
|
+
const file = path.posix.basename(normalized);
|
|
101
|
+
const showAliases = [target.name, target.title, target.path, relationId(target),
|
|
102
|
+
file === 'SKILL.md' ? path.posix.basename(path.posix.dirname(normalized)) : file.replace(/\.[^.]+$/, '')]
|
|
103
|
+
.filter((value) => !!value);
|
|
104
|
+
const binding = Object.entries(BINDING_TYPES).find(([, type]) => type === target.type)?.[0];
|
|
105
|
+
const bound = binding ? compiled.filter(({ bindings }) => bindings[binding]?.some(({ pattern, matcher }) => showAliases.some(alias => alias === pattern || matcher.match(alias)))).map(({ rule }) => relationId(rule)) : [];
|
|
106
|
+
index.targets[key] = { name: target.name ?? slug(target), path: target.path,
|
|
107
|
+
rules: bound, rule_stats: emptyRuleStats() };
|
|
108
|
+
}
|
|
109
|
+
// Forward edges deliberately use deploy's strict canonical-ID resolver. Do not
|
|
110
|
+
// turn stale/misspelled/ambiguous bindings into silently missing contracts.
|
|
111
|
+
const resolved = new Map();
|
|
112
|
+
for (const rule of rules) {
|
|
113
|
+
const edges = new Map();
|
|
114
|
+
for (const [binding, type] of Object.entries(BINDING_TYPES)) {
|
|
115
|
+
for (const alias of rule.bound_to?.[binding] ?? []) {
|
|
116
|
+
const key = `${type}:${alias}`;
|
|
117
|
+
let target = resolved.get(key);
|
|
118
|
+
if (!target) {
|
|
119
|
+
target = resolveRuleBindingTarget(aliases.get(key)?.entries ?? [], type, alias);
|
|
120
|
+
resolved.set(key, target);
|
|
121
|
+
}
|
|
122
|
+
const id = relationId(target);
|
|
123
|
+
edges.set(`${type}:${id}`, { type, id });
|
|
124
|
+
if (type === 'flow') {
|
|
125
|
+
// A provider may wrap this flow as a skill, or share an authored skill's
|
|
126
|
+
// body. Keep a distinct projection identity so show parity is preserved.
|
|
127
|
+
const projectedId = `projected:${id}`;
|
|
128
|
+
const projectedKey = `skill:${projectedId}`;
|
|
129
|
+
index.targets[projectedKey] ??= { ...index.targets[`flow:${id}`],
|
|
130
|
+
rules: [...index.targets[`flow:${id}`].rules], projected_from: { type: 'flow', id } };
|
|
131
|
+
edges.set(projectedKey, { type: 'skill', id: projectedId });
|
|
132
|
+
}
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
index.rules[relationId(rule)].targets = [...edges.values()].sort((a, b) => `${a.type}:${a.id}`.localeCompare(`${b.type}:${b.id}`));
|
|
136
|
+
}
|
|
137
|
+
// Resolve each accepted spelling once at build time, retaining ambiguities.
|
|
138
|
+
for (const [key, group] of aliases) {
|
|
139
|
+
let matches = group.entries;
|
|
140
|
+
if (group.type !== 'command') {
|
|
141
|
+
try {
|
|
142
|
+
matches = [resolveRuleBindingTarget(group.entries, group.type, group.alias)];
|
|
143
|
+
}
|
|
144
|
+
catch { /* Preserve all candidates for an explicit ambiguity diagnostic. */ }
|
|
145
|
+
}
|
|
146
|
+
index.aliases.targets[key] = matches.map(entry => `${entry.type}:${relationId(entry)}`);
|
|
147
|
+
}
|
|
148
|
+
for (const [key, target] of Object.entries(index.targets)) {
|
|
149
|
+
if (target.projected_from)
|
|
150
|
+
index.aliases.targets[`skill:projected:${target.name}`] = [key];
|
|
151
|
+
target.rule_stats = statsFor(target.rules, index);
|
|
152
|
+
}
|
|
153
|
+
return index;
|
|
154
|
+
}
|
|
155
|
+
export async function writeRelations(entries, cwd, indexDir, force = false) {
|
|
156
|
+
const values = Object.values(entries);
|
|
157
|
+
const fingerprint = relationsFingerprint(values);
|
|
158
|
+
try {
|
|
159
|
+
const existing = JSON.parse(fs.readFileSync(path.join(indexDir, 'relations.json'), 'utf8'));
|
|
160
|
+
if (!force && existing.version === RELATIONS_VERSION && existing.$schema === RELATIONS_SCHEMA
|
|
161
|
+
&& existing.fingerprint.version === fingerprint.version && existing.fingerprint.sources === fingerprint.sources
|
|
162
|
+
&& existing.artifacts && existing.rules && existing.targets && existing.capabilities && existing.aliases?.targets && existing.aliases.rules)
|
|
163
|
+
return;
|
|
164
|
+
}
|
|
165
|
+
catch { /* Missing, corrupt, and unsupported sidecars are regenerated. */ }
|
|
166
|
+
writeIndexFile(cwd, 'relations.json', buildRelations(values), indexDir);
|
|
167
|
+
}
|
|
168
|
+
//# sourceMappingURL=relations-builder.js.map
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
/** Small framework relationship reader. This module never reads metadata.json. */
|
|
2
|
+
import fs from 'node:fs';
|
|
3
|
+
import path from 'node:path';
|
|
4
|
+
import { getGraphIndexDir } from './types.js';
|
|
5
|
+
import { resolveFrameworkIndexRoot } from './framework-index-paths.js';
|
|
6
|
+
import { frameworkSourceDigest } from './framework-source-digest.js';
|
|
7
|
+
import { createHash } from 'node:crypto';
|
|
8
|
+
import { loadRulePinConfigs, resolveRulePins } from '../rules/pins.mjs';
|
|
9
|
+
export const RELATIONS_VERSION = 1;
|
|
10
|
+
export const RELATIONS_SCHEMA = 'https://aiwg.io/schemas/artifacts/relations.v1.schema.json';
|
|
11
|
+
export const RULE_TIERS = ['critical', 'high', 'medium', 'low'];
|
|
12
|
+
export function emptyRuleStats() {
|
|
13
|
+
return { by_enforcement: {}, by_activation: {}, required_checks: 0 };
|
|
14
|
+
}
|
|
15
|
+
function lookupAlias(aliases, id) {
|
|
16
|
+
const matches = aliases[id];
|
|
17
|
+
if (matches?.length > 1)
|
|
18
|
+
throw new Error(`Ambiguous relationship ID: ${id}: ${matches.join(', ')}`);
|
|
19
|
+
return matches?.[0];
|
|
20
|
+
}
|
|
21
|
+
export class RelationsReader {
|
|
22
|
+
index;
|
|
23
|
+
pinnedRuleIds;
|
|
24
|
+
constructor(index, pinnedRuleIds = new Set()) {
|
|
25
|
+
this.index = index;
|
|
26
|
+
this.pinnedRuleIds = pinnedRuleIds;
|
|
27
|
+
}
|
|
28
|
+
rulesForTarget(type, id) {
|
|
29
|
+
const key = `${type}:${id}`;
|
|
30
|
+
const resolved = Object.hasOwn(this.index.targets, key) ? key : lookupAlias(this.index.aliases.targets, key);
|
|
31
|
+
return [...(resolved ? this.index.targets[resolved]?.rules ?? [] : [])];
|
|
32
|
+
}
|
|
33
|
+
targetsForRule(id) {
|
|
34
|
+
const resolved = Object.hasOwn(this.index.rules, id) ? id : lookupAlias(this.index.aliases.rules, id);
|
|
35
|
+
return resolved ? (this.index.rules[resolved]?.targets ?? []).map(target => ({ ...target })) : [];
|
|
36
|
+
}
|
|
37
|
+
rulesForCapability(id, tiers = RULE_TIERS) {
|
|
38
|
+
const capability = this.index.capabilities[id];
|
|
39
|
+
return [...new Set(tiers.flatMap(tier => capability?.rules_by_tier[tier] ?? []))];
|
|
40
|
+
}
|
|
41
|
+
ruleStats(type, id) {
|
|
42
|
+
const key = `${type}:${id}`;
|
|
43
|
+
const resolved = Object.hasOwn(this.index.targets, key) ? key : lookupAlias(this.index.aliases.targets, key);
|
|
44
|
+
const stats = resolved ? this.index.targets[resolved]?.rule_stats : undefined;
|
|
45
|
+
if (!stats)
|
|
46
|
+
return emptyRuleStats();
|
|
47
|
+
const result = { by_enforcement: { ...stats.by_enforcement }, by_activation: { ...stats.by_activation }, required_checks: stats.required_checks };
|
|
48
|
+
for (const ruleId of this.index.targets[resolved].rules) {
|
|
49
|
+
if (!this.pinnedRuleIds.has(ruleId))
|
|
50
|
+
continue;
|
|
51
|
+
const activation = this.index.rules[ruleId]?.activation ?? 'unknown';
|
|
52
|
+
if (activation === 'kernel')
|
|
53
|
+
continue;
|
|
54
|
+
result.by_activation[activation] = Math.max(0, (result.by_activation[activation] ?? 0) - 1);
|
|
55
|
+
if (!result.by_activation[activation])
|
|
56
|
+
delete result.by_activation[activation];
|
|
57
|
+
result.by_activation.kernel = (result.by_activation.kernel ?? 0) + 1;
|
|
58
|
+
}
|
|
59
|
+
return result;
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
function readerWithPins(index, pinCwd) {
|
|
63
|
+
const pins = resolveRulePins({ configs: loadRulePinConfigs(pinCwd),
|
|
64
|
+
rules: Object.entries(index.rules).map(([id, rule]) => ({ ...rule, id })) });
|
|
65
|
+
return new RelationsReader(index, new Set(pins.rules.map(rule => rule.id)));
|
|
66
|
+
}
|
|
67
|
+
/** Missing, corrupt, or unsupported sidecars return null; invalid pin policy remains an explicit error. */
|
|
68
|
+
export function loadBuiltRelations(cwd, pinCwd = cwd) {
|
|
69
|
+
let index;
|
|
70
|
+
try {
|
|
71
|
+
index = JSON.parse(fs.readFileSync(path.join(getGraphIndexDir(cwd, 'framework'), 'relations.json'), 'utf8'));
|
|
72
|
+
if (index.version !== RELATIONS_VERSION || index.$schema !== RELATIONS_SCHEMA
|
|
73
|
+
|| index.fingerprint?.version !== RELATIONS_VERSION || !/^sha256:[a-f0-9]{64}$/.test(index.fingerprint.sources)
|
|
74
|
+
|| !index.rules || !index.targets || !index.capabilities || !index.aliases?.targets || !index.aliases.rules)
|
|
75
|
+
return null;
|
|
76
|
+
}
|
|
77
|
+
catch {
|
|
78
|
+
return null;
|
|
79
|
+
}
|
|
80
|
+
return readerWithPins(index, pinCwd);
|
|
81
|
+
}
|
|
82
|
+
export const PREBUILT_RELATIONS_DIR = 'prebuilt/framework-relations';
|
|
83
|
+
/** Validate the running root, never the root from which this module was loaded. */
|
|
84
|
+
function selectPrebuiltRelationsSource(cwd, cacheSourceDigest = true) {
|
|
85
|
+
const root = resolveFrameworkIndexRoot(cwd);
|
|
86
|
+
const dir = path.join(root, PREBUILT_RELATIONS_DIR);
|
|
87
|
+
try {
|
|
88
|
+
const stamp = JSON.parse(fs.readFileSync(path.join(dir, 'manifest.json'), 'utf8'));
|
|
89
|
+
const pkg = JSON.parse(fs.readFileSync(path.join(root, 'package.json'), 'utf8'));
|
|
90
|
+
if (stamp.schema_version !== 'aiwg.relationships.prebuilt.v1')
|
|
91
|
+
return { reader: null, reason: 'unsupported prebuilt relationship schema' };
|
|
92
|
+
if (stamp.package_version !== pkg.version)
|
|
93
|
+
return { reader: null, reason: 'prebuilt relationship package version differs' };
|
|
94
|
+
if (stamp.source_digest !== frameworkSourceDigest(root, cacheSourceDigest))
|
|
95
|
+
return { reader: null, reason: 'prebuilt relationship source digest differs (modified, added or removed corpus source)' };
|
|
96
|
+
const text = fs.readFileSync(path.join(dir, 'relations.json'), 'utf8');
|
|
97
|
+
if (createHash('sha256').update(text).digest('hex') !== stamp.checksums['relations.json'])
|
|
98
|
+
return { reader: null, reason: 'prebuilt relationship checksum differs' };
|
|
99
|
+
const bindings = fs.readFileSync(path.join(dir, 'bindings.json'), 'utf8');
|
|
100
|
+
if (createHash('sha256').update(bindings).digest('hex') !== stamp.checksums['bindings.json'])
|
|
101
|
+
return { reader: null, reason: 'prebuilt binding checksum differs' };
|
|
102
|
+
const index = JSON.parse(text);
|
|
103
|
+
if (index.version !== RELATIONS_VERSION || index.$schema !== RELATIONS_SCHEMA || !index.artifacts
|
|
104
|
+
|| index.fingerprint?.version !== RELATIONS_VERSION || !/^sha256:[a-f0-9]{64}$/.test(index.fingerprint.sources)
|
|
105
|
+
|| !index.rules || !index.targets || !index.capabilities || !index.aliases?.targets || !index.aliases.rules)
|
|
106
|
+
return { reader: null, reason: 'unsupported prebuilt relationship table' };
|
|
107
|
+
return { reader: new RelationsReader(index) };
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return { reader: null, reason: 'prebuilt relationship tables unavailable or corrupt' };
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
/** Apply local pins only after cache validation so policy errors cannot masquerade as cache misses. */
|
|
114
|
+
export function selectPrebuiltRelations(cwd, pinCwd = cwd, cacheSourceDigest = true) {
|
|
115
|
+
const selected = selectPrebuiltRelationsSource(cwd, cacheSourceDigest);
|
|
116
|
+
return selected.reader ? { reader: readerWithPins(selected.reader.index, pinCwd) } : selected;
|
|
117
|
+
}
|
|
118
|
+
/** Synchronous read API: prebuilt first, then this root's built sidecar. */
|
|
119
|
+
export function loadRelations(cwd, pinCwd = cwd, cacheSourceDigest = true) {
|
|
120
|
+
return selectPrebuiltRelations(cwd, pinCwd, cacheSourceDigest).reader ?? loadBuiltRelations(cwd, pinCwd);
|
|
121
|
+
}
|
|
122
|
+
/** Read paths reconcile through the existing lock/receipt when prebuilt is stale. */
|
|
123
|
+
export async function ensureRelations(cwd, pinCwd = cwd) {
|
|
124
|
+
const selected = selectPrebuiltRelations(cwd, pinCwd);
|
|
125
|
+
if (selected.reader)
|
|
126
|
+
return selected.reader;
|
|
127
|
+
const root = resolveFrameworkIndexRoot(cwd);
|
|
128
|
+
if (fs.existsSync(path.join(root, PREBUILT_RELATIONS_DIR, 'manifest.json'))) {
|
|
129
|
+
console.error(`Relationship tables: ${selected.reason}; using the per-root index (rebuilding if stale).`);
|
|
130
|
+
}
|
|
131
|
+
const { refreshFrameworkCapabilities } = await import('./framework-capabilities.js');
|
|
132
|
+
await refreshFrameworkCapabilities(root, false);
|
|
133
|
+
return loadBuiltRelations(cwd, pinCwd);
|
|
134
|
+
}
|
|
135
|
+
// Convenience entry points; use one loaded reader for a batch of lookups.
|
|
136
|
+
export function rulesForTarget(type, id, cwd = process.cwd()) {
|
|
137
|
+
return loadRelations(cwd)?.rulesForTarget(type, id) ?? [];
|
|
138
|
+
}
|
|
139
|
+
export function targetsForRule(id, cwd = process.cwd()) {
|
|
140
|
+
return loadRelations(cwd)?.targetsForRule(id) ?? [];
|
|
141
|
+
}
|
|
142
|
+
export function rulesForCapability(id, tiers, cwd = process.cwd()) {
|
|
143
|
+
return loadRelations(cwd)?.rulesForCapability(id, tiers) ?? [];
|
|
144
|
+
}
|
|
145
|
+
export function ruleStats(type, id, cwd = process.cwd()) {
|
|
146
|
+
return loadRelations(cwd)?.ruleStats(type, id) ?? emptyRuleStats();
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=relations.js.map
|
|
@@ -7,6 +7,7 @@
|
|
|
7
7
|
* @source @src/artifacts/types.ts
|
|
8
8
|
* @tests @test/unit/artifacts/stats.test.ts
|
|
9
9
|
*/
|
|
10
|
+
import { loadPrebuiltDeploymentIndex } from './prebuilt-deployment.js';
|
|
10
11
|
import { GRAPH_CONFIGS, loadGlobalGraphConfigs, loadUserGraphConfigs, resolveGraphBackendType } from './types.js';
|
|
11
12
|
import { loadIndexStats, loadGraphIndexFile } from './index-reader.js';
|
|
12
13
|
import { collectGraphIndexFiles, indexPathFor } from './index-files.js';
|
|
@@ -34,7 +35,8 @@ export async function showStats(cwd, options = {}) {
|
|
|
34
35
|
loadGlobalGraphConfigs();
|
|
35
36
|
if (graph) {
|
|
36
37
|
// Single graph mode
|
|
37
|
-
const stats =
|
|
38
|
+
const stats = (graph === 'framework' ? loadPrebuiltDeploymentIndex(cwd)?.stats : undefined)
|
|
39
|
+
?? loadGraphIndexFile(cwd, 'stats.json', graph);
|
|
38
40
|
if (!stats) {
|
|
39
41
|
console.error(`Error: No artifact index found for graph '${graph}'.`);
|
|
40
42
|
console.log("Run 'aiwg index build' first to create the index.");
|
|
@@ -49,7 +51,8 @@ export async function showStats(cwd, options = {}) {
|
|
|
49
51
|
.map(([name]) => name);
|
|
50
52
|
const availableGraphs = [];
|
|
51
53
|
for (const g of graphTypes) {
|
|
52
|
-
const s =
|
|
54
|
+
const s = (g === 'framework' ? loadPrebuiltDeploymentIndex(cwd)?.stats : undefined)
|
|
55
|
+
?? loadGraphIndexFile(cwd, 'stats.json', g);
|
|
53
56
|
if (s)
|
|
54
57
|
availableGraphs.push({ type: g, stats: s });
|
|
55
58
|
}
|
|
@@ -9,8 +9,10 @@
|
|
|
9
9
|
* @tests @test/unit/artifacts/index-builder.test.ts
|
|
10
10
|
*/
|
|
11
11
|
import fs from 'fs';
|
|
12
|
+
import { validateIndexGraphOverrides } from '../config/index-graph-overrides.js';
|
|
12
13
|
import os from 'node:os';
|
|
13
14
|
import path from 'node:path';
|
|
15
|
+
import { getFrameworkIndexBaseDir } from './framework-index-paths.js';
|
|
14
16
|
import { load as loadYaml } from 'js-yaml';
|
|
15
17
|
import { DEFAULT_PROJECT_AIWG_DIR, projectAiwgPath, projectControlPath, resolveProjectAiwgDir, } from '../config/project-artifacts.js';
|
|
16
18
|
/**
|
|
@@ -108,7 +110,7 @@ export const INDEX_VERSION = '1.0.0';
|
|
|
108
110
|
* making the serialized index schema incompatible; a mismatch simply forces a
|
|
109
111
|
* one-time content re-extraction during the next incremental build.
|
|
110
112
|
*/
|
|
111
|
-
export const INDEX_EXTRACTOR_VERSION = '2026.
|
|
113
|
+
export const INDEX_EXTRACTOR_VERSION = '2026.10.19.1';
|
|
112
114
|
/**
|
|
113
115
|
* Built-in graph definitions
|
|
114
116
|
*/
|
|
@@ -463,10 +465,11 @@ export function loadModuleGraphConfigs(cwd, diagnostics) {
|
|
|
463
465
|
* @implements #426 #726
|
|
464
466
|
*/
|
|
465
467
|
export function loadUserGraphConfigs(cwd, diagnostics) {
|
|
466
|
-
// Built-ins are immutable in index.graphs, but codebase
|
|
468
|
+
// Built-ins are immutable in index.graphs, but project/codebase scan fields may
|
|
467
469
|
// be adapted through the explicitly bounded graphOverrides contract (#2123).
|
|
468
470
|
// Reset on every project load so a prior cwd cannot leak its override or
|
|
469
471
|
// detected Python package roots into a later build in the same process.
|
|
472
|
+
GRAPH_CONFIGS.project = freshBuiltinGraphConfig('project');
|
|
470
473
|
GRAPH_CONFIGS.codebase = detectPythonCodebaseConfig(cwd, freshBuiltinGraphConfig('codebase'));
|
|
471
474
|
projectGraphBackend = undefined;
|
|
472
475
|
// Load module-declared graphs first (frameworks/addons)
|
|
@@ -493,8 +496,7 @@ export function loadUserGraphConfigs(cwd, diagnostics) {
|
|
|
493
496
|
if (g && typeof g === 'object')
|
|
494
497
|
graphs = g;
|
|
495
498
|
const overrides = idx?.graphOverrides;
|
|
496
|
-
|
|
497
|
-
graphOverrides = overrides;
|
|
499
|
+
graphOverrides = overrides;
|
|
498
500
|
}
|
|
499
501
|
}
|
|
500
502
|
catch {
|
|
@@ -521,7 +523,7 @@ export function loadUserGraphConfigs(cwd, diagnostics) {
|
|
|
521
523
|
fromDeprecatedYaml = true;
|
|
522
524
|
}
|
|
523
525
|
const overrides = idx?.graphOverrides;
|
|
524
|
-
if (overrides
|
|
526
|
+
if (overrides !== undefined) {
|
|
525
527
|
graphOverrides = overrides;
|
|
526
528
|
fromDeprecatedYaml = true;
|
|
527
529
|
}
|
|
@@ -531,9 +533,22 @@ export function loadUserGraphConfigs(cwd, diagnostics) {
|
|
|
531
533
|
// best-effort
|
|
532
534
|
}
|
|
533
535
|
}
|
|
534
|
-
const
|
|
535
|
-
|
|
536
|
-
|
|
536
|
+
const warnOverride = (graph, reason) => {
|
|
537
|
+
if (diagnostics)
|
|
538
|
+
diagnostics.push({ graph, reason, source: 'operator-config' });
|
|
539
|
+
else
|
|
540
|
+
console.warn(`[aiwg index] Warning: ${reason}`);
|
|
541
|
+
};
|
|
542
|
+
const overrideErrors = validateIndexGraphOverrides(graphOverrides);
|
|
543
|
+
for (const reason of overrideErrors)
|
|
544
|
+
warnOverride('graphOverrides', reason);
|
|
545
|
+
if (graphOverrides && typeof graphOverrides === 'object' && !Array.isArray(graphOverrides)) {
|
|
546
|
+
for (const name of ['project', 'codebase']) {
|
|
547
|
+
const override = graphOverrides[name];
|
|
548
|
+
if (override === undefined || validateIndexGraphOverrides({ [name]: override }).length > 0)
|
|
549
|
+
continue;
|
|
550
|
+
GRAPH_CONFIGS[name] = applyBuiltinGraphOverride(GRAPH_CONFIGS[name], override);
|
|
551
|
+
}
|
|
537
552
|
}
|
|
538
553
|
if (!graphs)
|
|
539
554
|
return loaded;
|
|
@@ -543,7 +558,10 @@ export function loadUserGraphConfigs(cwd, diagnostics) {
|
|
|
543
558
|
}
|
|
544
559
|
for (const [name, def] of Object.entries(graphs)) {
|
|
545
560
|
if (name in BUILTIN_GRAPH_CONFIGS) {
|
|
546
|
-
|
|
561
|
+
warnOverride(name, `index.graphs.${name}: built-in graph definitions cannot be overridden here; ` +
|
|
562
|
+
(name === 'project' || name === 'codebase'
|
|
563
|
+
? `use index.graphOverrides.${name} (supported: scanDirs, extensions)`
|
|
564
|
+
: 'no built-in override is supported for this graph'));
|
|
547
565
|
continue;
|
|
548
566
|
}
|
|
549
567
|
const graphConfig = parseGraphDef(name, def);
|
|
@@ -662,8 +680,10 @@ let yamlIndexDeprecationWarned = false;
|
|
|
662
680
|
* @returns Absolute path to the graph's index directory
|
|
663
681
|
*/
|
|
664
682
|
export function getGraphIndexDir(cwd, graphType) {
|
|
683
|
+
if (graphType === 'framework')
|
|
684
|
+
return path.join(getFrameworkIndexBaseDir(cwd), graphType);
|
|
665
685
|
const config = GRAPH_CONFIGS[graphType];
|
|
666
|
-
if (
|
|
686
|
+
if (config?.shared) {
|
|
667
687
|
// Shared across projects — XDG data directory
|
|
668
688
|
const xdgData = process.env.XDG_DATA_HOME ?? path.join(os.homedir(), '.local', 'share');
|
|
669
689
|
return path.join(xdgData, 'aiwg', 'index', graphType);
|
|
@@ -38,7 +38,7 @@ export function getRunningPid(cwd) {
|
|
|
38
38
|
return null;
|
|
39
39
|
try {
|
|
40
40
|
const pid = parseInt(fs.readFileSync(pidFile, 'utf-8').trim(), 10);
|
|
41
|
-
if (!Number.
|
|
41
|
+
if (!Number.isSafeInteger(pid) || pid <= 0)
|
|
42
42
|
return null;
|
|
43
43
|
// Check if the process is still alive
|
|
44
44
|
try {
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { signalChild } from '../process/signal-child.mjs';
|
|
1
2
|
import { spawn } from "node:child_process";
|
|
2
3
|
import fs from "node:fs/promises";
|
|
3
4
|
import os from "node:os";
|
|
@@ -10,7 +11,7 @@ export const defaultCommandRunner = (command, args, stdin = "") => new Promise((
|
|
|
10
11
|
const collect = (target, chunk) => {
|
|
11
12
|
outputBytes += chunk.length;
|
|
12
13
|
if (outputBytes > 1024 * 1024)
|
|
13
|
-
child
|
|
14
|
+
signalChild(child);
|
|
14
15
|
else
|
|
15
16
|
target.push(chunk);
|
|
16
17
|
};
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
export function printCatalogHelp(): void;
|
|
2
|
+
export function handleCatalogList(args: string[]): Promise<void>;
|
|
3
|
+
export function handleCatalogInfo(args: string[]): Promise<void>;
|
|
4
|
+
export function handleCatalogSearch(args: string[]): Promise<void>;
|
|
5
|
+
export function main(args: string[]): Promise<void>;
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export function getPackageRoot(): string;
|
|
2
|
+
export function resolveEffectiveInstallationRoot(
|
|
3
|
+
packageRoot: string,
|
|
4
|
+
config: { devMode?: boolean; edgePath?: string } | null | undefined,
|
|
5
|
+
): string;
|
|
6
|
+
export function resolveMcpServerEntrypointPath(
|
|
7
|
+
packageRoot: string,
|
|
8
|
+
config: { devMode?: boolean; edgePath?: string } | null | undefined,
|
|
9
|
+
): string;
|
|
10
|
+
export function loadConfig(options?: Record<string, unknown>): Promise<any>;
|
|
11
|
+
export function saveConfig(config: any, options?: Record<string, unknown>): Promise<void>;
|
|
12
|
+
export function getChannel(): Promise<string>;
|
|
13
|
+
export function getFrameworkRoot(options?: Record<string, unknown>): Promise<string>;
|
|
14
|
+
export function switchToEdge(): Promise<void>;
|
|
15
|
+
export function switchToStable(): Promise<void>;
|
|
16
|
+
export function switchToDev(devPath: string): Promise<void>;
|
|
17
|
+
export function switchToNext(): Promise<void>;
|
|
18
|
+
export function switchToNightly(): Promise<void>;
|
|
19
|
+
export function getVersionInfo(): Promise<any>;
|
|
20
|
+
export function updateEdge(): Promise<void>;
|
|
@@ -9,6 +9,7 @@
|
|
|
9
9
|
* @version 2024.12.0
|
|
10
10
|
*/
|
|
11
11
|
|
|
12
|
+
import { signalChild } from '../process/signal-child.mjs';
|
|
12
13
|
import fs from 'fs/promises';
|
|
13
14
|
import { readFileSync, existsSync } from 'fs';
|
|
14
15
|
import path from 'path';
|
|
@@ -53,9 +54,9 @@ async function runWithTimeout(cmd, args, options = {}) {
|
|
|
53
54
|
let settled = false;
|
|
54
55
|
const timer = setTimeout(() => {
|
|
55
56
|
if (settled) return;
|
|
56
|
-
try { child
|
|
57
|
+
try { signalChild(child, 'SIGTERM'); } catch { /* already exited */ }
|
|
57
58
|
const kill9 = setTimeout(() => {
|
|
58
|
-
try { child
|
|
59
|
+
try { signalChild(child, 'SIGKILL'); } catch { /* already exited */ }
|
|
59
60
|
}, 5_000);
|
|
60
61
|
kill9.unref?.();
|
|
61
62
|
settled = true;
|
|
@@ -540,6 +541,19 @@ export async function getVersionInfo() {
|
|
|
540
541
|
const packageJsonPath = path.join(packageRoot, 'package.json');
|
|
541
542
|
const packageJson = JSON.parse(await fs.readFile(packageJsonPath, 'utf8'));
|
|
542
543
|
|
|
544
|
+
const launcherRoot = process.env.AIWG_LAUNCHER_ROOT || packageRoot;
|
|
545
|
+
const runtimePath = resolveEffectiveInstallationRoot(launcherRoot, config);
|
|
546
|
+
const readVersion = async (root) => {
|
|
547
|
+
try {
|
|
548
|
+
const pkg = JSON.parse(await fs.readFile(path.join(root, 'package.json'), 'utf8'));
|
|
549
|
+
return typeof pkg.version === 'string' ? pkg.version : '(unknown)';
|
|
550
|
+
} catch {
|
|
551
|
+
return '(unknown)';
|
|
552
|
+
}
|
|
553
|
+
};
|
|
554
|
+
const launcherVersion = await readVersion(launcherRoot);
|
|
555
|
+
const runtimeVersion = await readVersion(runtimePath);
|
|
556
|
+
|
|
543
557
|
// Detect pre-release channel from version string when channel.json says 'stable'
|
|
544
558
|
// This handles the case where a user ran `npm install -g aiwg@next` directly —
|
|
545
559
|
// npm updates the binary but channel.json stays as 'stable'.
|
|
@@ -559,6 +573,9 @@ export async function getVersionInfo() {
|
|
|
559
573
|
|
|
560
574
|
const info = {
|
|
561
575
|
version,
|
|
576
|
+
launcherVersion,
|
|
577
|
+
runtimeVersion,
|
|
578
|
+
runtimePath,
|
|
562
579
|
channel,
|
|
563
580
|
packageRoot,
|
|
564
581
|
installation,
|
|
@@ -2,7 +2,7 @@ import { mkdir, readFile, rename, stat, writeFile, appendFile } from 'fs/promise
|
|
|
2
2
|
import { existsSync } from 'fs';
|
|
3
3
|
import { createHash } from 'crypto';
|
|
4
4
|
import path from 'path';
|
|
5
|
-
import
|
|
5
|
+
import { getUserStateDir } from '../config/user-state.js';
|
|
6
6
|
import { readAiwgConfig } from '../config/aiwg-config.js';
|
|
7
7
|
import { PROJECT_AIWG_LOCATION_FILE, projectAiwgPath, projectControlPath, } from '../config/project-artifacts.js';
|
|
8
8
|
const DEFAULT_MAX_BYTES = 1_048_576;
|
|
@@ -170,8 +170,7 @@ function resolveLogPath(scope, projectRoot, env) {
|
|
|
170
170
|
return null;
|
|
171
171
|
return projectAiwgPath(projectRoot, 'telemetry', 'cli-commands.jsonl');
|
|
172
172
|
}
|
|
173
|
-
|
|
174
|
-
return path.join(stateHome, 'aiwg', 'cli-commands.jsonl');
|
|
173
|
+
return path.join(getUserStateDir(env), 'cli-commands.jsonl');
|
|
175
174
|
}
|
|
176
175
|
async function appendBoundedJsonl(filePath, event, maxBytes) {
|
|
177
176
|
await mkdir(path.dirname(filePath), { recursive: true });
|
|
@@ -32,6 +32,9 @@ export const artifactsHandler = {
|
|
|
32
32
|
description: 'Move or inspect the configured project AIWG artifact root',
|
|
33
33
|
category: 'index',
|
|
34
34
|
aliases: ['artifact'],
|
|
35
|
+
async help() {
|
|
36
|
+
return { exitCode: 0, message: usage(), rawOutput: true };
|
|
37
|
+
},
|
|
35
38
|
async execute(ctx) {
|
|
36
39
|
const action = ctx.args.find(arg => !arg.startsWith('-')) ?? 'help';
|
|
37
40
|
if (action === 'help' || ctx.args.includes('--help') || ctx.args.includes('-h')) {
|
|
@@ -37,6 +37,9 @@ export function createAuthHandler(dependencies = {}) {
|
|
|
37
37
|
description: "Log in, inspect access, and log out of paid AIWG web resources",
|
|
38
38
|
category: "maintenance",
|
|
39
39
|
aliases: [],
|
|
40
|
+
async help() {
|
|
41
|
+
return { exitCode: 0, message: usage(), rawOutput: true };
|
|
42
|
+
},
|
|
40
43
|
async execute(ctx) {
|
|
41
44
|
if (!ctx.args.length || ["help", "--help", "-h"].includes(ctx.args[0])) {
|
|
42
45
|
console.log(usage());
|