agentwheel 0.14.8 → 0.14.9
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/dist/index.js +97 -3
- package/package.json +1 -1
package/dist/index.js
CHANGED
|
@@ -1270,6 +1270,23 @@ async function removeApplyJournal(targetRoot, adapter, transport = localTranspor
|
|
|
1270
1270
|
await transport.rm(applyJournalPath(targetRoot, adapter, scope));
|
|
1271
1271
|
await transport.rm(applyBackupDir(targetRoot, adapter, scope));
|
|
1272
1272
|
}
|
|
1273
|
+
async function abortApplyJournal(targetRoot, adapter, transport = localTransport, scope = {}) {
|
|
1274
|
+
const lock = await acquireApplyLock(targetRoot, adapter, transport, {}, scope);
|
|
1275
|
+
try {
|
|
1276
|
+
const journalPath = applyJournalPath(targetRoot, adapter, scope);
|
|
1277
|
+
if (!await transport.pathExists(journalPath)) return void 0;
|
|
1278
|
+
const stateKey = stateKeyFor(adapter, scope);
|
|
1279
|
+
const archivePath = join3(metadataDir(targetRoot), "archive", `${stateKey}.apply-journal.failed-${journalTimestamp(/* @__PURE__ */ new Date())}.json`);
|
|
1280
|
+
const content = await transport.readFile(journalPath);
|
|
1281
|
+
await transport.writeFileAtomic(archivePath, content.endsWith("\n") ? content : `${content}
|
|
1282
|
+
`);
|
|
1283
|
+
await transport.rm(journalPath);
|
|
1284
|
+
await transport.rm(applyBackupDir(targetRoot, adapter, scope));
|
|
1285
|
+
return { journalPath, archivePath };
|
|
1286
|
+
} finally {
|
|
1287
|
+
await lock.release();
|
|
1288
|
+
}
|
|
1289
|
+
}
|
|
1273
1290
|
async function recordBackup(operation, index, targetRoot, adapter, transport = localTransport, scope = {}) {
|
|
1274
1291
|
const hadExisting = await transport.pathExists(operation.destPath);
|
|
1275
1292
|
if (!hadExisting || transport.kind !== "local" || operation.action !== "update" && operation.action !== "remove" && operation.action !== "create") {
|
|
@@ -1326,6 +1343,9 @@ async function readLockOwner(ownerPath, transport) {
|
|
|
1326
1343
|
function isAlreadyExists(error) {
|
|
1327
1344
|
return typeof error === "object" && error !== null && "code" in error && error.code === "EEXIST";
|
|
1328
1345
|
}
|
|
1346
|
+
function journalTimestamp(date) {
|
|
1347
|
+
return date.toISOString().replace(/[-:]/g, "").replace(/\.\d{3}Z$/, "Z");
|
|
1348
|
+
}
|
|
1329
1349
|
async function localPathExists(path) {
|
|
1330
1350
|
try {
|
|
1331
1351
|
await stat2(path);
|
|
@@ -2038,7 +2058,12 @@ async function executePluginInstall(operation, transport) {
|
|
|
2038
2058
|
async function executePluginUninstall(operation, transport) {
|
|
2039
2059
|
const commands = operation.semanticPlugin?.uninstallCommands ?? [];
|
|
2040
2060
|
if (commands.length === 0) throw new Error(`Invalid semantic plugin operation missing uninstall command: ${operation.relativeDestPath}`);
|
|
2041
|
-
|
|
2061
|
+
try {
|
|
2062
|
+
await executeSemanticCommands(operation, commands, transport);
|
|
2063
|
+
} catch (error) {
|
|
2064
|
+
if (!isPluginAlreadyAbsentError(operation, error)) throw error;
|
|
2065
|
+
console.warn(`WARNING plugin-already-absent ${operation.relativeDestPath}: ${firstErrorLine(error)}`);
|
|
2066
|
+
}
|
|
2042
2067
|
if (operation.semanticPlugin?.stateRoot) {
|
|
2043
2068
|
await transport.rm(operation.semanticPlugin.stateRoot);
|
|
2044
2069
|
}
|
|
@@ -2185,6 +2210,35 @@ async function executeSemanticCommands(operation, commands, transport, options =
|
|
|
2185
2210
|
await transport.rm(stagingRoot);
|
|
2186
2211
|
}
|
|
2187
2212
|
}
|
|
2213
|
+
function isPluginAlreadyAbsentError(operation, error) {
|
|
2214
|
+
const output = commandErrorOutput(error).toLowerCase();
|
|
2215
|
+
if (!output || output.includes("command not found") || output.includes("module not found")) return false;
|
|
2216
|
+
const pluginName = (operation.semanticPlugin?.pluginName ?? operation.artifactName).toLowerCase();
|
|
2217
|
+
const escapedName = escapeRegExp(pluginName);
|
|
2218
|
+
const namedAbsent = [
|
|
2219
|
+
new RegExp(`${escapedName}.{0,120}\\b(not installed|not found|does not exist|absent)\\b`, "s"),
|
|
2220
|
+
new RegExp(`\\b(not installed|not found|does not exist|absent)\\b.{0,120}${escapedName}`, "s"),
|
|
2221
|
+
new RegExp(`\\bunknown plugin\\b.{0,120}${escapedName}`, "s"),
|
|
2222
|
+
new RegExp(`${escapedName}.{0,120}\\bunknown plugin\\b`, "s")
|
|
2223
|
+
].some((pattern) => pattern.test(output));
|
|
2224
|
+
const genericAbsent = /\b(no such|unknown)\s+plugins?\b/.test(output) || /\bplugins?\b.{0,80}\bnot installed\b/s.test(output);
|
|
2225
|
+
return namedAbsent || genericAbsent;
|
|
2226
|
+
}
|
|
2227
|
+
function commandErrorOutput(error) {
|
|
2228
|
+
if (typeof error === "object" && error !== null) {
|
|
2229
|
+
const stderr = "stderr" in error ? String(error.stderr ?? "") : "";
|
|
2230
|
+
if (stderr.trim()) return stderr;
|
|
2231
|
+
const stdout = "stdout" in error ? String(error.stdout ?? "") : "";
|
|
2232
|
+
if (stdout.trim()) return stdout;
|
|
2233
|
+
}
|
|
2234
|
+
return error instanceof Error ? error.message : String(error);
|
|
2235
|
+
}
|
|
2236
|
+
function firstErrorLine(error) {
|
|
2237
|
+
return commandErrorOutput(error).split(/\r?\n/).map((line) => line.trim()).find(Boolean) ?? "plugin is already absent";
|
|
2238
|
+
}
|
|
2239
|
+
function escapeRegExp(value) {
|
|
2240
|
+
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2241
|
+
}
|
|
2188
2242
|
function semanticInstallCommands(operation) {
|
|
2189
2243
|
if (operation.semanticPlugin) return operation.semanticPlugin.installCommands;
|
|
2190
2244
|
return operation.semanticCommand ? [operation.semanticCommand] : [];
|
|
@@ -2430,7 +2484,7 @@ function codexAgentName(artifact) {
|
|
|
2430
2484
|
}
|
|
2431
2485
|
function validateCodexAgentToml(content, path) {
|
|
2432
2486
|
for (const field of requiredCodexAgentFields) {
|
|
2433
|
-
const pattern = new RegExp(`(^|\\n)\\s*${
|
|
2487
|
+
const pattern = new RegExp(`(^|\\n)\\s*${escapeRegExp2(field)}\\s*=`, "m");
|
|
2434
2488
|
if (!pattern.test(content)) {
|
|
2435
2489
|
throw new Error(`Codex custom agent TOML ${path} is missing required field '${field}'.`);
|
|
2436
2490
|
}
|
|
@@ -2476,7 +2530,7 @@ function tomlMultilineString(value) {
|
|
|
2476
2530
|
${escaped.endsWith("\n") ? escaped : `${escaped}
|
|
2477
2531
|
`}"""`;
|
|
2478
2532
|
}
|
|
2479
|
-
function
|
|
2533
|
+
function escapeRegExp2(value) {
|
|
2480
2534
|
return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
|
|
2481
2535
|
}
|
|
2482
2536
|
|
|
@@ -9514,6 +9568,38 @@ program.command("status").description("show configured packages and runtime inst
|
|
|
9514
9568
|
await printStatus(target, normalizedOptions);
|
|
9515
9569
|
}
|
|
9516
9570
|
});
|
|
9571
|
+
var journalCommand = program.command("journal").description("inspect or abort pending apply journals");
|
|
9572
|
+
journalCommand.command("list").description("show pending apply journals for resolved runtime targets").option("--adapter <adapter>", "built-in adapter or comma-separated adapters").option("-i, --installation-type <type>", "installation type (for example local or user)").option("--user", "shortcut for --installation-type user and home-scoped state", false).option("--local", "shortcut for --installation-type local", false).option("--adapter-config <path>", "adapter JSON/JSONC file").option("--adapter-module <path>", "local programmatic adapter module").option("--allow-adapter-code", "allow loading local adapter code", false).option("-t, --target-root <path>", "runtime/project root").option("--agent <name>", "named agent from merged config").option("--all", "run for every configured agent", false).option("--profile <name>", "workspace runtime profile").action(async (options) => {
|
|
9573
|
+
const normalizedOptions = normalizeRuntimeScopeOptions(options);
|
|
9574
|
+
const targets = await resolveCliTargets(normalizedOptions, { preferAllProfile: true });
|
|
9575
|
+
let pending = 0;
|
|
9576
|
+
for (const target of targets) {
|
|
9577
|
+
const state = await journalStateForTarget(target, normalizedOptions);
|
|
9578
|
+
const journal = await readApplyJournal(state.installRoot, state.adapter.name, state.transport, state.state);
|
|
9579
|
+
if (!journal) continue;
|
|
9580
|
+
pending += 1;
|
|
9581
|
+
console.log(`PENDING ${state.adapter.name}/${state.installationType} at ${state.installRoot}`);
|
|
9582
|
+
console.log(` journal: ${join41(state.installRoot, ".agentwheel", `${state.state.stateKey}.apply-journal.json`)}`);
|
|
9583
|
+
console.log(` stateKey: ${state.state.stateKey}`);
|
|
9584
|
+
console.log(` createdAt: ${journal.createdAt}`);
|
|
9585
|
+
console.log(` updatedAt: ${journal.updatedAt}`);
|
|
9586
|
+
console.log(` operations: ${journal.operations.length}, completed: ${journal.completed.length}`);
|
|
9587
|
+
}
|
|
9588
|
+
if (pending === 0) console.log("No pending apply journals.");
|
|
9589
|
+
});
|
|
9590
|
+
journalCommand.command("abort").description("archive pending apply journals without touching runtime files").option("--adapter <adapter>", "built-in adapter or comma-separated adapters").option("-i, --installation-type <type>", "installation type (for example local or user)").option("--user", "shortcut for --installation-type user and home-scoped state", false).option("--local", "shortcut for --installation-type local", false).option("--adapter-config <path>", "adapter JSON/JSONC file").option("--adapter-module <path>", "local programmatic adapter module").option("--allow-adapter-code", "allow loading local adapter code", false).option("-t, --target-root <path>", "runtime/project root").option("--agent <name>", "named agent from merged config").option("--all", "run for every configured agent", false).option("--profile <name>", "workspace runtime profile").action(async (options) => {
|
|
9591
|
+
const normalizedOptions = normalizeRuntimeScopeOptions(options);
|
|
9592
|
+
const targets = await resolveCliTargets(normalizedOptions, { preferAllProfile: true });
|
|
9593
|
+
let aborted = 0;
|
|
9594
|
+
for (const target of targets) {
|
|
9595
|
+
const state = await journalStateForTarget(target, normalizedOptions);
|
|
9596
|
+
const result = await abortApplyJournal(state.installRoot, state.adapter.name, state.transport, state.state);
|
|
9597
|
+
if (!result) continue;
|
|
9598
|
+
aborted += 1;
|
|
9599
|
+
console.log(`Archived ${state.adapter.name}/${state.installationType} pending journal: ${result.archivePath}`);
|
|
9600
|
+
}
|
|
9601
|
+
if (aborted === 0) console.log("No pending apply journals.");
|
|
9602
|
+
});
|
|
9517
9603
|
program.command("doctor").description("check agentwheel runtime setup and companion skill guidance").option("--adapter <adapter>", "built-in adapter").option("-i, --installation-type <type>", "installation type (for example local or user)").option("--user", "shortcut for --installation-type user and home-scoped state", false).option("--local", "shortcut for --installation-type local", false).option("-t, --target-root <path>", "runtime/project root").option("--agent <name>", "named agent from merged config").option("--adapter-config <path>", "adapter JSON/JSONC file").option("--adapter-module <path>", "local programmatic adapter module").option("--allow-adapter-code", "allow loading local adapter code", false).option("--skill <name>", "check a specific skill by name (repeatable or comma-separated)", collectSkillOption, []).option("--source <source>", "source to use in suggested install commands").option("--json", "print machine-readable doctor report", false).action(async (options) => {
|
|
9518
9604
|
const normalizedOptions = normalizeRuntimeScopeOptions(options);
|
|
9519
9605
|
const target = await resolveRuntimeTarget({
|
|
@@ -10206,6 +10292,14 @@ async function printStatus(target, options) {
|
|
|
10206
10292
|
}
|
|
10207
10293
|
await printPendingInstallWork(target, options);
|
|
10208
10294
|
}
|
|
10295
|
+
async function journalStateForTarget(target, options) {
|
|
10296
|
+
const adapterOptions = adapterOptionsForTarget(target, options);
|
|
10297
|
+
const adapter = await resolveAdapterForTarget(target, adapterOptions);
|
|
10298
|
+
const transport = transportForTarget(target);
|
|
10299
|
+
const installationType = options.installationType ?? target.installationType ?? resolveInstallationTypeForAdapter(adapter);
|
|
10300
|
+
const state = installStateForTarget(target, adapter, adapterOptions, installationType);
|
|
10301
|
+
return { adapter, transport, installationType, installRoot: state.installRoot, state };
|
|
10302
|
+
}
|
|
10209
10303
|
async function printPendingInstallWork(target, options) {
|
|
10210
10304
|
let results = [];
|
|
10211
10305
|
try {
|