artifact-chain-assistant 0.14.2 → 0.15.0
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/.claude-plugin/plugin.json +1 -1
- package/.codex-plugin/plugin.json +1 -1
- package/.kimi-plugin/plugin.json +1 -1
- package/CHANGELOG.md +10 -0
- package/EXTENDED-ARTIFACT-CATALOG.md +12 -8
- package/EXTENDED-ARTIFACT-CATALOG.zh-CN.md +12 -10
- package/INSTALL.md +39 -17
- package/README.md +10 -6
- package/README.zh-CN.md +7 -5
- package/adapters/claude/.claude-plugin/plugin.json +1 -1
- package/adapters/claude/EXTENDED-ARTIFACT-CATALOG.md +12 -8
- package/adapters/claude/EXTENDED-ARTIFACT-CATALOG.zh-CN.md +12 -10
- package/adapters/claude/INSTALL.md +39 -17
- package/adapters/claude/agent-methods/catalog.yaml +1 -1
- package/adapters/claude/compatibility.json +4 -4
- package/adapters/claude/family-apis/catalog.json +1 -1
- package/adapters/claude/scripts/batch-merge.mjs +2 -1
- package/adapters/claude/scripts/batch-split.mjs +2 -1
- package/adapters/claude/scripts/check-workflow-profile.mjs +2 -1
- package/adapters/claude/scripts/lib/adoption-readiness.mjs +210 -28
- package/adapters/claude/scripts/lib/artifact-graph-runtime.mjs +70 -0
- package/adapters/claude/skills/artifact-chain-bootstrap/SKILL.md +29 -21
- package/adapters/claude/templates/core/e2e_test/starter.md +28 -26
- package/adapters/codex/.codex-plugin/plugin.json +1 -1
- package/adapters/codex/EXTENDED-ARTIFACT-CATALOG.md +12 -8
- package/adapters/codex/EXTENDED-ARTIFACT-CATALOG.zh-CN.md +12 -10
- package/adapters/codex/INSTALL.md +39 -17
- package/adapters/codex/agent-methods/catalog.yaml +1 -1
- package/adapters/codex/compatibility.json +4 -4
- package/adapters/codex/family-apis/catalog.json +1 -1
- package/adapters/codex/scripts/batch-merge.mjs +2 -1
- package/adapters/codex/scripts/batch-split.mjs +2 -1
- package/adapters/codex/scripts/check-workflow-profile.mjs +2 -1
- package/adapters/codex/scripts/lib/adoption-readiness.mjs +210 -28
- package/adapters/codex/scripts/lib/artifact-graph-runtime.mjs +70 -0
- package/adapters/codex/skills/artifact-chain-bootstrap/SKILL.md +29 -21
- package/adapters/codex/templates/core/e2e_test/starter.md +28 -26
- package/adapters/kimi/.kimi-plugin/plugin.json +1 -1
- package/adapters/kimi/EXTENDED-ARTIFACT-CATALOG.md +12 -8
- package/adapters/kimi/EXTENDED-ARTIFACT-CATALOG.zh-CN.md +12 -10
- package/adapters/kimi/INSTALL.md +39 -17
- package/adapters/kimi/agent-methods/catalog.yaml +1 -1
- package/adapters/kimi/compatibility.json +4 -4
- package/adapters/kimi/family-apis/catalog.json +1 -1
- package/adapters/kimi/scripts/batch-merge.mjs +2 -1
- package/adapters/kimi/scripts/batch-split.mjs +2 -1
- package/adapters/kimi/scripts/check-workflow-profile.mjs +2 -1
- package/adapters/kimi/scripts/lib/adoption-readiness.mjs +210 -28
- package/adapters/kimi/scripts/lib/artifact-graph-runtime.mjs +70 -0
- package/adapters/kimi/skills/artifact-chain-bootstrap/SKILL.md +29 -21
- package/adapters/kimi/templates/core/e2e_test/starter.md +28 -26
- package/agent-methods/catalog.yaml +1 -1
- package/compatibility.json +4 -4
- package/family-apis/catalog.json +1 -1
- package/package.json +2 -2
- package/scripts/batch-merge.mjs +2 -1
- package/scripts/batch-split.mjs +2 -1
- package/scripts/check-workflow-profile.mjs +2 -1
- package/scripts/lib/adoption-readiness.mjs +210 -28
- package/scripts/lib/artifact-graph-runtime.mjs +70 -0
- package/site/00-matrix.html +1 -1
- package/site/01-what.html +1 -1
- package/site/02-architecture.html +1 -1
- package/site/03-concepts.html +1 -1
- package/site/04-cli.html +1 -1
- package/site/05-scenarios.html +13 -12
- package/site/06-method-registry.html +1 -1
- package/site/07-glossary.html +1 -1
- package/site/08-maintainer.html +1 -1
- package/site/09-troubleshoot.html +2 -2
- package/site/10-roadmap.html +1 -1
- package/site/index.html +2 -2
- package/skills/artifact-chain-bootstrap/SKILL.md +29 -21
- package/skills-src/artifact-chain-bootstrap/SKILL.md +29 -21
- package/templates/core/e2e_test/starter.md +28 -26
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
import { readdir, readFile } from 'node:fs/promises';
|
|
5
5
|
import { join, resolve } from 'node:path';
|
|
6
|
+
import { pathToFileURL } from 'node:url';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Severity ordering for status/decision aggregation.
|
|
@@ -250,7 +251,7 @@ export async function batchMerge(resultsDir, options = {}) {
|
|
|
250
251
|
}
|
|
251
252
|
|
|
252
253
|
// CLI entry point
|
|
253
|
-
const isMain = import.meta.url ===
|
|
254
|
+
const isMain = Boolean(process.argv[1]) && import.meta.url === pathToFileURL(process.argv[1]).href;
|
|
254
255
|
if (isMain) {
|
|
255
256
|
const args = process.argv.slice(2);
|
|
256
257
|
const resultsDir = args[0];
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
|
|
4
4
|
import { readdir, readFile, stat } from 'node:fs/promises';
|
|
5
5
|
import { join, relative, resolve } from 'node:path';
|
|
6
|
+
import { pathToFileURL } from 'node:url';
|
|
6
7
|
|
|
7
8
|
/**
|
|
8
9
|
* Recursively collect all .md files under a directory.
|
|
@@ -154,7 +155,7 @@ export async function batchSplit(targetDir, options = {}) {
|
|
|
154
155
|
}
|
|
155
156
|
|
|
156
157
|
// CLI entry point
|
|
157
|
-
const isMain = import.meta.url ===
|
|
158
|
+
const isMain = Boolean(process.argv[1]) && import.meta.url === pathToFileURL(process.argv[1]).href;
|
|
158
159
|
if (isMain) {
|
|
159
160
|
const args = process.argv.slice(2);
|
|
160
161
|
const targetDir = args[0];
|
|
@@ -6,6 +6,7 @@
|
|
|
6
6
|
// @decision D-ACA-17
|
|
7
7
|
// Thin CLI wrapper. scripts/lib/workflow-profile.mjs is the single resolver.
|
|
8
8
|
import { resolve } from 'node:path';
|
|
9
|
+
import { pathToFileURL } from 'node:url';
|
|
9
10
|
import { buildCheckerOutput } from './lib/workflow-profile.mjs';
|
|
10
11
|
import { checkAdoptionReadiness } from './lib/adoption-readiness.mjs';
|
|
11
12
|
|
|
@@ -32,7 +33,7 @@ export async function checkWorkflowProfile({ root = process.cwd(), action = 'rev
|
|
|
32
33
|
};
|
|
33
34
|
}
|
|
34
35
|
|
|
35
|
-
const isMain = import.meta.url ===
|
|
36
|
+
const isMain = Boolean(process.argv[1]) && import.meta.url === pathToFileURL(process.argv[1]).href;
|
|
36
37
|
if (isMain) {
|
|
37
38
|
const args = process.argv.slice(2);
|
|
38
39
|
const value = flag => {
|
|
@@ -1,23 +1,17 @@
|
|
|
1
|
-
import { existsSync, statSync } from 'node:fs';
|
|
1
|
+
import { existsSync, readFileSync, statSync } from 'node:fs';
|
|
2
2
|
import { dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
|
|
3
|
-
import { loadArtifactGraphConfig } from './artifact-graph-runtime.mjs';
|
|
3
|
+
import { loadArtifactGraphConfig, loadProjectArtifactProfiles } from './artifact-graph-runtime.mjs';
|
|
4
4
|
import { buildCheckerOutput, loadProfile } from './workflow-profile.mjs';
|
|
5
5
|
|
|
6
6
|
const PROJECT_SHAPES = ['cli-library', 'web', 'desktop', 'skill-plugin'];
|
|
7
7
|
const ADOPTION_STAGES = ['initial', 'legacy-backfill', 'daily-iteration'];
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
const SHAPE_CANDIDATES = {
|
|
16
|
-
'cli-library': ['cli_contract'],
|
|
17
|
-
web: ['ui_contract', 'api_contract'],
|
|
18
|
-
desktop: ['ui_contract', 'ipc_contract', 'e2e_test'],
|
|
19
|
-
'skill-plugin': ['agent_skill', 'hook_policy', 'prompt_packet'],
|
|
20
|
-
};
|
|
8
|
+
const APPLICABILITY = Object.freeze({
|
|
9
|
+
common_minimum: 'common_minimum',
|
|
10
|
+
project_standard: 'project_standard',
|
|
11
|
+
lifecycle: 'lifecycle',
|
|
12
|
+
conditional: 'conditional',
|
|
13
|
+
project_extra: 'project_extra',
|
|
14
|
+
});
|
|
21
15
|
|
|
22
16
|
const TEMPLATE_PATHS = {
|
|
23
17
|
requirement: 'templates/core/requirement-entry.starter.md',
|
|
@@ -35,12 +29,166 @@ const TEMPLATE_PATHS = {
|
|
|
35
29
|
agent_skill: 'templates/extended/agent/agent_skill/starter.md',
|
|
36
30
|
hook_policy: 'templates/extended/agent/hook_policy/starter.md',
|
|
37
31
|
prompt_packet: 'templates/extended/agent/prompt_packet/starter.md',
|
|
32
|
+
data_contract: 'templates/extended/contracts/data_contract/starter.md',
|
|
33
|
+
release_policy: 'templates/extended/governance/release_policy/starter.md',
|
|
34
|
+
domain_model: 'templates/extended/domain/domain_model/starter.md',
|
|
38
35
|
};
|
|
39
36
|
|
|
40
37
|
function unique(values) {
|
|
41
38
|
return [...new Set(values)];
|
|
42
39
|
}
|
|
43
40
|
|
|
41
|
+
function flowMappingKeys(text) {
|
|
42
|
+
const keys = [];
|
|
43
|
+
let depth = 0;
|
|
44
|
+
let index = 0;
|
|
45
|
+
let quote = null;
|
|
46
|
+
let collect = false;
|
|
47
|
+
let token = '';
|
|
48
|
+
let expectKey = false;
|
|
49
|
+
while (index < text.length) {
|
|
50
|
+
const char = text[index];
|
|
51
|
+
if (quote) {
|
|
52
|
+
if (char === '\\' && quote === '"') {
|
|
53
|
+
if (collect) token += text[index + 1] ?? '';
|
|
54
|
+
index += 2;
|
|
55
|
+
continue;
|
|
56
|
+
}
|
|
57
|
+
if (char === quote) {
|
|
58
|
+
quote = null;
|
|
59
|
+
index += 1;
|
|
60
|
+
continue;
|
|
61
|
+
}
|
|
62
|
+
if (collect) token += char;
|
|
63
|
+
index += 1;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
if (char === '"' || char === "'") {
|
|
67
|
+
quote = char;
|
|
68
|
+
if (depth === 1 && expectKey) {
|
|
69
|
+
collect = true;
|
|
70
|
+
expectKey = false;
|
|
71
|
+
token = '';
|
|
72
|
+
}
|
|
73
|
+
index += 1;
|
|
74
|
+
continue;
|
|
75
|
+
}
|
|
76
|
+
if (char === '{' || char === '[') {
|
|
77
|
+
depth += 1;
|
|
78
|
+
if (char === '{' && depth === 1) expectKey = true;
|
|
79
|
+
index += 1;
|
|
80
|
+
continue;
|
|
81
|
+
}
|
|
82
|
+
if (char === '}' || char === ']') {
|
|
83
|
+
depth -= 1;
|
|
84
|
+
collect = false;
|
|
85
|
+
token = '';
|
|
86
|
+
if (depth === 0) break;
|
|
87
|
+
index += 1;
|
|
88
|
+
continue;
|
|
89
|
+
}
|
|
90
|
+
if (depth === 1 && expectKey) {
|
|
91
|
+
if (char === ' ' || char === '\t' || char === '\n' || char === '\r' || char === ',') {
|
|
92
|
+
index += 1;
|
|
93
|
+
continue;
|
|
94
|
+
}
|
|
95
|
+
if (/[A-Za-z]/u.test(char)) {
|
|
96
|
+
collect = true;
|
|
97
|
+
expectKey = false;
|
|
98
|
+
token = char;
|
|
99
|
+
index += 1;
|
|
100
|
+
continue;
|
|
101
|
+
}
|
|
102
|
+
}
|
|
103
|
+
if (collect) {
|
|
104
|
+
if (/[A-Za-z0-9_-]/u.test(char)) {
|
|
105
|
+
token += char;
|
|
106
|
+
index += 1;
|
|
107
|
+
continue;
|
|
108
|
+
}
|
|
109
|
+
if (char === ' ' || char === '\t') {
|
|
110
|
+
index += 1;
|
|
111
|
+
continue;
|
|
112
|
+
}
|
|
113
|
+
if (char === ':') {
|
|
114
|
+
if (/^[A-Za-z][A-Za-z0-9_-]*$/u.test(token)) keys.push(token);
|
|
115
|
+
collect = false;
|
|
116
|
+
token = '';
|
|
117
|
+
index += 1;
|
|
118
|
+
continue;
|
|
119
|
+
}
|
|
120
|
+
collect = false;
|
|
121
|
+
token = '';
|
|
122
|
+
}
|
|
123
|
+
if (char === ',' && depth === 1) expectKey = true;
|
|
124
|
+
index += 1;
|
|
125
|
+
}
|
|
126
|
+
return keys;
|
|
127
|
+
}
|
|
128
|
+
|
|
129
|
+
function blockMappingKeys(source, typesIndex) {
|
|
130
|
+
const lineStart = source.lastIndexOf('\n', typesIndex) + 1;
|
|
131
|
+
const lineEnd = source.indexOf('\n', typesIndex);
|
|
132
|
+
const typesLine = source.slice(lineStart, lineEnd < 0 ? source.length : lineEnd);
|
|
133
|
+
const indent = (typesLine.match(/^[ \t]*/u)?.[0] ?? '').length;
|
|
134
|
+
if (lineEnd < 0) return [];
|
|
135
|
+
const keys = [];
|
|
136
|
+
let childIndent = null;
|
|
137
|
+
for (const line of source.slice(lineEnd + 1).split('\n')) {
|
|
138
|
+
if (/^[ \t]*#/u.test(line) || /^[ \t]*$/u.test(line)) continue;
|
|
139
|
+
const leading = line.match(/^[ \t]*/u)?.[0] ?? '';
|
|
140
|
+
if (leading.includes('\t') || leading.length <= indent) break;
|
|
141
|
+
childIndent ??= leading.length;
|
|
142
|
+
if (leading.length !== childIndent) continue;
|
|
143
|
+
const key = line.slice(leading.length).match(/^(?:([A-Za-z][A-Za-z0-9_-]*)|"([A-Za-z][A-Za-z0-9_-]*)"|'([A-Za-z][A-Za-z0-9_-]*)')[ \t]*:/u);
|
|
144
|
+
if (key) keys.push(key[1] ?? key[2] ?? key[3]);
|
|
145
|
+
}
|
|
146
|
+
return keys;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
function declaredConfigTypeNames(source) {
|
|
150
|
+
if (typeof source !== 'string' || source.length === 0) return [];
|
|
151
|
+
const match = /(?:^|\n)types:[ \t]*/u.exec(source);
|
|
152
|
+
if (!match) return [];
|
|
153
|
+
const typesIndex = match.index + match[0].indexOf('types:');
|
|
154
|
+
const rest = source.slice(typesIndex + 'types:'.length).replace(/^[ \t]+/u, '');
|
|
155
|
+
if (rest.startsWith('{')) return flowMappingKeys(rest);
|
|
156
|
+
return blockMappingKeys(source, typesIndex);
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
function addCandidate(map, type, applicability, condition = null) {
|
|
160
|
+
const current = map.get(type) ?? { type, applicability: [], condition: null };
|
|
161
|
+
if (!current.applicability.includes(applicability)) current.applicability.push(applicability);
|
|
162
|
+
if (condition && !current.condition) current.condition = condition;
|
|
163
|
+
map.set(type, current);
|
|
164
|
+
}
|
|
165
|
+
|
|
166
|
+
function candidatesFromProfiles(profiles, projectShape, adoptionStage) {
|
|
167
|
+
const map = new Map();
|
|
168
|
+
for (const type of profiles.common_minimum ?? []) {
|
|
169
|
+
addCandidate(map, type, APPLICABILITY.common_minimum);
|
|
170
|
+
}
|
|
171
|
+
const standard = profiles.project_standards?.[projectShape];
|
|
172
|
+
for (const type of standard?.additional_types ?? []) {
|
|
173
|
+
addCandidate(map, type, APPLICABILITY.project_standard);
|
|
174
|
+
}
|
|
175
|
+
for (const entry of profiles.lifecycle ?? []) {
|
|
176
|
+
if (entry.adoption_stages?.includes(adoptionStage)) {
|
|
177
|
+
addCandidate(map, entry.type, APPLICABILITY.lifecycle, entry.condition ?? null);
|
|
178
|
+
}
|
|
179
|
+
}
|
|
180
|
+
for (const entry of profiles.conditional ?? []) {
|
|
181
|
+
if (entry.project_shapes?.includes(projectShape)) {
|
|
182
|
+
addCandidate(map, entry.type, APPLICABILITY.conditional, entry.condition ?? null);
|
|
183
|
+
}
|
|
184
|
+
}
|
|
185
|
+
return map;
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
function isStandardApplicability(applicability) {
|
|
189
|
+
return applicability.includes(APPLICABILITY.common_minimum) || applicability.includes(APPLICABILITY.project_standard);
|
|
190
|
+
}
|
|
191
|
+
|
|
44
192
|
function contained(root, target) {
|
|
45
193
|
const rel = relative(root, target);
|
|
46
194
|
return rel === '' || (!rel.startsWith(`..${sep}`) && rel !== '..' && !isAbsolute(rel));
|
|
@@ -150,26 +298,39 @@ export async function checkAdoptionReadiness({
|
|
|
150
298
|
const projectRoot = resolve(root);
|
|
151
299
|
const pluginRoot = resolve(import.meta.dirname, '..', '..');
|
|
152
300
|
const hasConfig = existsSync(join(projectRoot, 'artifact-graph.config.yaml'));
|
|
153
|
-
const [configResult, loadedProfile] = await Promise.all([
|
|
301
|
+
const [configResult, loadedProfile, profilesResult] = await Promise.all([
|
|
154
302
|
loadArtifactGraphConfig({ projectRoot, env }),
|
|
155
303
|
loadProfile({ root: projectRoot, profilePath }),
|
|
304
|
+
loadProjectArtifactProfiles({ projectRoot, env }),
|
|
156
305
|
]);
|
|
157
306
|
const schema = configResult.ok && hasConfig ? configResult.schema : null;
|
|
158
|
-
const
|
|
307
|
+
const configRaw = hasConfig ? readFileSync(join(projectRoot, 'artifact-graph.config.yaml'), 'utf8') : '';
|
|
308
|
+
const declaredTypes = hasConfig ? declaredConfigTypeNames(configRaw) : [];
|
|
159
309
|
const profiledTypes = loadedProfile.data ? profileTypes(loadedProfile.data) : [];
|
|
160
|
-
const
|
|
161
|
-
const
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
310
|
+
const evidenceTypes = unique([...declaredTypes, ...profiledTypes, ...selectedTypes]);
|
|
311
|
+
const candidateMap = profilesResult.ok
|
|
312
|
+
? candidatesFromProfiles(profilesResult.profiles, projectShape, adoptionStage)
|
|
313
|
+
: new Map();
|
|
314
|
+
for (const type of evidenceTypes) {
|
|
315
|
+
if (!candidateMap.has(type)) addCandidate(candidateMap, type, APPLICABILITY.project_extra);
|
|
316
|
+
}
|
|
317
|
+
const candidates = [...candidateMap.values()];
|
|
318
|
+
const enabledTypes = candidates.filter(item => evidenceTypes.includes(item.type)).map(item => item.type);
|
|
319
|
+
const candidateTypes = candidates.map(item => ({
|
|
320
|
+
type: item.type,
|
|
321
|
+
enabled: enabledTypes.includes(item.type),
|
|
322
|
+
applicability: item.applicability,
|
|
323
|
+
condition: item.condition,
|
|
166
324
|
sources: [
|
|
167
|
-
...(
|
|
168
|
-
...(profiledTypes.includes(type) ? ['workflow-profile'] : []),
|
|
169
|
-
...(selectedTypes.includes(type) ? ['explicit-selection'] : []),
|
|
325
|
+
...(declaredTypes.includes(item.type) ? ['effective-config'] : []),
|
|
326
|
+
...(profiledTypes.includes(item.type) ? ['workflow-profile'] : []),
|
|
327
|
+
...(selectedTypes.includes(item.type) ? ['explicit-selection'] : []),
|
|
170
328
|
],
|
|
171
|
-
template_available: Boolean(TEMPLATE_PATHS[type] && existsSync(join(pluginRoot, TEMPLATE_PATHS[type]))),
|
|
329
|
+
template_available: Boolean(TEMPLATE_PATHS[item.type] && existsSync(join(pluginRoot, TEMPLATE_PATHS[item.type]))),
|
|
172
330
|
}));
|
|
331
|
+
const missingStandardTypes = candidateTypes
|
|
332
|
+
.filter(item => isStandardApplicability(item.applicability) && !item.enabled)
|
|
333
|
+
.map(item => item.type);
|
|
173
334
|
const artifacts = [];
|
|
174
335
|
|
|
175
336
|
for (const type of enabledTypes) {
|
|
@@ -212,17 +373,38 @@ export async function checkAdoptionReadiness({
|
|
|
212
373
|
|
|
213
374
|
const ready = artifacts.length > 0 && artifacts.every(item => item.registration.ready && item.template.ready && item.methods.generate.status === 'OK' && item.methods.review.status === 'OK');
|
|
214
375
|
const diagnostics = [];
|
|
376
|
+
const profileContract = profilesResult.ok
|
|
377
|
+
? {
|
|
378
|
+
status: 'OK',
|
|
379
|
+
schema_version: profilesResult.profiles.schema_version,
|
|
380
|
+
source: 'artifact-graph/project-artifact-profiles',
|
|
381
|
+
reason: null,
|
|
382
|
+
}
|
|
383
|
+
: {
|
|
384
|
+
status: 'UNAVAILABLE',
|
|
385
|
+
schema_version: null,
|
|
386
|
+
source: 'artifact-graph/project-artifact-profiles',
|
|
387
|
+
reason: profilesResult.reason,
|
|
388
|
+
};
|
|
389
|
+
if (!profilesResult.ok) {
|
|
390
|
+
diagnostics.push(`Project artifact profiles unavailable: ${profilesResult.reason}. List-dependent recommendations are paused; copied STAGE/SHAPE tables are not used.`);
|
|
391
|
+
}
|
|
215
392
|
if (!configResult.ok) diagnostics.push(`Effective artifact-graph config unavailable: ${configResult.reason}`);
|
|
216
393
|
if (loadedProfile.error) diagnostics.push(loadedProfile.error);
|
|
394
|
+
if (missingStandardTypes.length > 0) {
|
|
395
|
+
diagnostics.push(`Common or skill-plugin standard types are visible and not adopted: ${missingStandardTypes.join(', ')}. Reading the list does not enable them.`);
|
|
396
|
+
}
|
|
217
397
|
if (enabledTypes.length === 0) diagnostics.push('No candidate artifact type is enabled by effective config, workflow profile, or explicit selection.');
|
|
218
398
|
if (!ready && enabledTypes.length > 0) diagnostics.push('One or more enabled artifact types are not fully ready; inspect each item.gaps.');
|
|
219
399
|
return {
|
|
220
|
-
status: ready ? 'OK' : 'NEEDS_INPUT',
|
|
400
|
+
status: profilesResult.ok && ready ? 'OK' : 'NEEDS_INPUT',
|
|
221
401
|
root: projectRoot,
|
|
222
402
|
project_shape: projectShape,
|
|
223
403
|
adoption_stage: adoptionStage,
|
|
404
|
+
profile_contract: profileContract,
|
|
224
405
|
candidate_types: candidateTypes,
|
|
225
406
|
enabled_types: enabledTypes,
|
|
407
|
+
missing_standard_types: missingStandardTypes,
|
|
226
408
|
artifacts,
|
|
227
409
|
diagnostics,
|
|
228
410
|
next: ready
|
|
@@ -119,6 +119,76 @@ export async function loadArtifactGraphConfig({ projectRoot, env } = {}) {
|
|
|
119
119
|
}
|
|
120
120
|
}
|
|
121
121
|
|
|
122
|
+
const PROFILES_SUBPATH = './project-artifact-profiles';
|
|
123
|
+
const PROFILES_SCHEMA_VERSION = '1.0';
|
|
124
|
+
|
|
125
|
+
function profilesExportPath(packageJson) {
|
|
126
|
+
const exported = packageJson.exports?.[PROFILES_SUBPATH];
|
|
127
|
+
if (typeof exported === 'string' && exported.length > 0) return exported;
|
|
128
|
+
if (exported && typeof exported === 'object') {
|
|
129
|
+
if (typeof exported.default === 'string' && exported.default.length > 0) return exported.default;
|
|
130
|
+
if (typeof exported.import === 'string' && exported.import.length > 0) return exported.import;
|
|
131
|
+
}
|
|
132
|
+
return null;
|
|
133
|
+
}
|
|
134
|
+
|
|
135
|
+
function profilesContractValid(raw) {
|
|
136
|
+
return Boolean(
|
|
137
|
+
raw
|
|
138
|
+
&& raw.schema_version === PROFILES_SCHEMA_VERSION
|
|
139
|
+
&& Array.isArray(raw.common_minimum)
|
|
140
|
+
&& raw.common_minimum.length > 0
|
|
141
|
+
&& raw.project_standards
|
|
142
|
+
&& typeof raw.project_standards === 'object'
|
|
143
|
+
&& Array.isArray(raw.lifecycle)
|
|
144
|
+
&& Array.isArray(raw.conditional),
|
|
145
|
+
);
|
|
146
|
+
}
|
|
147
|
+
|
|
148
|
+
/**
|
|
149
|
+
* Load the static project-artifact-profiles JSON from the resolved artifact-graph package.
|
|
150
|
+
* Missing export or incompatible schema_version fail closed; callers must not fall back to copied tables.
|
|
151
|
+
* The subpath is a candidate contract until a later provider publishes it; it is not a published 0.14.1 API.
|
|
152
|
+
*/
|
|
153
|
+
export async function loadProjectArtifactProfiles({ projectRoot, env } = {}) {
|
|
154
|
+
const runtime = await inspectArtifactGraphRuntime({ projectRoot: resolve(projectRoot), env });
|
|
155
|
+
if (!runtime.ok) {
|
|
156
|
+
return { ok: false, runtime, profiles: null, reason: runtime.reason };
|
|
157
|
+
}
|
|
158
|
+
try {
|
|
159
|
+
const packageRoot = dirname(runtime.packagePath);
|
|
160
|
+
const packageJson = JSON.parse(await readFile(runtime.packagePath, 'utf8'));
|
|
161
|
+
const exportPath = profilesExportPath(packageJson);
|
|
162
|
+
if (!exportPath) {
|
|
163
|
+
return {
|
|
164
|
+
ok: false,
|
|
165
|
+
runtime,
|
|
166
|
+
profiles: null,
|
|
167
|
+
reason: 'profiles_export_missing',
|
|
168
|
+
remediation: 'Resolved artifact-graph package does not export artifact-graph/project-artifact-profiles. Pause list-dependent recommendations; do not use a copied STAGE/SHAPE table. This subpath is a candidate contract, not a published 0.14.1 API.',
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
const raw = JSON.parse(await readFile(join(packageRoot, exportPath), 'utf8'));
|
|
172
|
+
if (!profilesContractValid(raw)) {
|
|
173
|
+
return {
|
|
174
|
+
ok: false,
|
|
175
|
+
runtime,
|
|
176
|
+
profiles: null,
|
|
177
|
+
reason: 'profiles_schema_incompatible',
|
|
178
|
+
remediation: `project-artifact-profiles schema_version is ${raw?.schema_version ?? 'missing'}, expected ${PROFILES_SCHEMA_VERSION}. Pause list-dependent recommendations; do not use a copied STAGE/SHAPE table.`,
|
|
179
|
+
};
|
|
180
|
+
}
|
|
181
|
+
return { ok: true, runtime, profiles: raw, reason: null };
|
|
182
|
+
} catch (error) {
|
|
183
|
+
return {
|
|
184
|
+
ok: false,
|
|
185
|
+
runtime,
|
|
186
|
+
profiles: null,
|
|
187
|
+
reason: `profiles_load_failed: ${error.message}`,
|
|
188
|
+
};
|
|
189
|
+
}
|
|
190
|
+
}
|
|
191
|
+
|
|
122
192
|
/**
|
|
123
193
|
* Resolve a path to its realpath if it exists and is executable (X_OK).
|
|
124
194
|
*/
|
|
@@ -37,25 +37,31 @@ initialization, migration, or repair of project setup, not for routine feature w
|
|
|
37
37
|
|
|
38
38
|
Use only artifact types that have stable local sources.
|
|
39
39
|
|
|
40
|
-
The
|
|
40
|
+
The published lists live in `artifact-graph/project-artifact-profiles` (`schema_version` `1.0`).
|
|
41
|
+
Graph owns `common_minimum` and approved `project_standards`. This assistant reads that JSON
|
|
42
|
+
through the resolved artifact-graph package, then checks registration, starter templates, and
|
|
43
|
+
methods. If the subpath is missing or `schema_version` is not `1.0`, report the gap and pause
|
|
44
|
+
only list-dependent recommendations; do not fall back to a copied STAGE/SHAPE table.
|
|
45
|
+
|
|
46
|
+
The assistant may maintain a broad reusable catalog of templates, but bootstrap must enable a small
|
|
41
47
|
project-specific profile. Treat extended artifact types as opt-in starter guidance, not
|
|
42
|
-
global policy.
|
|
48
|
+
global policy. Reading the published lists does not enable types.
|
|
43
49
|
|
|
44
50
|
**Starter Templates**: The plugin provides starter templates for extended types in
|
|
45
51
|
`templates/extended/`. These are onboarding guidance, not project authority. After bootstrap,
|
|
46
52
|
projects should copy relevant templates to `artifacts/templates/` and customize them locally.
|
|
47
53
|
|
|
48
|
-
| Project shape | Start
|
|
54
|
+
| Project shape | Start from published lists | Usually defer |
|
|
49
55
|
| --- | --- | --- |
|
|
50
|
-
| Docs/planning repo | `feature`, `scenario`, `
|
|
51
|
-
| TypeScript library or CLI
|
|
52
|
-
| API service
|
|
53
|
-
| Enterprise Java/Spring or JVM service |
|
|
54
|
-
| Desktop or full-stack app
|
|
55
|
-
| Agent or plugin toolkit |
|
|
56
|
-
| Parent or release governance repo |
|
|
56
|
+
| Docs/planning repo | common minimum `feature`, `scenario`, `design`; add `decision` when a choice must be traced | `test`, `e2e_test` until trace comments/tests exist |
|
|
57
|
+
| TypeScript library or CLI (`cli-library`) | common minimum; add `cli_contract` only when CLI/API docs exist | capability types without local evidence |
|
|
58
|
+
| API service (`web`) | common minimum; add `api_contract` and `data_contract` only when local contract files exist | `ui_contract`, `ipc_contract` |
|
|
59
|
+
| Enterprise Java/Spring or JVM service | common minimum; add `api_contract`, `data_contract`, `integration_contract`, `batch_job_contract`, `database_migration`, `security_review`, `performance_budget`, `deployment_manifest`, or `runbook` only from local evidence | `ui_contract`, `ipc_contract`, agent-specific artifacts |
|
|
60
|
+
| Desktop or full-stack app (`desktop`) | common minimum; add `ui_contract`, `ipc_contract`, `api_contract`, or `data_contract` only from local evidence | custom entities until registry format is stable |
|
|
61
|
+
| Agent or plugin toolkit (`skill-plugin`) | common minimum plus skill-plugin standard `agent_skill`, `e2e_test`; add `hook_policy` or `prompt_packet` only when local hook/prompt files exist | release governance types unless this project owns releases |
|
|
62
|
+
| Parent or release governance repo | common minimum; add `release_policy`, `publish_skill`, or `oss_compliance` only when local release files exist | product UI/API contracts |
|
|
57
63
|
| Existing mature artifact repo | types already present in `artifacts/**` | any type without templates or ID rules |
|
|
58
|
-
| Small project trying artifact-chain for the first time | `feature`, `
|
|
64
|
+
| Small project trying artifact-chain for the first time | common minimum `feature`, `scenario`, `design` | everything else until useful |
|
|
59
65
|
|
|
60
66
|
Prefer a small correct graph over a large noisy one. Add more types only after the project has
|
|
61
67
|
templates, ID patterns, and review rules for them. See `../../EXTENDED-ARTIFACT-CATALOG.md` for
|
|
@@ -63,7 +69,7 @@ per-type recommended paths, ID patterns, lifecycle rules, and review checkpoints
|
|
|
63
69
|
|
|
64
70
|
### 形态与采用阶段的实际就绪度
|
|
65
71
|
|
|
66
|
-
把项目实际证据归到一种形态:`cli-library`、`web`、`desktop` 或 `skill-plugin
|
|
72
|
+
把项目实际证据归到一种形态:`cli-library`、`web`、`desktop` 或 `skill-plugin`;再选当前阶段:`initial`(初建)、`legacy-backfill`(存量补档)或 `daily-iteration`(日常迭代)。候选来自 Graph 公开清单。共同最小三项 `feature`、`scenario`、`design` 始终可见,但可见不等于已启用。只有 `skill-plugin` 另有类别标准 `agent_skill` 与 `e2e_test`。阶段项按生命周期出现:`requirement` 在 `initial` 与 `daily-iteration`;`spec` 只在 `daily-iteration`;`decision` 在三个阶段都出现。接口、钩子、提示和发布类按能力出现。阶段项和能力项都只是候选,配置、profile 或用户明确选择之前不得启用。共同最小或技能族标准还没采用时,必须在结果里看得见。运行同一个只读计算入口:
|
|
67
73
|
|
|
68
74
|
```bash
|
|
69
75
|
node <plugin-root>/scripts/check-workflow-profile.mjs \
|
|
@@ -74,15 +80,17 @@ node <plugin-root>/scripts/check-workflow-profile.mjs \
|
|
|
74
80
|
--format json
|
|
75
81
|
```
|
|
76
82
|
|
|
77
|
-
`--types`
|
|
78
|
-
|
|
79
|
-
- `
|
|
80
|
-
- `
|
|
81
|
-
- `
|
|
82
|
-
- `
|
|
83
|
-
- `
|
|
84
|
-
- `
|
|
85
|
-
- `
|
|
83
|
+
`--types` 只传用户已经明确选择、但还没写入配置或 profile 的类型;没有这种选择时省略。形态只产生候选,不证明项目已经有对应能力。库没有 CLI、静态 Web 没有 API、技能插件没有 hook 时,把相应契约留在 `candidate_types`,不要要求补齐。项目已有配置或方法绑定里的额外类型必须保留。公开清单读不到,或 `schema_version` 不是 `1.0` 时,只暂停依赖清单的推荐路径,不回退复制表;已有额外类型仍保留。以检查结果为准:
|
|
84
|
+
|
|
85
|
+
- `profile_contract` 说明公开清单是否读到、`schema_version` 是否为 `1.0`;读不到或版本不兼容时只暂停清单推荐,不回退复制表。它不充当 `registration.ready` 的开关。
|
|
86
|
+
- `candidate_types` 列出共同最小、类别标准、阶段项、能力项和项目追加,并用 `applicability` 区分来源;`enabled` 只在有效配置、已有 profile 或明确选择时为 true。
|
|
87
|
+
- `missing_standard_types` 列出尚未采用的共同最小或技能族标准项。读清单成功不能当成已经采用。它和 `gaps` 分开看。
|
|
88
|
+
- `enabled_types` 只包含有上述依据的候选,候选本身不算缺口。
|
|
89
|
+
- `registration.ready` 同时检查有效类型、ID 模式、路径声明和目录。
|
|
90
|
+
- `template.ready` 检查插件 starter 是否真实存在。
|
|
91
|
+
- `methods.generate` 与 `methods.review` 复用当前 workflow profile 解析结果;需求/SPEC 的直接制作入口标为 `bundled-skill`,没有审阅方法时如实报告缺口。
|
|
92
|
+
- `project_specific_method_ready` 只在实际解析到 `project-worker` 时为 true;`bundled-skill`、`public-worker` 和 `project-worker` 分开报告。
|
|
93
|
+
- `gaps` 给出当前组合缺少的目录、模板或方法。清单可读不能掩盖模板或方法未就绪。
|
|
86
94
|
|
|
87
95
|
无配置项目仍能用 `artifact-chain-requirements` 把想法保存到 `artifacts/requirements/`。不要为了收集需求先强迫用户完成 bootstrap;需要把需求纳入图、建立当前制品或运行专业方法时,再按这里的结果补最小配置。
|
|
88
96
|
|
|
@@ -2,21 +2,23 @@
|
|
|
2
2
|
id: {E2E_TEST_ID}
|
|
3
3
|
title: {标题}
|
|
4
4
|
status: draft
|
|
5
|
+
test_batch: {TEST_BATCH}
|
|
5
6
|
related_features: []
|
|
6
7
|
related_scenarios: []
|
|
8
|
+
scope: {FEATURE_ID}
|
|
9
|
+
ac_coverage: {}
|
|
7
10
|
---
|
|
8
11
|
|
|
9
12
|
# {E2E_TEST_ID}: {标题}
|
|
10
13
|
|
|
11
14
|
<!-- 本模板是插件 starter 指导,项目本地模板可完全覆盖 -->
|
|
15
|
+
<!-- 用例标题必须是 `## TC-nnn:` 或 `### TC-nnn:`,内核按该标题解析节点;`主场景` 标题不会生成 TC 节点。 -->
|
|
12
16
|
|
|
13
17
|
## 测试目标
|
|
14
18
|
|
|
15
19
|
{描述这个端到端测试要验证的完整用户流程}
|
|
16
20
|
|
|
17
|
-
##
|
|
18
|
-
|
|
19
|
-
### 主场景:{场景名称}
|
|
21
|
+
## TC-001: {主场景名称}
|
|
20
22
|
|
|
21
23
|
**前置条件**:
|
|
22
24
|
- {条件 1}
|
|
@@ -31,40 +33,40 @@ related_scenarios: []
|
|
|
31
33
|
- {结果 1}
|
|
32
34
|
- {结果 2}
|
|
33
35
|
|
|
34
|
-
|
|
36
|
+
**后置清理**:
|
|
37
|
+
- {清理 1}
|
|
35
38
|
|
|
36
|
-
{
|
|
39
|
+
**覆盖场景**: {SCENARIO_ID}
|
|
40
|
+
**覆盖功能**: {FEATURE_ID}(AC1)
|
|
41
|
+
**优先级**: P0
|
|
37
42
|
|
|
38
|
-
##
|
|
43
|
+
## TC-002: {备选场景名称}
|
|
39
44
|
|
|
40
|
-
|
|
45
|
+
**前置条件**:
|
|
46
|
+
- {条件 1}
|
|
41
47
|
|
|
42
|
-
|
|
48
|
+
**测试步骤**:
|
|
49
|
+
1. {步骤 1}
|
|
43
50
|
|
|
44
|
-
|
|
51
|
+
**预期结果**:
|
|
52
|
+
- {结果 1}
|
|
45
53
|
|
|
46
|
-
|
|
54
|
+
**后置清理**:
|
|
55
|
+
- {清理 1}
|
|
47
56
|
|
|
48
|
-
{
|
|
57
|
+
**覆盖场景**: {SCENARIO_ID}
|
|
58
|
+
**覆盖功能**: {FEATURE_ID}(AC1)
|
|
59
|
+
**优先级**: P1
|
|
49
60
|
|
|
50
|
-
|
|
51
|
-
// 示例:Playwright E2E 测试
|
|
52
|
-
import { test, expect } from '@playwright/test';
|
|
61
|
+
## 测试数据
|
|
53
62
|
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
}
|
|
59
|
-
```
|
|
63
|
+
{描述测试所需的数据准备}
|
|
64
|
+
|
|
65
|
+
## 环境要求
|
|
66
|
+
|
|
67
|
+
{列出测试环境的特殊要求}
|
|
60
68
|
|
|
61
69
|
## 关联制品
|
|
62
70
|
|
|
63
71
|
- 功能特性:{related_features}
|
|
64
72
|
- 场景:{related_scenarios}
|
|
65
|
-
|
|
66
|
-
## 变更日志
|
|
67
|
-
|
|
68
|
-
| 日期 | 变更 | 作者 |
|
|
69
|
-
|------|------|------|
|
|
70
|
-
| {YYYY-MM-DD} | 初始草稿 | {作者} |
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "artifact-chain-assistant",
|
|
3
3
|
"displayName": "Artifact Chain Assistant",
|
|
4
|
-
"version": "0.
|
|
4
|
+
"version": "0.15.0",
|
|
5
5
|
"description": "Artifact-chain intake, review/repair/batch/audit workflows, diagnostics, and version-lock maintenance helpers.",
|
|
6
6
|
"author": {
|
|
7
7
|
"name": "广州市风荷科技有限公司"
|
|
@@ -14,8 +14,8 @@ plugin README and INSTALL.md. This document covers opt-in types beyond the core
|
|
|
14
14
|
|
|
15
15
|
| Layer | Scope | Responsibility for Extended Types |
|
|
16
16
|
| --- | --- | --- |
|
|
17
|
-
| **artifact-graph** | Deterministic graph capabilities | Reads type definitions from config; indexes artifacts; provides context/packet/validate.
|
|
18
|
-
| **artifact-chain-assistant** | General assistant guidance |
|
|
17
|
+
| **artifact-graph** | Deterministic graph capabilities, plus the published common-minimum and project-type standard lists at `artifact-graph/project-artifact-profiles` | Reads type definitions from config; indexes artifacts; provides context/packet/validate. Ships recommendation lists only; it does **not** auto-enable types or ship default paths or ID patterns for extended types. Types without configured paths are not indexed. |
|
|
18
|
+
| **artifact-chain-assistant** | General assistant guidance | Reads the Graph lists, then provides starter templates, adoption-readiness checks, and generic review checklists. **Templates are guidance, not authority.** The assistant does not keep a second list source of truth. Project-local templates and review skills override plugin suggestions. |
|
|
19
19
|
| **Target project** | Final working method | Decides which extended types to enable; maintains config, local templates, review skills, and ID rules. **Project-local overrides plugin suggestions.** Enables new types progressively as maturity grows. |
|
|
20
20
|
|
|
21
21
|
## Extended Artifact Type Catalog
|
|
@@ -90,15 +90,19 @@ has corresponding files or processes.
|
|
|
90
90
|
## Bootstrap Trimming Strategy
|
|
91
91
|
|
|
92
92
|
Bootstrap selects a **minimum viable profile** rather than enabling all known types.
|
|
93
|
+
The published lists are `artifact-graph/project-artifact-profiles`. Reading them does not enable types.
|
|
93
94
|
|
|
94
95
|
Rules:
|
|
95
96
|
|
|
96
|
-
1. **
|
|
97
|
-
2. **
|
|
98
|
-
3. **
|
|
99
|
-
4. **
|
|
100
|
-
5. **
|
|
101
|
-
6. **
|
|
97
|
+
1. **Common minimum is visible, not auto-enabled**: `feature`, `scenario`, `design`. Missing items stay visible until the project adopts them.
|
|
98
|
+
2. **Only `skill-plugin` has an approved category standard**: it adds `agent_skill` and `e2e_test` on top of the common minimum. Other shapes use the common minimum plus matching stage and capability candidates.
|
|
99
|
+
3. **Stage items stay candidates**: `requirement`, `spec`, and `decision` appear for matching adoption stages and are enabled only by config, profile, or explicit selection.
|
|
100
|
+
4. **Contracts by evidence**: Enable `cli_contract`, `api_contract`, `ui_contract`, `ipc_contract`, or `data_contract` only when the project has corresponding interface files.
|
|
101
|
+
5. **Domain/data by project shape**: Enterprise Java/DDD projects may enable `domain_model`; projects with databases may enable `database_migration`.
|
|
102
|
+
6. **Ops by operational process**: Enable only when the project has deployment configs, security review processes, or operational manuals.
|
|
103
|
+
7. **Agent/hook by local files**: `hook_policy` and `prompt_packet` remain capability candidates for `skill-plugin`; enable them only when the project has `skills/`, `policies/`, or hook config files.
|
|
104
|
+
8. **Release by duty**: Enable `release_policy` and related types only when the project owns publish and distribution.
|
|
105
|
+
9. **Progressive expansion**: As project maturity grows, add new types in `artifact-graph.config.yaml`. Existing extras and traceability relationships are kept.
|
|
102
106
|
|
|
103
107
|
After bootstrap, the enabled types, paths, and ID patterns are recorded in
|
|
104
108
|
`artifact-graph.config.yaml`. Deferred types and their evidence conditions are documented in the
|