@aiwg/cli 2026.9.7 → 2026.9.10
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/bin/aiwg.mjs +55 -10
- package/dist/src/artifacts/cli.js +20 -8
- package/dist/src/artifacts/corpus-views/taxonomies.js +1 -1
- package/dist/src/artifacts/index-builder.js +43 -1
- package/dist/src/artifacts/query-engine.js +7 -0
- package/dist/src/cli/handlers/help.js +6 -5
- package/dist/src/cli/handlers/init.js +7 -2
- package/dist/src/cli/handlers/installation.js +102 -2
- package/dist/src/cli/handlers/mc.js +87 -17
- package/dist/src/cli/handlers/ralph.js +8 -8
- package/dist/src/cli/handlers/refresh.js +67 -7
- package/dist/src/cli/handlers/repo-access.js +155 -4
- package/dist/src/cli/handlers/setup.js +5 -5
- package/dist/src/cli/handlers/steward.js +39 -2
- package/dist/src/cli/handlers/use.js +13 -4
- package/dist/src/cli/handlers/version.js +49 -14
- package/dist/src/cli/handlers/workspace-context.js +8 -0
- package/dist/src/cli/services/deployment-verification.js +71 -10
- package/dist/src/cli/watch-service.js +43 -3
- package/dist/src/config/aiwg-config.js +95 -3
- package/dist/src/config/cli.js +16 -1
- package/dist/src/config/gitignore.js +5 -0
- package/dist/src/dataset/fortemi-capability.d.ts +70 -0
- package/dist/src/dataset/fortemi-capability.js +211 -0
- package/dist/src/dataset/fortemi-dataset-execution.d.ts +9 -0
- package/dist/src/dataset/fortemi-dataset-execution.js +49 -8
- package/dist/src/dataset/fortemi-run-receipt.d.ts +1 -0
- package/dist/src/dataset/fortemi-run-receipt.js +2 -19
- package/dist/src/dataset/fortemi-schema-path.d.ts +7 -0
- package/dist/src/dataset/fortemi-schema-path.js +24 -0
- package/dist/src/dataset/index.d.ts +1 -0
- package/dist/src/dataset/index.js +1 -0
- package/dist/src/extensions/claude-hooks-installer.js +22 -6
- package/dist/src/extensions/project-local-doctor.js +15 -1
- package/dist/src/lint/cli.js +5 -1
- package/dist/src/lint/reporters.js +17 -0
- package/dist/src/lint/runner.js +297 -4
- package/dist/src/policy/authorization.js +1 -1
- package/dist/src/smiths/context-pipeline/workspace-context.js +138 -49
- package/package.json +1 -1
- package/schemas/dataset/fortemi-capability-validation/1.0.1/authority.json +61 -0
- package/schemas/dataset/fortemi-capability-validation/1.0.1/capability.schema.json +469 -0
- package/schemas/security/threat-assessment-report.v1.schema.json +2 -1
- package/tools/agents/deploy-agents.mjs +8 -0
- package/tools/agents/providers/base.mjs +261 -16
- package/tools/agents/providers/claude.mjs +61 -4
- package/tools/agents/providers/codex.mjs +9 -0
- package/tools/skills/deploy-skills-codex.mjs +121 -7
|
@@ -33,6 +33,12 @@ const LEGACY_ROOT_FILES = [
|
|
|
33
33
|
'.github/copilot-instructions.md',
|
|
34
34
|
'AIWG.md',
|
|
35
35
|
];
|
|
36
|
+
/**
|
|
37
|
+
* Operator-content volume above which a provider-named source is surfaced for a scope
|
|
38
|
+
* decision instead of being routed on filename alone (#2537). A genuine provider adapter
|
|
39
|
+
* is a few hundred bytes; a migrated project contract is tens of KB.
|
|
40
|
+
*/
|
|
41
|
+
const SCOPE_REVIEW_BYTES = 4096;
|
|
36
42
|
const GENERATED_BLOCKS = [
|
|
37
43
|
[PROVIDER_BOOTSTRAP_START, PROVIDER_BOOTSTRAP_END],
|
|
38
44
|
['<!-- AIWG:context-hook:start -->', '<!-- AIWG:context-hook:end -->'],
|
|
@@ -381,7 +387,8 @@ export function buildWorkspaceManagedBlock(projectPath, providerFiles = []) {
|
|
|
381
387
|
'',
|
|
382
388
|
'- Edit project-neutral notes only inside the protected Project Context section below.',
|
|
383
389
|
'- Keep detailed policies, runbooks, hooks, and quickrefs in linked files.',
|
|
384
|
-
'-
|
|
390
|
+
'- `.aiwg/context/providers/` is reference only: no provider bootstrap auto-loads it.',
|
|
391
|
+
' Put directives you want read into Project Context above.',
|
|
385
392
|
'- Never store secrets, tokens, credentials, or machine-local sensitive values here.',
|
|
386
393
|
'',
|
|
387
394
|
'### Artifact Routing',
|
|
@@ -419,11 +426,16 @@ export async function ensureWorkspaceContext(projectPath, options = {}) {
|
|
|
419
426
|
const workspacePath = path.join(projectPath, 'WORKSPACE.md');
|
|
420
427
|
const warnings = [];
|
|
421
428
|
const existing = await readOptional(workspacePath);
|
|
429
|
+
// `aiwg use` and `aiwg regenerate` rebuild the managed block without
|
|
430
|
+
// knowing about earlier migrations. Rediscover the migrated provider files
|
|
431
|
+
// so their links survive every regeneration instead of only the one that
|
|
432
|
+
// wrote them (#2558).
|
|
433
|
+
const providerFiles = options.providerFiles ?? await migratedProviderFiles(projectPath);
|
|
422
434
|
if (existing === null) {
|
|
423
|
-
await atomicWrite(workspacePath, buildWorkspaceDocument(projectPath, '',
|
|
435
|
+
await atomicWrite(workspacePath, buildWorkspaceDocument(projectPath, '', providerFiles));
|
|
424
436
|
return { path: workspacePath, action: 'created', warnings };
|
|
425
437
|
}
|
|
426
|
-
const block = buildWorkspaceManagedBlock(projectPath,
|
|
438
|
+
const block = buildWorkspaceManagedBlock(projectPath, providerFiles);
|
|
427
439
|
if (existing.includes(WORKSPACE_MANAGED_START) || existing.includes(WORKSPACE_MANAGED_END)) {
|
|
428
440
|
let updated = replaceBlock(existing, WORKSPACE_MANAGED_START, WORKSPACE_MANAGED_END, block);
|
|
429
441
|
// A managed project-extraction block explicitly points operators back to
|
|
@@ -445,7 +457,7 @@ export async function ensureWorkspaceContext(projectPath, options = {}) {
|
|
|
445
457
|
}
|
|
446
458
|
const backupPath = `${workspacePath}.bak.${new Date().toISOString().replace(/[:.]/g, '-')}`;
|
|
447
459
|
await fs.writeFile(backupPath, existing, 'utf8');
|
|
448
|
-
await atomicWrite(workspacePath, buildWorkspaceDocument(projectPath, existing,
|
|
460
|
+
await atomicWrite(workspacePath, buildWorkspaceDocument(projectPath, existing, providerFiles));
|
|
449
461
|
return { path: workspacePath, action: 'updated', backupPath, warnings };
|
|
450
462
|
}
|
|
451
463
|
export function buildProviderBootstrapBlock(provider) {
|
|
@@ -689,14 +701,29 @@ export async function auditWorkspaceContext(projectPath) {
|
|
|
689
701
|
.filter(([, values]) => new Set(values.map((value) => value.polarity)).size > 1)
|
|
690
702
|
.map(([key, values]) => ({ key, sources: values.map(({ path: sourcePath, directive }) => ({ path: sourcePath, directive })).sort((a, b) => a.path.localeCompare(b.path)) }));
|
|
691
703
|
const rootOperator = sources.filter((source) => source.scope === 'root' && source.operatorContent.trim());
|
|
692
|
-
// Provider startup
|
|
693
|
-
//
|
|
694
|
-
//
|
|
695
|
-
//
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
704
|
+
// Provider startup files (CLAUDE.md, AGENTS.md, WARP.md, …) are bootstrap
|
|
705
|
+
// surfaces: AIWG rewrites them to a managed bootstrap that `@`-imports
|
|
706
|
+
// WORKSPACE.md. The operator content they carried therefore ports into the
|
|
707
|
+
// WORKSPACE.md operator block, which every provider bootstrap loads and
|
|
708
|
+
// which `aiwg use` and `aiwg regenerate` preserve byte-for-byte. Routing
|
|
709
|
+
// it to `.aiwg/context/providers/` instead left it linked but never
|
|
710
|
+
// loaded, and a later `aiwg use` dropped even the link (#2558).
|
|
711
|
+
const neutralSources = rootOperator.map((source) => source.path);
|
|
712
|
+
const providerSources = [];
|
|
713
|
+
const providerOutputs = [];
|
|
699
714
|
const workspaceExists = sources.some((source) => source.path === 'WORKSPACE.md');
|
|
715
|
+
// Report volume and destination per source. A substantial provider-named
|
|
716
|
+
// body is still surfaced for review (#2537): it now lands where every
|
|
717
|
+
// provider reads it, so anything genuinely provider-only should be moved to
|
|
718
|
+
// `.aiwg/context/providers/` by the operator after migration.
|
|
719
|
+
const routing = rootOperator.map((source) => ({
|
|
720
|
+
source: source.path,
|
|
721
|
+
operatorBytes: Buffer.byteLength(source.operatorContent, 'utf8'),
|
|
722
|
+
destination: 'WORKSPACE.md',
|
|
723
|
+
scope: 'project-neutral',
|
|
724
|
+
provider: source.path === 'WORKSPACE.md' ? null : source.provider,
|
|
725
|
+
})).sort((a, b) => b.operatorBytes - a.operatorBytes);
|
|
726
|
+
const scopeReview = routing.filter((entry) => entry.source !== 'WORKSPACE.md' && entry.operatorBytes >= SCOPE_REVIEW_BYTES);
|
|
700
727
|
return {
|
|
701
728
|
version: 1,
|
|
702
729
|
projectPath,
|
|
@@ -708,6 +735,8 @@ export async function auditWorkspaceContext(projectPath) {
|
|
|
708
735
|
conflicts,
|
|
709
736
|
sensitiveFindings,
|
|
710
737
|
plan: {
|
|
738
|
+
routing,
|
|
739
|
+
scopeReview,
|
|
711
740
|
neutralSources,
|
|
712
741
|
providerSources,
|
|
713
742
|
nestedSources: sources.filter((source) => source.scope === 'nested').map((source) => source.path),
|
|
@@ -719,34 +748,48 @@ export async function auditWorkspaceContext(projectPath) {
|
|
|
719
748
|
function projectOutputPath(projectPath, absPath) {
|
|
720
749
|
return path.relative(projectPath, absPath).replace(/\\/g, '/');
|
|
721
750
|
}
|
|
722
|
-
|
|
723
|
-
|
|
724
|
-
|
|
751
|
+
const LEGACY_PROJECT_CONTEXT_PLACEHOLDER = [
|
|
752
|
+
'## Project Context',
|
|
753
|
+
'',
|
|
754
|
+
'Add provider-neutral project conventions and links here.',
|
|
755
|
+
].join('\n');
|
|
756
|
+
/**
|
|
757
|
+
* Operator content for the WORKSPACE.md operator block after migration.
|
|
758
|
+
*
|
|
759
|
+
* Existing WORKSPACE.md operator content is kept verbatim; the operator body
|
|
760
|
+
* of each provider startup file is appended once, verbatim, under an
|
|
761
|
+
* attributed heading. Tables, procedures, and code blocks survive intact —
|
|
762
|
+
* the earlier line-flattened directive list lost exactly the runbook content
|
|
763
|
+
* operators keep in CLAUDE.md (#2558). Re-running the migration is a no-op:
|
|
764
|
+
* a body that already appears in the block is not appended again.
|
|
765
|
+
*/
|
|
725
766
|
function neutralMigrationContent(audit) {
|
|
726
|
-
const
|
|
727
|
-
|
|
728
|
-
|
|
729
|
-
|
|
730
|
-
|
|
731
|
-
|
|
732
|
-
|
|
733
|
-
if (
|
|
767
|
+
const workspace = audit.sources.find((source) => source.path === 'WORKSPACE.md');
|
|
768
|
+
let base = workspace?.operatorContent.trim() ?? '';
|
|
769
|
+
if (base === PROJECT_CONTEXT_PLACEHOLDER || base === LEGACY_PROJECT_CONTEXT_PLACEHOLDER)
|
|
770
|
+
base = '';
|
|
771
|
+
const sections = [];
|
|
772
|
+
let accumulated = base;
|
|
773
|
+
for (const source of audit.sources) {
|
|
774
|
+
if (source.path === 'WORKSPACE.md' || !audit.plan.neutralSources.includes(source.path))
|
|
734
775
|
continue;
|
|
735
|
-
|
|
776
|
+
const body = source.operatorContent.trim();
|
|
777
|
+
if (!body || accumulated.includes(body))
|
|
778
|
+
continue;
|
|
779
|
+
sections.push([
|
|
780
|
+
`### Migrated from ${source.path}`,
|
|
781
|
+
'',
|
|
782
|
+
`Source attribution: migrated from \`${source.path}\`; checksum \`${source.checksum}\`.`,
|
|
783
|
+
'',
|
|
784
|
+
body,
|
|
785
|
+
].join('\n'));
|
|
786
|
+
accumulated = `${accumulated}\n${body}`;
|
|
736
787
|
}
|
|
737
|
-
|
|
738
|
-
|
|
739
|
-
|
|
740
|
-
}
|
|
741
|
-
|
|
742
|
-
return [
|
|
743
|
-
`# Provider-specific context from ${source.path}`,
|
|
744
|
-
'',
|
|
745
|
-
`Source attribution: migrated from \`${source.path}\`; checksum \`${source.checksum}\`.`,
|
|
746
|
-
'',
|
|
747
|
-
source.operatorContent.trim() || '(No operator-authored content remained after managed blocks were removed.)',
|
|
748
|
-
'',
|
|
749
|
-
].join('\n');
|
|
788
|
+
const parts = [base || '## Project Context', ...sections];
|
|
789
|
+
if (!base && sections.length === 0) {
|
|
790
|
+
parts.push('Add project conventions, local hook/context pointers, and links to deeper project documents here.');
|
|
791
|
+
}
|
|
792
|
+
return parts.join('\n\n').trim();
|
|
750
793
|
}
|
|
751
794
|
async function configuredProviders(projectPath) {
|
|
752
795
|
try {
|
|
@@ -761,17 +804,8 @@ async function configuredProviders(projectPath) {
|
|
|
761
804
|
}
|
|
762
805
|
async function stageMigrationWrites(projectPath, audit, options = {}) {
|
|
763
806
|
const writes = new Map();
|
|
764
|
-
|
|
765
|
-
|
|
766
|
-
}
|
|
767
|
-
const providerFiles = [...new Set([
|
|
768
|
-
...audit.sources.filter((source) => source.path.replace(/\\/g, '/').includes('/context/providers/')).map((source) => source.path),
|
|
769
|
-
...writes.keys(),
|
|
770
|
-
])].sort();
|
|
771
|
-
const existingWorkspace = audit.sources.find((source) => source.path === 'WORKSPACE.md');
|
|
772
|
-
let workspaceOperatorContent = existingWorkspace?.managed
|
|
773
|
-
? existingWorkspace.operatorContent
|
|
774
|
-
: neutralMigrationContent(audit);
|
|
807
|
+
const providerFiles = [...new Set(audit.sources.filter((source) => source.path.replace(/\\/g, '/').includes('/context/providers/')).map((source) => source.path))].sort();
|
|
808
|
+
let workspaceOperatorContent = neutralMigrationContent(audit);
|
|
775
809
|
if (options.extractProject) {
|
|
776
810
|
const extracted = await extractExistingProjectContext(projectPath);
|
|
777
811
|
workspaceOperatorContent = mergeProjectExtraction(workspaceOperatorContent, extracted.content);
|
|
@@ -945,8 +979,35 @@ export async function rollbackWorkspaceContext(projectPath, requestedId) {
|
|
|
945
979
|
await atomicWrite(manifestPath, `${JSON.stringify(manifest, null, 2)}\n`);
|
|
946
980
|
return { id, restored: manifest.files.map((file) => file.path) };
|
|
947
981
|
}
|
|
982
|
+
/**
|
|
983
|
+
* Blank out fenced code blocks and inline code spans, preserving offsets and line
|
|
984
|
+
* structure, so link extraction sees only prose. Illustrative paths inside an
|
|
985
|
+
* example block are documentation, not context links the graph should resolve (#2536).
|
|
986
|
+
*/
|
|
987
|
+
function maskCodeRegions(content) {
|
|
988
|
+
const lines = content.split('\n');
|
|
989
|
+
let fence = null;
|
|
990
|
+
const masked = lines.map((line) => {
|
|
991
|
+
const openOrClose = /^\s{0,3}(`{3,}|~{3,})(.*)$/.exec(line);
|
|
992
|
+
if (fence) {
|
|
993
|
+
// A closing fence uses the same character, is at least as long, and carries no info string.
|
|
994
|
+
if (openOrClose && openOrClose[1][0] === fence.marker && openOrClose[1].length >= fence.length && openOrClose[2].trim() === '') {
|
|
995
|
+
fence = null;
|
|
996
|
+
}
|
|
997
|
+
return ' '.repeat(line.length);
|
|
998
|
+
}
|
|
999
|
+
if (openOrClose) {
|
|
1000
|
+
fence = { marker: openOrClose[1][0], length: openOrClose[1].length };
|
|
1001
|
+
return ' '.repeat(line.length);
|
|
1002
|
+
}
|
|
1003
|
+
// Inline code spans: a run of N backticks closes on the next run of exactly N.
|
|
1004
|
+
return line.replace(/(`+)(?:[^`]|(?!\1)`)*?\1/g, (span) => ' '.repeat(span.length));
|
|
1005
|
+
});
|
|
1006
|
+
return masked.join('\n');
|
|
1007
|
+
}
|
|
948
1008
|
function markdownLinks(content) {
|
|
949
|
-
|
|
1009
|
+
const prose = maskCodeRegions(content);
|
|
1010
|
+
return [...prose.matchAll(/\[[^\]]+\]\((\.\/?[^)#]+)(?:#[^)]+)?\)/g)].map((match) => match[1]);
|
|
950
1011
|
}
|
|
951
1012
|
export async function workspaceLinkedFiles(projectPath) {
|
|
952
1013
|
const content = await readOptional(path.join(projectPath, 'WORKSPACE.md'));
|
|
@@ -1011,8 +1072,36 @@ export async function diagnoseWorkspaceContext(projectPath) {
|
|
|
1011
1072
|
for (const conflict of audit.conflicts) {
|
|
1012
1073
|
diagnostics.push({ severity: 'error', code: 'directive-conflict', message: `Conflicting duplicate directive group '${conflict.key}' appears in ${conflict.sources.map((source) => source.path).join(', ')}.` });
|
|
1013
1074
|
}
|
|
1075
|
+
// One diagnostic per source pair, not one per duplicated line: a shared
|
|
1076
|
+
// pointer stub otherwise reports every line as a separate policy conflict
|
|
1077
|
+
// and degrades the workspace over content that agrees with itself (#2558).
|
|
1078
|
+
const duplicatesByPair = new Map();
|
|
1014
1079
|
for (const overlap of audit.identical) {
|
|
1015
|
-
|
|
1080
|
+
const key = overlap.sources.join(', ');
|
|
1081
|
+
duplicatesByPair.set(key, (duplicatesByPair.get(key) ?? 0) + overlap.directives.length);
|
|
1082
|
+
}
|
|
1083
|
+
const operatorBodies = new Map(audit.sources.map((source) => [source.path, source.operatorContent.trim()]));
|
|
1084
|
+
for (const [pair, count] of duplicatesByPair) {
|
|
1085
|
+
const paths = pair.split(', ');
|
|
1086
|
+
const bodies = paths.map((item) => operatorBodies.get(item) ?? '');
|
|
1087
|
+
const wholeFileDuplicate = bodies.every((body) => body.length > 0 && body === bodies[0]);
|
|
1088
|
+
diagnostics.push({
|
|
1089
|
+
severity: wholeFileDuplicate ? 'info' : 'warning',
|
|
1090
|
+
code: 'duplicate-directive',
|
|
1091
|
+
message: wholeFileDuplicate
|
|
1092
|
+
? `${pair} carry identical operator content (${count} directive(s)); keep one copy or accept the shared stub.`
|
|
1093
|
+
: `${count} identical directive(s) duplicated across ${pair}.`,
|
|
1094
|
+
});
|
|
1095
|
+
}
|
|
1096
|
+
for (const source of audit.sources) {
|
|
1097
|
+
if (!source.path.replace(/\\/g, '/').includes('/context/providers/') || !source.operatorContent.trim())
|
|
1098
|
+
continue;
|
|
1099
|
+
diagnostics.push({
|
|
1100
|
+
severity: 'info',
|
|
1101
|
+
code: 'provider-context-not-loaded',
|
|
1102
|
+
message: `${source.path} is linked from WORKSPACE.md but no provider bootstrap auto-loads it; move its operator content into the WORKSPACE.md Project Context section (\`aiwg regenerate --existing-project\` ports startup files there) or keep it as reference only.`,
|
|
1103
|
+
path: source.path,
|
|
1104
|
+
});
|
|
1016
1105
|
}
|
|
1017
1106
|
for (const finding of audit.sensitiveFindings) {
|
|
1018
1107
|
diagnostics.push({ severity: 'error', code: 'possible-secret', message: 'Possible credential value found in context; remove it.', path: finding.path });
|
package/package.json
CHANGED
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
{
|
|
2
|
+
"contract": "fortemi.dataset-capability-validation/v1",
|
|
3
|
+
"revision": "1.0.1",
|
|
4
|
+
"wireContract": "fortemi.dataset-execution-capabilities/v1",
|
|
5
|
+
"wireSchemaVersion": "1.0.0",
|
|
6
|
+
"consumerIssue": 2242,
|
|
7
|
+
"authority": {
|
|
8
|
+
"repository": "Fortemi/fortemi-react",
|
|
9
|
+
"issue": "https://git.integrolabs.net/Fortemi/fortemi-react/issues/422",
|
|
10
|
+
"commit": "5625215762a8fd06db8fef4ccedd87f3c370ec31",
|
|
11
|
+
"mergedCommit": "35edcd9f8429fcd91a417021cbe4c427f900ed73",
|
|
12
|
+
"path": "packages/core/schemas/dataset-execution-capabilities/validation/1.0.1",
|
|
13
|
+
"manifestSha256": "20b59bb871c3afc9bb972896b2a2da718970c6fe7ef54b49000418f62a5701c0"
|
|
14
|
+
},
|
|
15
|
+
"files": [
|
|
16
|
+
{
|
|
17
|
+
"path": "capability.schema.json",
|
|
18
|
+
"authorityPath": "schema.json",
|
|
19
|
+
"sha256": "a4e9b427da669a02e83db00d39f48c2e106770d6cd2ec1b717938c57793b754c"
|
|
20
|
+
},
|
|
21
|
+
{
|
|
22
|
+
"path": "../../../../test/fixtures/dataset/fortemi-capability/negotiation-vectors.json",
|
|
23
|
+
"authorityPath": "negotiation-vectors.json",
|
|
24
|
+
"sha256": "2793990a842d5969f1f64c90170ab97ca4ffc4b93d1302a2f358fae54631a6dc"
|
|
25
|
+
},
|
|
26
|
+
{
|
|
27
|
+
"path": "../../../../test/fixtures/dataset/fortemi-capability/wire-vectors.json",
|
|
28
|
+
"authorityPath": "wire-vectors.json",
|
|
29
|
+
"sha256": "c52d32d0b1d0d312cf8b242f11fc116c47d104a74112cbd5d0019e6d39df9744"
|
|
30
|
+
}
|
|
31
|
+
],
|
|
32
|
+
"consumer": {
|
|
33
|
+
"repository": "roctinam/aiwg",
|
|
34
|
+
"implementation": "src/dataset/fortemi-capability.ts",
|
|
35
|
+
"binding": "src/dataset/fortemi-dataset-execution.ts",
|
|
36
|
+
"test": "test/unit/dataset/fortemi-capability.test.ts",
|
|
37
|
+
"boundary": "Independent AIWG implementation of the wire rules. AIWG never imports the producer's validator; agreement is established by the shared authority vectors."
|
|
38
|
+
},
|
|
39
|
+
"observedDescriptor": {
|
|
40
|
+
"source": "Fortemi/fortemi mcp-server/lib/dataset-execution.js buildDatasetExecutionDescriptor",
|
|
41
|
+
"commit": "a701847db779a0a3adfa36a09dfa1055a10a0a0a",
|
|
42
|
+
"fixture": "test/fixtures/dataset/fortemi-capability/server-descriptor.json",
|
|
43
|
+
"sha256": "66ee315912429645e97c77a96e3f5110fe9db5e6909ff3c39e8b6e22135d8b95",
|
|
44
|
+
"runtimeVersion": "2026.9.10",
|
|
45
|
+
"qualification": "Descriptor rendered from pinned producer source; not a released-artifact or live-session receipt."
|
|
46
|
+
},
|
|
47
|
+
"qualification": {
|
|
48
|
+
"status": "source-consumer-adoption",
|
|
49
|
+
"covers": [
|
|
50
|
+
"advertised capability descriptor validation before preview or execute",
|
|
51
|
+
"independent negotiation bound to the advertised descriptor",
|
|
52
|
+
"receipt capabilityDecision bound to that independent negotiation"
|
|
53
|
+
],
|
|
54
|
+
"remaining": [
|
|
55
|
+
"clean installed and released consumer qualification",
|
|
56
|
+
"live Fortemi Server session evidence under roctinam/aiwg#2194 authorization"
|
|
57
|
+
],
|
|
58
|
+
"maturity": "alpha",
|
|
59
|
+
"suiteAudit": "NO-GO"
|
|
60
|
+
}
|
|
61
|
+
}
|