aiwg 2026.7.4 → 2026.7.7
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 +13 -2
- package/dist/src/artifacts/browser-export.js +17 -2
- package/dist/src/artifacts/cli.js +130 -13
- package/dist/src/artifacts/fortemi-core-query-adapter.js +1 -1
- package/dist/src/artifacts/fortemi-core-sync.js +7 -0
- package/dist/src/artifacts/index-builder.js +39 -6
- package/dist/src/artifacts/index-status.js +2 -1
- package/dist/src/artifacts/legacy-index-migration.js +169 -0
- package/dist/src/artifacts/query-engine.js +363 -141
- package/dist/src/artifacts/source-graph.js +527 -0
- package/dist/src/artifacts/types.js +119 -7
- package/dist/src/cli/handlers/help.js +2 -0
- package/dist/src/cli/handlers/index.js +3 -1
- package/dist/src/cli/handlers/init.js +9 -6
- package/dist/src/cli/handlers/run.js +2 -2
- package/dist/src/cli/handlers/setup.js +440 -0
- package/dist/src/cli/handlers/use.js +3 -3
- package/dist/src/config/cli.js +3 -3
- package/dist/src/extensions/commands/definitions.js +33 -0
- package/dist/src/mcp/tools/subsystems.mjs +1 -1
- package/docs/cli-reference.md +117 -25
- package/docs/getting-started/existing-project.md +31 -6
- package/docs/integrations/fortemi-index-export.md +32 -0
- package/docs/local-issues.md +6 -0
- package/docs/quickstart.md +12 -1
- package/docs/releases/v2026.7.5-announcement.md +27 -0
- package/docs/releases/v2026.7.6-announcement.md +34 -0
- package/docs/releases/v2026.7.7-announcement.md +32 -0
- package/docs/user-level-indices.md +147 -0
- package/package.json +2 -2
- package/prebuilt/fortemi-core/framework/aiwg-fortemi-index-v2.json +1 -1
- package/prebuilt/fortemi-core/framework/manifest.json +2 -2
package/README.md
CHANGED
|
@@ -13,6 +13,11 @@ npm i -g aiwg # install globally
|
|
|
13
13
|
aiwg use sdlc # deploy SDLC framework
|
|
14
14
|
```
|
|
15
15
|
|
|
16
|
+
Then ask your AI assistant to set up the project for AIWG. The agent-led setup
|
|
17
|
+
conversation should establish remotes, issue storage, delivery behavior,
|
|
18
|
+
signing policy, and provider choices; the assistant may call `aiwg setup project`
|
|
19
|
+
as the underlying CLI helper.
|
|
20
|
+
|
|
16
21
|
macOS users: if npm fails with `EACCES` under `/usr/local/lib/node_modules`,
|
|
17
22
|
use the [macOS Install Guide](docs/getting-started/macos-install.md).
|
|
18
23
|
Agents and stewards setting up AIWG end-to-end should use the
|
|
@@ -133,7 +138,8 @@ The user surface is the conversation with your AI tool. You install AIWG, deploy
|
|
|
133
138
|
The CLI exists mostly for the agent to call under the hood. The commands a user typically runs by hand are a short list:
|
|
134
139
|
|
|
135
140
|
- `aiwg use <framework>` — deploy AIWG to your project (one-time per framework, per project)
|
|
136
|
-
-
|
|
141
|
+
- Project setup agent/skill — recommended guided setup conversation for repo, tracker, delivery, signing, and provider policy
|
|
142
|
+
- `aiwg wizard` — guided first-run goal routing
|
|
137
143
|
- `aiwg new <project>` — scaffold a new project
|
|
138
144
|
- `aiwg status` — what's deployed and engaged in this workspace
|
|
139
145
|
- `aiwg doctor` — health check
|
|
@@ -1089,13 +1095,18 @@ The headline operator surface for finding and reading AIWG capabilities. Most AI
|
|
|
1089
1095
|
aiwg discover "deploy production" # → flow-deploy-to-production
|
|
1090
1096
|
aiwg discover "create intake" # → intake-* family
|
|
1091
1097
|
aiwg discover "audit security" --type skill --limit 5
|
|
1092
|
-
aiwg discover "<phrase>" --json
|
|
1098
|
+
aiwg discover "<phrase>" --format json # stable ids for sub-agents, no paths
|
|
1099
|
+
aiwg discover "<phrase>" --format json --compact
|
|
1093
1100
|
|
|
1094
1101
|
# Fetch the full body of a specific artifact (companion to discover)
|
|
1102
|
+
aiwg show skill aiwg:skill:6f1477d99813ca8d
|
|
1095
1103
|
aiwg show skill flow-deploy-to-production
|
|
1096
1104
|
aiwg show agent aiwg-steward
|
|
1097
1105
|
aiwg show command discover
|
|
1098
1106
|
aiwg show rule no-attribution
|
|
1107
|
+
|
|
1108
|
+
# Inspect Fortemi metadata and resolved paths when needed
|
|
1109
|
+
aiwg show metadata aiwg:skill:6f1477d99813ca8d --json
|
|
1099
1110
|
```
|
|
1100
1111
|
|
|
1101
1112
|
The kernel quickrefs ship **curated, validated discovery phrases per capability domain** — phrases tested against the live scorer to surface the right top-3 candidates. The 6 self-maintenance ops (`steward`, `aiwg-doctor`, `aiwg-refresh`, `aiwg-status`, `aiwg-help`, `use`) stay loaded so the agent retains repair surfaces even when discovery itself is broken. See [`docs/discovery-and-kernel-skills.md`](docs/discovery-and-kernel-skills.md) for the full best-practices guide, ASCII flow diagrams, and verification steps.
|
|
@@ -6,7 +6,7 @@ function stableArtifactId(artifactPath) {
|
|
|
6
6
|
return ("aiwg:artifact:" +
|
|
7
7
|
createHash("sha256").update(artifactPath).digest("hex").slice(0, 16));
|
|
8
8
|
}
|
|
9
|
-
function stableRecordId(recordType, artifactPath) {
|
|
9
|
+
export function stableRecordId(recordType, artifactPath) {
|
|
10
10
|
if (recordType === "aiwg.artifact")
|
|
11
11
|
return stableArtifactId(artifactPath);
|
|
12
12
|
return (recordType.replaceAll(".", ":") +
|
|
@@ -65,6 +65,7 @@ function relationshipsForEntry(entry, graph, recordTypesByPath) {
|
|
|
65
65
|
source_path: edge.path,
|
|
66
66
|
target_path: edge.path,
|
|
67
67
|
direction: prefix,
|
|
68
|
+
metadata: Object.fromEntries(Object.entries(edge).filter(([key]) => key !== "path" && key !== "type")),
|
|
68
69
|
});
|
|
69
70
|
};
|
|
70
71
|
for (const edge of edges.upstream)
|
|
@@ -78,7 +79,7 @@ function relationshipsForEntry(entry, graph, recordTypesByPath) {
|
|
|
78
79
|
return left.target_id.localeCompare(right.target_id);
|
|
79
80
|
});
|
|
80
81
|
}
|
|
81
|
-
function recordTypeForEntry(entry, schemaVersion) {
|
|
82
|
+
export function recordTypeForEntry(entry, schemaVersion) {
|
|
82
83
|
if (schemaVersion === "v1")
|
|
83
84
|
return "aiwg.artifact";
|
|
84
85
|
const normalized = entry.type.toLowerCase().replace(/_/g, "-");
|
|
@@ -125,6 +126,20 @@ function recordTypeForEntry(entry, schemaVersion) {
|
|
|
125
126
|
return "aiwg.memory.entry";
|
|
126
127
|
case "issue":
|
|
127
128
|
return "aiwg.issue";
|
|
129
|
+
case "source.file":
|
|
130
|
+
return "aiwg.source.file";
|
|
131
|
+
case "source.module":
|
|
132
|
+
return "aiwg.source.module";
|
|
133
|
+
case "source.package":
|
|
134
|
+
return "aiwg.source.package";
|
|
135
|
+
case "source.builtin":
|
|
136
|
+
return "aiwg.source.builtin";
|
|
137
|
+
case "source.asset":
|
|
138
|
+
return "aiwg.source.asset";
|
|
139
|
+
case "source.unresolved":
|
|
140
|
+
return "aiwg.source.unresolved";
|
|
141
|
+
case "source.entrypoint":
|
|
142
|
+
return "aiwg.source.entrypoint";
|
|
128
143
|
default:
|
|
129
144
|
if (pathText.includes("/research/references/") ||
|
|
130
145
|
/^ref[-_]/i.test(entry.name ?? entry.title))
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
* @source @src/cli/handlers/subcommands.ts
|
|
17
17
|
* @tests @test/unit/artifacts/cli.test.ts
|
|
18
18
|
*/
|
|
19
|
-
import { GRAPH_CONFIGS, loadUserGraphConfigs } from './types.js';
|
|
19
|
+
import { GRAPH_CONFIGS, loadUserGraphConfigs, loadGlobalGraphConfigs } from './types.js';
|
|
20
20
|
import { SUPPORTED_VIEWS } from './corpus-views/renderers.js';
|
|
21
21
|
/** Parse --graph flag from args, returns undefined for "all graphs" */
|
|
22
22
|
function parseGraphFlag(args) {
|
|
@@ -30,6 +30,7 @@ function parseGraphFlag(args) {
|
|
|
30
30
|
const val = args[idx + 1];
|
|
31
31
|
// Load user-defined graphs so validation is complete
|
|
32
32
|
loadUserGraphConfigs(process.cwd());
|
|
33
|
+
loadGlobalGraphConfigs();
|
|
33
34
|
if (val in GRAPH_CONFIGS)
|
|
34
35
|
return val;
|
|
35
36
|
// Corpus markdown views (#1490) are valid --graph targets for `index build`.
|
|
@@ -135,6 +136,9 @@ export async function main(args) {
|
|
|
135
136
|
case 'sync':
|
|
136
137
|
await handleSync(subcommandArgs);
|
|
137
138
|
break;
|
|
139
|
+
case 'migrate-legacy':
|
|
140
|
+
await handleMigrateLegacy(subcommandArgs);
|
|
141
|
+
break;
|
|
138
142
|
case 'deps':
|
|
139
143
|
await handleDeps(subcommandArgs);
|
|
140
144
|
break;
|
|
@@ -186,7 +190,7 @@ export async function main(args) {
|
|
|
186
190
|
break;
|
|
187
191
|
default:
|
|
188
192
|
console.error(`Error: Unknown index subcommand '${subcommand}'`);
|
|
189
|
-
console.log('Available: build, query, discover, show, export, sync, deps, stats, status, list, neighbors, set, embed, similar, dedup-report, watch');
|
|
193
|
+
console.log('Available: build, query, discover, show, export, sync, migrate-legacy, deps, stats, status, list, neighbors, set, embed, similar, dedup-report, watch');
|
|
190
194
|
process.exit(1);
|
|
191
195
|
}
|
|
192
196
|
}
|
|
@@ -200,6 +204,7 @@ function printIndexUsage() {
|
|
|
200
204
|
console.log(' show Print the full text of a specific skill/agent/command/rule');
|
|
201
205
|
console.log(' export Export a browser-consumable index contract');
|
|
202
206
|
console.log(' sync Materialize the Fortemi Core static index cache');
|
|
207
|
+
console.log(' migrate-legacy Move legacy root indexes into graph sidecar indexes');
|
|
203
208
|
console.log(' deps Show artifact dependency graph');
|
|
204
209
|
console.log(' stats Show index statistics');
|
|
205
210
|
console.log(' status Enumerate the index-graph registry (freshness + drift); alias: list');
|
|
@@ -211,7 +216,7 @@ function printIndexUsage() {
|
|
|
211
216
|
console.log(' watch Start a filesystem watcher for automatic incremental index updates');
|
|
212
217
|
console.log('');
|
|
213
218
|
console.log('Options:');
|
|
214
|
-
console.log(' --graph <name> Target a specific graph (framework, project, codebase, or user-defined)');
|
|
219
|
+
console.log(' --graph <name> Target a specific graph (framework, project, codebase, source, user, or user-defined)');
|
|
215
220
|
console.log(' --all Build all known graphs (including user-defined)');
|
|
216
221
|
console.log('');
|
|
217
222
|
console.log('Examples:');
|
|
@@ -223,8 +228,10 @@ function printIndexUsage() {
|
|
|
223
228
|
console.log(' aiwg index discover "audit security" --type skill');
|
|
224
229
|
console.log(' aiwg index show skill intake-wizard');
|
|
225
230
|
console.log(' aiwg index show skill flow-deploy-to-production --json');
|
|
231
|
+
console.log(' aiwg index show metadata aiwg:skill:4840fa441622f676 --json');
|
|
226
232
|
console.log(' aiwg index show agent aiwg-steward');
|
|
227
233
|
console.log(' aiwg index export --format fortemi --graph project --out aiwg-fortemi-index.json');
|
|
234
|
+
console.log(' aiwg index migrate-legacy --scope project --dry-run');
|
|
228
235
|
console.log(' aiwg index query "authentication" --type use-case');
|
|
229
236
|
console.log(' aiwg index query "security rules" --graph framework --json');
|
|
230
237
|
console.log(' aiwg index query "mixture of experts" --fulltext --graph papers # body text, BM25');
|
|
@@ -332,7 +339,7 @@ async function handleBuild(args) {
|
|
|
332
339
|
console.log(' --scope <dir> Limit scan to a specific subdirectory');
|
|
333
340
|
console.log(' --graph <name> Build a specific graph only (built-in or user-defined)');
|
|
334
341
|
console.log('');
|
|
335
|
-
console.log('Built-in graph names: project, codebase, framework');
|
|
342
|
+
console.log('Built-in graph names: project, codebase, source, user, framework');
|
|
336
343
|
console.log('User-defined graphs: configure under index.graphs in .aiwg/aiwg.config');
|
|
337
344
|
console.log('');
|
|
338
345
|
console.log('Default behavior (no --graph): builds all graphs with defaultBuild: true');
|
|
@@ -342,6 +349,8 @@ async function handleBuild(args) {
|
|
|
342
349
|
console.log(' aiwg index build');
|
|
343
350
|
console.log(' aiwg index build --force');
|
|
344
351
|
console.log(' aiwg index build --graph codebase --force');
|
|
352
|
+
console.log(' aiwg index build --graph source --force');
|
|
353
|
+
console.log(' aiwg index build --graph user --force');
|
|
345
354
|
console.log(' aiwg index build --graph references # user-defined graph');
|
|
346
355
|
console.log(' aiwg index build --scope documentation/references');
|
|
347
356
|
console.log(' aiwg index build --all');
|
|
@@ -363,6 +372,7 @@ async function handleBuild(args) {
|
|
|
363
372
|
}
|
|
364
373
|
// Load user-defined graphs
|
|
365
374
|
loadUserGraphConfigs(cwd);
|
|
375
|
+
loadGlobalGraphConfigs();
|
|
366
376
|
let jsonBuilt = false;
|
|
367
377
|
if (graph) {
|
|
368
378
|
// --graph X: build the JSON graph if X is one; otherwise X may be a
|
|
@@ -821,6 +831,83 @@ async function handleSync(args) {
|
|
|
821
831
|
process.exit(1);
|
|
822
832
|
}
|
|
823
833
|
}
|
|
834
|
+
/**
|
|
835
|
+
* Handle 'index migrate-legacy' command.
|
|
836
|
+
*/
|
|
837
|
+
async function handleMigrateLegacy(args) {
|
|
838
|
+
if (args.includes('--help') || args.includes('-h')) {
|
|
839
|
+
console.log('Usage: aiwg index migrate-legacy [--scope project|user|global | --all] [options]');
|
|
840
|
+
console.log('');
|
|
841
|
+
console.log('Migrates compatible legacy root index files into graph sidecar index');
|
|
842
|
+
console.log('directories. Project scope moves .aiwg/.index/*.json to');
|
|
843
|
+
console.log('.aiwg/.index/project/*.json and refreshes the Fortemi Core static');
|
|
844
|
+
console.log('cache. User/global scopes report or migrate their corresponding');
|
|
845
|
+
console.log('sidecar locations without modifying packaged/prebuilt AIWG indexes.');
|
|
846
|
+
console.log('');
|
|
847
|
+
console.log('Options:');
|
|
848
|
+
console.log(' --scope <name> Scope to migrate: project, user, or global (default: project)');
|
|
849
|
+
console.log(' --all Migrate project, user, and global scopes');
|
|
850
|
+
console.log(' --dry-run Print planned changes without writing files');
|
|
851
|
+
console.log(' --no-fortemi-sync Do not refresh the project Fortemi Core static cache');
|
|
852
|
+
console.log(' --generated-at <iso> Override generated timestamp for deterministic fixtures');
|
|
853
|
+
console.log(' --json Print the migration report as JSON');
|
|
854
|
+
console.log('');
|
|
855
|
+
console.log('Examples:');
|
|
856
|
+
console.log(' aiwg index migrate-legacy --scope project --dry-run');
|
|
857
|
+
console.log(' aiwg index migrate-legacy --all --json');
|
|
858
|
+
return;
|
|
859
|
+
}
|
|
860
|
+
const all = args.includes('--all');
|
|
861
|
+
const scopeValue = parseFlagValue(args, '--scope', 'Error: --scope requires project, user, or global');
|
|
862
|
+
if (all && scopeValue) {
|
|
863
|
+
console.error('Error: pass either --all or --scope, not both');
|
|
864
|
+
process.exit(1);
|
|
865
|
+
}
|
|
866
|
+
const allowedScopes = ['project', 'user', 'global'];
|
|
867
|
+
const scopes = all
|
|
868
|
+
? [...allowedScopes]
|
|
869
|
+
: scopeValue
|
|
870
|
+
? [scopeValue]
|
|
871
|
+
: ['project'];
|
|
872
|
+
const invalidScope = scopes.find((scope) => !allowedScopes.includes(scope));
|
|
873
|
+
if (invalidScope) {
|
|
874
|
+
console.error('Error: --scope must be project, user, or global');
|
|
875
|
+
process.exit(1);
|
|
876
|
+
}
|
|
877
|
+
const generatedAt = parseFlagValue(args, '--generated-at', 'Error: --generated-at requires an ISO timestamp value');
|
|
878
|
+
const { migrateLegacyIndex } = await import('./legacy-index-migration.js');
|
|
879
|
+
try {
|
|
880
|
+
const report = migrateLegacyIndex(process.cwd(), {
|
|
881
|
+
scopes: scopes,
|
|
882
|
+
dryRun: args.includes('--dry-run'),
|
|
883
|
+
syncFortemi: !args.includes('--no-fortemi-sync'),
|
|
884
|
+
generatedAt,
|
|
885
|
+
});
|
|
886
|
+
if (args.includes('--json')) {
|
|
887
|
+
console.log(JSON.stringify(report, null, 2));
|
|
888
|
+
return;
|
|
889
|
+
}
|
|
890
|
+
console.log(`Legacy index migration ${report.dryRun ? '(DRY RUN)' : 'complete'}`);
|
|
891
|
+
for (const result of report.results) {
|
|
892
|
+
const entries = result.entries === null ? 'unknown' : String(result.entries);
|
|
893
|
+
const detail = result.reason ? ` — ${result.reason}` : '';
|
|
894
|
+
console.log(` ${result.scope}: ${result.status} (${entries} entries)${detail}`);
|
|
895
|
+
for (const file of result.files) {
|
|
896
|
+
console.log(` ${file.name}: ${file.status}`);
|
|
897
|
+
}
|
|
898
|
+
if (result.fortemiCore) {
|
|
899
|
+
console.log(` fortemi-core: ${result.fortemiCore.status} (${result.fortemiCore.itemCount} item(s)) → ${result.fortemiCore.exportPath}`);
|
|
900
|
+
}
|
|
901
|
+
}
|
|
902
|
+
if (report.reportPath) {
|
|
903
|
+
console.log(` report: ${report.reportPath}`);
|
|
904
|
+
}
|
|
905
|
+
}
|
|
906
|
+
catch (err) {
|
|
907
|
+
console.error('Error: ' + (err instanceof Error ? err.message : String(err)));
|
|
908
|
+
process.exit(1);
|
|
909
|
+
}
|
|
910
|
+
}
|
|
824
911
|
/**
|
|
825
912
|
* Handle 'index deps' command
|
|
826
913
|
*
|
|
@@ -1027,13 +1114,13 @@ async function handleDiscover(args) {
|
|
|
1027
1114
|
if (!phrase) {
|
|
1028
1115
|
console.error('Error: aiwg index discover requires a search phrase');
|
|
1029
1116
|
console.log('');
|
|
1030
|
-
console.log('Usage: aiwg index discover "<phrase>" [--type <kinds>] [--limit N] [--json] [--graph <name>] [--backend local|fortemi-core]');
|
|
1117
|
+
console.log('Usage: aiwg index discover "<phrase>" [--type <kinds>] [--limit N] [--json|--format json|text] [--pretty|--compact] [--graph <name>] [--backend local|fortemi-core]');
|
|
1031
1118
|
console.log('');
|
|
1032
1119
|
console.log('Examples:');
|
|
1033
1120
|
console.log(' aiwg index discover "create intake"');
|
|
1034
1121
|
console.log(' aiwg index discover "deploy production" --limit 5');
|
|
1035
1122
|
console.log(' aiwg index discover "audit security" --type skill,agent');
|
|
1036
|
-
console.log(' aiwg index discover "intake" --json');
|
|
1123
|
+
console.log(' aiwg index discover "intake" --format json --pretty');
|
|
1037
1124
|
process.exit(1);
|
|
1038
1125
|
}
|
|
1039
1126
|
const typeValue = parseFlagValue(flags, '--type', 'Error: --type requires a value');
|
|
@@ -1043,7 +1130,17 @@ async function handleDiscover(args) {
|
|
|
1043
1130
|
.filter(Boolean);
|
|
1044
1131
|
// K=5 default — see query-engine.ts comment (#1218 Wave A).
|
|
1045
1132
|
const limit = parsePositiveIntegerFlag(flags, '--limit', 5, 'Error: --limit must be a positive integer');
|
|
1046
|
-
const
|
|
1133
|
+
const format = parseFlagValue(flags, '--format', 'Error: --format requires text or json') ?? 'text';
|
|
1134
|
+
if (format !== 'text' && format !== 'json') {
|
|
1135
|
+
console.error('Error: --format must be text or json');
|
|
1136
|
+
process.exit(1);
|
|
1137
|
+
}
|
|
1138
|
+
const json = flags.includes('--json') || format === 'json';
|
|
1139
|
+
if (flags.includes('--pretty') && flags.includes('--compact')) {
|
|
1140
|
+
console.error('Error: --pretty and --compact cannot be used together');
|
|
1141
|
+
process.exit(1);
|
|
1142
|
+
}
|
|
1143
|
+
const jsonPretty = !flags.includes('--compact');
|
|
1047
1144
|
const graph = parseGraphFlag(flags);
|
|
1048
1145
|
const backend = parseSearchBackendFlag(flags);
|
|
1049
1146
|
await discoverCapability(cwd, {
|
|
@@ -1051,8 +1148,10 @@ async function handleDiscover(args) {
|
|
|
1051
1148
|
typeFilter,
|
|
1052
1149
|
limit,
|
|
1053
1150
|
json,
|
|
1151
|
+
jsonPretty,
|
|
1054
1152
|
graph,
|
|
1055
1153
|
backend,
|
|
1154
|
+
includePaths: false,
|
|
1056
1155
|
});
|
|
1057
1156
|
}
|
|
1058
1157
|
/**
|
|
@@ -1069,7 +1168,7 @@ async function handleDiscover(args) {
|
|
|
1069
1168
|
* the artifact body so consumers don't need to navigate the filesystem.
|
|
1070
1169
|
*/
|
|
1071
1170
|
async function handleShow(args) {
|
|
1072
|
-
const { showArtifact } = await import('./query-engine.js');
|
|
1171
|
+
const { showArtifact, showMetadata } = await import('./query-engine.js');
|
|
1073
1172
|
const cwd = process.cwd();
|
|
1074
1173
|
const positional = [];
|
|
1075
1174
|
const flags = [];
|
|
@@ -1086,6 +1185,7 @@ async function handleShow(args) {
|
|
|
1086
1185
|
const HELP_TEXT = [
|
|
1087
1186
|
'',
|
|
1088
1187
|
'Usage: aiwg show <type> <name> [--json] [--first] [--graph <name>] [--backend local|fortemi-core]',
|
|
1188
|
+
' aiwg show metadata <id-or-name-or-path> [--json] [--first] [--graph <name>] [--backend local|fortemi-core]',
|
|
1089
1189
|
' aiwg index show <type> <name> ...',
|
|
1090
1190
|
'',
|
|
1091
1191
|
'Types: skill | agent | command | rule',
|
|
@@ -1093,16 +1193,22 @@ async function handleShow(args) {
|
|
|
1093
1193
|
'Examples:',
|
|
1094
1194
|
' aiwg show skill intake-wizard',
|
|
1095
1195
|
' aiwg show skill flow-deploy-to-production --json',
|
|
1196
|
+
' aiwg show metadata aiwg:skill:4840fa441622f676 --json',
|
|
1096
1197
|
' aiwg show agent aiwg-steward',
|
|
1097
1198
|
' aiwg show command discover',
|
|
1098
1199
|
'',
|
|
1099
|
-
'Tip: use `aiwg discover "<phrase>"` first to find the
|
|
1200
|
+
'Tip: use `aiwg discover "<phrase>" --json` first to find the stable id.',
|
|
1100
1201
|
].join('\n');
|
|
1101
1202
|
if (positional.length === 0) {
|
|
1102
1203
|
console.error('Error: aiwg show requires a type and name');
|
|
1103
1204
|
console.error(HELP_TEXT);
|
|
1104
1205
|
process.exit(1);
|
|
1105
1206
|
}
|
|
1207
|
+
const firstLower = positional[0].toLowerCase();
|
|
1208
|
+
const metadataMode = firstLower === 'metadata';
|
|
1209
|
+
if (metadataMode) {
|
|
1210
|
+
positional.shift();
|
|
1211
|
+
}
|
|
1106
1212
|
// Wave A (#1218): if the first positional is a known type, treat it
|
|
1107
1213
|
// as the type. If it's NOT a known type, fall through to single-name
|
|
1108
1214
|
// mode — `aiwg show intake-wizard` works as long as the name is
|
|
@@ -1110,8 +1216,15 @@ async function handleShow(args) {
|
|
|
1110
1216
|
// with the disambiguation list (existing behavior in showArtifact).
|
|
1111
1217
|
let type = null;
|
|
1112
1218
|
let name;
|
|
1113
|
-
|
|
1114
|
-
|
|
1219
|
+
if (metadataMode) {
|
|
1220
|
+
name = positional.join(' ').trim();
|
|
1221
|
+
if (!name) {
|
|
1222
|
+
console.error('Error: aiwg show metadata requires an id, name, or path');
|
|
1223
|
+
console.error(HELP_TEXT);
|
|
1224
|
+
process.exit(1);
|
|
1225
|
+
}
|
|
1226
|
+
}
|
|
1227
|
+
else if (ALLOWED_TYPES.includes(firstLower)) {
|
|
1115
1228
|
type = firstLower;
|
|
1116
1229
|
name = positional.slice(1).join(' ').trim();
|
|
1117
1230
|
if (!name) {
|
|
@@ -1139,13 +1252,17 @@ async function handleShow(args) {
|
|
|
1139
1252
|
}
|
|
1140
1253
|
const graph = parseGraphFlag(flags);
|
|
1141
1254
|
const backend = parseSearchBackendFlag(flags);
|
|
1142
|
-
|
|
1255
|
+
const params = {
|
|
1143
1256
|
name,
|
|
1144
1257
|
typeFilter: type ? [type] : undefined,
|
|
1145
1258
|
json,
|
|
1146
1259
|
first,
|
|
1147
1260
|
graph,
|
|
1148
1261
|
backend,
|
|
1149
|
-
}
|
|
1262
|
+
};
|
|
1263
|
+
if (metadataMode)
|
|
1264
|
+
await showMetadata(cwd, params);
|
|
1265
|
+
else
|
|
1266
|
+
await showArtifact(cwd, params);
|
|
1150
1267
|
}
|
|
1151
1268
|
//# sourceMappingURL=cli.js.map
|
|
@@ -85,7 +85,7 @@ function matchesPath(recordPath, pattern) {
|
|
|
85
85
|
}
|
|
86
86
|
return recordPath.includes(pattern);
|
|
87
87
|
}
|
|
88
|
-
function loadFortemiCoreExport(cwd, graph = "project") {
|
|
88
|
+
export function loadFortemiCoreExport(cwd, graph = "project") {
|
|
89
89
|
let status = getFortemiCoreSyncStatus(cwd, graph);
|
|
90
90
|
if ((!status.optedIn || !status.built || status.stale) && graph === "framework") {
|
|
91
91
|
const prebuilt = getFortemiCorePrebuiltStatus(graph);
|
|
@@ -1,9 +1,16 @@
|
|
|
1
1
|
import fs from "node:fs";
|
|
2
2
|
import path from "node:path";
|
|
3
3
|
import { createHash } from "node:crypto";
|
|
4
|
+
import { GRAPH_CONFIGS, loadGlobalGraphConfigs } from "./types.js";
|
|
4
5
|
import { buildAiwgFortemiIndexExport, } from "./browser-export.js";
|
|
5
6
|
import { loadGraphIndexFile } from "./index-reader.js";
|
|
6
7
|
function syncDir(cwd, graph) {
|
|
8
|
+
loadGlobalGraphConfigs();
|
|
9
|
+
const config = GRAPH_CONFIGS[graph];
|
|
10
|
+
if (graph === "framework" || config?.shared) {
|
|
11
|
+
const xdgData = process.env.XDG_DATA_HOME ?? path.join(process.env.HOME ?? cwd, ".local", "share");
|
|
12
|
+
return path.join(xdgData, "aiwg", "index", "fortemi-core", graph);
|
|
13
|
+
}
|
|
7
14
|
return path.join(cwd, ".aiwg", ".index", "fortemi-core", graph);
|
|
8
15
|
}
|
|
9
16
|
function findPackageRoot(startDir) {
|
|
@@ -13,10 +13,29 @@ import fs from 'fs';
|
|
|
13
13
|
import path from 'path';
|
|
14
14
|
import { createHash } from 'crypto';
|
|
15
15
|
import { load as loadYaml } from 'js-yaml';
|
|
16
|
-
import { INDEX_VERSION, INDEX_DIR, PHASE_DIRECTORIES, GRAPH_CONFIGS, loadUserGraphConfigs } from './types.js';
|
|
16
|
+
import { INDEX_VERSION, INDEX_DIR, PHASE_DIRECTORIES, GRAPH_CONFIGS, loadUserGraphConfigs, loadGlobalGraphConfigs } from './types.js';
|
|
17
17
|
import { parseCitationSidecar, citationResultToEdges, buildRefToPathMap } from './citation-parser.js';
|
|
18
18
|
import { writeIndexFile, resolveIndexDir, loadGraphIndexFile } from './index-reader.js';
|
|
19
19
|
import { loadManifest, writeManifest, statMatches, makeEntry } from './checksum-manifest.js';
|
|
20
|
+
function expandScanDir(cwd, scanDir) {
|
|
21
|
+
if (scanDir === '~')
|
|
22
|
+
return process.env.HOME ?? scanDir;
|
|
23
|
+
if (scanDir.startsWith('~/')) {
|
|
24
|
+
return path.join(process.env.HOME ?? '', scanDir.slice(2));
|
|
25
|
+
}
|
|
26
|
+
if (path.isAbsolute(scanDir))
|
|
27
|
+
return scanDir;
|
|
28
|
+
return path.join(cwd, scanDir);
|
|
29
|
+
}
|
|
30
|
+
function indexPathFor(cwd, fullPath) {
|
|
31
|
+
const rel = path.relative(cwd, fullPath);
|
|
32
|
+
if (!rel.startsWith('..') && !path.isAbsolute(rel))
|
|
33
|
+
return rel;
|
|
34
|
+
return fullPath;
|
|
35
|
+
}
|
|
36
|
+
function absoluteEntryPath(cwd, entryPath) {
|
|
37
|
+
return path.isAbsolute(entryPath) ? entryPath : path.join(cwd, entryPath);
|
|
38
|
+
}
|
|
20
39
|
/**
|
|
21
40
|
* Parse YAML frontmatter from markdown content
|
|
22
41
|
*/
|
|
@@ -498,6 +517,7 @@ export async function buildIndex(cwd, options = {}) {
|
|
|
498
517
|
const startTime = Date.now();
|
|
499
518
|
// Ensure user-defined graphs are loaded
|
|
500
519
|
loadUserGraphConfigs(cwd);
|
|
520
|
+
loadGlobalGraphConfigs();
|
|
501
521
|
// Determine scan directories based on graph type
|
|
502
522
|
const graphConfig = graph ? GRAPH_CONFIGS[graph] : undefined;
|
|
503
523
|
let scanDirs;
|
|
@@ -508,7 +528,7 @@ export async function buildIndex(cwd, options = {}) {
|
|
|
508
528
|
fileExtensions = ['.md', '.yaml', '.json'];
|
|
509
529
|
}
|
|
510
530
|
else if (graphConfig) {
|
|
511
|
-
scanDirs = graphConfig.scanDirs.map(d =>
|
|
531
|
+
scanDirs = graphConfig.scanDirs.map(d => expandScanDir(cwd, d));
|
|
512
532
|
fileExtensions = graphConfig.extensions;
|
|
513
533
|
}
|
|
514
534
|
else {
|
|
@@ -548,6 +568,19 @@ export async function buildIndex(cwd, options = {}) {
|
|
|
548
568
|
fs.mkdirSync(indexOutputDir, { recursive: true });
|
|
549
569
|
// effectiveOutputCwd is used for backward-compat loadMetadataIndex calls
|
|
550
570
|
const effectiveOutputCwd = outputDir ?? cwd;
|
|
571
|
+
if (graph === 'source') {
|
|
572
|
+
const { buildSourceGraphIndex } = await import('./source-graph.js');
|
|
573
|
+
await buildSourceGraphIndex({
|
|
574
|
+
cwd,
|
|
575
|
+
outputDir: indexOutputDir,
|
|
576
|
+
effectiveOutputCwd,
|
|
577
|
+
verbose,
|
|
578
|
+
});
|
|
579
|
+
const buildTimeMs = Date.now() - startTime;
|
|
580
|
+
console.log(`Source graph built in ${buildTimeMs}ms`);
|
|
581
|
+
console.log(` Output: ${INDEX_DIR}/source/`);
|
|
582
|
+
return;
|
|
583
|
+
}
|
|
551
584
|
// Load existing index for incremental updates
|
|
552
585
|
const existingIndex = force ? null : loadGraphIndexFile(effectiveOutputCwd, 'metadata.json', graph);
|
|
553
586
|
const existingEntries = existingIndex?.entries ?? {};
|
|
@@ -577,7 +610,7 @@ export async function buildIndex(cwd, options = {}) {
|
|
|
577
610
|
let unchangedCount = 0;
|
|
578
611
|
const useFilenameMetadata = graphConfig?.nodeStrategy === 'filename-metadata';
|
|
579
612
|
for (const fullPath of files) {
|
|
580
|
-
const relativePath =
|
|
613
|
+
const relativePath = indexPathFor(cwd, fullPath);
|
|
581
614
|
let entry;
|
|
582
615
|
if (useFilenameMetadata) {
|
|
583
616
|
// Filename-metadata strategy: derive metadata from filename, skip content read.
|
|
@@ -728,7 +761,7 @@ export async function buildIndex(cwd, options = {}) {
|
|
|
728
761
|
// Build REF-XXX → path map from all entries with ref frontmatter
|
|
729
762
|
const entryFrontmatter = new Map();
|
|
730
763
|
for (const entryPath of Object.keys(entries)) {
|
|
731
|
-
const fullPath =
|
|
764
|
+
const fullPath = absoluteEntryPath(cwd, entryPath);
|
|
732
765
|
if (fs.existsSync(fullPath)) {
|
|
733
766
|
const content = fs.readFileSync(fullPath, 'utf-8');
|
|
734
767
|
const { data } = parseFrontmatter(content);
|
|
@@ -739,7 +772,7 @@ export async function buildIndex(cwd, options = {}) {
|
|
|
739
772
|
// Parse each entry as a citation sidecar and extract edges
|
|
740
773
|
let citationEdgeCount = 0;
|
|
741
774
|
for (const entryPath of Object.keys(entries)) {
|
|
742
|
-
const fullPath =
|
|
775
|
+
const fullPath = absoluteEntryPath(cwd, entryPath);
|
|
743
776
|
if (!fs.existsSync(fullPath))
|
|
744
777
|
continue;
|
|
745
778
|
const content = fs.readFileSync(fullPath, 'utf-8');
|
|
@@ -848,7 +881,7 @@ export async function buildIndex(cwd, options = {}) {
|
|
|
848
881
|
console.log(` Pruned ${manifestStats.pruned} stale manifest entries (files no longer on disk)`);
|
|
849
882
|
}
|
|
850
883
|
}
|
|
851
|
-
const displayDir = graph ?
|
|
884
|
+
const displayDir = graph ? indexOutputDir : `${INDEX_DIR}/`;
|
|
852
885
|
console.log(` Output: ${displayDir}`);
|
|
853
886
|
}
|
|
854
887
|
//# sourceMappingURL=index-builder.js.map
|
|
@@ -18,7 +18,7 @@
|
|
|
18
18
|
*/
|
|
19
19
|
import * as fs from 'node:fs';
|
|
20
20
|
import * as path from 'node:path';
|
|
21
|
-
import { GRAPH_CONFIGS, BUILTIN_GRAPH_CONFIGS, getGraphIndexDir, loadUserGraphConfigs, } from './types.js';
|
|
21
|
+
import { GRAPH_CONFIGS, BUILTIN_GRAPH_CONFIGS, getGraphIndexDir, loadGlobalGraphConfigs, loadUserGraphConfigs, } from './types.js';
|
|
22
22
|
import { getFortemiCoreSyncStatus, } from './fortemi-core-sync.js';
|
|
23
23
|
function readBuiltMeta(indexDir) {
|
|
24
24
|
try {
|
|
@@ -47,6 +47,7 @@ export function collectIndexStatus(cwd, nowMs) {
|
|
|
47
47
|
// instead of letting malformed defs vanish (#1624).
|
|
48
48
|
const warnings = [];
|
|
49
49
|
loadUserGraphConfigs(cwd, warnings);
|
|
50
|
+
loadGlobalGraphConfigs(warnings);
|
|
50
51
|
const now = nowMs ?? Date.now();
|
|
51
52
|
const graphs = [];
|
|
52
53
|
for (const [name, config] of Object.entries(GRAPH_CONFIGS)) {
|