agentxchain 2.136.1 → 2.137.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
CHANGED
|
@@ -66,6 +66,7 @@ import { kickoffCommand } from '../src/commands/kickoff.js';
|
|
|
66
66
|
import { rebindCommand } from '../src/commands/rebind.js';
|
|
67
67
|
import { branchCommand } from '../src/commands/branch.js';
|
|
68
68
|
import { migrateCommand } from '../src/commands/migrate.js';
|
|
69
|
+
import { migrateIntentsCommand } from '../src/commands/migrate-intents.js';
|
|
69
70
|
import { resumeCommand } from '../src/commands/resume.js';
|
|
70
71
|
import { unblockCommand } from '../src/commands/unblock.js';
|
|
71
72
|
import { injectCommand } from '../src/commands/inject.js';
|
|
@@ -645,6 +646,13 @@ program
|
|
|
645
646
|
.option('-j, --json', 'Output migration report as JSON')
|
|
646
647
|
.action(migrateCommand);
|
|
647
648
|
|
|
649
|
+
program
|
|
650
|
+
.command('migrate-intents')
|
|
651
|
+
.description('Archive legacy intents with no run scope (pre-BUG-34 repair)')
|
|
652
|
+
.option('-j, --json', 'Output as JSON')
|
|
653
|
+
.option('--dry-run', 'List legacy intents without modifying them')
|
|
654
|
+
.action(migrateIntentsCommand);
|
|
655
|
+
|
|
648
656
|
program
|
|
649
657
|
.command('resume')
|
|
650
658
|
.description('Resume a governed project: initialize or continue a run and assign the next turn')
|
package/package.json
CHANGED
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* One-shot repair command for legacy intents stuck with approved_run_id: null.
|
|
3
|
+
*
|
|
4
|
+
* Belt-and-suspenders insurance for BUG-41: the automatic startup migration
|
|
5
|
+
* is now idempotent, but operators who already have stuck repos need a direct
|
|
6
|
+
* lever that works without starting a governed run.
|
|
7
|
+
*/
|
|
8
|
+
|
|
9
|
+
import { existsSync, readFileSync, readdirSync } from 'node:fs';
|
|
10
|
+
import { join } from 'node:path';
|
|
11
|
+
import chalk from 'chalk';
|
|
12
|
+
|
|
13
|
+
import { findProjectRoot } from '../lib/config.js';
|
|
14
|
+
import { migratePreBug34Intents } from '../lib/intent-startup-migration.js';
|
|
15
|
+
|
|
16
|
+
function loadRunId(root) {
|
|
17
|
+
const statePath = join(root, '.agentxchain', 'state.json');
|
|
18
|
+
if (!existsSync(statePath)) return 'manual-migration';
|
|
19
|
+
try {
|
|
20
|
+
const state = JSON.parse(readFileSync(statePath, 'utf8'));
|
|
21
|
+
return state.run_id || 'manual-migration';
|
|
22
|
+
} catch {
|
|
23
|
+
return 'manual-migration';
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
|
|
27
|
+
function listLegacyIntents(root) {
|
|
28
|
+
const intentsDir = join(root, '.agentxchain', 'intake', 'intents');
|
|
29
|
+
if (!existsSync(intentsDir)) return [];
|
|
30
|
+
|
|
31
|
+
const DISPATCHABLE = new Set(['planned', 'approved']);
|
|
32
|
+
const results = [];
|
|
33
|
+
|
|
34
|
+
for (const file of readdirSync(intentsDir)) {
|
|
35
|
+
if (!file.endsWith('.json') || file.startsWith('.tmp-')) continue;
|
|
36
|
+
const intentPath = join(intentsDir, file);
|
|
37
|
+
let intent;
|
|
38
|
+
try {
|
|
39
|
+
intent = JSON.parse(readFileSync(intentPath, 'utf8'));
|
|
40
|
+
} catch {
|
|
41
|
+
continue;
|
|
42
|
+
}
|
|
43
|
+
if (!intent || !DISPATCHABLE.has(intent.status)) continue;
|
|
44
|
+
if (intent.cross_run_durable === true) continue;
|
|
45
|
+
if (intent.approved_run_id) continue;
|
|
46
|
+
results.push({ file, intent_id: intent.intent_id || file.replace('.json', ''), status: intent.status });
|
|
47
|
+
}
|
|
48
|
+
return results;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
export function migrateIntentsCommand(opts) {
|
|
52
|
+
const root = findProjectRoot();
|
|
53
|
+
if (!root) {
|
|
54
|
+
if (opts.json) {
|
|
55
|
+
console.log(JSON.stringify({ error: 'No agentxchain.json found. Run from inside a governed project.' }));
|
|
56
|
+
} else {
|
|
57
|
+
console.error(chalk.red(' No agentxchain.json found. Run this from inside a governed project.'));
|
|
58
|
+
}
|
|
59
|
+
process.exit(1);
|
|
60
|
+
}
|
|
61
|
+
|
|
62
|
+
const legacyIntents = listLegacyIntents(root);
|
|
63
|
+
|
|
64
|
+
if (opts.dryRun) {
|
|
65
|
+
if (opts.json) {
|
|
66
|
+
console.log(JSON.stringify({
|
|
67
|
+
archived_count: legacyIntents.length,
|
|
68
|
+
archived_intent_ids: legacyIntents.map(i => i.intent_id),
|
|
69
|
+
dry_run: true,
|
|
70
|
+
message: legacyIntents.length > 0
|
|
71
|
+
? `Would archive ${legacyIntents.length} pre-BUG-34 intent(s)`
|
|
72
|
+
: 'No legacy intents found',
|
|
73
|
+
}, null, 2));
|
|
74
|
+
} else {
|
|
75
|
+
if (legacyIntents.length === 0) {
|
|
76
|
+
console.log(chalk.green(' No legacy intents found. Nothing to migrate.'));
|
|
77
|
+
} else {
|
|
78
|
+
console.log(chalk.yellow(` Would archive ${legacyIntents.length} legacy intent(s):`));
|
|
79
|
+
for (const item of legacyIntents) {
|
|
80
|
+
console.log(` ${chalk.dim('•')} ${item.intent_id} (${item.status})`);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
return;
|
|
85
|
+
}
|
|
86
|
+
|
|
87
|
+
if (legacyIntents.length === 0) {
|
|
88
|
+
if (opts.json) {
|
|
89
|
+
console.log(JSON.stringify({
|
|
90
|
+
archived_count: 0,
|
|
91
|
+
archived_intent_ids: [],
|
|
92
|
+
dry_run: false,
|
|
93
|
+
message: 'No legacy intents found',
|
|
94
|
+
}, null, 2));
|
|
95
|
+
} else {
|
|
96
|
+
console.log(chalk.green(' No legacy intents found. Nothing to migrate.'));
|
|
97
|
+
}
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const runId = loadRunId(root);
|
|
102
|
+
const result = migratePreBug34Intents(root, runId);
|
|
103
|
+
|
|
104
|
+
if (opts.json) {
|
|
105
|
+
console.log(JSON.stringify({
|
|
106
|
+
archived_count: result.archived_migration_count,
|
|
107
|
+
archived_intent_ids: result.archived_migration_intent_ids,
|
|
108
|
+
dry_run: false,
|
|
109
|
+
message: result.migration_notice || `Archived ${result.archived_migration_count} pre-BUG-34 intent(s)`,
|
|
110
|
+
}, null, 2));
|
|
111
|
+
} else {
|
|
112
|
+
if (result.archived_migration_count === 0) {
|
|
113
|
+
console.log(chalk.green(' No legacy intents found. Nothing to migrate.'));
|
|
114
|
+
} else {
|
|
115
|
+
console.log(chalk.green(` ✓ ${result.migration_notice}`));
|
|
116
|
+
for (const id of result.archived_migration_intent_ids) {
|
|
117
|
+
console.log(` ${chalk.dim('•')} ${id}`);
|
|
118
|
+
}
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
}
|
|
@@ -154,7 +154,7 @@ function reconcileContinuousStartupState(context, session, contOpts, log) {
|
|
|
154
154
|
sessionChanged = true;
|
|
155
155
|
}
|
|
156
156
|
|
|
157
|
-
if (scopedRunId
|
|
157
|
+
if (scopedRunId) {
|
|
158
158
|
const startupIntents = archiveStaleIntentsForRun(root, scopedRunId, {
|
|
159
159
|
protocolVersion: governedState?.protocol_version || config?.schema_version || '2.x',
|
|
160
160
|
});
|
|
@@ -172,8 +172,10 @@ function reconcileContinuousStartupState(context, session, contOpts, log) {
|
|
|
172
172
|
const migrationNotice = formatLegacyIntentMigrationNotice(startupIntents.archived_migration_intent_ids);
|
|
173
173
|
if (migrationNotice) log(migrationNotice);
|
|
174
174
|
}
|
|
175
|
-
session.startup_reconciled_run_id
|
|
176
|
-
|
|
175
|
+
if (session.startup_reconciled_run_id !== scopedRunId) {
|
|
176
|
+
session.startup_reconciled_run_id = scopedRunId;
|
|
177
|
+
sessionChanged = true;
|
|
178
|
+
}
|
|
177
179
|
}
|
|
178
180
|
|
|
179
181
|
if (sessionChanged) {
|