agentxchain 2.2.0 → 2.4.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/README.md +17 -0
- package/bin/agentxchain.js +97 -1
- package/package.json +10 -3
- package/scripts/publish-from-tag.sh +14 -9
- package/scripts/release-postflight.sh +42 -2
- package/src/commands/init.js +1 -0
- package/src/commands/intake-approve.js +44 -0
- package/src/commands/intake-plan.js +62 -0
- package/src/commands/intake-record.js +86 -0
- package/src/commands/intake-resolve.js +45 -0
- package/src/commands/intake-scan.js +87 -0
- package/src/commands/intake-start.js +53 -0
- package/src/commands/intake-status.js +113 -0
- package/src/commands/intake-triage.js +54 -0
- package/src/commands/step.js +56 -2
- package/src/commands/template-validate.js +159 -0
- package/src/commands/verify.js +8 -3
- package/src/lib/adapters/api-proxy-adapter.js +125 -27
- package/src/lib/adapters/mcp-adapter.js +306 -0
- package/src/lib/governed-templates.js +236 -1
- package/src/lib/intake.js +924 -0
- package/src/lib/normalized-config.js +44 -1
- package/src/lib/protocol-conformance.js +28 -4
- package/src/lib/repo-observer.js +9 -8
- package/src/lib/validation.js +23 -0
- package/src/templates/governed/library.json +31 -0
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import { existsSync, readFileSync } from 'node:fs';
|
|
1
|
+
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
2
2
|
import { dirname, join } from 'node:path';
|
|
3
3
|
import { fileURLToPath } from 'node:url';
|
|
4
4
|
|
|
@@ -9,6 +9,7 @@ export const VALID_GOVERNED_TEMPLATE_IDS = Object.freeze([
|
|
|
9
9
|
'generic',
|
|
10
10
|
'api-service',
|
|
11
11
|
'cli-tool',
|
|
12
|
+
'library',
|
|
12
13
|
'web-app',
|
|
13
14
|
]);
|
|
14
15
|
|
|
@@ -143,3 +144,237 @@ export function loadGovernedTemplate(templateId) {
|
|
|
143
144
|
export function loadAllGovernedTemplates() {
|
|
144
145
|
return VALID_GOVERNED_TEMPLATE_IDS.map((templateId) => loadGovernedTemplate(templateId));
|
|
145
146
|
}
|
|
147
|
+
|
|
148
|
+
export function listGovernedTemplateManifestIds(manifestDir = GOVERNED_TEMPLATES_DIR) {
|
|
149
|
+
if (!existsSync(manifestDir)) {
|
|
150
|
+
return [];
|
|
151
|
+
}
|
|
152
|
+
|
|
153
|
+
return readdirSync(manifestDir)
|
|
154
|
+
.filter((entry) => entry.endsWith('.json'))
|
|
155
|
+
.map((entry) => entry.slice(0, -'.json'.length))
|
|
156
|
+
.sort();
|
|
157
|
+
}
|
|
158
|
+
|
|
159
|
+
export function validateGovernedTemplateRegistry(options = {}) {
|
|
160
|
+
const manifestDir = options.manifestDir || GOVERNED_TEMPLATES_DIR;
|
|
161
|
+
const registeredIds = options.registeredIds || [...VALID_GOVERNED_TEMPLATE_IDS];
|
|
162
|
+
const errors = [];
|
|
163
|
+
const warnings = [];
|
|
164
|
+
const manifestIds = listGovernedTemplateManifestIds(manifestDir);
|
|
165
|
+
|
|
166
|
+
for (const templateId of registeredIds) {
|
|
167
|
+
const manifestPath = join(manifestDir, `${templateId}.json`);
|
|
168
|
+
if (!existsSync(manifestPath)) {
|
|
169
|
+
errors.push(`Registered template "${templateId}" is missing its manifest file.`);
|
|
170
|
+
continue;
|
|
171
|
+
}
|
|
172
|
+
|
|
173
|
+
let manifest;
|
|
174
|
+
try {
|
|
175
|
+
manifest = JSON.parse(readFileSync(manifestPath, 'utf8'));
|
|
176
|
+
} catch (err) {
|
|
177
|
+
errors.push(`Template "${templateId}" manifest is invalid JSON: ${err.message}`);
|
|
178
|
+
continue;
|
|
179
|
+
}
|
|
180
|
+
|
|
181
|
+
const validation = validateGovernedTemplateManifest(manifest, templateId);
|
|
182
|
+
if (!validation.ok) {
|
|
183
|
+
errors.push(`Template "${templateId}" manifest is invalid: ${validation.errors.join('; ')}`);
|
|
184
|
+
}
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
for (const manifestId of manifestIds) {
|
|
188
|
+
if (!registeredIds.includes(manifestId)) {
|
|
189
|
+
errors.push(`Manifest "${manifestId}.json" exists on disk but is not registered in VALID_GOVERNED_TEMPLATE_IDS.`);
|
|
190
|
+
}
|
|
191
|
+
}
|
|
192
|
+
|
|
193
|
+
return {
|
|
194
|
+
ok: errors.length === 0,
|
|
195
|
+
registered_ids: registeredIds,
|
|
196
|
+
manifest_ids: manifestIds,
|
|
197
|
+
errors,
|
|
198
|
+
warnings,
|
|
199
|
+
};
|
|
200
|
+
}
|
|
201
|
+
|
|
202
|
+
export function validateProjectPlanningArtifacts(root, templateId) {
|
|
203
|
+
const effectiveTemplateId = templateId || 'generic';
|
|
204
|
+
const errors = [];
|
|
205
|
+
const warnings = [];
|
|
206
|
+
|
|
207
|
+
let manifest;
|
|
208
|
+
try {
|
|
209
|
+
manifest = loadGovernedTemplate(effectiveTemplateId);
|
|
210
|
+
} catch {
|
|
211
|
+
// Template load failure is already reported by validateGovernedProjectTemplate.
|
|
212
|
+
// Skip artifact check — we cannot know what artifacts to expect.
|
|
213
|
+
return {
|
|
214
|
+
ok: true,
|
|
215
|
+
template: effectiveTemplateId,
|
|
216
|
+
expected: [],
|
|
217
|
+
present: [],
|
|
218
|
+
missing: [],
|
|
219
|
+
errors,
|
|
220
|
+
warnings: ['Template could not be loaded; planning artifact check skipped.'],
|
|
221
|
+
};
|
|
222
|
+
}
|
|
223
|
+
|
|
224
|
+
const artifacts = manifest.planning_artifacts || [];
|
|
225
|
+
const expected = artifacts.map((a) => a.filename);
|
|
226
|
+
const present = [];
|
|
227
|
+
const missing = [];
|
|
228
|
+
|
|
229
|
+
for (const filename of expected) {
|
|
230
|
+
const artifactPath = join(root, '.planning', filename);
|
|
231
|
+
if (existsSync(artifactPath)) {
|
|
232
|
+
present.push(filename);
|
|
233
|
+
} else {
|
|
234
|
+
missing.push(filename);
|
|
235
|
+
errors.push(`Template "${effectiveTemplateId}" requires planning artifact ".planning/${filename}" but it is missing.`);
|
|
236
|
+
}
|
|
237
|
+
}
|
|
238
|
+
|
|
239
|
+
return {
|
|
240
|
+
ok: errors.length === 0,
|
|
241
|
+
template: effectiveTemplateId,
|
|
242
|
+
expected,
|
|
243
|
+
present,
|
|
244
|
+
missing,
|
|
245
|
+
errors,
|
|
246
|
+
warnings,
|
|
247
|
+
};
|
|
248
|
+
}
|
|
249
|
+
|
|
250
|
+
const TEMPLATE_GUIDANCE_HEADER = '## Template Guidance';
|
|
251
|
+
|
|
252
|
+
export function validateAcceptanceHintCompletion(root, templateId) {
|
|
253
|
+
const effectiveTemplateId = templateId || 'generic';
|
|
254
|
+
const errors = [];
|
|
255
|
+
const warnings = [];
|
|
256
|
+
|
|
257
|
+
let manifest;
|
|
258
|
+
try {
|
|
259
|
+
manifest = loadGovernedTemplate(effectiveTemplateId);
|
|
260
|
+
} catch {
|
|
261
|
+
return {
|
|
262
|
+
ok: true,
|
|
263
|
+
template: effectiveTemplateId,
|
|
264
|
+
total: 0,
|
|
265
|
+
checked: 0,
|
|
266
|
+
unchecked: 0,
|
|
267
|
+
missing_file: false,
|
|
268
|
+
missing_section: false,
|
|
269
|
+
unchecked_hints: [],
|
|
270
|
+
errors,
|
|
271
|
+
warnings: ['Template could not be loaded; acceptance hint check skipped.'],
|
|
272
|
+
};
|
|
273
|
+
}
|
|
274
|
+
|
|
275
|
+
const hints = manifest.acceptance_hints || [];
|
|
276
|
+
if (hints.length === 0) {
|
|
277
|
+
return {
|
|
278
|
+
ok: true,
|
|
279
|
+
template: effectiveTemplateId,
|
|
280
|
+
total: 0,
|
|
281
|
+
checked: 0,
|
|
282
|
+
unchecked: 0,
|
|
283
|
+
missing_file: false,
|
|
284
|
+
missing_section: false,
|
|
285
|
+
unchecked_hints: [],
|
|
286
|
+
errors,
|
|
287
|
+
warnings,
|
|
288
|
+
};
|
|
289
|
+
}
|
|
290
|
+
|
|
291
|
+
const matrixPath = join(root, '.planning', 'acceptance-matrix.md');
|
|
292
|
+
if (!existsSync(matrixPath)) {
|
|
293
|
+
warnings.push('acceptance-matrix.md not found; cannot verify template acceptance hints.');
|
|
294
|
+
return {
|
|
295
|
+
ok: true,
|
|
296
|
+
template: effectiveTemplateId,
|
|
297
|
+
total: hints.length,
|
|
298
|
+
checked: 0,
|
|
299
|
+
unchecked: hints.length,
|
|
300
|
+
missing_file: true,
|
|
301
|
+
missing_section: false,
|
|
302
|
+
unchecked_hints: [...hints],
|
|
303
|
+
errors,
|
|
304
|
+
warnings,
|
|
305
|
+
};
|
|
306
|
+
}
|
|
307
|
+
|
|
308
|
+
const matrixContent = readFileSync(matrixPath, 'utf8');
|
|
309
|
+
const sectionIndex = matrixContent.indexOf(TEMPLATE_GUIDANCE_HEADER);
|
|
310
|
+
if (sectionIndex === -1) {
|
|
311
|
+
warnings.push('acceptance-matrix.md has no "## Template Guidance" section; cannot verify template acceptance hints.');
|
|
312
|
+
return {
|
|
313
|
+
ok: true,
|
|
314
|
+
template: effectiveTemplateId,
|
|
315
|
+
total: hints.length,
|
|
316
|
+
checked: 0,
|
|
317
|
+
unchecked: hints.length,
|
|
318
|
+
missing_file: false,
|
|
319
|
+
missing_section: true,
|
|
320
|
+
unchecked_hints: [...hints],
|
|
321
|
+
errors,
|
|
322
|
+
warnings,
|
|
323
|
+
};
|
|
324
|
+
}
|
|
325
|
+
|
|
326
|
+
// Parse the Template Guidance section for checked/unchecked items
|
|
327
|
+
const sectionContent = matrixContent.slice(sectionIndex);
|
|
328
|
+
const checkedPattern = /^- \[x\]\s+(.+)$/gim;
|
|
329
|
+
const checkedTexts = new Set();
|
|
330
|
+
let match;
|
|
331
|
+
while ((match = checkedPattern.exec(sectionContent)) !== null) {
|
|
332
|
+
checkedTexts.add(match[1].trim());
|
|
333
|
+
}
|
|
334
|
+
|
|
335
|
+
const uncheckedHints = [];
|
|
336
|
+
let checkedCount = 0;
|
|
337
|
+
|
|
338
|
+
for (const hint of hints) {
|
|
339
|
+
if (checkedTexts.has(hint)) {
|
|
340
|
+
checkedCount++;
|
|
341
|
+
} else {
|
|
342
|
+
uncheckedHints.push(hint);
|
|
343
|
+
warnings.push(`Acceptance hint unchecked: "${hint}"`);
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
return {
|
|
348
|
+
ok: true,
|
|
349
|
+
template: effectiveTemplateId,
|
|
350
|
+
total: hints.length,
|
|
351
|
+
checked: checkedCount,
|
|
352
|
+
unchecked: uncheckedHints.length,
|
|
353
|
+
missing_file: false,
|
|
354
|
+
missing_section: false,
|
|
355
|
+
unchecked_hints: uncheckedHints,
|
|
356
|
+
errors,
|
|
357
|
+
warnings,
|
|
358
|
+
};
|
|
359
|
+
}
|
|
360
|
+
|
|
361
|
+
export function validateGovernedProjectTemplate(templateId, source = 'agentxchain.json') {
|
|
362
|
+
const effectiveTemplateId = templateId || 'generic';
|
|
363
|
+
const effectiveSource = templateId ? source : 'implicit_default';
|
|
364
|
+
const errors = [];
|
|
365
|
+
const warnings = [];
|
|
366
|
+
|
|
367
|
+
try {
|
|
368
|
+
loadGovernedTemplate(effectiveTemplateId);
|
|
369
|
+
} catch (err) {
|
|
370
|
+
errors.push(err.message);
|
|
371
|
+
}
|
|
372
|
+
|
|
373
|
+
return {
|
|
374
|
+
ok: errors.length === 0,
|
|
375
|
+
template: effectiveTemplateId,
|
|
376
|
+
source: effectiveSource,
|
|
377
|
+
errors,
|
|
378
|
+
warnings,
|
|
379
|
+
};
|
|
380
|
+
}
|