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.
Files changed (75) hide show
  1. package/.claude-plugin/plugin.json +1 -1
  2. package/.codex-plugin/plugin.json +1 -1
  3. package/.kimi-plugin/plugin.json +1 -1
  4. package/CHANGELOG.md +10 -0
  5. package/EXTENDED-ARTIFACT-CATALOG.md +12 -8
  6. package/EXTENDED-ARTIFACT-CATALOG.zh-CN.md +12 -10
  7. package/INSTALL.md +39 -17
  8. package/README.md +10 -6
  9. package/README.zh-CN.md +7 -5
  10. package/adapters/claude/.claude-plugin/plugin.json +1 -1
  11. package/adapters/claude/EXTENDED-ARTIFACT-CATALOG.md +12 -8
  12. package/adapters/claude/EXTENDED-ARTIFACT-CATALOG.zh-CN.md +12 -10
  13. package/adapters/claude/INSTALL.md +39 -17
  14. package/adapters/claude/agent-methods/catalog.yaml +1 -1
  15. package/adapters/claude/compatibility.json +4 -4
  16. package/adapters/claude/family-apis/catalog.json +1 -1
  17. package/adapters/claude/scripts/batch-merge.mjs +2 -1
  18. package/adapters/claude/scripts/batch-split.mjs +2 -1
  19. package/adapters/claude/scripts/check-workflow-profile.mjs +2 -1
  20. package/adapters/claude/scripts/lib/adoption-readiness.mjs +210 -28
  21. package/adapters/claude/scripts/lib/artifact-graph-runtime.mjs +70 -0
  22. package/adapters/claude/skills/artifact-chain-bootstrap/SKILL.md +29 -21
  23. package/adapters/claude/templates/core/e2e_test/starter.md +28 -26
  24. package/adapters/codex/.codex-plugin/plugin.json +1 -1
  25. package/adapters/codex/EXTENDED-ARTIFACT-CATALOG.md +12 -8
  26. package/adapters/codex/EXTENDED-ARTIFACT-CATALOG.zh-CN.md +12 -10
  27. package/adapters/codex/INSTALL.md +39 -17
  28. package/adapters/codex/agent-methods/catalog.yaml +1 -1
  29. package/adapters/codex/compatibility.json +4 -4
  30. package/adapters/codex/family-apis/catalog.json +1 -1
  31. package/adapters/codex/scripts/batch-merge.mjs +2 -1
  32. package/adapters/codex/scripts/batch-split.mjs +2 -1
  33. package/adapters/codex/scripts/check-workflow-profile.mjs +2 -1
  34. package/adapters/codex/scripts/lib/adoption-readiness.mjs +210 -28
  35. package/adapters/codex/scripts/lib/artifact-graph-runtime.mjs +70 -0
  36. package/adapters/codex/skills/artifact-chain-bootstrap/SKILL.md +29 -21
  37. package/adapters/codex/templates/core/e2e_test/starter.md +28 -26
  38. package/adapters/kimi/.kimi-plugin/plugin.json +1 -1
  39. package/adapters/kimi/EXTENDED-ARTIFACT-CATALOG.md +12 -8
  40. package/adapters/kimi/EXTENDED-ARTIFACT-CATALOG.zh-CN.md +12 -10
  41. package/adapters/kimi/INSTALL.md +39 -17
  42. package/adapters/kimi/agent-methods/catalog.yaml +1 -1
  43. package/adapters/kimi/compatibility.json +4 -4
  44. package/adapters/kimi/family-apis/catalog.json +1 -1
  45. package/adapters/kimi/scripts/batch-merge.mjs +2 -1
  46. package/adapters/kimi/scripts/batch-split.mjs +2 -1
  47. package/adapters/kimi/scripts/check-workflow-profile.mjs +2 -1
  48. package/adapters/kimi/scripts/lib/adoption-readiness.mjs +210 -28
  49. package/adapters/kimi/scripts/lib/artifact-graph-runtime.mjs +70 -0
  50. package/adapters/kimi/skills/artifact-chain-bootstrap/SKILL.md +29 -21
  51. package/adapters/kimi/templates/core/e2e_test/starter.md +28 -26
  52. package/agent-methods/catalog.yaml +1 -1
  53. package/compatibility.json +4 -4
  54. package/family-apis/catalog.json +1 -1
  55. package/package.json +2 -2
  56. package/scripts/batch-merge.mjs +2 -1
  57. package/scripts/batch-split.mjs +2 -1
  58. package/scripts/check-workflow-profile.mjs +2 -1
  59. package/scripts/lib/adoption-readiness.mjs +210 -28
  60. package/scripts/lib/artifact-graph-runtime.mjs +70 -0
  61. package/site/00-matrix.html +1 -1
  62. package/site/01-what.html +1 -1
  63. package/site/02-architecture.html +1 -1
  64. package/site/03-concepts.html +1 -1
  65. package/site/04-cli.html +1 -1
  66. package/site/05-scenarios.html +13 -12
  67. package/site/06-method-registry.html +1 -1
  68. package/site/07-glossary.html +1 -1
  69. package/site/08-maintainer.html +1 -1
  70. package/site/09-troubleshoot.html +2 -2
  71. package/site/10-roadmap.html +1 -1
  72. package/site/index.html +2 -2
  73. package/skills/artifact-chain-bootstrap/SKILL.md +29 -21
  74. package/skills-src/artifact-chain-bootstrap/SKILL.md +29 -21
  75. 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 === `file://${process.argv[1]}`;
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 === `file://${process.argv[1]}`;
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 === `file://${process.argv[1]}`;
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
- const STAGE_CANDIDATES = {
10
- initial: ['requirement', 'feature', 'decision'],
11
- 'legacy-backfill': ['feature', 'scenario', 'decision', 'design', 'test'],
12
- 'daily-iteration': ['requirement', 'spec', 'feature', 'scenario', 'decision', 'design', 'test'],
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 configuredTypes = schema ? Object.keys(schema.types ?? {}) : [];
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 candidates = unique([...STAGE_CANDIDATES[adoptionStage], ...SHAPE_CANDIDATES[projectShape]]);
161
- const evidenceTypes = new Set([...configuredTypes, ...profiledTypes, ...selectedTypes]);
162
- const enabledTypes = candidates.filter(type => evidenceTypes.has(type));
163
- const candidateTypes = candidates.map(type => ({
164
- type,
165
- enabled: enabledTypes.includes(type),
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
- ...(configuredTypes.includes(type) ? ['effective-config'] : []),
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 assistant may maintain a broad reusable catalog, but bootstrap must enable a small
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 with | Usually defer |
54
+ | Project shape | Start from published lists | Usually defer |
49
55
  | --- | --- | --- |
50
- | Docs/planning repo | `feature`, `scenario`, `decision`, `design` | `test`, `e2e_test` until trace comments/tests exist |
51
- | TypeScript library or CLI | `feature`, `decision`, `design`, `test`; add `cli_contract` only when CLI/API docs exist | `scenario` if no scenario scripts exist |
52
- | API service | `feature`, `scenario`, `decision`, `design`, `test`; add `api_contract` and `data_contract` only when local contract files exist | `ui_contract`, `ipc_contract` |
53
- | Enterprise Java/Spring or JVM service | `feature`, `scenario`, `decision`, `design`, `test`; 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 |
54
- | Desktop or full-stack app | `feature`, `scenario`, `decision`, `design`, `test`, `e2e_test`; add `ui_contract`, `ipc_contract`, `api_contract`, or `data_contract` only from local evidence | custom entities until registry format is stable |
55
- | Agent or plugin toolkit | `feature`, `scenario`, `decision`, `design`, `test`; add `agent_skill`, `hook_policy`, or `prompt_packet` only when local skill/hook/prompt files exist | release governance types unless this project owns releases |
56
- | Parent or release governance repo | `feature`, `scenario`, `decision`, `design`, `e2e_test`; add `release_policy`, `publish_skill`, or `oss_compliance` only when local release files exist | product UI/API contracts |
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`, `decision`, `test` | everything else until useful |
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`;再选择当前阶段:`initial`(初建)、`legacy-backfill`(存量补档)或 `daily-iteration`(日常迭代)。运行同一个只读计算入口:
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` 只传已经由用户明确选择、但尚未写入配置或 profile 的类型;没有这种选择时省略。形态只产生候选,不证明项目拥有对应能力。库没有 CLI、静态 Web 没有 API、技能插件没有 hook 时,让相应契约留在 `candidate_types`,不要要求补齐。以脚本结果为准:
78
-
79
- - `candidate_types` 列出形态和阶段建议,并说明是否由有效配置、已有 profile 或明确选择启用;
80
- - `enabled_types` 只包含有上述依据的候选,候选本身不算缺口;
81
- - `registration.ready` 同时检查有效类型、ID 模式、路径声明和目录;
82
- - `template.ready` 检查插件 starter 是否真实存在;
83
- - `methods.generate` 与 `methods.review` 复用当前 workflow profile 解析结果;需求/SPEC 的直接制作入口标为 `bundled-skill`,没有审阅方法时如实报告缺口;
84
- - `project_specific_method_ready` 只在实际解析到 `project-worker` 时为 true;`bundled-skill`、`public-worker` 和 `project-worker` 分开报告;
85
- - `gaps` 给出当前组合缺少的类型、目录、模板或方法,不把缺口写成已启用能力。
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
- ```typescript
51
- // 示例:Playwright E2E 测试
52
- import { test, expect } from '@playwright/test';
61
+ ## 测试数据
53
62
 
54
- test('{测试名称}', async ({ page }) => {
55
- await page.goto('{URL}');
56
- await page.click('{选择器}');
57
- await expect(page.locator('{选择器}')).toHaveText('{预期文本}');
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.14.2",
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. Does **not** ship default paths or ID patterns for extended types. Types without configured paths are not indexed. |
18
- | **artifact-chain-assistant** | General assistant guidance | Provides starter templates, profile suggestions, and generic review checklists. **Templates are guidance, not authority.** Project-local templates and review skills override plugin suggestions. |
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. **Core set always enabled**: `feature`, `scenario`, `decision`, `design`, `test`, `e2e_test`.
97
- 2. **Contracts by evidence**: Enable only when the project has corresponding interface files (e.g., OpenAPI spec, CLI entry, IPC channel definition).
98
- 3. **Domain/data by project shape**: Enterprise Java/DDD projects may enable `domain_model`; projects with databases may enable `database_migration`.
99
- 4. **Ops by operational process**: Enable only when the project has deployment configs, security review processes, or operational manuals.
100
- 5. **Agent/hook by local files**: Enable only when the project has `skills/`, `policies/`, or hook config files.
101
- 6. **Progressive expansion**: As project maturity grows, add new types in `artifact-graph.config.yaml`. Existing artifacts and traceability relationships are unaffected.
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