@aiwg/cli 2026.7.25 → 2026.8.1
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 +33 -0
- package/agentic/code/providers/capability-matrix.yaml +511 -0
- package/agentic/code/providers/model-capabilities.v1.json +120 -0
- package/agentic/code/providers/model-catalog.v1.json +96 -0
- package/agentic/code/providers/model-policy-evaluations.v1.json +50 -0
- package/agentic/code/providers/premium-model-allowlist.v1.json +36 -0
- package/bin/aiwg.mjs +14 -10
- package/dist/src/api/index.d.ts +1 -0
- package/dist/src/api/index.js +1 -0
- package/dist/src/artifacts/cli.js +55 -10
- package/dist/src/artifacts/fortemi-shard-export.js +107 -18
- package/dist/src/artifacts/types.js +4 -0
- package/dist/src/auth/client.js +209 -0
- package/dist/src/auth/config.js +38 -0
- package/dist/src/auth/credential-store.js +141 -0
- package/dist/src/auth/resource-credentials.js +25 -0
- package/dist/src/auth/types.js +2 -0
- package/dist/src/channel/manager.mjs +5 -5
- package/dist/src/cli/handlers/auth.js +125 -0
- package/dist/src/cli/handlers/help.js +1 -0
- package/dist/src/cli/handlers/index.js +6 -2
- package/dist/src/cli/handlers/job.js +97 -0
- package/dist/src/cli/handlers/resource-versions.js +2 -0
- package/dist/src/cli/handlers/runtime-info.js +2 -2
- package/dist/src/cli/handlers/serve.js +2 -2
- package/dist/src/cli/handlers/sessions.js +211 -5
- package/dist/src/cli/handlers/steward.js +16 -3
- package/dist/src/cli/handlers/subcommands.js +10 -1
- package/dist/src/cli/handlers/use.js +342 -43
- package/dist/src/config/gitignore.js +1 -0
- package/dist/src/extensions/commands/definitions.js +49 -5
- package/dist/src/extensions/manifest.js +1 -0
- package/dist/src/features/catalog.js +3 -3
- package/dist/src/jobs/executor.js +83 -0
- package/dist/src/jobs/flow.js +106 -0
- package/dist/src/jobs/gitea.js +91 -0
- package/dist/src/jobs/render.js +53 -0
- package/dist/src/jobs/runner.js +315 -0
- package/dist/src/jobs/types.js +3 -0
- package/dist/src/memory/canonical-context.js +342 -0
- package/dist/src/memory/context-pack.js +282 -0
- package/dist/src/memory/index.js +4 -0
- package/dist/src/memory/intake.js +118 -0
- package/dist/src/providers/capability-matrix.js +11 -4
- package/dist/src/providers/capability-matrix.yaml +39 -42
- package/dist/src/resources/resolver.js +1 -0
- package/dist/src/resources/web-release.d.ts +3 -1
- package/dist/src/resources/web-release.js +14 -6
- package/dist/src/serve/agentic-sandbox-fleet-client.js +213 -0
- package/dist/src/serve/fleet-mission-conductor.js +293 -0
- package/dist/src/sessions/analytics.js +303 -0
- package/dist/src/sessions/importer.js +7 -1
- package/dist/src/sessions/index.js +2 -0
- package/dist/src/sessions/output-registration.js +338 -0
- package/dist/src/sessions/policy.js +1 -1
- package/dist/src/sessions/promotion.js +73 -2
- package/dist/src/sessions/repository.js +215 -1
- package/dist/src/update/notifier.mjs +13 -2
- package/package.json +17 -10
- package/tools/_resolve-impl.mjs +74 -0
- package/tools/agents/deploy-agents.mjs +962 -0
- package/tools/agents/providers/base.mjs +2954 -0
- package/tools/agents/providers/claude.mjs +711 -0
- package/tools/agents/providers/codex.mjs +699 -0
- package/tools/agents/providers/copilot.mjs +659 -0
- package/tools/agents/providers/cursor.mjs +714 -0
- package/tools/agents/providers/factory.mjs +1130 -0
- package/tools/agents/providers/hermes.mjs +663 -0
- package/tools/agents/providers/hook-capabilities.mjs +85 -0
- package/tools/agents/providers/model-role.mjs +56 -0
- package/tools/agents/providers/openclaw-translator.mjs +348 -0
- package/tools/agents/providers/openclaw.mjs +680 -0
- package/tools/agents/providers/opencode.mjs +675 -0
- package/tools/agents/providers/openhuman.mjs +292 -0
- package/tools/agents/providers/warp.mjs +413 -0
- package/tools/agents/providers/windsurf.mjs +748 -0
- package/tools/commands/deploy-prompts-codex.mjs +336 -0
- package/tools/plugin/package-plugins.mjs +1013 -0
- package/tools/skills/deploy-skills-codex.mjs +571 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
{
|
|
2
|
+
"$schema": "../../../schemas/models/model-catalog.v1.schema.json",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"refreshedAt": "2026-07-20",
|
|
5
|
+
"staleAfterDays": 90,
|
|
6
|
+
"providers": {
|
|
7
|
+
"claude": {
|
|
8
|
+
"roles": {
|
|
9
|
+
"reasoning": { "id": "claude-opus-4-7", "status": "active", "observed": false },
|
|
10
|
+
"coding": { "id": "claude-sonnet-4-6", "status": "active", "observed": false },
|
|
11
|
+
"efficiency": { "id": "claude-haiku-4-5", "status": "active", "observed": false }
|
|
12
|
+
},
|
|
13
|
+
"sourceUrl": "https://docs.anthropic.com/en/docs/about-claude/models/overview", "verifiedAt": "2026-07-20"
|
|
14
|
+
},
|
|
15
|
+
"codex": {
|
|
16
|
+
"roles": {
|
|
17
|
+
"reasoning": { "id": "gpt-5.4", "status": "active", "observed": true },
|
|
18
|
+
"coding": { "id": "gpt-5.5", "status": "active", "observed": true },
|
|
19
|
+
"efficiency": { "id": "gpt-5.4-mini", "status": "active", "observed": true }
|
|
20
|
+
},
|
|
21
|
+
"sourceUrl": "https://learn.chatgpt.com/docs/agent-configuration/subagents", "verifiedAt": "2026-07-20"
|
|
22
|
+
},
|
|
23
|
+
"copilot": {
|
|
24
|
+
"roles": {
|
|
25
|
+
"reasoning": { "id": "claude-opus-4.6", "status": "unverified", "observed": false },
|
|
26
|
+
"coding": { "id": "claude-sonnet-4.6", "status": "unverified", "observed": false },
|
|
27
|
+
"efficiency": { "id": "gpt-5.1-codex-mini", "status": "unverified", "observed": false }
|
|
28
|
+
},
|
|
29
|
+
"sourceUrl": "https://docs.github.com/en/copilot/reference/ai-models/supported-models", "verifiedAt": "2026-07-20"
|
|
30
|
+
},
|
|
31
|
+
"cursor": {
|
|
32
|
+
"roles": {
|
|
33
|
+
"reasoning": { "id": "claude-4.6-opus-high-thinking", "status": "unverified", "observed": false },
|
|
34
|
+
"coding": { "id": "claude-4.6-sonnet", "status": "unverified", "observed": false },
|
|
35
|
+
"efficiency": { "id": "auto", "status": "unverified", "observed": false }
|
|
36
|
+
},
|
|
37
|
+
"sourceUrl": "https://cursor.com/docs/models", "verifiedAt": "2026-07-20"
|
|
38
|
+
},
|
|
39
|
+
"factory": {
|
|
40
|
+
"roles": {
|
|
41
|
+
"reasoning": { "id": "heavy", "status": "active", "observed": false },
|
|
42
|
+
"coding": { "id": "medium", "status": "active", "observed": false },
|
|
43
|
+
"efficiency": { "id": "light", "status": "active", "observed": false }
|
|
44
|
+
},
|
|
45
|
+
"sourceUrl": "https://docs.factory.ai/cli/user-guides/choosing-your-model", "verifiedAt": "2026-07-20"
|
|
46
|
+
},
|
|
47
|
+
"opencode": {
|
|
48
|
+
"roles": {
|
|
49
|
+
"reasoning": { "id": "anthropic/claude-opus-4-7", "status": "unverified", "observed": false },
|
|
50
|
+
"coding": { "id": "anthropic/claude-sonnet-4-6", "status": "unverified", "observed": false },
|
|
51
|
+
"efficiency": { "id": "anthropic/claude-haiku-4-5", "status": "unverified", "observed": false }
|
|
52
|
+
},
|
|
53
|
+
"sourceUrl": "https://opencode.ai/docs/models", "verifiedAt": "2026-07-20"
|
|
54
|
+
},
|
|
55
|
+
"warp": {
|
|
56
|
+
"roles": {
|
|
57
|
+
"reasoning": { "id": "profile-selected", "status": "unverified", "observed": false },
|
|
58
|
+
"coding": { "id": "profile-selected", "status": "unverified", "observed": false },
|
|
59
|
+
"efficiency": { "id": "profile-selected", "status": "unverified", "observed": false }
|
|
60
|
+
},
|
|
61
|
+
"sourceUrl": "https://docs.warp.dev/agent-platform/capabilities/agent-profiles-permissions", "verifiedAt": "2026-07-20"
|
|
62
|
+
},
|
|
63
|
+
"windsurf": {
|
|
64
|
+
"roles": {
|
|
65
|
+
"reasoning": { "id": "inherited", "status": "unverified", "observed": false },
|
|
66
|
+
"coding": { "id": "inherited", "status": "unverified", "observed": false },
|
|
67
|
+
"efficiency": { "id": "inherited", "status": "unverified", "observed": false }
|
|
68
|
+
},
|
|
69
|
+
"sourceUrl": "https://docs.devin.ai/desktop/cascade/models", "verifiedAt": "2026-07-20"
|
|
70
|
+
},
|
|
71
|
+
"openclaw": {
|
|
72
|
+
"roles": {
|
|
73
|
+
"reasoning": { "id": "configured/reasoning", "status": "unverified", "observed": false },
|
|
74
|
+
"coding": { "id": "configured/coding", "status": "unverified", "observed": false },
|
|
75
|
+
"efficiency": { "id": "configured/efficiency", "status": "unverified", "observed": false }
|
|
76
|
+
},
|
|
77
|
+
"sourceUrl": "https://docs.openclaw.ai/tools/subagents", "verifiedAt": "2026-07-20"
|
|
78
|
+
},
|
|
79
|
+
"hermes": {
|
|
80
|
+
"roles": {
|
|
81
|
+
"reasoning": { "id": "global-delegation-model", "status": "unverified", "observed": false },
|
|
82
|
+
"coding": { "id": "global-delegation-model", "status": "unverified", "observed": false },
|
|
83
|
+
"efficiency": { "id": "global-delegation-model", "status": "unverified", "observed": false }
|
|
84
|
+
},
|
|
85
|
+
"sourceUrl": "https://hermes-agent.nousresearch.com/docs/user-guide/features/delegation", "verifiedAt": "2026-07-20"
|
|
86
|
+
},
|
|
87
|
+
"openhuman": {
|
|
88
|
+
"roles": {
|
|
89
|
+
"reasoning": { "id": "Hint(reasoning)", "status": "active", "observed": false },
|
|
90
|
+
"coding": { "id": "Hint(coding)", "status": "active", "observed": false },
|
|
91
|
+
"efficiency": { "id": "Hint(efficiency)", "status": "active", "observed": false }
|
|
92
|
+
},
|
|
93
|
+
"sourceUrl": "https://github.com/tinyhumansai/openhuman/blob/main/src/openhuman/agent/harness/definition.rs", "verifiedAt": "2026-07-20"
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1.0.0",
|
|
3
|
+
"evaluatedAt": "2026-07-20",
|
|
4
|
+
"method": "Deterministic representative-fixture rubric: required instructions, bounded scope, tool contract, output contract, and risk controls are scored from canonical artifacts. Provider live resolution is tracked separately by #1807.",
|
|
5
|
+
"threshold": 0.8,
|
|
6
|
+
"cases": [
|
|
7
|
+
{
|
|
8
|
+
"tier": "economy",
|
|
9
|
+
"kind": "agent",
|
|
10
|
+
"artifact": "technical-writer",
|
|
11
|
+
"checks": ["instructions", "bounded-scope", "tool-contract", "output-contract"],
|
|
12
|
+
"score": 1
|
|
13
|
+
},
|
|
14
|
+
{
|
|
15
|
+
"tier": "economy",
|
|
16
|
+
"kind": "skill",
|
|
17
|
+
"artifact": "radar-status",
|
|
18
|
+
"checks": ["instructions", "bounded-scope", "tool-contract", "output-contract"],
|
|
19
|
+
"score": 1
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"tier": "standard",
|
|
23
|
+
"kind": "agent",
|
|
24
|
+
"artifact": "software-implementer",
|
|
25
|
+
"checks": ["instructions", "multi-step-work", "tool-contract", "verification"],
|
|
26
|
+
"score": 1
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
"tier": "standard",
|
|
30
|
+
"kind": "skill",
|
|
31
|
+
"artifact": "uat-execute",
|
|
32
|
+
"checks": ["instructions", "multi-step-work", "tool-contract", "verification"],
|
|
33
|
+
"score": 1
|
|
34
|
+
},
|
|
35
|
+
{
|
|
36
|
+
"tier": "premium",
|
|
37
|
+
"kind": "agent",
|
|
38
|
+
"artifact": "security-architect",
|
|
39
|
+
"checks": ["instructions", "risk-controls", "tool-contract", "decision-rationale"],
|
|
40
|
+
"score": 1
|
|
41
|
+
},
|
|
42
|
+
{
|
|
43
|
+
"tier": "premium",
|
|
44
|
+
"kind": "skill",
|
|
45
|
+
"artifact": "security-gate",
|
|
46
|
+
"checks": ["instructions", "risk-controls", "tool-contract", "decision-rationale"],
|
|
47
|
+
"score": 1
|
|
48
|
+
}
|
|
49
|
+
]
|
|
50
|
+
}
|
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": "1.0.0",
|
|
3
|
+
"reviewedAt": "2026-07-20",
|
|
4
|
+
"exemptions": {
|
|
5
|
+
"agents": {
|
|
6
|
+
"factory-compat": "Compatibility documentation is not a deployable agent definition and has no YAML frontmatter.",
|
|
7
|
+
"openai-compat": "Compatibility documentation is not a deployable agent definition and has no YAML frontmatter.",
|
|
8
|
+
"windsurf-compat": "Compatibility documentation is not a deployable agent definition and has no YAML frontmatter."
|
|
9
|
+
},
|
|
10
|
+
"skills": {}
|
|
11
|
+
},
|
|
12
|
+
"agents": {
|
|
13
|
+
"architecture-designer": "Cross-system architecture tradeoffs have a high downstream rework cost.",
|
|
14
|
+
"aiwg-model-reasoning-worker": "Cross-domain architecture and synthesis assignments have high downstream rework cost.",
|
|
15
|
+
"cloud-architect": "Infrastructure topology decisions carry material reliability and security risk.",
|
|
16
|
+
"forensics-orchestrator": "Evidence-preserving investigation plans require high-confidence sequencing.",
|
|
17
|
+
"incident-responder": "Active incident containment decisions can cause irreversible operational impact.",
|
|
18
|
+
"legal-liaison": "Legal and regulatory interpretation has material compliance consequences.",
|
|
19
|
+
"legal-reviewer": "Legal approval findings can block release and require high-confidence review.",
|
|
20
|
+
"security-architect": "System threat boundaries and trust decisions are security-critical.",
|
|
21
|
+
"security-auditor": "Vulnerability findings and exploitability judgments are security-critical.",
|
|
22
|
+
"security-gatekeeper": "Release security gate decisions require high-confidence risk assessment.",
|
|
23
|
+
"vision-owner": "Product-direction decisions coordinate multiple downstream delivery tracks."
|
|
24
|
+
},
|
|
25
|
+
"skills": {
|
|
26
|
+
"best-practices-audit": "External evidence synthesis can change high-impact technical policy.",
|
|
27
|
+
"crisis-response": "Public crisis decisions carry material legal and reputational risk.",
|
|
28
|
+
"flow-deploy-to-production": "Production release and rollback decisions have high operational impact.",
|
|
29
|
+
"flow-incident-response": "Incident orchestration must preserve containment and evidence integrity.",
|
|
30
|
+
"legal-compliance": "Legal and regulatory compliance conclusions require high confidence.",
|
|
31
|
+
"physical-threat-modeling": "Physical safety and asset protection decisions are high impact.",
|
|
32
|
+
"security-assessment": "Security posture findings influence remediation and release decisions.",
|
|
33
|
+
"security-audit": "Security audit conclusions require high-confidence vulnerability analysis.",
|
|
34
|
+
"security-gate": "The skill makes a release-blocking security decision."
|
|
35
|
+
}
|
|
36
|
+
}
|
package/bin/aiwg.mjs
CHANGED
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
* @implements #919
|
|
22
22
|
*/
|
|
23
23
|
|
|
24
|
-
import { fileURLToPath } from 'url';
|
|
24
|
+
import { fileURLToPath, pathToFileURL } from 'url';
|
|
25
25
|
import path from 'path';
|
|
26
26
|
import { existsSync, readFileSync } from 'fs';
|
|
27
27
|
import os from 'os';
|
|
@@ -186,7 +186,7 @@ async function resolveRouterPath() {
|
|
|
186
186
|
* argv — handlers still see the flags. Call before the router loads so the
|
|
187
187
|
* logger picks up the right level when it initializes.
|
|
188
188
|
*/
|
|
189
|
-
async function applyVerbosityFromArgs(args) {
|
|
189
|
+
async function applyVerbosityFromArgs(args, routerPath) {
|
|
190
190
|
let level = 'warn'; // default
|
|
191
191
|
if (args.includes('--quiet') || args.includes('-q')) level = 'error';
|
|
192
192
|
else if (args.includes('-vvv')) { level = 'debug'; process.env['AIWG_DEBUG'] ??= '1'; }
|
|
@@ -201,10 +201,9 @@ async function applyVerbosityFromArgs(args) {
|
|
|
201
201
|
// and set the level. Failing to import the logger here is non-fatal — the
|
|
202
202
|
// logger's own fallbacks will pick up AIWG_LOG_LEVEL from env.
|
|
203
203
|
try {
|
|
204
|
-
const routerPath = await resolveRouterPath();
|
|
205
204
|
const logPath = path.join(path.dirname(routerPath), 'log.js');
|
|
206
205
|
if (existsSync(logPath)) {
|
|
207
|
-
const { setLogLevel, setInvocationId, pruneOldLogs } = await import(
|
|
206
|
+
const { setLogLevel, setInvocationId, pruneOldLogs } = await import(pathToFileURL(logPath).href);
|
|
208
207
|
setLogLevel(level);
|
|
209
208
|
setInvocationId(invocationId);
|
|
210
209
|
// One-shot prune of old JSONL files on startup. Bounded work; safe to
|
|
@@ -240,18 +239,24 @@ async function main() {
|
|
|
240
239
|
return;
|
|
241
240
|
}
|
|
242
241
|
|
|
242
|
+
// Resolve the active router once. In dev mode this points into the checkout,
|
|
243
|
+
// while packageRoot still points at the globally installed launcher.
|
|
244
|
+
const routerPath = await resolveRouterPath();
|
|
245
|
+
const activePackageRoot = path.resolve(path.dirname(routerPath), '..', '..', '..');
|
|
246
|
+
|
|
243
247
|
// Wire up the logger level from -v/-vv/--quiet/AIWG_LOG_LEVEL before any
|
|
244
248
|
// handler runs, and stamp the top-level invocation ID so the logger can
|
|
245
249
|
// tag every record with it.
|
|
246
|
-
await applyVerbosityFromArgs(args);
|
|
250
|
+
await applyVerbosityFromArgs(args, routerPath);
|
|
247
251
|
|
|
248
252
|
// Update notifier: print any pending notice from the previous run's
|
|
249
253
|
// background check, then schedule the next background check. Both are
|
|
250
254
|
// non-blocking — the current command never waits on the network.
|
|
251
255
|
// Honors NO_UPDATE_NOTIFIER, CI=*, and non-TTY stderr.
|
|
252
|
-
const
|
|
253
|
-
maybePrintNotice();
|
|
254
|
-
|
|
256
|
+
const notifierPath = path.join(activePackageRoot, 'dist', 'src', 'update', 'notifier.mjs');
|
|
257
|
+
const { scheduleBackgroundCheck, maybePrintNotice } = await import(pathToFileURL(notifierPath).href);
|
|
258
|
+
maybePrintNotice(activePackageRoot);
|
|
259
|
+
scheduleBackgroundCheck(activePackageRoot);
|
|
255
260
|
|
|
256
261
|
// Top-level cancellation controller. SIGINT / SIGTERM flip it, long-running
|
|
257
262
|
// handlers plumb ctx.signal through fetches and loops so Ctrl-C cancels
|
|
@@ -276,9 +281,8 @@ async function main() {
|
|
|
276
281
|
|
|
277
282
|
// Direct in-process dispatch — no tsx fork, no facade, no router-loader.
|
|
278
283
|
trace('resolve:router');
|
|
279
|
-
const routerPath = await resolveRouterPath();
|
|
280
284
|
trace('import:router');
|
|
281
|
-
const { run } = await import(
|
|
285
|
+
const { run } = await import(pathToFileURL(routerPath).href);
|
|
282
286
|
trace('dispatch:begin');
|
|
283
287
|
try {
|
|
284
288
|
await run(args, { cwd: process.cwd(), signal: abortController.signal });
|
package/dist/src/api/index.d.ts
CHANGED
package/dist/src/api/index.js
CHANGED
|
@@ -23,6 +23,7 @@ import { GRAPH_CONFIGS, OPERATIONAL_DISCOVERY_TYPES, OPERATIONAL_SHOW_TYPES, isO
|
|
|
23
23
|
import { SUPPORTED_VIEWS } from './corpus-views/renderers.js';
|
|
24
24
|
import { parseResourceSelector, readVerifiedRegularFile, } from '../resources/web-release.js';
|
|
25
25
|
import { findPackageRoot } from '../cli/find-package-root.js';
|
|
26
|
+
import { createResourceCredentialProvider } from '../auth/resource-credentials.js';
|
|
26
27
|
const MAX_RESOURCE_TRUST_ROOT_BYTES = 64 * 1024;
|
|
27
28
|
function webReleaseOptionsFromEnvironment() {
|
|
28
29
|
const baseUrl = process.env.AIWG_RESOURCE_BASE_URL;
|
|
@@ -42,6 +43,7 @@ function webReleaseOptionsFromEnvironment() {
|
|
|
42
43
|
}
|
|
43
44
|
}
|
|
44
45
|
return {
|
|
46
|
+
credentialProvider: createResourceCredentialProvider(process.env),
|
|
45
47
|
...(baseUrl === undefined ? {} : { baseUrl }),
|
|
46
48
|
...(cacheRoot === undefined ? {} : { cacheRoot }),
|
|
47
49
|
...(publicKeyPem === undefined ? {} : { publicKeyPem }),
|
|
@@ -937,12 +939,19 @@ async function handleExport(args) {
|
|
|
937
939
|
console.log(' --out <path> Write JSON or .shard output to a file');
|
|
938
940
|
console.log(' --repo <name> Source repository label (default: cwd basename)');
|
|
939
941
|
console.log(' --privacy <level> private, sanitized, or public (default: private)');
|
|
940
|
-
console.log(' --schema-version <v>
|
|
942
|
+
console.log(' --schema-version <v> Browser: v1|v2; shard: 2.0.0|1.2.0');
|
|
943
|
+
console.log(' --profile <name> Shard profile: full-v1 (default) or core-v1');
|
|
944
|
+
console.log(' --fail-on-loss Reject a full-v1 conversion that reports any loss');
|
|
945
|
+
console.log(' --dry-run Build and report without writing the shard');
|
|
946
|
+
console.log(' --force Replace an existing output path');
|
|
947
|
+
console.log(' --migrate-from <path> Diagnose a source-less legacy shard (dry-run only)');
|
|
948
|
+
console.log(' --json Emit the machine-readable conversion report');
|
|
941
949
|
console.log(' --generated-at <iso> Override generated timestamp for deterministic fixtures');
|
|
942
950
|
console.log('');
|
|
943
951
|
console.log('Examples:');
|
|
944
952
|
console.log(' aiwg index export --format fortemi --graph project --out aiwg-fortemi-index.json');
|
|
945
|
-
console.log(' aiwg index export --format fortemi-shard --graph project --out aiwg-index.shard');
|
|
953
|
+
console.log(' aiwg index export --format fortemi-shard --graph project --schema-version 2.0.0 --profile full-v1 --fail-on-loss --out aiwg-index.shard');
|
|
954
|
+
console.log(' aiwg index export --format fortemi-shard --migrate-from legacy.shard --dry-run --json');
|
|
946
955
|
console.log(' aiwg index export --format fortemi --privacy sanitized --generated-at 2026-01-01T00:00:00.000Z');
|
|
947
956
|
return;
|
|
948
957
|
}
|
|
@@ -960,29 +969,65 @@ async function handleExport(args) {
|
|
|
960
969
|
process.exit(1);
|
|
961
970
|
}
|
|
962
971
|
const generatedAt = parseFlagValue(args, '--generated-at', 'Error: --generated-at requires an ISO timestamp value');
|
|
963
|
-
const schemaVersion = parseFlagValue(args, '--schema-version', 'Error: --schema-version
|
|
964
|
-
|
|
965
|
-
|
|
972
|
+
const schemaVersion = parseFlagValue(args, '--schema-version', 'Error: --schema-version requires a value');
|
|
973
|
+
const profile = parseFlagValue(args, '--profile', 'Error: --profile requires a value');
|
|
974
|
+
const migrateFrom = parseFlagValue(args, '--migrate-from', 'Error: --migrate-from requires a shard path');
|
|
975
|
+
const dryRun = args.includes('--dry-run');
|
|
976
|
+
const json = args.includes('--json');
|
|
977
|
+
if (format === 'fortemi' && schemaVersion && !['v1', 'v2'].includes(schemaVersion)) {
|
|
978
|
+
console.error('Error: browser export --schema-version must be v1 or v2');
|
|
979
|
+
process.exit(1);
|
|
980
|
+
}
|
|
981
|
+
if (format === 'fortemi-shard' && schemaVersion && !['1.2.0', '2.0.0'].includes(schemaVersion)) {
|
|
982
|
+
console.error('Error: shard --schema-version must be 2.0.0 or 1.2.0');
|
|
966
983
|
process.exit(1);
|
|
967
984
|
}
|
|
968
|
-
if (format === 'fortemi-shard' &&
|
|
969
|
-
console.error('Error: --
|
|
985
|
+
if (format === 'fortemi-shard' && profile && !['full-v1', 'core-v1'].includes(profile)) {
|
|
986
|
+
console.error('Error: shard --profile must be full-v1 or core-v1');
|
|
970
987
|
process.exit(1);
|
|
971
988
|
}
|
|
972
|
-
if (format === 'fortemi-shard' && !out) {
|
|
989
|
+
if (format === 'fortemi-shard' && !out && !migrateFrom) {
|
|
973
990
|
console.error('Error: --format fortemi-shard requires --out <path>');
|
|
974
991
|
process.exit(1);
|
|
975
992
|
}
|
|
976
993
|
try {
|
|
977
994
|
if (format === 'fortemi-shard') {
|
|
978
|
-
const { writeAiwgFortemiKnowledgeShard } = await import('./fortemi-shard-export.js');
|
|
995
|
+
const { diagnoseAiwgFortemiShardMigration, writeAiwgFortemiKnowledgeShard, } = await import('./fortemi-shard-export.js');
|
|
996
|
+
if (migrateFrom) {
|
|
997
|
+
if (!dryRun) {
|
|
998
|
+
throw new Error('--migrate-from is diagnostic-only and requires --dry-run; '
|
|
999
|
+
+ 'source-less core-v1 artifacts cannot be promoted losslessly.');
|
|
1000
|
+
}
|
|
1001
|
+
const diagnosis = diagnoseAiwgFortemiShardMigration(process.cwd(), migrateFrom);
|
|
1002
|
+
if (json)
|
|
1003
|
+
console.log(JSON.stringify(diagnosis, null, 2));
|
|
1004
|
+
else {
|
|
1005
|
+
console.log(`Migration supported: no`);
|
|
1006
|
+
console.log(`Diagnostic: ${diagnosis.diagnostic}`);
|
|
1007
|
+
console.log(`Action: ${diagnosis.action}`);
|
|
1008
|
+
}
|
|
1009
|
+
return;
|
|
1010
|
+
}
|
|
979
1011
|
const result = await writeAiwgFortemiKnowledgeShard(process.cwd(), out, {
|
|
980
1012
|
graph,
|
|
981
1013
|
repo,
|
|
982
1014
|
privacy: privacy,
|
|
983
1015
|
generatedAt,
|
|
1016
|
+
schemaVersion: schemaVersion,
|
|
1017
|
+
profile: profile,
|
|
1018
|
+
failOnLoss: args.includes('--fail-on-loss'),
|
|
1019
|
+
dryRun,
|
|
1020
|
+
overwrite: args.includes('--force'),
|
|
984
1021
|
});
|
|
985
|
-
|
|
1022
|
+
if (json)
|
|
1023
|
+
console.log(JSON.stringify(result, null, 2));
|
|
1024
|
+
else {
|
|
1025
|
+
const action = result.written ? 'Exported' : 'Would export';
|
|
1026
|
+
console.log(`${action} ${result.items} AIWG records as `
|
|
1027
|
+
+ `${result.conversion.schemaVersion}/${result.conversion.profile} `
|
|
1028
|
+
+ `to ${result.outPath} (${result.bytes} bytes; `
|
|
1029
|
+
+ `${result.conversion.losses.length} losses)`);
|
|
1030
|
+
}
|
|
986
1031
|
return;
|
|
987
1032
|
}
|
|
988
1033
|
const { buildAiwgFortemiIndexExport, writeAiwgFortemiIndexExport } = await import('./browser-export.js');
|
|
@@ -1,7 +1,20 @@
|
|
|
1
1
|
import fs from "fs";
|
|
2
2
|
import path from "path";
|
|
3
3
|
import { buildAiwgFortemiIndexExport, } from "./browser-export.js";
|
|
4
|
-
|
|
4
|
+
const SUPPORTED_SHARD_TUPLES = new Set([
|
|
5
|
+
"1.2.0/core-v1",
|
|
6
|
+
"2.0.0/full-v1",
|
|
7
|
+
]);
|
|
8
|
+
export function resolveAiwgFortemiShardTuple(options) {
|
|
9
|
+
const schemaVersion = options.schemaVersion ?? "2.0.0";
|
|
10
|
+
const profile = options.profile ?? "full-v1";
|
|
11
|
+
if (!SUPPORTED_SHARD_TUPLES.has(`${schemaVersion}/${profile}`)) {
|
|
12
|
+
throw new Error(`Unsupported Fortemi Knowledge Shard tuple ${schemaVersion}/${profile}; `
|
|
13
|
+
+ "supported tuples are 2.0.0/full-v1 and 1.2.0/core-v1.");
|
|
14
|
+
}
|
|
15
|
+
return { schemaVersion, profile };
|
|
16
|
+
}
|
|
17
|
+
async function loadFortemiShardConverters() {
|
|
5
18
|
let core;
|
|
6
19
|
try {
|
|
7
20
|
core = (await import(
|
|
@@ -10,35 +23,111 @@ async function loadFortemiShardConverter() {
|
|
|
10
23
|
catch {
|
|
11
24
|
throw new Error("Portable Fortemi shard export requires @fortemi/core with aiwgFortemiIndexToKnowledgeShard.");
|
|
12
25
|
}
|
|
13
|
-
if (!core.aiwgFortemiIndexToKnowledgeShard
|
|
14
|
-
|
|
26
|
+
if (!core.aiwgFortemiIndexToKnowledgeShard
|
|
27
|
+
|| !core.aiwgFortemiIndexToKnowledgeShardWithReport) {
|
|
28
|
+
throw new Error("Installed @fortemi/core does not support both public AIWG shard converters; "
|
|
29
|
+
+ "upgrade to a compatible published release.");
|
|
15
30
|
}
|
|
16
|
-
return core
|
|
31
|
+
return core;
|
|
17
32
|
}
|
|
18
|
-
export async function
|
|
33
|
+
export async function buildAiwgFortemiKnowledgeShardWithReport(cwd, options = {}, converter, reportConverter) {
|
|
19
34
|
const exported = buildAiwgFortemiIndexExport(cwd, {
|
|
20
35
|
...options,
|
|
21
36
|
schemaVersion: "v2",
|
|
22
37
|
});
|
|
23
|
-
const
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
38
|
+
const tuple = resolveAiwgFortemiShardTuple(options);
|
|
39
|
+
const needsCore = tuple.profile === "core-v1" ? !converter : !reportConverter;
|
|
40
|
+
const core = needsCore ? await loadFortemiShardConverters() : null;
|
|
41
|
+
if (tuple.profile === "core-v1") {
|
|
42
|
+
const archive = await (converter ?? core.aiwgFortemiIndexToKnowledgeShard)(exported, { createdAt: options.generatedAt, matricVersion: "aiwg" });
|
|
43
|
+
return {
|
|
44
|
+
...tuple,
|
|
45
|
+
success: true,
|
|
46
|
+
lossless: true,
|
|
47
|
+
losses: [],
|
|
48
|
+
receipt: null,
|
|
49
|
+
archive,
|
|
50
|
+
};
|
|
51
|
+
}
|
|
52
|
+
const result = await (reportConverter ?? core.aiwgFortemiIndexToKnowledgeShardWithReport)(exported, { createdAt: options.generatedAt, matricVersion: "aiwg" });
|
|
53
|
+
if (!result.success || !result.archive) {
|
|
54
|
+
throw new Error("Fortemi full-v1 conversion failed without producing an archive; losses="
|
|
55
|
+
+ JSON.stringify(result.losses));
|
|
56
|
+
}
|
|
57
|
+
if (options.failOnLoss && (!result.lossless || result.losses.length > 0)) {
|
|
58
|
+
throw new Error(`Fortemi full-v1 conversion reported ${result.losses.length} loss(es); `
|
|
59
|
+
+ "archive was not written because --fail-on-loss was set.");
|
|
60
|
+
}
|
|
61
|
+
return {
|
|
62
|
+
...tuple,
|
|
63
|
+
success: result.success,
|
|
64
|
+
lossless: result.lossless,
|
|
65
|
+
losses: result.losses,
|
|
66
|
+
receipt: result.receipt,
|
|
67
|
+
archive: result.archive,
|
|
68
|
+
};
|
|
69
|
+
}
|
|
70
|
+
export async function buildAiwgFortemiKnowledgeShard(cwd, options = {}, converter, reportConverter) {
|
|
71
|
+
return (await buildAiwgFortemiKnowledgeShardWithReport(cwd, options, converter, reportConverter)).archive;
|
|
28
72
|
}
|
|
29
|
-
export async function writeAiwgFortemiKnowledgeShard(cwd, outPath, options = {}, converter) {
|
|
73
|
+
export async function writeAiwgFortemiKnowledgeShard(cwd, outPath, options = {}, converter, reportConverter) {
|
|
30
74
|
const exported = buildAiwgFortemiIndexExport(cwd, {
|
|
31
75
|
...options,
|
|
32
76
|
schemaVersion: "v2",
|
|
33
77
|
});
|
|
34
|
-
const
|
|
35
|
-
const shard = await convert(exported, {
|
|
36
|
-
createdAt: options.generatedAt,
|
|
37
|
-
matricVersion: "aiwg",
|
|
38
|
-
});
|
|
78
|
+
const conversion = await buildAiwgFortemiKnowledgeShardWithReport(cwd, options, converter, reportConverter);
|
|
39
79
|
const resolved = path.resolve(cwd, outPath);
|
|
80
|
+
const report = {
|
|
81
|
+
bytes: conversion.archive.byteLength,
|
|
82
|
+
items: exported.items.length,
|
|
83
|
+
outPath: resolved,
|
|
84
|
+
written: !options.dryRun,
|
|
85
|
+
conversion: {
|
|
86
|
+
schemaVersion: conversion.schemaVersion,
|
|
87
|
+
profile: conversion.profile,
|
|
88
|
+
success: conversion.success,
|
|
89
|
+
lossless: conversion.lossless,
|
|
90
|
+
losses: conversion.losses,
|
|
91
|
+
receipt: conversion.receipt,
|
|
92
|
+
},
|
|
93
|
+
};
|
|
94
|
+
if (options.dryRun)
|
|
95
|
+
return report;
|
|
96
|
+
if (fs.existsSync(resolved) && !options.overwrite) {
|
|
97
|
+
throw new Error(`Refusing to overwrite existing shard ${resolved}; choose a new path or pass --force.`);
|
|
98
|
+
}
|
|
40
99
|
fs.mkdirSync(path.dirname(resolved), { recursive: true });
|
|
41
|
-
|
|
42
|
-
|
|
100
|
+
const temporary = `${resolved}.tmp-${process.pid}`;
|
|
101
|
+
try {
|
|
102
|
+
fs.writeFileSync(temporary, conversion.archive, { flag: "wx" });
|
|
103
|
+
if (options.overwrite) {
|
|
104
|
+
fs.renameSync(temporary, resolved);
|
|
105
|
+
}
|
|
106
|
+
else {
|
|
107
|
+
fs.linkSync(temporary, resolved);
|
|
108
|
+
fs.unlinkSync(temporary);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
catch (error) {
|
|
112
|
+
if (fs.existsSync(temporary))
|
|
113
|
+
fs.unlinkSync(temporary);
|
|
114
|
+
throw error;
|
|
115
|
+
}
|
|
116
|
+
return report;
|
|
117
|
+
}
|
|
118
|
+
export function diagnoseAiwgFortemiShardMigration(cwd, inputPath) {
|
|
119
|
+
const resolved = path.resolve(cwd, inputPath);
|
|
120
|
+
if (!fs.existsSync(resolved) || !fs.statSync(resolved).isFile()) {
|
|
121
|
+
throw new Error(`Legacy shard input does not exist or is not a regular file: ${resolved}`);
|
|
122
|
+
}
|
|
123
|
+
return {
|
|
124
|
+
supported: false,
|
|
125
|
+
inputPath: resolved,
|
|
126
|
+
mutationPlanned: false,
|
|
127
|
+
diagnostic: "Source-less core-v1 to full-v1 conversion is unsupported because omitted rich "
|
|
128
|
+
+ "components cannot be reconstructed without loss.",
|
|
129
|
+
action: "Regenerate from the source-backed AIWG index with "
|
|
130
|
+
+ "--schema-version 2.0.0 --profile full-v1; retain the legacy shard for rollback.",
|
|
131
|
+
};
|
|
43
132
|
}
|
|
44
133
|
//# sourceMappingURL=fortemi-shard-export.js.map
|
|
@@ -178,6 +178,10 @@ export const BUILTIN_GRAPH_CONFIGS = {
|
|
|
178
178
|
'~/.aiwg/flows',
|
|
179
179
|
'~/.aiwg/runbooks',
|
|
180
180
|
'~/.aiwg/frameworks',
|
|
181
|
+
'~/.aiwg/addons',
|
|
182
|
+
'~/.aiwg/extensions',
|
|
183
|
+
'~/.aiwg/plugins',
|
|
184
|
+
'~/.aiwg/providers',
|
|
181
185
|
],
|
|
182
186
|
extensions: [...DEFAULT_INDEX_EXTENSIONS],
|
|
183
187
|
shared: true,
|