akm-cli 0.9.25-alpha.2 → 0.9.25-alpha.3
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/CHANGELOG.md +84 -0
- package/dist/assets/prompts/reflect-feedback-framing.md +1 -1
- package/dist/assets/prompts/reflect-llm-framed-contract.md +2 -9
- package/dist/assets/prompts/reflect-llm-schema-contract.md +1 -3
- package/dist/assets/prompts/reflect-output-repair.md +1 -1
- package/dist/commands/improve/extract-cli.js +3 -2
- package/dist/commands/improve/extract.js +1 -1
- package/dist/commands/improve/reflect.js +140 -320
- package/dist/commands/improve/session-asset.js +6 -0
- package/dist/commands/proposal/validators/proposal-quality-validators.js +7 -3
- package/dist/commands/proposal/validators/proposal-validators.js +4 -5
- package/dist/core/asset/asset-serialize.js +1 -1
- package/dist/core/content-safety.js +0 -24
- package/dist/integrations/agent/prompts.js +51 -91
- package/dist/integrations/harnesses/codex/index.js +6 -11
- package/dist/integrations/harnesses/codex/session-log.js +211 -0
- package/dist/integrations/harnesses/types.js +3 -3
- package/dist/scripts/akm-migrate-node.js +258 -92
- package/dist/scripts/akm-migrate.js +258 -92
- package/docs/reference/cli.md +17 -9
- package/docs/reference/configuration.md +1 -3
- package/package.json +1 -1
|
@@ -51767,6 +51767,170 @@ var codexResultExtractor = (result) => {
|
|
|
51767
51767
|
return sessionId === undefined ? { text } : { text, sessionId };
|
|
51768
51768
|
};
|
|
51769
51769
|
|
|
51770
|
+
// src/integrations/harnesses/codex/session-log.ts
|
|
51771
|
+
import fs36 from "node:fs";
|
|
51772
|
+
import os5 from "node:os";
|
|
51773
|
+
import path43 from "node:path";
|
|
51774
|
+
function codexSessionsDir() {
|
|
51775
|
+
return path43.join(process.env.CODEX_HOME || path43.join(os5.homedir(), ".codex"), "sessions");
|
|
51776
|
+
}
|
|
51777
|
+
var META_PEEK_BYTES = 128 * 1024;
|
|
51778
|
+
var INJECTED_CONTEXT_RE = /^\s*(?:# AGENTS\.md instructions[\s\S]*<\/INSTRUCTIONS>|<(environment_context|user_instructions|recommended_plugins|skill|turn_aborted)>[\s\S]*<\/\1>)\s*$/i;
|
|
51779
|
+
function parseSessionMeta(entry) {
|
|
51780
|
+
const e = entry;
|
|
51781
|
+
if (e?.type !== "session_meta" || !e.payload)
|
|
51782
|
+
return;
|
|
51783
|
+
const { timestamp, cwd, source } = e.payload;
|
|
51784
|
+
const startedAt = typeof timestamp === "string" ? Date.parse(timestamp) : Number.NaN;
|
|
51785
|
+
return {
|
|
51786
|
+
...Number.isNaN(startedAt) ? {} : { startedAt },
|
|
51787
|
+
...typeof cwd === "string" ? { cwd } : {},
|
|
51788
|
+
isAgent: typeof source === "object" && source !== null && (("subagent" in source) || ("internal" in source))
|
|
51789
|
+
};
|
|
51790
|
+
}
|
|
51791
|
+
function blockText(blocks, keep = () => true) {
|
|
51792
|
+
if (typeof blocks === "string")
|
|
51793
|
+
return blocks;
|
|
51794
|
+
if (!Array.isArray(blocks))
|
|
51795
|
+
return "";
|
|
51796
|
+
const parts = [];
|
|
51797
|
+
for (const block of blocks) {
|
|
51798
|
+
const text = block?.text;
|
|
51799
|
+
if (typeof text === "string" && keep(text))
|
|
51800
|
+
parts.push(text);
|
|
51801
|
+
}
|
|
51802
|
+
return parts.join(`
|
|
51803
|
+
`);
|
|
51804
|
+
}
|
|
51805
|
+
function toolInputText(input) {
|
|
51806
|
+
let args = input;
|
|
51807
|
+
if (typeof input === "string") {
|
|
51808
|
+
try {
|
|
51809
|
+
args = JSON.parse(input);
|
|
51810
|
+
} catch {
|
|
51811
|
+
return input;
|
|
51812
|
+
}
|
|
51813
|
+
}
|
|
51814
|
+
const fields = args && typeof args === "object" ? args : {};
|
|
51815
|
+
const cmd = fields.cmd ?? fields.command;
|
|
51816
|
+
if (typeof cmd === "string")
|
|
51817
|
+
return cmd;
|
|
51818
|
+
if (Array.isArray(cmd))
|
|
51819
|
+
return cmd.join(" ");
|
|
51820
|
+
return typeof input === "string" ? input : JSON.stringify(input) ?? "";
|
|
51821
|
+
}
|
|
51822
|
+
function parseCodexRecord(entry, sessionId, filePath, fallbackTsMs) {
|
|
51823
|
+
const e = entry;
|
|
51824
|
+
const item = e?.type === "response_item" ? e.payload : undefined;
|
|
51825
|
+
if (!item)
|
|
51826
|
+
return;
|
|
51827
|
+
const toolName2 = typeof item.name === "string" ? item.name : "tool";
|
|
51828
|
+
let role = "assistant";
|
|
51829
|
+
let text;
|
|
51830
|
+
switch (item.type) {
|
|
51831
|
+
case "message":
|
|
51832
|
+
if (item.role !== "user" && item.role !== "assistant")
|
|
51833
|
+
return;
|
|
51834
|
+
role = item.role;
|
|
51835
|
+
text = blockText(item.content, item.role === "user" ? (t) => !INJECTED_CONTEXT_RE.test(t) : undefined);
|
|
51836
|
+
break;
|
|
51837
|
+
case "function_call":
|
|
51838
|
+
text = `[tool:${toolName2}] ${toolInputText(item.arguments)}`;
|
|
51839
|
+
break;
|
|
51840
|
+
case "custom_tool_call":
|
|
51841
|
+
text = `[tool:${toolName2}] ${typeof item.input === "string" ? item.input : ""}`;
|
|
51842
|
+
break;
|
|
51843
|
+
case "local_shell_call":
|
|
51844
|
+
text = `[tool:shell] ${toolInputText(item.action)}`;
|
|
51845
|
+
break;
|
|
51846
|
+
case "function_call_output":
|
|
51847
|
+
case "custom_tool_call_output": {
|
|
51848
|
+
role = "tool";
|
|
51849
|
+
const output = blockText(item.output);
|
|
51850
|
+
text = output ? `[tool_result] ${output}` : "";
|
|
51851
|
+
break;
|
|
51852
|
+
}
|
|
51853
|
+
default:
|
|
51854
|
+
return;
|
|
51855
|
+
}
|
|
51856
|
+
if (!text.trim())
|
|
51857
|
+
return;
|
|
51858
|
+
const ts = typeof e?.timestamp === "string" ? Date.parse(e.timestamp) || fallbackTsMs : fallbackTsMs;
|
|
51859
|
+
return { harness: "codex", text, ts, sessionId, role, filePath };
|
|
51860
|
+
}
|
|
51861
|
+
|
|
51862
|
+
class CodexProvider extends AbstractSessionLogProvider {
|
|
51863
|
+
name = "codex";
|
|
51864
|
+
availabilityRoot() {
|
|
51865
|
+
return codexSessionsDir();
|
|
51866
|
+
}
|
|
51867
|
+
listSessions(input = {}) {
|
|
51868
|
+
return this.listSessionsFromFiles({
|
|
51869
|
+
sinceMs: input.sinceMs ?? 0,
|
|
51870
|
+
enumerate: () => this.walkFiles(input.location ?? codexSessionsDir(), (name) => /^rollout-.+\.jsonl$/.test(name)),
|
|
51871
|
+
summarize: (rolloutPath, stat) => {
|
|
51872
|
+
const meta = this.#peekMeta(rolloutPath);
|
|
51873
|
+
if (meta?.isAgent)
|
|
51874
|
+
return;
|
|
51875
|
+
return this.sessionRef({
|
|
51876
|
+
sessionId: path43.basename(rolloutPath, ".jsonl").slice(-36),
|
|
51877
|
+
filePath: rolloutPath,
|
|
51878
|
+
startedAt: meta?.startedAt ?? stat.ctimeMs,
|
|
51879
|
+
endedAt: stat.mtimeMs,
|
|
51880
|
+
projectHint: meta?.cwd
|
|
51881
|
+
});
|
|
51882
|
+
}
|
|
51883
|
+
});
|
|
51884
|
+
}
|
|
51885
|
+
readSession(ref) {
|
|
51886
|
+
const stat = fs36.statSync(ref.filePath);
|
|
51887
|
+
const events = [];
|
|
51888
|
+
const inlineRefs = [];
|
|
51889
|
+
let meta;
|
|
51890
|
+
for (const line of fs36.readFileSync(ref.filePath, "utf8").split(`
|
|
51891
|
+
`).filter(Boolean)) {
|
|
51892
|
+
let entry;
|
|
51893
|
+
try {
|
|
51894
|
+
entry = JSON.parse(line);
|
|
51895
|
+
} catch {
|
|
51896
|
+
continue;
|
|
51897
|
+
}
|
|
51898
|
+
meta ??= parseSessionMeta(entry);
|
|
51899
|
+
const parsed = parseCodexRecord(entry, ref.sessionId, ref.filePath, stat.mtimeMs);
|
|
51900
|
+
if (!parsed)
|
|
51901
|
+
continue;
|
|
51902
|
+
events.push(parsed);
|
|
51903
|
+
inlineRefs.push(...extractInlineRefMentions(parsed.text, parsed.ts));
|
|
51904
|
+
}
|
|
51905
|
+
return {
|
|
51906
|
+
ref: this.sessionRef({
|
|
51907
|
+
sessionId: ref.sessionId,
|
|
51908
|
+
filePath: ref.filePath,
|
|
51909
|
+
startedAt: meta?.startedAt ?? events[0]?.ts ?? stat.ctimeMs,
|
|
51910
|
+
endedAt: events[events.length - 1]?.ts ?? stat.mtimeMs,
|
|
51911
|
+
projectHint: meta?.cwd
|
|
51912
|
+
}),
|
|
51913
|
+
events,
|
|
51914
|
+
inlineRefs
|
|
51915
|
+
};
|
|
51916
|
+
}
|
|
51917
|
+
#peekMeta(filePath) {
|
|
51918
|
+
try {
|
|
51919
|
+
const fd = fs36.openSync(filePath, "r");
|
|
51920
|
+
try {
|
|
51921
|
+
const head = Buffer.alloc(META_PEEK_BYTES);
|
|
51922
|
+
const firstLine = head.toString("utf8", 0, fs36.readSync(fd, head, 0, head.length, 0)).split(`
|
|
51923
|
+
`, 1)[0] ?? "";
|
|
51924
|
+
return parseSessionMeta(JSON.parse(firstLine));
|
|
51925
|
+
} finally {
|
|
51926
|
+
fs36.closeSync(fd);
|
|
51927
|
+
}
|
|
51928
|
+
} catch {
|
|
51929
|
+
return;
|
|
51930
|
+
}
|
|
51931
|
+
}
|
|
51932
|
+
}
|
|
51933
|
+
|
|
51770
51934
|
// src/integrations/harnesses/codex/index.ts
|
|
51771
51935
|
class CodexHarness extends BaseHarness {
|
|
51772
51936
|
id = "codex";
|
|
@@ -51774,7 +51938,9 @@ class CodexHarness extends BaseHarness {
|
|
|
51774
51938
|
agentBuilder = codexBuilder;
|
|
51775
51939
|
resultExtractor = codexResultExtractor;
|
|
51776
51940
|
presenceEnv = ["CODEX_SANDBOX"];
|
|
51941
|
+
sessionLogProvider = () => new CodexProvider;
|
|
51777
51942
|
capabilities = caps({
|
|
51943
|
+
sessionLogs: true,
|
|
51778
51944
|
agentDispatch: true,
|
|
51779
51945
|
detection: true
|
|
51780
51946
|
});
|
|
@@ -52095,7 +52261,7 @@ function opencodeInferenceConfig(inference, modelWork) {
|
|
|
52095
52261
|
}
|
|
52096
52262
|
|
|
52097
52263
|
// src/integrations/harnesses/opencode/model-work-agent.ts
|
|
52098
|
-
import
|
|
52264
|
+
import path44 from "node:path";
|
|
52099
52265
|
var MODEL_WORK_OPENCODE_AGENT = "akm-model-work";
|
|
52100
52266
|
var MODEL_WORK_PROMPT = "You do one bounded task for akm. Use tools only to check what the task needs, never repeat a tool call, and reply with exactly what the task asks for.";
|
|
52101
52267
|
function modelWorkPermission(stash) {
|
|
@@ -52132,7 +52298,7 @@ function modelWorkPluginEnv() {
|
|
|
52132
52298
|
AKM_AUTO_LEARNING: "0",
|
|
52133
52299
|
AKM_AUTO_SKILL_PROPOSALS: "0",
|
|
52134
52300
|
AKM_WRITE_GATE: "off",
|
|
52135
|
-
XDG_STATE_HOME:
|
|
52301
|
+
XDG_STATE_HOME: path44.join(getStateDir(), "opencode-model-work"),
|
|
52136
52302
|
...process.platform === "win32" ? {} : { AKM_OPENCODE_CLI: "/bin/true" }
|
|
52137
52303
|
};
|
|
52138
52304
|
}
|
|
@@ -52215,15 +52381,15 @@ var opencodeBuilder = {
|
|
|
52215
52381
|
};
|
|
52216
52382
|
|
|
52217
52383
|
// src/integrations/harnesses/opencode/session-log.ts
|
|
52218
|
-
import
|
|
52219
|
-
import
|
|
52220
|
-
import
|
|
52384
|
+
import fs38 from "node:fs";
|
|
52385
|
+
import os7 from "node:os";
|
|
52386
|
+
import path46 from "node:path";
|
|
52221
52387
|
|
|
52222
52388
|
// src/storage/sqlite-read-snapshot.ts
|
|
52223
52389
|
import { spawnSync as spawnSync5 } from "node:child_process";
|
|
52224
|
-
import
|
|
52225
|
-
import
|
|
52226
|
-
import
|
|
52390
|
+
import fs37 from "node:fs";
|
|
52391
|
+
import os6 from "node:os";
|
|
52392
|
+
import path45 from "node:path";
|
|
52227
52393
|
var SNAPSHOT_MAX_ATTEMPTS = 8;
|
|
52228
52394
|
var SNAPSHOT_BACKOFF_MS = 25;
|
|
52229
52395
|
|
|
@@ -52235,7 +52401,7 @@ class SqliteReadSnapshotUnavailableError extends Error {
|
|
|
52235
52401
|
}
|
|
52236
52402
|
function pathExists(filePath) {
|
|
52237
52403
|
try {
|
|
52238
|
-
|
|
52404
|
+
fs37.lstatSync(filePath);
|
|
52239
52405
|
return true;
|
|
52240
52406
|
} catch (error2) {
|
|
52241
52407
|
if (error2.code === "ENOENT")
|
|
@@ -52245,7 +52411,7 @@ function pathExists(filePath) {
|
|
|
52245
52411
|
}
|
|
52246
52412
|
function fileFingerprint(filePath) {
|
|
52247
52413
|
try {
|
|
52248
|
-
const stat =
|
|
52414
|
+
const stat = fs37.statSync(filePath, { bigint: true });
|
|
52249
52415
|
return { size: stat.size, mtimeNs: stat.mtimeNs, ctimeNs: stat.ctimeNs };
|
|
52250
52416
|
} catch (error2) {
|
|
52251
52417
|
if (error2.code === "ENOENT")
|
|
@@ -52267,7 +52433,7 @@ function fingerprintsEqual(left, right) {
|
|
|
52267
52433
|
}
|
|
52268
52434
|
function copyFileOutsideThisProcess(source, destination) {
|
|
52269
52435
|
if (process.platform === "win32") {
|
|
52270
|
-
|
|
52436
|
+
fs37.copyFileSync(source, destination);
|
|
52271
52437
|
return;
|
|
52272
52438
|
}
|
|
52273
52439
|
const result = spawnSync5("cp", ["--", source, destination], {
|
|
@@ -52288,8 +52454,8 @@ function copyFileOutsideThisProcess(source, destination) {
|
|
|
52288
52454
|
function openSqliteReadSnapshot(dbPath) {
|
|
52289
52455
|
if (!pathExists(dbPath))
|
|
52290
52456
|
return;
|
|
52291
|
-
const snapshotDir =
|
|
52292
|
-
const snapshotPath =
|
|
52457
|
+
const snapshotDir = fs37.mkdtempSync(path45.join(os6.tmpdir(), "akm-sqlite-read-"));
|
|
52458
|
+
const snapshotPath = path45.join(snapshotDir, "snapshot.db");
|
|
52293
52459
|
let db;
|
|
52294
52460
|
try {
|
|
52295
52461
|
let copied = false;
|
|
@@ -52304,7 +52470,7 @@ function openSqliteReadSnapshot(dbPath) {
|
|
|
52304
52470
|
if (before.wal)
|
|
52305
52471
|
copyFileOutsideThisProcess(`${dbPath}-wal`, `${snapshotPath}-wal`);
|
|
52306
52472
|
else
|
|
52307
|
-
|
|
52473
|
+
fs37.rmSync(`${snapshotPath}-wal`, { force: true });
|
|
52308
52474
|
const after = databaseFingerprint(dbPath);
|
|
52309
52475
|
if (fingerprintsEqual(before, after) && !pathExists(`${dbPath}-journal`)) {
|
|
52310
52476
|
copied = true;
|
|
@@ -52332,14 +52498,14 @@ function openSqliteReadSnapshot(dbPath) {
|
|
|
52332
52498
|
closeSnapshot();
|
|
52333
52499
|
} catch {}
|
|
52334
52500
|
try {
|
|
52335
|
-
|
|
52501
|
+
fs37.rmSync(snapshotDir, { recursive: true, force: true });
|
|
52336
52502
|
} catch {}
|
|
52337
52503
|
return;
|
|
52338
52504
|
}
|
|
52339
52505
|
try {
|
|
52340
52506
|
closeSnapshot();
|
|
52341
52507
|
} finally {
|
|
52342
|
-
|
|
52508
|
+
fs37.rmSync(snapshotDir, { recursive: true, force: true });
|
|
52343
52509
|
}
|
|
52344
52510
|
};
|
|
52345
52511
|
const cleanupOnExit = () => cleanup(true);
|
|
@@ -52350,7 +52516,7 @@ function openSqliteReadSnapshot(dbPath) {
|
|
|
52350
52516
|
try {
|
|
52351
52517
|
db?.close();
|
|
52352
52518
|
} finally {
|
|
52353
|
-
|
|
52519
|
+
fs37.rmSync(snapshotDir, { recursive: true, force: true });
|
|
52354
52520
|
}
|
|
52355
52521
|
throw error2;
|
|
52356
52522
|
}
|
|
@@ -52359,9 +52525,9 @@ function openSqliteReadSnapshot(dbPath) {
|
|
|
52359
52525
|
// src/integrations/harnesses/opencode/session-log.ts
|
|
52360
52526
|
function getOpenCodeBaseDir() {
|
|
52361
52527
|
if (process.platform === "darwin") {
|
|
52362
|
-
return
|
|
52528
|
+
return path46.join(os7.homedir(), "Library", "Application Support", "opencode");
|
|
52363
52529
|
}
|
|
52364
|
-
return
|
|
52530
|
+
return path46.join(os7.homedir(), ".local", "share", "opencode");
|
|
52365
52531
|
}
|
|
52366
52532
|
var OPENCODE_DB_FILENAME = "opencode.db";
|
|
52367
52533
|
|
|
@@ -52372,13 +52538,13 @@ class OpenCodeProvider extends AbstractSessionLogProvider {
|
|
|
52372
52538
|
return this.#dbPath(this.#baseDir);
|
|
52373
52539
|
}
|
|
52374
52540
|
#dbPath(base) {
|
|
52375
|
-
return
|
|
52541
|
+
return path46.join(base, OPENCODE_DB_FILENAME);
|
|
52376
52542
|
}
|
|
52377
52543
|
listSessions(input = {}) {
|
|
52378
52544
|
const base = input.location ?? this.#baseDir;
|
|
52379
52545
|
const sinceMs = input.sinceMs ?? 0;
|
|
52380
52546
|
const dbPath = this.#dbPath(base);
|
|
52381
|
-
if (!
|
|
52547
|
+
if (!fs38.existsSync(dbPath))
|
|
52382
52548
|
return [];
|
|
52383
52549
|
return this.#listSessionsFromDb(dbPath, sinceMs, input.isolatedSnapshot ?? false);
|
|
52384
52550
|
}
|
|
@@ -53287,8 +53453,8 @@ Commands:
|
|
|
53287
53453
|
`;
|
|
53288
53454
|
|
|
53289
53455
|
// scripts/akm-migrate/migrate/dead-residue.ts
|
|
53290
|
-
import
|
|
53291
|
-
import
|
|
53456
|
+
import fs39 from "node:fs";
|
|
53457
|
+
import path47 from "node:path";
|
|
53292
53458
|
var DEAD_RESIDUE_PATHS = [
|
|
53293
53459
|
{ name: "proposals", reason: "superseded by the `proposals` table in $DATA/state.db (0.9.0)" },
|
|
53294
53460
|
{ prefix: "runs.archived-", reason: "orphaned archive of a directory that no longer exists" },
|
|
@@ -53305,43 +53471,43 @@ function dirSizeBytes(target) {
|
|
|
53305
53471
|
let total = 0;
|
|
53306
53472
|
let entries;
|
|
53307
53473
|
try {
|
|
53308
|
-
entries =
|
|
53474
|
+
entries = fs39.readdirSync(target, { withFileTypes: true });
|
|
53309
53475
|
} catch {
|
|
53310
53476
|
return 0;
|
|
53311
53477
|
}
|
|
53312
53478
|
for (const entry of entries) {
|
|
53313
|
-
const entryPath =
|
|
53479
|
+
const entryPath = path47.join(target, entry.name);
|
|
53314
53480
|
if (entry.isDirectory()) {
|
|
53315
53481
|
total += dirSizeBytes(entryPath);
|
|
53316
53482
|
} else if (entry.isFile()) {
|
|
53317
53483
|
try {
|
|
53318
|
-
total +=
|
|
53484
|
+
total += fs39.statSync(entryPath).size;
|
|
53319
53485
|
} catch {}
|
|
53320
53486
|
}
|
|
53321
53487
|
}
|
|
53322
53488
|
return total;
|
|
53323
53489
|
}
|
|
53324
53490
|
function sizeOf(target) {
|
|
53325
|
-
const st =
|
|
53491
|
+
const st = fs39.statSync(target);
|
|
53326
53492
|
return st.isDirectory() ? dirSizeBytes(target) : st.size;
|
|
53327
53493
|
}
|
|
53328
53494
|
function hostResidue() {
|
|
53329
53495
|
const data = getDataDir();
|
|
53330
53496
|
const state = getStateDir();
|
|
53331
|
-
const configDir =
|
|
53497
|
+
const configDir = path47.dirname(getConfigPath());
|
|
53332
53498
|
const named = [
|
|
53333
|
-
{ absolutePath:
|
|
53334
|
-
{ absolutePath:
|
|
53335
|
-
{ absolutePath:
|
|
53336
|
-
{ absolutePath:
|
|
53337
|
-
{ absolutePath:
|
|
53338
|
-
{ absolutePath:
|
|
53339
|
-
{ absolutePath:
|
|
53499
|
+
{ absolutePath: path47.join(data, "txn"), reason: "filesystem transaction journals (removed in 0.9.17)" },
|
|
53500
|
+
{ absolutePath: path47.join(data, "txn-quarantine"), reason: "quarantined transaction journals (removed in 0.9.17)" },
|
|
53501
|
+
{ absolutePath: path47.join(data, "maintenance.barrier.lock"), reason: "maintenance barrier (removed in 0.9.17)" },
|
|
53502
|
+
{ absolutePath: path47.join(data, "maintenance-activities"), reason: "per-process activity registry (removed in 0.9.17)" },
|
|
53503
|
+
{ absolutePath: path47.join(state, "maintenance-activities"), reason: "per-process activity registry (removed in 0.9.17)" },
|
|
53504
|
+
{ absolutePath: path47.join(state, "version-reconcile.json"), reason: "startup reconcile stamp (removed in 0.9.17)" },
|
|
53505
|
+
{ absolutePath: path47.join(state, "locks", "version-reconcile.lock"), reason: "startup reconcile lock (removed in 0.9.17)" }
|
|
53340
53506
|
];
|
|
53341
53507
|
const found = [];
|
|
53342
53508
|
const claimed = new Set;
|
|
53343
53509
|
for (const entry of named) {
|
|
53344
|
-
if (claimed.has(entry.absolutePath) || !
|
|
53510
|
+
if (claimed.has(entry.absolutePath) || !fs39.existsSync(entry.absolutePath))
|
|
53345
53511
|
continue;
|
|
53346
53512
|
try {
|
|
53347
53513
|
found.push({ ...entry, relativePath: entry.absolutePath, sizeBytes: sizeOf(entry.absolutePath) });
|
|
@@ -53365,13 +53531,13 @@ function hostResidue() {
|
|
|
53365
53531
|
function findSidecars(root, depth, skip) {
|
|
53366
53532
|
let entries;
|
|
53367
53533
|
try {
|
|
53368
|
-
entries =
|
|
53534
|
+
entries = fs39.readdirSync(root, { withFileTypes: true });
|
|
53369
53535
|
} catch {
|
|
53370
53536
|
return [];
|
|
53371
53537
|
}
|
|
53372
53538
|
const found = [];
|
|
53373
53539
|
for (const entry of entries) {
|
|
53374
|
-
const entryPath =
|
|
53540
|
+
const entryPath = path47.join(root, entry.name);
|
|
53375
53541
|
if (entry.isFile() && entry.name.endsWith(".operations.sensitive"))
|
|
53376
53542
|
found.push(entryPath);
|
|
53377
53543
|
else if (entry.isDirectory() && depth > 0 && !skip.has(entryPath)) {
|
|
@@ -53384,10 +53550,10 @@ function findDeadResidueEntries(stashDir) {
|
|
|
53384
53550
|
const host = hostResidue();
|
|
53385
53551
|
if (stashDir === undefined)
|
|
53386
53552
|
return host;
|
|
53387
|
-
const akmDir =
|
|
53553
|
+
const akmDir = path47.join(stashDir, ".akm");
|
|
53388
53554
|
let names;
|
|
53389
53555
|
try {
|
|
53390
|
-
names =
|
|
53556
|
+
names = fs39.readdirSync(akmDir);
|
|
53391
53557
|
} catch {
|
|
53392
53558
|
return [];
|
|
53393
53559
|
}
|
|
@@ -53397,14 +53563,14 @@ function findDeadResidueEntries(stashDir) {
|
|
|
53397
53563
|
for (const name of matches) {
|
|
53398
53564
|
if (!names.includes(name))
|
|
53399
53565
|
continue;
|
|
53400
|
-
const absolutePath =
|
|
53566
|
+
const absolutePath = path47.join(akmDir, name);
|
|
53401
53567
|
let sizeBytes;
|
|
53402
53568
|
try {
|
|
53403
53569
|
sizeBytes = sizeOf(absolutePath);
|
|
53404
53570
|
} catch {
|
|
53405
53571
|
continue;
|
|
53406
53572
|
}
|
|
53407
|
-
found.push({ relativePath:
|
|
53573
|
+
found.push({ relativePath: path47.join(".akm", name), absolutePath, sizeBytes, reason: spec.reason });
|
|
53408
53574
|
}
|
|
53409
53575
|
}
|
|
53410
53576
|
return found;
|
|
@@ -53413,7 +53579,7 @@ function removeDeadResidue(stashDir) {
|
|
|
53413
53579
|
const entries = findDeadResidueEntries(stashDir);
|
|
53414
53580
|
return entries.map((entry) => {
|
|
53415
53581
|
try {
|
|
53416
|
-
|
|
53582
|
+
fs39.rmSync(entry.absolutePath, { recursive: true, force: true });
|
|
53417
53583
|
return { relativePath: entry.relativePath, sizeBytes: entry.sizeBytes, removed: true };
|
|
53418
53584
|
} catch (error2) {
|
|
53419
53585
|
return {
|
|
@@ -53428,18 +53594,18 @@ function removeDeadResidue(stashDir) {
|
|
|
53428
53594
|
|
|
53429
53595
|
// scripts/akm-migrate/task-migrate.ts
|
|
53430
53596
|
import { randomUUID as randomUUID3 } from "node:crypto";
|
|
53431
|
-
import
|
|
53432
|
-
import
|
|
53433
|
-
import
|
|
53597
|
+
import fs41 from "node:fs";
|
|
53598
|
+
import os8 from "node:os";
|
|
53599
|
+
import path50 from "node:path";
|
|
53434
53600
|
|
|
53435
53601
|
// scripts/akm-migrate/migrate/task-files.ts
|
|
53436
53602
|
import crypto4 from "node:crypto";
|
|
53437
|
-
import
|
|
53438
|
-
import
|
|
53603
|
+
import fs40 from "node:fs";
|
|
53604
|
+
import path49 from "node:path";
|
|
53439
53605
|
|
|
53440
53606
|
// src/tasks/source/task-to-v4.ts
|
|
53441
53607
|
import crypto3 from "node:crypto";
|
|
53442
|
-
import
|
|
53608
|
+
import path48 from "node:path";
|
|
53443
53609
|
|
|
53444
53610
|
// src/tasks/task-id.ts
|
|
53445
53611
|
var VALID_TASK_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
@@ -54248,7 +54414,7 @@ function addSharedNonPromptOverrides(data, akm) {
|
|
|
54248
54414
|
}
|
|
54249
54415
|
function promptSourceKind(raw) {
|
|
54250
54416
|
const trimmed = raw.trim();
|
|
54251
|
-
if (trimmed.startsWith("./") || trimmed.startsWith("../") ||
|
|
54417
|
+
if (trimmed.startsWith("./") || trimmed.startsWith("../") || path48.isAbsolute(trimmed) || /^[A-Za-z]:[\\/]/.test(trimmed)) {
|
|
54252
54418
|
return "file";
|
|
54253
54419
|
}
|
|
54254
54420
|
try {
|
|
@@ -54352,7 +54518,7 @@ function planV2DataToV4(input, data) {
|
|
|
54352
54518
|
return blocked(input, "read-only-source", !input.writable ? "the owning source is not writable" : "the source file or publication directory is read-only");
|
|
54353
54519
|
}
|
|
54354
54520
|
try {
|
|
54355
|
-
validateTaskId(
|
|
54521
|
+
validateTaskId(path48.basename(input.filePath, ".yml"));
|
|
54356
54522
|
} catch (cause) {
|
|
54357
54523
|
return blocked(input, "invalid-v2-task", causeMessage(cause));
|
|
54358
54524
|
}
|
|
@@ -54497,7 +54663,7 @@ function taskToV4PlanFromOutcomes(outcomes) {
|
|
|
54497
54663
|
for (let index = 1;index < files.length; index += 1) {
|
|
54498
54664
|
const previous = files[index - 1];
|
|
54499
54665
|
const current = files[index];
|
|
54500
|
-
if (previous && current &&
|
|
54666
|
+
if (previous && current && path48.resolve(previous.filePath) === path48.resolve(current.filePath)) {
|
|
54501
54667
|
throw new Error(`duplicate task migration file path: ${current.filePath}`);
|
|
54502
54668
|
}
|
|
54503
54669
|
}
|
|
@@ -54509,18 +54675,18 @@ function migrationError(detail) {
|
|
|
54509
54675
|
return new ConfigError(`Task migration failed: ${detail}`, "INVALID_CONFIG_FILE");
|
|
54510
54676
|
}
|
|
54511
54677
|
function contained2(root, candidate) {
|
|
54512
|
-
const relative =
|
|
54513
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
54678
|
+
const relative = path49.relative(root, candidate);
|
|
54679
|
+
return relative === "" || !relative.startsWith("..") && !path49.isAbsolute(relative);
|
|
54514
54680
|
}
|
|
54515
54681
|
function realDirectory(filePath) {
|
|
54516
|
-
const stat =
|
|
54682
|
+
const stat = fs40.lstatSync(filePath);
|
|
54517
54683
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
54518
54684
|
throw migrationError(`${filePath} must be a real directory.`);
|
|
54519
|
-
return
|
|
54685
|
+
return fs40.realpathSync(filePath);
|
|
54520
54686
|
}
|
|
54521
54687
|
function isWritable(filePath) {
|
|
54522
54688
|
try {
|
|
54523
|
-
|
|
54689
|
+
fs40.accessSync(filePath, fs40.constants.W_OK);
|
|
54524
54690
|
return true;
|
|
54525
54691
|
} catch {
|
|
54526
54692
|
return false;
|
|
@@ -54533,12 +54699,12 @@ function walkTasks(root, tasksDir, out) {
|
|
|
54533
54699
|
throw migrationError(`${root.root} resolves outside bundle ${root.bundleId}.`);
|
|
54534
54700
|
}
|
|
54535
54701
|
const visit2 = (directory) => {
|
|
54536
|
-
const physicalDirectory =
|
|
54702
|
+
const physicalDirectory = fs40.realpathSync(directory);
|
|
54537
54703
|
if (!contained2(physicalRoot, physicalDirectory)) {
|
|
54538
54704
|
throw migrationError(`${directory} resolves outside bundle ${root.bundleId}.`);
|
|
54539
54705
|
}
|
|
54540
|
-
for (const entry of
|
|
54541
|
-
const candidate =
|
|
54706
|
+
for (const entry of fs40.readdirSync(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
54707
|
+
const candidate = path49.join(directory, entry.name);
|
|
54542
54708
|
if (entry.isSymbolicLink())
|
|
54543
54709
|
throw migrationError(`task migration does not follow symbolic link ${candidate}.`);
|
|
54544
54710
|
if (entry.isDirectory()) {
|
|
@@ -54547,11 +54713,11 @@ function walkTasks(root, tasksDir, out) {
|
|
|
54547
54713
|
}
|
|
54548
54714
|
if (!entry.isFile() || !entry.name.endsWith(".yml"))
|
|
54549
54715
|
continue;
|
|
54550
|
-
const stat =
|
|
54716
|
+
const stat = fs40.lstatSync(candidate);
|
|
54551
54717
|
const mode = stat.mode & 511;
|
|
54552
54718
|
out.push({
|
|
54553
54719
|
filePath: candidate,
|
|
54554
|
-
bytes:
|
|
54720
|
+
bytes: fs40.readFileSync(candidate),
|
|
54555
54721
|
mode,
|
|
54556
54722
|
writable: root.writable,
|
|
54557
54723
|
onDiskWritable: isWritable(candidate) && isWritable(directory) && (mode & 146) !== 0,
|
|
@@ -54564,9 +54730,9 @@ function walkTasks(root, tasksDir, out) {
|
|
|
54564
54730
|
function inspectTaskFiles(roots) {
|
|
54565
54731
|
const files = [];
|
|
54566
54732
|
for (const root of [...roots].sort((a, b) => a.bundleId.localeCompare(b.bundleId))) {
|
|
54567
|
-
const tasksDir = root.layout === "akm-task" ? root.root :
|
|
54733
|
+
const tasksDir = root.layout === "akm-task" ? root.root : path49.join(root.root, "tasks");
|
|
54568
54734
|
try {
|
|
54569
|
-
const stat =
|
|
54735
|
+
const stat = fs40.lstatSync(tasksDir);
|
|
54570
54736
|
if (stat.isSymbolicLink())
|
|
54571
54737
|
throw migrationError(`task migration does not follow symbolic link ${tasksDir}.`);
|
|
54572
54738
|
if (!stat.isDirectory())
|
|
@@ -54584,18 +54750,18 @@ function planTaskFilesMigration(inputs) {
|
|
|
54584
54750
|
return taskToV4PlanFromOutcomes(inputs.map(planTaskToV4File));
|
|
54585
54751
|
}
|
|
54586
54752
|
function taskFileBackupPath(backupRoot, filePath) {
|
|
54587
|
-
const digest = crypto4.createHash("sha256").update(
|
|
54588
|
-
return
|
|
54753
|
+
const digest = crypto4.createHash("sha256").update(path49.resolve(filePath)).digest("hex").slice(0, 16);
|
|
54754
|
+
return path49.join(backupRoot, "files", `${digest}-${path49.basename(filePath)}`);
|
|
54589
54755
|
}
|
|
54590
54756
|
function fsyncDirectory(directory) {
|
|
54591
54757
|
if (process.platform === "win32")
|
|
54592
54758
|
return;
|
|
54593
54759
|
try {
|
|
54594
|
-
const fd =
|
|
54760
|
+
const fd = fs40.openSync(directory, "r");
|
|
54595
54761
|
try {
|
|
54596
|
-
|
|
54762
|
+
fs40.fsyncSync(fd);
|
|
54597
54763
|
} finally {
|
|
54598
|
-
|
|
54764
|
+
fs40.closeSync(fd);
|
|
54599
54765
|
}
|
|
54600
54766
|
} catch (cause) {
|
|
54601
54767
|
const code = cause.code;
|
|
@@ -54604,25 +54770,25 @@ function fsyncDirectory(directory) {
|
|
|
54604
54770
|
}
|
|
54605
54771
|
}
|
|
54606
54772
|
function writeDurable(filePath, bytes, mode, exclusive = false) {
|
|
54607
|
-
|
|
54608
|
-
const fd =
|
|
54773
|
+
fs40.mkdirSync(path49.dirname(filePath), { recursive: true });
|
|
54774
|
+
const fd = fs40.openSync(filePath, exclusive ? "wx" : "w", mode);
|
|
54609
54775
|
try {
|
|
54610
|
-
|
|
54611
|
-
|
|
54776
|
+
fs40.writeFileSync(fd, bytes);
|
|
54777
|
+
fs40.fsyncSync(fd);
|
|
54612
54778
|
} finally {
|
|
54613
|
-
|
|
54779
|
+
fs40.closeSync(fd);
|
|
54614
54780
|
}
|
|
54615
|
-
|
|
54616
|
-
fsyncDirectory(
|
|
54781
|
+
fs40.chmodSync(filePath, mode);
|
|
54782
|
+
fsyncDirectory(path49.dirname(filePath));
|
|
54617
54783
|
}
|
|
54618
54784
|
function replaceAtomically(filePath, bytes, mode) {
|
|
54619
|
-
const temporary =
|
|
54785
|
+
const temporary = path49.join(path49.dirname(filePath), `.${path49.basename(filePath)}.migrate-${crypto4.randomUUID()}`);
|
|
54620
54786
|
try {
|
|
54621
54787
|
writeDurable(temporary, bytes, mode, true);
|
|
54622
|
-
|
|
54623
|
-
fsyncDirectory(
|
|
54788
|
+
fs40.renameSync(temporary, filePath);
|
|
54789
|
+
fsyncDirectory(path49.dirname(filePath));
|
|
54624
54790
|
} finally {
|
|
54625
|
-
|
|
54791
|
+
fs40.rmSync(temporary, { force: true });
|
|
54626
54792
|
}
|
|
54627
54793
|
}
|
|
54628
54794
|
function applyTaskFilesPlan(plan, options) {
|
|
@@ -54645,7 +54811,7 @@ function applyTaskFilesPlan(plan, options) {
|
|
|
54645
54811
|
}
|
|
54646
54812
|
} catch (cause) {
|
|
54647
54813
|
for (const change of [...replaced].reverse()) {
|
|
54648
|
-
replaceAtomically(change.filePath,
|
|
54814
|
+
replaceAtomically(change.filePath, fs40.readFileSync(taskFileBackupPath(options.backupRoot, change.filePath)), change.mode);
|
|
54649
54815
|
}
|
|
54650
54816
|
throw cause;
|
|
54651
54817
|
}
|
|
@@ -54655,14 +54821,14 @@ function applyTaskFilesPlan(plan, options) {
|
|
|
54655
54821
|
// scripts/akm-migrate/task-migrate.ts
|
|
54656
54822
|
function expandTilde(value) {
|
|
54657
54823
|
if (value === "~")
|
|
54658
|
-
return
|
|
54824
|
+
return os8.homedir();
|
|
54659
54825
|
if (value.startsWith("~/") || value.startsWith("~\\"))
|
|
54660
|
-
return
|
|
54826
|
+
return path50.join(os8.homedir(), value.slice(2));
|
|
54661
54827
|
return value;
|
|
54662
54828
|
}
|
|
54663
54829
|
function existingDirectory(target) {
|
|
54664
54830
|
try {
|
|
54665
|
-
return
|
|
54831
|
+
return fs41.statSync(target).isDirectory();
|
|
54666
54832
|
} catch (cause) {
|
|
54667
54833
|
if (cause.code === "ENOENT")
|
|
54668
54834
|
return false;
|
|
@@ -54683,14 +54849,14 @@ function taskRoots(config, resolutionBase = process.cwd()) {
|
|
|
54683
54849
|
const source = sources.get(bundleId);
|
|
54684
54850
|
if (!source)
|
|
54685
54851
|
continue;
|
|
54686
|
-
const configuredRoot = source.type === "filesystem" && source.path ?
|
|
54852
|
+
const configuredRoot = source.type === "filesystem" && source.path ? path50.resolve(resolutionBase, expandTilde(source.path)) : lockContentRootFor(bundleId, source.type);
|
|
54687
54853
|
if (!configuredRoot || !existingDirectory(configuredRoot))
|
|
54688
54854
|
continue;
|
|
54689
|
-
const bundleRoot =
|
|
54855
|
+
const bundleRoot = path50.resolve(configuredRoot);
|
|
54690
54856
|
const component = bundleComponentConfig(bundle);
|
|
54691
|
-
const componentRoot =
|
|
54692
|
-
const relative =
|
|
54693
|
-
if (relative === ".." || relative.startsWith(`..${
|
|
54857
|
+
const componentRoot = path50.resolve(bundleRoot, component?.root ?? ".");
|
|
54858
|
+
const relative = path50.relative(bundleRoot, componentRoot);
|
|
54859
|
+
if (relative === ".." || relative.startsWith(`..${path50.sep}`) || path50.isAbsolute(relative)) {
|
|
54694
54860
|
throw new ConfigError(`Task migration component root ${componentRoot} escapes bundle ${bundleId} at ${bundleRoot}.`, "INVALID_CONFIG_FILE");
|
|
54695
54861
|
}
|
|
54696
54862
|
if (!existingDirectory(componentRoot))
|
|
@@ -54707,7 +54873,7 @@ function taskRoots(config, resolutionBase = process.cwd()) {
|
|
|
54707
54873
|
}
|
|
54708
54874
|
const envStash = process.env.AKM_BUNDLE_DIR?.trim();
|
|
54709
54875
|
if (envStash && existingDirectory(envStash)) {
|
|
54710
|
-
const stashRoot =
|
|
54876
|
+
const stashRoot = path50.resolve(envStash);
|
|
54711
54877
|
if (!rootsByPath.has(stashRoot)) {
|
|
54712
54878
|
const bundleId = deriveBundleId(undefined, stashRoot, new Set(Object.keys(config.bundles ?? {})));
|
|
54713
54879
|
const candidate = taskRoot(bundleId, stashRoot, stashRoot, detectAdapterId(stashRoot), () => true);
|
|
@@ -54720,7 +54886,7 @@ function taskRoots(config, resolutionBase = process.cwd()) {
|
|
|
54720
54886
|
function taskRoot(bundleId, bundleRoot, componentRoot, configuredAdapter, writable) {
|
|
54721
54887
|
const adapter = configuredAdapter ?? detectAdapterId(componentRoot, "");
|
|
54722
54888
|
if (!configuredAdapter && adapter === "") {
|
|
54723
|
-
const flatTasks =
|
|
54889
|
+
const flatTasks = fs41.readdirSync(componentRoot, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".yml")).map((entry) => entry.name).sort();
|
|
54724
54890
|
if (flatTasks.length > 0) {
|
|
54725
54891
|
throw new ConfigError(`Task migration cannot classify top-level task file(s) ${flatTasks.join(", ")} in bundle ${bundleId}; configure adapter "akm-task" or move them under tasks/.`, "INVALID_CONFIG_FILE");
|
|
54726
54892
|
}
|
|
@@ -54776,7 +54942,7 @@ function applyTaskFilesMigration() {
|
|
|
54776
54942
|
const before = inspectCurrent();
|
|
54777
54943
|
if (before.result.taskFiles.changed === 0)
|
|
54778
54944
|
return before.result;
|
|
54779
|
-
const backupPath =
|
|
54945
|
+
const backupPath = path50.join(getDataDir(), "backups", "tasks", `${Date.now()}-${randomUUID3()}`);
|
|
54780
54946
|
const applied = applyTaskFilesPlan(before.plan, { backupRoot: backupPath });
|
|
54781
54947
|
return { ...inspectCurrent().result, backupPath, applied: applied.changed.length };
|
|
54782
54948
|
});
|