agentxchain 2.54.0 → 2.56.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/bin/agentxchain.js +1 -0
- package/dashboard/components/run-history.js +14 -0
- package/package.json +1 -1
- package/src/commands/demo.js +1 -1
- package/src/commands/history.js +8 -3
- package/src/commands/init.js +2 -0
- package/src/commands/status.js +4 -0
- package/src/lib/dispatch-bundle.js +9 -0
- package/src/lib/export.js +2 -0
- package/src/lib/normalized-config.js +11 -0
- package/src/lib/report.js +3 -0
- package/src/lib/run-history.js +15 -0
package/bin/agentxchain.js
CHANGED
|
@@ -128,6 +128,7 @@ program
|
|
|
128
128
|
.option('--template <id>', 'Governed scaffold template: generic, api-service, cli-tool, library, web-app, enterprise-app')
|
|
129
129
|
.option('--dev-command <parts...>', 'Governed local-dev command parts. Include {prompt} for argv prompt delivery.')
|
|
130
130
|
.option('--dev-prompt-transport <mode>', 'Governed local-dev prompt transport: argv, stdin, dispatch_bundle_only')
|
|
131
|
+
.option('--goal <text>', 'Project goal — persisted in config and rendered in every dispatch bundle')
|
|
131
132
|
.option('--schema-version <version>', 'Schema version (3 for legacy, or use --governed for current)')
|
|
132
133
|
.action(initCommand);
|
|
133
134
|
|
|
@@ -68,6 +68,14 @@ function truncateId(id, len = 12) {
|
|
|
68
68
|
return id.length > len ? id.slice(0, len) + '…' : id;
|
|
69
69
|
}
|
|
70
70
|
|
|
71
|
+
function isInheritable(entry) {
|
|
72
|
+
const snap = entry?.inheritance_snapshot;
|
|
73
|
+
if (!snap) return false;
|
|
74
|
+
const hasDecisions = Array.isArray(snap.recent_decisions) && snap.recent_decisions.length > 0;
|
|
75
|
+
const hasTurns = Array.isArray(snap.recent_accepted_turns) && snap.recent_accepted_turns.length > 0;
|
|
76
|
+
return hasDecisions || hasTurns;
|
|
77
|
+
}
|
|
78
|
+
|
|
71
79
|
function renderRow(entry, index) {
|
|
72
80
|
const rowClass = entry.status === 'blocked'
|
|
73
81
|
? ' style="border-left:3px solid var(--yellow)"'
|
|
@@ -83,10 +91,15 @@ function renderRow(entry, index) {
|
|
|
83
91
|
? `<div class="blocked-hint" style="font-size:0.85em;color:var(--yellow);margin-top:2px">${esc(typeof entry.blocked_reason === 'string' ? entry.blocked_reason : entry.blocked_reason?.detail || entry.blocked_reason?.category || '')}</div>`
|
|
84
92
|
: '';
|
|
85
93
|
|
|
94
|
+
const ctxIndicator = isInheritable(entry)
|
|
95
|
+
? `<span title="Has inheritance snapshot — usable by child runs" style="color:var(--green)">✓</span>`
|
|
96
|
+
: `<span style="color:var(--text-dim)">—</span>`;
|
|
97
|
+
|
|
86
98
|
return `<tr${rowClass}>
|
|
87
99
|
<td style="color:var(--text-dim)">${index + 1}</td>
|
|
88
100
|
<td class="mono" title="${esc(entry.run_id)}">${esc(truncateId(entry.run_id))}</td>
|
|
89
101
|
<td>${statusBadge(entry.status)}${blockedInfo}</td>
|
|
102
|
+
<td>${ctxIndicator}</td>
|
|
90
103
|
<td>${phases}</td>
|
|
91
104
|
<td>${entry.total_turns ?? '—'}</td>
|
|
92
105
|
<td>${formatCost(entry.total_cost_usd)}</td>
|
|
@@ -125,6 +138,7 @@ export function render({ runHistory }) {
|
|
|
125
138
|
<th>#</th>
|
|
126
139
|
<th>Run ID</th>
|
|
127
140
|
<th>Status</th>
|
|
141
|
+
<th>Ctx</th>
|
|
128
142
|
<th>Phases</th>
|
|
129
143
|
<th>Turns</th>
|
|
130
144
|
<th>Cost</th>
|
package/package.json
CHANGED
package/src/commands/demo.js
CHANGED
|
@@ -19,7 +19,7 @@ function makeConfig() {
|
|
|
19
19
|
return {
|
|
20
20
|
schema_version: 4,
|
|
21
21
|
protocol_mode: 'governed',
|
|
22
|
-
project: { id: 'agentxchain-demo', name: 'AgentXchain Demo', default_branch: 'main' },
|
|
22
|
+
project: { id: 'agentxchain-demo', name: 'AgentXchain Demo', goal: 'Build an auth token rotation service with expiry, graceful rollover, and audit logging', default_branch: 'main' },
|
|
23
23
|
roles: {
|
|
24
24
|
pm: {
|
|
25
25
|
title: 'Product Manager',
|
package/src/commands/history.js
CHANGED
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
import { resolve } from 'path';
|
|
8
8
|
import { existsSync, readFileSync } from 'fs';
|
|
9
9
|
import chalk from 'chalk';
|
|
10
|
-
import { queryRunHistory, queryRunLineage } from '../lib/run-history.js';
|
|
10
|
+
import { queryRunHistory, queryRunLineage, isInheritable } from '../lib/run-history.js';
|
|
11
11
|
import { getRunTriggerLabel, summarizeRunProvenance } from '../lib/run-provenance.js';
|
|
12
12
|
|
|
13
13
|
/**
|
|
@@ -46,11 +46,12 @@ export async function historyCommand(opts) {
|
|
|
46
46
|
const turns = `${entry.total_turns || 0} turns`;
|
|
47
47
|
const cost = entry.total_cost_usd != null ? `$${entry.total_cost_usd.toFixed(2)}` : '';
|
|
48
48
|
const trigger = getRunTriggerLabel(entry.provenance);
|
|
49
|
+
const ctxMarker = isInheritable(entry) ? ' [ctx]' : '';
|
|
49
50
|
const parentNote = entry.provenance?.parent_run_id
|
|
50
51
|
? ` from ${entry.provenance.parent_run_id.slice(0, 12)}`
|
|
51
52
|
: '';
|
|
52
53
|
const prefix = i === 0 ? ' ' : ' └─ ';
|
|
53
|
-
console.log(`${prefix}${runId} ${status} ${pad(phases, 20)} ${pad(turns, 10)} ${pad(cost, 8)} (${trigger}${parentNote})`);
|
|
54
|
+
console.log(`${prefix}${runId} ${status} ${pad(phases, 20)} ${pad(turns, 10)} ${pad(cost, 8)} (${trigger}${parentNote})${ctxMarker}`);
|
|
54
55
|
});
|
|
55
56
|
return;
|
|
56
57
|
}
|
|
@@ -63,7 +64,8 @@ export async function historyCommand(opts) {
|
|
|
63
64
|
});
|
|
64
65
|
|
|
65
66
|
if (opts.json) {
|
|
66
|
-
|
|
67
|
+
const enriched = entries.map(e => ({ ...e, inheritable: isInheritable(e) }));
|
|
68
|
+
console.log(JSON.stringify(enriched, null, 2));
|
|
67
69
|
return;
|
|
68
70
|
}
|
|
69
71
|
|
|
@@ -81,6 +83,7 @@ export async function historyCommand(opts) {
|
|
|
81
83
|
pad('Run ID', 14),
|
|
82
84
|
pad('Status', 11),
|
|
83
85
|
pad('Trigger', 14),
|
|
86
|
+
pad('Ctx', 4),
|
|
84
87
|
pad('Phases', 8),
|
|
85
88
|
pad('Turns', 6),
|
|
86
89
|
pad('Cost', 10),
|
|
@@ -96,6 +99,7 @@ export async function historyCommand(opts) {
|
|
|
96
99
|
const runId = (entry.run_id || '—').slice(0, 12);
|
|
97
100
|
const status = formatStatus(entry.status);
|
|
98
101
|
const trigger = getRunTriggerLabel(entry.provenance);
|
|
102
|
+
const ctx = isInheritable(entry) ? '✓' : '—';
|
|
99
103
|
const phases = String(entry.phases_completed?.length || 0);
|
|
100
104
|
const turns = String(entry.total_turns || 0);
|
|
101
105
|
const cost = entry.total_cost_usd != null
|
|
@@ -113,6 +117,7 @@ export async function historyCommand(opts) {
|
|
|
113
117
|
pad(runId, 14),
|
|
114
118
|
pad(status, 11),
|
|
115
119
|
pad(trigger, 14),
|
|
120
|
+
pad(ctx, 4),
|
|
116
121
|
pad(phases, 8),
|
|
117
122
|
pad(turns, 6),
|
|
118
123
|
pad(cost, 10),
|
package/src/commands/init.js
CHANGED
|
@@ -656,12 +656,14 @@ export function scaffoldGoverned(dir, projectName, projectId, templateId = 'gene
|
|
|
656
656
|
.filter(Boolean)
|
|
657
657
|
)].map((gateId) => [gateId, 'pending'])
|
|
658
658
|
);
|
|
659
|
+
const projectGoal = runtimeOptions.goal;
|
|
659
660
|
const config = {
|
|
660
661
|
schema_version: '1.0',
|
|
661
662
|
template: template.id,
|
|
662
663
|
project: {
|
|
663
664
|
id: projectId,
|
|
664
665
|
name: projectName,
|
|
666
|
+
...(typeof projectGoal === 'string' && projectGoal.trim() ? { goal: projectGoal.trim() } : {}),
|
|
665
667
|
default_branch: 'main'
|
|
666
668
|
},
|
|
667
669
|
roles,
|
package/src/commands/status.js
CHANGED
|
@@ -89,6 +89,7 @@ function renderGovernedStatus(context, opts) {
|
|
|
89
89
|
version,
|
|
90
90
|
protocol_mode: config.protocol_mode,
|
|
91
91
|
template: config.template || 'generic',
|
|
92
|
+
project_goal: config.project?.goal || null,
|
|
92
93
|
config,
|
|
93
94
|
state,
|
|
94
95
|
provenance: state?.provenance || null,
|
|
@@ -106,6 +107,9 @@ function renderGovernedStatus(context, opts) {
|
|
|
106
107
|
console.log('');
|
|
107
108
|
|
|
108
109
|
console.log(` ${chalk.dim('Project:')} ${config.project.name}`);
|
|
110
|
+
if (config.project.goal) {
|
|
111
|
+
console.log(` ${chalk.dim('Goal:')} ${config.project.goal}`);
|
|
112
|
+
}
|
|
109
113
|
console.log(` ${chalk.dim('Protocol:')} ${chalk.cyan(`governed (v${version})`)}`);
|
|
110
114
|
console.log(` ${chalk.dim('Template:')} ${config.template || 'generic'}`);
|
|
111
115
|
console.log(` ${chalk.dim('Phase:')} ${state?.phase ? formatGovernedPhase(state.phase) : chalk.dim('unknown')}`);
|
|
@@ -512,6 +512,15 @@ function renderContext(state, config, root, turn, role) {
|
|
|
512
512
|
}
|
|
513
513
|
lines.push('');
|
|
514
514
|
|
|
515
|
+
// Project goal (when set in agentxchain.json)
|
|
516
|
+
const projectGoal = config?.project?.goal;
|
|
517
|
+
if (typeof projectGoal === 'string' && projectGoal.trim()) {
|
|
518
|
+
lines.push('## Project Goal');
|
|
519
|
+
lines.push('');
|
|
520
|
+
lines.push(projectGoal.trim());
|
|
521
|
+
lines.push('');
|
|
522
|
+
}
|
|
523
|
+
|
|
515
524
|
// Inherited context from parent run (when --inherit-context was used)
|
|
516
525
|
if (state.inherited_context) {
|
|
517
526
|
// First turn gets the full rendering; subsequent turns get compact
|
package/src/lib/export.js
CHANGED
|
@@ -295,11 +295,13 @@ export function buildRunExport(startDir = process.cwd()) {
|
|
|
295
295
|
project: {
|
|
296
296
|
id: config.project.id,
|
|
297
297
|
name: config.project.name,
|
|
298
|
+
goal: config.project.goal || null,
|
|
298
299
|
template: config.template || 'generic',
|
|
299
300
|
protocol_mode: config.protocol_mode,
|
|
300
301
|
schema_version: version,
|
|
301
302
|
},
|
|
302
303
|
summary: {
|
|
304
|
+
project_goal: config.project.goal || null,
|
|
303
305
|
run_id: state?.run_id || null,
|
|
304
306
|
status: state?.status || null,
|
|
305
307
|
phase: state?.phase || null,
|
|
@@ -340,6 +340,16 @@ export function validateV4Config(data, projectRoot) {
|
|
|
340
340
|
} else {
|
|
341
341
|
if (typeof data.project.id !== 'string' || !data.project.id.trim()) errors.push('project.id must be a non-empty string');
|
|
342
342
|
if (typeof data.project.name !== 'string' || !data.project.name.trim()) errors.push('project.name must be a non-empty string');
|
|
343
|
+
// Optional project.goal field
|
|
344
|
+
if (data.project.goal !== undefined && data.project.goal !== null) {
|
|
345
|
+
if (typeof data.project.goal !== 'string') {
|
|
346
|
+
errors.push('project.goal must be a string');
|
|
347
|
+
} else if (!data.project.goal.trim()) {
|
|
348
|
+
errors.push('project.goal must be a non-empty string when provided');
|
|
349
|
+
} else if (data.project.goal.trim().length > 500) {
|
|
350
|
+
errors.push('project.goal must be 500 characters or fewer');
|
|
351
|
+
}
|
|
352
|
+
}
|
|
343
353
|
}
|
|
344
354
|
|
|
345
355
|
// Roles
|
|
@@ -968,6 +978,7 @@ export function normalizeV4(raw) {
|
|
|
968
978
|
project: {
|
|
969
979
|
id: raw.project?.id || 'unknown',
|
|
970
980
|
name: raw.project?.name || 'Unknown',
|
|
981
|
+
...(typeof raw.project?.goal === 'string' && raw.project.goal.trim() ? { goal: raw.project.goal.trim() } : {}),
|
|
971
982
|
default_branch: raw.project?.default_branch || 'main',
|
|
972
983
|
},
|
|
973
984
|
roles,
|
package/src/lib/report.js
CHANGED
|
@@ -630,6 +630,7 @@ function buildRunSubject(artifact) {
|
|
|
630
630
|
project: {
|
|
631
631
|
id: artifact.project?.id || null,
|
|
632
632
|
name: artifact.project?.name || null,
|
|
633
|
+
goal: artifact.project?.goal || null,
|
|
633
634
|
template: artifact.project?.template || 'generic',
|
|
634
635
|
protocol_mode: artifact.project?.protocol_mode || null,
|
|
635
636
|
schema_version: artifact.project?.schema_version || null,
|
|
@@ -876,6 +877,7 @@ export function formatGovernanceReportText(report) {
|
|
|
876
877
|
`Export kind: ${report.export_kind}`,
|
|
877
878
|
'Verification: PASS',
|
|
878
879
|
`Project: ${project.name || 'unknown'} (${project.id || 'unknown'})`,
|
|
880
|
+
...(project.goal ? [`Goal: ${project.goal}`] : []),
|
|
879
881
|
`Template: ${project.template}`,
|
|
880
882
|
`Protocol: ${project.protocol_mode || 'unknown'} (config schema ${project.schema_version || 'unknown'})`,
|
|
881
883
|
`Run: ${run.run_id || 'none'}`,
|
|
@@ -1285,6 +1287,7 @@ export function formatGovernanceReportMarkdown(report) {
|
|
|
1285
1287
|
`- Export kind: \`${report.export_kind}\``,
|
|
1286
1288
|
'- Verification: `pass`',
|
|
1287
1289
|
`- Project: ${project.name || 'unknown'} (\`${project.id || 'unknown'}\`)`,
|
|
1290
|
+
...(project.goal ? [`- Goal: ${project.goal}`] : []),
|
|
1288
1291
|
`- Template: \`${project.template}\``,
|
|
1289
1292
|
`- Protocol: \`${project.protocol_mode || 'unknown'}\` (config schema \`${project.schema_version || 'unknown'}\`)`,
|
|
1290
1293
|
`- Run: \`${run.run_id || 'none'}\``,
|
package/src/lib/run-history.js
CHANGED
|
@@ -249,6 +249,21 @@ export function validateParentRun(root, runId) {
|
|
|
249
249
|
return { ok: true, entry };
|
|
250
250
|
}
|
|
251
251
|
|
|
252
|
+
/**
|
|
253
|
+
* Check whether a run-history entry has a usable inheritance snapshot
|
|
254
|
+
* (at least one decision or one accepted turn available for child runs).
|
|
255
|
+
*
|
|
256
|
+
* @param {object} entry - a run-history record
|
|
257
|
+
* @returns {boolean}
|
|
258
|
+
*/
|
|
259
|
+
export function isInheritable(entry) {
|
|
260
|
+
const snap = entry?.inheritance_snapshot;
|
|
261
|
+
if (!snap) return false;
|
|
262
|
+
const hasDecisions = Array.isArray(snap.recent_decisions) && snap.recent_decisions.length > 0;
|
|
263
|
+
const hasTurns = Array.isArray(snap.recent_accepted_turns) && snap.recent_accepted_turns.length > 0;
|
|
264
|
+
return hasDecisions || hasTurns;
|
|
265
|
+
}
|
|
266
|
+
|
|
252
267
|
/**
|
|
253
268
|
* Get the path to the run-history file.
|
|
254
269
|
*/
|