@aiwg/cli 2026.8.8 → 2026.8.11
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 +23 -8
- package/THIRD_PARTY_NOTICES.md +35 -0
- package/agentic/code/providers/capability-matrix.yaml +3 -3
- package/bin/aiwg.mjs +125 -0
- package/dist/src/agents/packaged-agent-inventory.js +37 -1
- package/dist/src/artifacts/backends/graphology-backend.js +4 -3
- package/dist/src/artifacts/backends/sqlite-backend.js +4 -5
- package/dist/src/artifacts/cli.js +2 -2
- package/dist/src/artifacts/corpus-tools/cli.js +27 -0
- package/dist/src/artifacts/corpus-tools/profile-embed.js +3 -2
- package/dist/src/artifacts/corpus-tools/retrieval-lab.js +356 -0
- package/dist/src/artifacts/discover-facets.js +2 -2
- package/dist/src/artifacts/embedding-index.js +9 -8
- package/dist/src/artifacts/fortemi-core-sync.js +23 -8
- package/dist/src/artifacts/graph-backend.js +2 -2
- package/dist/src/artifacts/query-engine.js +21 -7
- package/dist/src/artifacts/repair.js +47 -0
- package/dist/src/artifacts/types.js +3 -3
- package/dist/src/cli/command-log.js +2 -2
- package/dist/src/cli/handlers/artifacts.js +50 -1
- package/dist/src/cli/handlers/cost-report.js +71 -0
- package/dist/src/cli/handlers/evidence.js +78 -0
- package/dist/src/cli/handlers/help.js +9 -0
- package/dist/src/cli/handlers/index.js +8 -3
- package/dist/src/cli/handlers/local-executor.js +4 -3
- package/dist/src/cli/handlers/refresh.js +63 -17
- package/dist/src/cli/handlers/regenerate.js +3 -3
- package/dist/src/cli/handlers/serve.js +15 -36
- package/dist/src/cli/handlers/setup-manifest.js +8 -1
- package/dist/src/cli/handlers/use.js +272 -70
- package/dist/src/cli/handlers/utilities.js +149 -0
- package/dist/src/cli/handlers/workspace.js +10 -0
- package/dist/src/cli/help-generator.js +2 -1
- package/dist/src/cli/router.js +4 -1
- package/dist/src/cli/services/deployment-verification.js +596 -0
- package/dist/src/cli/skill-usage.js +2 -2
- package/dist/src/cli/workflow-orchestrator.js +1 -1
- package/dist/src/cli/workspace-signals.js +2 -2
- package/dist/src/config/aiwg-config.js +54 -27
- package/dist/src/config/cli.js +3 -3
- package/dist/src/config/project-artifacts-health.js +2 -0
- package/dist/src/config/project-artifacts-health.mjs +123 -0
- package/dist/src/config/project-artifacts-runtime.mjs +16 -0
- package/dist/src/config/project-artifacts.js +2 -1
- package/dist/src/cost/fleet-report.js +329 -0
- package/dist/src/evidence/bundle.js +256 -0
- package/dist/src/extensions/commands/definitions.js +77 -25
- package/dist/src/extensions/deployment-registration.js +6 -4
- package/dist/src/features/catalog.js +26 -0
- package/dist/src/features/cli.js +1 -3
- package/dist/src/features/runtime.js +17 -1
- package/dist/src/issues/cli.js +91 -7
- package/dist/src/mcp/server.mjs +1 -1
- package/dist/src/ops/registry.js +2 -2
- package/dist/src/policy/authorization.js +2 -2
- package/dist/src/providers/capability-matrix.yaml +3 -3
- package/dist/src/providers/provider-definitions.js +7 -5
- package/dist/src/providers/provider-definitions.mjs +1 -1
- package/dist/src/serve/pty-bridge.js +2 -8
- package/dist/src/serve/screen-reader.js +3 -6
- package/dist/src/smiths/context-pipeline/aiwg-md.js +2 -2
- package/dist/src/smiths/context-pipeline/finalization.js +18 -5
- package/dist/src/smiths/context-pipeline/generator.js +2 -2
- package/dist/src/smiths/context-pipeline/workspace-context.js +16 -17
- package/package.json +2 -1
- package/tools/agents/deploy-agents.mjs +10 -11
- package/tools/agents/providers/base.mjs +61 -7
- package/tools/agents/providers/openclaw.mjs +5 -2
- package/tools/agents/providers/windsurf.mjs +13 -24
- package/tools/skills/deploy-skills-codex.mjs +21 -5
package/dist/src/issues/cli.js
CHANGED
|
@@ -8,6 +8,10 @@
|
|
|
8
8
|
* @issue #1462
|
|
9
9
|
*/
|
|
10
10
|
import { readFile, writeFile } from 'fs/promises';
|
|
11
|
+
import path from 'node:path';
|
|
12
|
+
import { pathToFileURL } from 'node:url';
|
|
13
|
+
import { getFrameworkRoot } from '../channel/manager.mjs';
|
|
14
|
+
import { readAiwgConfig } from '../config/aiwg-config.js';
|
|
11
15
|
import { LocalIssueProviderCore, buildExternalIssueSnapshotFromLocal, buildLocalIssueConflictReport, createLiveIssueClient, localIssueRoot, parseCommentIdMappings, parseExternalIssueSnapshot, } from './index.js';
|
|
12
16
|
export async function main(args, cwd = process.cwd()) {
|
|
13
17
|
const parsed = parseArgs(args);
|
|
@@ -27,7 +31,11 @@ export async function main(args, cwd = process.cwd()) {
|
|
|
27
31
|
return;
|
|
28
32
|
case 'new':
|
|
29
33
|
case 'create':
|
|
30
|
-
await handleNew(issues, parsed);
|
|
34
|
+
await handleNew(issues, parsed, cwd);
|
|
35
|
+
return;
|
|
36
|
+
case 'plan':
|
|
37
|
+
case 'draft-plan':
|
|
38
|
+
await handlePlan(parsed, cwd);
|
|
31
39
|
return;
|
|
32
40
|
case 'list':
|
|
33
41
|
case 'ls':
|
|
@@ -68,12 +76,19 @@ async function handleInit(issues, args) {
|
|
|
68
76
|
});
|
|
69
77
|
printJsonOrText(args, config, `Initialized local issues with prefix ${config.issue_key.prefix}`);
|
|
70
78
|
}
|
|
71
|
-
async function
|
|
79
|
+
async function loadIssueComposer() {
|
|
80
|
+
const frameworkRoot = await getFrameworkRoot();
|
|
81
|
+
const modulePath = path.join(frameworkRoot, 'tools', 'issues', 'policy-boundary-composer.mjs');
|
|
82
|
+
return import(pathToFileURL(modulePath).href);
|
|
83
|
+
}
|
|
84
|
+
async function buildIssuePlan(args, cwd) {
|
|
72
85
|
const title = stringFlag(args, 'title') ?? args.positional[1];
|
|
73
86
|
if (!title)
|
|
74
|
-
throw new Error('Usage: aiwg issue
|
|
87
|
+
throw new Error('Usage: aiwg issue plan --title <title> [--body <text>|--body-file <path>]');
|
|
75
88
|
const body = await readBody(args);
|
|
76
|
-
const
|
|
89
|
+
const config = await readAiwgConfig(cwd);
|
|
90
|
+
const composer = await loadIssueComposer();
|
|
91
|
+
return composer.planIssueDraft({
|
|
77
92
|
title,
|
|
78
93
|
body,
|
|
79
94
|
type: stringFlag(args, 'type'),
|
|
@@ -81,8 +96,76 @@ async function handleNew(issues, args) {
|
|
|
81
96
|
labels: csvFlag(args, 'label'),
|
|
82
97
|
assignees: csvFlag(args, 'assignee'),
|
|
83
98
|
author: stringFlag(args, 'author'),
|
|
84
|
-
});
|
|
85
|
-
|
|
99
|
+
}, { threatAssessment: config?.security?.threatAssessment });
|
|
100
|
+
}
|
|
101
|
+
async function handlePlan(args, cwd) {
|
|
102
|
+
const plan = await buildIssuePlan(args, cwd);
|
|
103
|
+
console.log(JSON.stringify(plan, null, 2));
|
|
104
|
+
}
|
|
105
|
+
async function handleNew(issues, args, cwd) {
|
|
106
|
+
const plan = await buildIssuePlan(args, cwd);
|
|
107
|
+
if (plan.disposition === 'blocked') {
|
|
108
|
+
throw new Error(`Issue draft rejected by ${plan.blockingRule}; no issue was written. Run aiwg issue plan to inspect suggested segments.`);
|
|
109
|
+
}
|
|
110
|
+
const authorizationDigest = stringFlag(args, 'authorize-policy');
|
|
111
|
+
if (plan.authorizationRequired && authorizationDigest !== plan.digest) {
|
|
112
|
+
throw new Error(`Issue draft requires explicit policy authorization. Review 'aiwg issue plan', then pass --authorize-policy ${plan.digest}. No issue was written.`);
|
|
113
|
+
}
|
|
114
|
+
const composer = await loadIssueComposer();
|
|
115
|
+
const records = new Map();
|
|
116
|
+
const adapter = {
|
|
117
|
+
async findByMarker(marker) {
|
|
118
|
+
const listed = await issues.listIssues({ limit: 10_000 });
|
|
119
|
+
for (const entry of listed.issues) {
|
|
120
|
+
const record = await issues.getIssue(entry.id, { body: true, comments: 0 });
|
|
121
|
+
if (record.body.includes(marker)) {
|
|
122
|
+
records.set(record.fields.id, record);
|
|
123
|
+
return { id: record.fields.id, reference: record.fields.id, body: record.body };
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
return null;
|
|
127
|
+
},
|
|
128
|
+
async create(draft) {
|
|
129
|
+
const record = await issues.createIssue({
|
|
130
|
+
title: draft.title,
|
|
131
|
+
body: draft.body,
|
|
132
|
+
type: stringFlag(args, 'type'),
|
|
133
|
+
priority: stringFlag(args, 'priority'),
|
|
134
|
+
labels: draft.labels,
|
|
135
|
+
assignees: draft.assignees,
|
|
136
|
+
author: stringFlag(args, 'author'),
|
|
137
|
+
});
|
|
138
|
+
records.set(record.fields.id, record);
|
|
139
|
+
return { id: record.fields.id, reference: record.fields.id, body: record.body };
|
|
140
|
+
},
|
|
141
|
+
async update(issue, patch) {
|
|
142
|
+
const record = records.get(issue.id) ?? await issues.getIssue(issue.id, { body: true, comments: 0 });
|
|
143
|
+
const references = [...patch.body.matchAll(/(?:Depends on|Related):\s+([A-Z][A-Z0-9_-]*-\d+)/g)]
|
|
144
|
+
.map((match) => match[1])
|
|
145
|
+
.filter((reference) => reference !== issue.id);
|
|
146
|
+
await issues.updateIssueFields(issue.id, {
|
|
147
|
+
links: {
|
|
148
|
+
...record.fields.links,
|
|
149
|
+
related: [...new Set([...record.fields.links.related, ...references])],
|
|
150
|
+
parent: patch.body.match(/Depends on:\s+([A-Z][A-Z0-9_-]*-\d+)/)?.[1] ?? record.fields.links.parent,
|
|
151
|
+
},
|
|
152
|
+
});
|
|
153
|
+
await issues.commentIssue(issue.id, patch.body.slice(patch.body.indexOf('## Related')), {
|
|
154
|
+
author: stringFlag(args, 'author') ?? 'aiwg',
|
|
155
|
+
});
|
|
156
|
+
},
|
|
157
|
+
};
|
|
158
|
+
const result = await composer.executeIssuePlan(plan, adapter, { authorizationDigest });
|
|
159
|
+
if (result.status !== 'created') {
|
|
160
|
+
throw new Error(`Issue creation ${result.status}: ${result.error ?? 'review the recovery envelope'}\n${JSON.stringify(result.recovery ?? result, null, 2)}`);
|
|
161
|
+
}
|
|
162
|
+
if (args.flags.has('json') || result.created.length > 1) {
|
|
163
|
+
console.log(JSON.stringify(result, null, 2));
|
|
164
|
+
}
|
|
165
|
+
else {
|
|
166
|
+
const issue = result.created[0];
|
|
167
|
+
console.log(`Created ${issue.reference}: ${plan.segments[0].title}`);
|
|
168
|
+
}
|
|
86
169
|
}
|
|
87
170
|
async function handleList(issues, args) {
|
|
88
171
|
const limit = stringFlag(args, 'limit');
|
|
@@ -313,7 +396,8 @@ function csvFlag(args, name) {
|
|
|
313
396
|
function printUsage() {
|
|
314
397
|
console.log(`Usage:
|
|
315
398
|
aiwg issue init [--prefix KEY] [--padding N]
|
|
316
|
-
aiwg issue
|
|
399
|
+
aiwg issue plan --title "..." [--body "..."] [--body-file path] [--json]
|
|
400
|
+
aiwg issue new --title "..." [--body "..."] [--body-file path] [--authorize-policy DIGEST]
|
|
317
401
|
aiwg issue list [--status open] [--label bug] [--search text] [--limit 20] [--json]
|
|
318
402
|
aiwg issue show <KEY> [--comments last:10|all]
|
|
319
403
|
aiwg issue import --from gitea|github --snapshot-file path [--json]
|
package/dist/src/mcp/server.mjs
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
* @see https://modelcontextprotocol.io/specification/2025-11-25
|
|
8
8
|
* @architecture @.aiwg/architecture/software-architecture-doc.md - Section 2.1 CLI Layer
|
|
9
9
|
* @reference @docs/references/REF-066-mcp-specification-2025.md
|
|
10
|
-
* @cli @docs/
|
|
10
|
+
* @cli @docs/cli/agent-usage.md - mcp serve command
|
|
11
11
|
* @frameworks @agentic/code/frameworks/sdlc-complete/
|
|
12
12
|
* @frameworks @agentic/code/frameworks/media-marketing-kit/
|
|
13
13
|
*/
|
package/dist/src/ops/registry.js
CHANGED
|
@@ -13,7 +13,7 @@ import { existsSync, readFileSync, readdirSync, statSync } from 'fs';
|
|
|
13
13
|
import { execSync } from 'child_process';
|
|
14
14
|
import { resolveConfigDir } from '../config/user-config.js';
|
|
15
15
|
import { resolveWorkspace } from '../config/workspace.js';
|
|
16
|
-
import {
|
|
16
|
+
import { projectControlPath } from '../config/project-artifacts.js';
|
|
17
17
|
/**
|
|
18
18
|
* Extension type abbreviations
|
|
19
19
|
*/
|
|
@@ -455,7 +455,7 @@ export class OpsRegistry {
|
|
|
455
455
|
throw new Error(`Workspace "${name}" not found`);
|
|
456
456
|
}
|
|
457
457
|
let canonical = null;
|
|
458
|
-
const canonicalConfigPath =
|
|
458
|
+
const canonicalConfigPath = projectControlPath(workspace.home, 'aiwg.config');
|
|
459
459
|
let canonicalDeclared = false;
|
|
460
460
|
if (existsSync(canonicalConfigPath)) {
|
|
461
461
|
try {
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
import { access, copyFile, mkdir, readFile, rename } from 'node:fs/promises';
|
|
10
10
|
import { isAbsolute, join, relative, resolve } from 'node:path';
|
|
11
11
|
import { load as loadYaml } from 'js-yaml';
|
|
12
|
-
import { projectAiwgPath } from '../config/project-artifacts.js';
|
|
12
|
+
import { projectAiwgPath, projectControlPath } from '../config/project-artifacts.js';
|
|
13
13
|
/**
|
|
14
14
|
* Export provider mappings without inventing provider grants. Stable IDs,
|
|
15
15
|
* principals, scopes, resources, actions, and conditions survive unchanged;
|
|
@@ -375,7 +375,7 @@ export async function archiveLegacyPermissionManifests(projectDir) {
|
|
|
375
375
|
return archived;
|
|
376
376
|
}
|
|
377
377
|
export async function backupConfig(projectDir) {
|
|
378
|
-
const source =
|
|
378
|
+
const source = projectControlPath(projectDir, 'aiwg.config');
|
|
379
379
|
const backupDir = projectAiwgPath(projectDir, 'backups');
|
|
380
380
|
await mkdir(backupDir, { recursive: true });
|
|
381
381
|
const content = await readFile(source);
|
|
@@ -323,9 +323,9 @@ providers:
|
|
|
323
323
|
aggregated_output: true
|
|
324
324
|
|
|
325
325
|
windsurf:
|
|
326
|
-
display_name:
|
|
327
|
-
status:
|
|
328
|
-
# Windsurf
|
|
326
|
+
display_name: Devin Desktop
|
|
327
|
+
status: stable
|
|
328
|
+
# Devin Desktop uses the Windsurf compatibility surface and requires a VS Code host — daemon not supported
|
|
329
329
|
daemon_tier: unsupported
|
|
330
330
|
daemon_pty_adapter: false
|
|
331
331
|
artifact_paths:
|
|
@@ -704,11 +704,13 @@ const BUILT_IN_SEEDS = [
|
|
|
704
704
|
},
|
|
705
705
|
{
|
|
706
706
|
id: 'windsurf',
|
|
707
|
-
|
|
707
|
+
displayName: 'Devin Desktop',
|
|
708
|
+
status: 'stable',
|
|
709
|
+
aliases: ['devin', 'devin-desktop', 'devin-local', 'cascade'],
|
|
708
710
|
builtIn: true,
|
|
709
711
|
surfaces: {
|
|
710
|
-
primary: '
|
|
711
|
-
compatibility: ['devin-desktop', 'devin-local', 'cascade'],
|
|
712
|
+
primary: 'devin',
|
|
713
|
+
compatibility: ['devin-desktop', 'windsurf', 'devin-local', 'cascade'],
|
|
712
714
|
precedence: ['.devin/rules/', '.windsurf/rules/', 'AGENTS.md', '.windsurfrules'],
|
|
713
715
|
related: [
|
|
714
716
|
{
|
|
@@ -716,7 +718,7 @@ const BUILT_IN_SEEDS = [
|
|
|
716
718
|
displayName: 'Devin Desktop',
|
|
717
719
|
relationship: 'same-provider',
|
|
718
720
|
deployable: true,
|
|
719
|
-
aliases: ['windsurf', 'cascade'],
|
|
721
|
+
aliases: ['devin', 'windsurf', 'cascade'],
|
|
720
722
|
paths: {
|
|
721
723
|
rules: ['.devin/rules/*.md', '.windsurf/rules/*.md'],
|
|
722
724
|
skills: [],
|
|
@@ -724,7 +726,7 @@ const BUILT_IN_SEEDS = [
|
|
|
724
726
|
legacy: ['.windsurfrules'],
|
|
725
727
|
},
|
|
726
728
|
notes: [
|
|
727
|
-
'Devin Desktop is the
|
|
729
|
+
'Devin Desktop is the current product name; --provider devin is preferred and --provider windsurf remains a deprecated compatibility id.',
|
|
728
730
|
'.devin/rules is preferred by Devin Desktop, but AIWG keeps .devin/ as ignored local provider output and currently emits the compatibility surface through .windsurf/ plus AGENTS.md.',
|
|
729
731
|
],
|
|
730
732
|
},
|
|
@@ -288,16 +288,10 @@ async function spawnSandboxWsPty(session, agentId, wsEndpoint, opts) {
|
|
|
288
288
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
289
289
|
let wsMod;
|
|
290
290
|
try {
|
|
291
|
-
wsMod = await (
|
|
291
|
+
wsMod = await loadFeaturePackage('ws');
|
|
292
292
|
}
|
|
293
293
|
catch {
|
|
294
|
-
|
|
295
|
-
// @ts-expect-error Optional runtime dependency; this workspace does not ship @types/ws.
|
|
296
|
-
wsMod = await import('ws');
|
|
297
|
-
}
|
|
298
|
-
catch {
|
|
299
|
-
throw new Error('ws package required for sandbox PTY bridge. Run: npm install ws');
|
|
300
|
-
}
|
|
294
|
+
throw new Error('WebSocket support is required for the sandbox PTY bridge; run `aiwg features install webserver`');
|
|
301
295
|
}
|
|
302
296
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
303
297
|
const WS = wsMod.WebSocket ?? wsMod.default?.WebSocket ?? wsMod.default;
|
|
@@ -10,15 +10,12 @@
|
|
|
10
10
|
* @see src/serve/pty-bridge.ts — PTY WebSocket bridge
|
|
11
11
|
*/
|
|
12
12
|
import { EventEmitter } from 'events';
|
|
13
|
-
import {
|
|
14
|
-
// @xterm/headless is an optional dependency. Load it once at module level
|
|
15
|
-
// using createRequire so we can import the CJS bundle from ESM.
|
|
16
|
-
const _require = createRequire(import.meta.url);
|
|
13
|
+
import { requireFeaturePackage } from '../features/runtime.js';
|
|
17
14
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
18
15
|
let XtermTerminal;
|
|
19
16
|
try {
|
|
20
17
|
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
21
|
-
const xterm =
|
|
18
|
+
const xterm = requireFeaturePackage('@xterm/headless');
|
|
22
19
|
XtermTerminal = xterm.Terminal;
|
|
23
20
|
}
|
|
24
21
|
catch {
|
|
@@ -48,7 +45,7 @@ export class ScreenReader {
|
|
|
48
45
|
disposed = false;
|
|
49
46
|
constructor(opts) {
|
|
50
47
|
if (!XtermTerminal) {
|
|
51
|
-
throw new Error('
|
|
48
|
+
throw new Error('Terminal screen parsing is unavailable; run `aiwg features install terminal`');
|
|
52
49
|
}
|
|
53
50
|
this._rows = opts?.rows ?? 24;
|
|
54
51
|
this._cols = opts?.cols ?? 80;
|
|
@@ -16,7 +16,7 @@
|
|
|
16
16
|
*/
|
|
17
17
|
import { promises as fs } from 'node:fs';
|
|
18
18
|
import * as path from 'node:path';
|
|
19
|
-
import {
|
|
19
|
+
import { projectControlPath } from '../../config/project-artifacts.js';
|
|
20
20
|
import { buildParallelismSection, replaceOrAppendParallelismBlock } from './parallelism-section.js';
|
|
21
21
|
import { buildContextFinalizationBlock, replaceOrAppendFinalizationBlock } from './finalization.js';
|
|
22
22
|
import { buildExternalLinksSection, replaceOrAppendExternalLinksBlock, } from './external-links-section.js';
|
|
@@ -79,7 +79,7 @@ export async function buildAiwgMdContent(projectPath, stagedClaudeMdContent) {
|
|
|
79
79
|
return replaceOrAppendExternalLinksBlock(withFinalization, externalLinksSection);
|
|
80
80
|
}
|
|
81
81
|
// Fallback stub.
|
|
82
|
-
const normalizedPath =
|
|
82
|
+
const normalizedPath = projectControlPath(projectPath, 'AIWG.md');
|
|
83
83
|
const normalizedRelative = path.relative(projectPath, normalizedPath).replace(/\\/g, '/');
|
|
84
84
|
const normalizedLink = normalizedRelative.startsWith('.') ? normalizedRelative : `./${normalizedRelative}`;
|
|
85
85
|
const stub = [
|
|
@@ -10,7 +10,7 @@ import * as path from 'node:path';
|
|
|
10
10
|
import { execFile } from 'node:child_process';
|
|
11
11
|
import { promisify } from 'node:util';
|
|
12
12
|
import { readAiwgConfig } from '../../config/aiwg-config.js';
|
|
13
|
-
import { projectAiwgPath } from '../../config/project-artifacts.js';
|
|
13
|
+
import { projectAiwgPath, projectControlPath, resolveProjectAiwgDir, } from '../../config/project-artifacts.js';
|
|
14
14
|
import { renderTrackerProtocol, resolveTrackerAuthority } from '../../tracker/capability-protocol.js';
|
|
15
15
|
import { buildExternalLinksSection, replaceOrAppendExternalLinksBlock, } from './external-links-section.js';
|
|
16
16
|
export const FINALIZATION_START = '<!-- aiwg-context-finalization:START -->';
|
|
@@ -61,7 +61,7 @@ export async function buildContextFinalizationBlock(projectPath) {
|
|
|
61
61
|
const installed = Object.entries(config?.installed ?? {});
|
|
62
62
|
const installedNames = installed.map(([name]) => name);
|
|
63
63
|
const providerDeployments = new Set();
|
|
64
|
-
const normalizedAiwgMdPath = displayProjectPath(projectPath,
|
|
64
|
+
const normalizedAiwgMdPath = displayProjectPath(projectPath, projectControlPath(projectPath, 'AIWG.md'));
|
|
65
65
|
const normalizedAiwgMdLabel = `\`${normalizedAiwgMdPath}\``;
|
|
66
66
|
for (const [, entry] of installed) {
|
|
67
67
|
for (const provider of Object.keys(entry.deployedTo ?? {})) {
|
|
@@ -114,7 +114,7 @@ export function replaceOrAppendFinalizationBlock(content, block) {
|
|
|
114
114
|
export async function buildNormalizedAiwgMd(projectPath, existing = '') {
|
|
115
115
|
const block = await buildContextFinalizationBlock(projectPath);
|
|
116
116
|
const externalLinksSection = await buildExternalLinksSection(projectPath);
|
|
117
|
-
const normalizedAiwgMdPath = displayProjectPath(projectPath,
|
|
117
|
+
const normalizedAiwgMdPath = displayProjectPath(projectPath, projectControlPath(projectPath, 'AIWG.md'));
|
|
118
118
|
const base = existing.trim().length > 0
|
|
119
119
|
? existing
|
|
120
120
|
: [
|
|
@@ -132,7 +132,7 @@ export async function buildNormalizedAiwgMd(projectPath, existing = '') {
|
|
|
132
132
|
return replaceOrAppendExternalLinksBlock(withFinalization, externalLinksSection);
|
|
133
133
|
}
|
|
134
134
|
export async function writeNormalizedAiwgMd(projectPath) {
|
|
135
|
-
const targetPath =
|
|
135
|
+
const targetPath = projectControlPath(projectPath, 'AIWG.md');
|
|
136
136
|
let existing = '';
|
|
137
137
|
try {
|
|
138
138
|
existing = await fs.readFile(targetPath, 'utf8');
|
|
@@ -143,7 +143,20 @@ export async function writeNormalizedAiwgMd(projectPath) {
|
|
|
143
143
|
}
|
|
144
144
|
const content = await buildNormalizedAiwgMd(projectPath, existing);
|
|
145
145
|
await fs.mkdir(path.dirname(targetPath), { recursive: true });
|
|
146
|
-
|
|
146
|
+
const normalizedContent = content.endsWith('\n') ? content : `${content}\n`;
|
|
147
|
+
await fs.writeFile(targetPath, normalizedContent, 'utf8');
|
|
148
|
+
const artifactRoot = resolveProjectAiwgDir(projectPath);
|
|
149
|
+
const artifactPath = projectAiwgPath(projectPath, 'AIWG.md');
|
|
150
|
+
if (artifactPath !== targetPath) {
|
|
151
|
+
try {
|
|
152
|
+
await fs.access(artifactRoot);
|
|
153
|
+
await fs.writeFile(artifactPath, normalizedContent, 'utf8');
|
|
154
|
+
}
|
|
155
|
+
catch (error) {
|
|
156
|
+
if (error.code !== 'ENOENT')
|
|
157
|
+
throw error;
|
|
158
|
+
}
|
|
159
|
+
}
|
|
147
160
|
return targetPath;
|
|
148
161
|
}
|
|
149
162
|
//# sourceMappingURL=finalization.js.map
|
|
@@ -21,7 +21,7 @@ import { shouldEmitAgentsMd, shouldEmitAiwgMd, shouldEmitClaudeMdHook } from './
|
|
|
21
21
|
import { ensureClaudeMdHook } from './claude-hook.js';
|
|
22
22
|
import { ensureManagedHook } from './managed-hook.js';
|
|
23
23
|
import { buildProviderBootstrapBlock, ensureWorkspaceContext, registerProviderContext, } from './workspace-context.js';
|
|
24
|
-
import {
|
|
24
|
+
import { projectControlPath } from '../../config/project-artifacts.js';
|
|
25
25
|
const SECTION_TITLES = {
|
|
26
26
|
agents: 'Agents',
|
|
27
27
|
rules: 'Rules',
|
|
@@ -137,7 +137,7 @@ export async function buildAgentsMd(opts) {
|
|
|
137
137
|
parts.push('');
|
|
138
138
|
parts.push('See [AIWG.md](./AIWG.md) for the full AIWG framework context');
|
|
139
139
|
parts.push('(active frameworks, addons, agents, behaviors, rules).');
|
|
140
|
-
const configRelative = path.relative(opts.projectPath,
|
|
140
|
+
const configRelative = path.relative(opts.projectPath, projectControlPath(opts.projectPath, 'aiwg.config')).replace(/\\/g, '/');
|
|
141
141
|
const configLink = configRelative.startsWith('.') ? configRelative : `./${configRelative}`;
|
|
142
142
|
parts.push(`Tracker and delivery source of truth: [${configRelative}](${configLink}).`);
|
|
143
143
|
parts.push('');
|
|
@@ -12,7 +12,8 @@ import * as path from 'node:path';
|
|
|
12
12
|
import { buildAiwgMdContent } from './aiwg-md.js';
|
|
13
13
|
import { buildNormalizedAiwgMd } from './finalization.js';
|
|
14
14
|
import { getProviderDefinition, listProviderDefinitions, } from '../../providers/provider-definitions.js';
|
|
15
|
-
import {
|
|
15
|
+
import { readAiwgConfig } from '../../config/aiwg-config.js';
|
|
16
|
+
import { projectAiwgPath, projectControlPath, resolveProjectAiwgDir, } from '../../config/project-artifacts.js';
|
|
16
17
|
export const WORKSPACE_MANAGED_START = '<!-- AIWG:workspace-context:start -->';
|
|
17
18
|
export const WORKSPACE_MANAGED_END = '<!-- AIWG:workspace-context:end -->';
|
|
18
19
|
export const WORKSPACE_OPERATOR_START = '<!-- AIWG:workspace-operator:start -->';
|
|
@@ -306,8 +307,8 @@ function providerForPath(relativePath) {
|
|
|
306
307
|
}
|
|
307
308
|
return null;
|
|
308
309
|
}
|
|
309
|
-
function
|
|
310
|
-
const rel = path.relative(projectPath,
|
|
310
|
+
function projectControlMarkdownPath(projectPath, ...segments) {
|
|
311
|
+
const rel = path.relative(projectPath, projectControlPath(projectPath, ...segments)).replace(/\\/g, '/');
|
|
311
312
|
if (rel === '')
|
|
312
313
|
return '.';
|
|
313
314
|
return rel.startsWith('.') ? rel : `./${rel}`;
|
|
@@ -315,14 +316,15 @@ function projectArtifactMarkdownPath(projectPath, ...segments) {
|
|
|
315
316
|
function workspaceLinks(projectPath, providerFiles = []) {
|
|
316
317
|
const links = new Set([
|
|
317
318
|
'[AIWG framework context](./AIWG.md)',
|
|
318
|
-
`[AIWG project configuration](${
|
|
319
|
+
`[AIWG project configuration](${projectControlMarkdownPath(projectPath, 'aiwg.config')})`,
|
|
319
320
|
]);
|
|
320
321
|
if (providerFiles.length > 0) {
|
|
321
322
|
for (const file of providerFiles)
|
|
322
323
|
links.add(`[Provider-specific context](./${file.replace(/\\/g, '/')})`);
|
|
323
324
|
}
|
|
324
|
-
//
|
|
325
|
-
|
|
325
|
+
// Keep the logical project path portable in committed context. Runtime
|
|
326
|
+
// quickref readers follow `.aiwg-location` to the external corpus.
|
|
327
|
+
links.add('[Project-local quickref](.aiwg/quickref.json) (when configured)');
|
|
326
328
|
return [...links];
|
|
327
329
|
}
|
|
328
330
|
export function buildWorkspaceManagedBlock(projectPath, providerFiles = []) {
|
|
@@ -692,16 +694,13 @@ function providerMigrationContent(source) {
|
|
|
692
694
|
].join('\n');
|
|
693
695
|
}
|
|
694
696
|
async function configuredProviders(projectPath) {
|
|
695
|
-
|
|
696
|
-
|
|
697
|
-
|
|
698
|
-
|
|
699
|
-
|
|
700
|
-
|
|
701
|
-
|
|
702
|
-
catch {
|
|
703
|
-
// Audit/migration reports malformed provider config through the normal CLI path.
|
|
704
|
-
}
|
|
697
|
+
try {
|
|
698
|
+
const config = await readAiwgConfig(projectPath);
|
|
699
|
+
if (config)
|
|
700
|
+
return config.providers.filter((provider) => typeof provider === 'string');
|
|
701
|
+
}
|
|
702
|
+
catch {
|
|
703
|
+
// Audit/migration reports malformed provider config through the normal CLI path.
|
|
705
704
|
}
|
|
706
705
|
return ['claude'];
|
|
707
706
|
}
|
|
@@ -783,7 +782,7 @@ async function stageMigrationWrites(projectPath, audit, options = {}) {
|
|
|
783
782
|
writes.set(configPath, `${JSON.stringify(config, null, 2)}\n`);
|
|
784
783
|
}
|
|
785
784
|
if (options.includeGeneratedContext) {
|
|
786
|
-
const normalizedPath = projectOutputPath(projectPath,
|
|
785
|
+
const normalizedPath = projectOutputPath(projectPath, projectControlPath(projectPath, 'AIWG.md'));
|
|
787
786
|
const existingNormalized = await readOptional(path.join(projectPath, normalizedPath)) ?? '';
|
|
788
787
|
writes.set(normalizedPath, await buildNormalizedAiwgMd(projectPath, existingNormalized));
|
|
789
788
|
const stagedClaude = writes.has('CLAUDE.md')
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aiwg/cli",
|
|
3
|
-
"version": "2026.8.
|
|
3
|
+
"version": "2026.8.11",
|
|
4
4
|
"description": "Lightweight AIWG CLI for signed, versioned web-backed resources.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -24,6 +24,7 @@
|
|
|
24
24
|
},
|
|
25
25
|
"files": [
|
|
26
26
|
"LICENSE",
|
|
27
|
+
"THIRD_PARTY_NOTICES.md",
|
|
27
28
|
"bin/",
|
|
28
29
|
"agentic/code/providers/",
|
|
29
30
|
"dist/src/",
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
* --rules-only Deploy only rules (skip agents)
|
|
21
21
|
* --dry-run Show what would be deployed without writing
|
|
22
22
|
* --force Overwrite existing files
|
|
23
|
-
* --provider <name> Target provider: claude (default), openai, codex, cursor, opencode, copilot, factory, warp,
|
|
23
|
+
* --provider <name> Target provider: claude (default), openai, codex, cursor, opencode, copilot, factory, warp, devin, hermes, or openclaw
|
|
24
24
|
* --model <name> Override model for all tiers (blanket)
|
|
25
25
|
* --reasoning-model <name> Override model for reasoning tasks
|
|
26
26
|
* --coding-model <name> Override model for coding tasks
|
|
@@ -49,7 +49,8 @@
|
|
|
49
49
|
* copilot - GitHub Copilot - .github/agents/, .github/commands/, .github/skills/, .github/copilot-rules/
|
|
50
50
|
* cursor - Cursor IDE - .cursor/agents/, .cursor/commands/, .cursor/skills/, .cursor/rules/
|
|
51
51
|
* warp - Warp Terminal - .warp/agents/, .warp/commands/, .warp/skills/, .warp/rules/ + WARP.md
|
|
52
|
-
*
|
|
52
|
+
* devin - Devin Desktop - .windsurf/agents/, .windsurf/workflows/, .windsurf/skills/, .windsurf/rules/
|
|
53
|
+
* windsurf - Deprecated alias for devin
|
|
53
54
|
* openclaw - OpenClaw - ~/.openclaw/agents/, ~/.openclaw/commands/, ~/.openclaw/skills/, ~/.openclaw/rules/, ~/.openclaw/behaviors/
|
|
54
55
|
*
|
|
55
56
|
* Defaults:
|
|
@@ -103,6 +104,7 @@ function getDeployVersion(srcRoot) {
|
|
|
103
104
|
|
|
104
105
|
const PROVIDER_ALIASES = {
|
|
105
106
|
'openai': 'codex',
|
|
107
|
+
'devin': 'windsurf',
|
|
106
108
|
'devin-desktop': 'windsurf',
|
|
107
109
|
'devin-local': 'windsurf',
|
|
108
110
|
'cascade': 'windsurf',
|
|
@@ -111,15 +113,9 @@ const PROVIDER_ALIASES = {
|
|
|
111
113
|
const AVAILABLE_PROVIDERS = ['claude', 'factory', 'codex', 'opencode', 'copilot', 'cursor', 'warp', 'windsurf', 'hermes', 'openclaw', 'openhuman'];
|
|
112
114
|
|
|
113
115
|
const UNSUPPORTED_PROVIDER_HINTS = {
|
|
114
|
-
devin: [
|
|
115
|
-
'Devin Desktop is supported through the Windsurf compatibility adapter:',
|
|
116
|
-
' aiwg use sdlc --provider windsurf',
|
|
117
|
-
' aiwg use sdlc --provider devin-desktop',
|
|
118
|
-
'Devin CLI has distinct rules/skills surfaces and is recorded as future-provider metadata; AIWG does not emit .devin/ provider output yet.',
|
|
119
|
-
],
|
|
120
116
|
'devin-cli': [
|
|
121
117
|
'Devin CLI has distinct rules/skills surfaces and is not a deployable AIWG provider yet.',
|
|
122
|
-
'Use --provider
|
|
118
|
+
'Use --provider devin for Devin Desktop deployments.',
|
|
123
119
|
],
|
|
124
120
|
};
|
|
125
121
|
|
|
@@ -531,7 +527,7 @@ Providers (all deploy agents, commands, skills, and rules):
|
|
|
531
527
|
Paths: .cursor/agents/, .cursor/commands/, .cursor/skills/, .cursor/rules/
|
|
532
528
|
warp - Warp Terminal
|
|
533
529
|
Paths: .warp/agents/, .warp/commands/, .warp/skills/, .warp/rules/ + WARP.md
|
|
534
|
-
|
|
530
|
+
devin - Devin Desktop (preferred; aliases: devin-desktop, windsurf)
|
|
535
531
|
Paths: .windsurf/agents/, .windsurf/workflows/, .windsurf/skills/, .windsurf/rules/
|
|
536
532
|
hermes - Hermes Agent (MCP-based integration)
|
|
537
533
|
Skills: ~/.hermes/skills/ (user-global) | Agents: AGENTS.md (lean routing guide)
|
|
@@ -865,7 +861,10 @@ export async function main() {
|
|
|
865
861
|
srcRoot,
|
|
866
862
|
target: cfg.target,
|
|
867
863
|
mode: cfg.mode,
|
|
868
|
-
|
|
864
|
+
// Provider aliases are selectors, not artifact identities. Passing the
|
|
865
|
+
// canonical id keeps generated frontmatter byte-identical for devin,
|
|
866
|
+
// devin-desktop, and the deprecated windsurf selector.
|
|
867
|
+
provider: resolveProvider(cfg.provider),
|
|
869
868
|
dryRun: cfg.dryRun,
|
|
870
869
|
force: cfg.force,
|
|
871
870
|
reasoningModel: cfg.reasoningModel,
|