akm-cli 0.9.25-alpha.2 → 0.9.25-alpha.4
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 +102 -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/improve/stage.js +15 -5
- 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
|
@@ -51762,6 +51762,170 @@ var codexResultExtractor = (result) => {
|
|
|
51762
51762
|
return sessionId === undefined ? { text } : { text, sessionId };
|
|
51763
51763
|
};
|
|
51764
51764
|
|
|
51765
|
+
// src/integrations/harnesses/codex/session-log.ts
|
|
51766
|
+
import fs36 from "fs";
|
|
51767
|
+
import os5 from "os";
|
|
51768
|
+
import path43 from "path";
|
|
51769
|
+
function codexSessionsDir() {
|
|
51770
|
+
return path43.join(process.env.CODEX_HOME || path43.join(os5.homedir(), ".codex"), "sessions");
|
|
51771
|
+
}
|
|
51772
|
+
var META_PEEK_BYTES = 128 * 1024;
|
|
51773
|
+
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;
|
|
51774
|
+
function parseSessionMeta(entry) {
|
|
51775
|
+
const e = entry;
|
|
51776
|
+
if (e?.type !== "session_meta" || !e.payload)
|
|
51777
|
+
return;
|
|
51778
|
+
const { timestamp, cwd, source } = e.payload;
|
|
51779
|
+
const startedAt = typeof timestamp === "string" ? Date.parse(timestamp) : Number.NaN;
|
|
51780
|
+
return {
|
|
51781
|
+
...Number.isNaN(startedAt) ? {} : { startedAt },
|
|
51782
|
+
...typeof cwd === "string" ? { cwd } : {},
|
|
51783
|
+
isAgent: typeof source === "object" && source !== null && (("subagent" in source) || ("internal" in source))
|
|
51784
|
+
};
|
|
51785
|
+
}
|
|
51786
|
+
function blockText(blocks, keep = () => true) {
|
|
51787
|
+
if (typeof blocks === "string")
|
|
51788
|
+
return blocks;
|
|
51789
|
+
if (!Array.isArray(blocks))
|
|
51790
|
+
return "";
|
|
51791
|
+
const parts = [];
|
|
51792
|
+
for (const block of blocks) {
|
|
51793
|
+
const text = block?.text;
|
|
51794
|
+
if (typeof text === "string" && keep(text))
|
|
51795
|
+
parts.push(text);
|
|
51796
|
+
}
|
|
51797
|
+
return parts.join(`
|
|
51798
|
+
`);
|
|
51799
|
+
}
|
|
51800
|
+
function toolInputText(input) {
|
|
51801
|
+
let args = input;
|
|
51802
|
+
if (typeof input === "string") {
|
|
51803
|
+
try {
|
|
51804
|
+
args = JSON.parse(input);
|
|
51805
|
+
} catch {
|
|
51806
|
+
return input;
|
|
51807
|
+
}
|
|
51808
|
+
}
|
|
51809
|
+
const fields = args && typeof args === "object" ? args : {};
|
|
51810
|
+
const cmd = fields.cmd ?? fields.command;
|
|
51811
|
+
if (typeof cmd === "string")
|
|
51812
|
+
return cmd;
|
|
51813
|
+
if (Array.isArray(cmd))
|
|
51814
|
+
return cmd.join(" ");
|
|
51815
|
+
return typeof input === "string" ? input : JSON.stringify(input) ?? "";
|
|
51816
|
+
}
|
|
51817
|
+
function parseCodexRecord(entry, sessionId, filePath, fallbackTsMs) {
|
|
51818
|
+
const e = entry;
|
|
51819
|
+
const item = e?.type === "response_item" ? e.payload : undefined;
|
|
51820
|
+
if (!item)
|
|
51821
|
+
return;
|
|
51822
|
+
const toolName2 = typeof item.name === "string" ? item.name : "tool";
|
|
51823
|
+
let role = "assistant";
|
|
51824
|
+
let text;
|
|
51825
|
+
switch (item.type) {
|
|
51826
|
+
case "message":
|
|
51827
|
+
if (item.role !== "user" && item.role !== "assistant")
|
|
51828
|
+
return;
|
|
51829
|
+
role = item.role;
|
|
51830
|
+
text = blockText(item.content, item.role === "user" ? (t) => !INJECTED_CONTEXT_RE.test(t) : undefined);
|
|
51831
|
+
break;
|
|
51832
|
+
case "function_call":
|
|
51833
|
+
text = `[tool:${toolName2}] ${toolInputText(item.arguments)}`;
|
|
51834
|
+
break;
|
|
51835
|
+
case "custom_tool_call":
|
|
51836
|
+
text = `[tool:${toolName2}] ${typeof item.input === "string" ? item.input : ""}`;
|
|
51837
|
+
break;
|
|
51838
|
+
case "local_shell_call":
|
|
51839
|
+
text = `[tool:shell] ${toolInputText(item.action)}`;
|
|
51840
|
+
break;
|
|
51841
|
+
case "function_call_output":
|
|
51842
|
+
case "custom_tool_call_output": {
|
|
51843
|
+
role = "tool";
|
|
51844
|
+
const output = blockText(item.output);
|
|
51845
|
+
text = output ? `[tool_result] ${output}` : "";
|
|
51846
|
+
break;
|
|
51847
|
+
}
|
|
51848
|
+
default:
|
|
51849
|
+
return;
|
|
51850
|
+
}
|
|
51851
|
+
if (!text.trim())
|
|
51852
|
+
return;
|
|
51853
|
+
const ts = typeof e?.timestamp === "string" ? Date.parse(e.timestamp) || fallbackTsMs : fallbackTsMs;
|
|
51854
|
+
return { harness: "codex", text, ts, sessionId, role, filePath };
|
|
51855
|
+
}
|
|
51856
|
+
|
|
51857
|
+
class CodexProvider extends AbstractSessionLogProvider {
|
|
51858
|
+
name = "codex";
|
|
51859
|
+
availabilityRoot() {
|
|
51860
|
+
return codexSessionsDir();
|
|
51861
|
+
}
|
|
51862
|
+
listSessions(input = {}) {
|
|
51863
|
+
return this.listSessionsFromFiles({
|
|
51864
|
+
sinceMs: input.sinceMs ?? 0,
|
|
51865
|
+
enumerate: () => this.walkFiles(input.location ?? codexSessionsDir(), (name) => /^rollout-.+\.jsonl$/.test(name)),
|
|
51866
|
+
summarize: (rolloutPath, stat) => {
|
|
51867
|
+
const meta = this.#peekMeta(rolloutPath);
|
|
51868
|
+
if (meta?.isAgent)
|
|
51869
|
+
return;
|
|
51870
|
+
return this.sessionRef({
|
|
51871
|
+
sessionId: path43.basename(rolloutPath, ".jsonl").slice(-36),
|
|
51872
|
+
filePath: rolloutPath,
|
|
51873
|
+
startedAt: meta?.startedAt ?? stat.ctimeMs,
|
|
51874
|
+
endedAt: stat.mtimeMs,
|
|
51875
|
+
projectHint: meta?.cwd
|
|
51876
|
+
});
|
|
51877
|
+
}
|
|
51878
|
+
});
|
|
51879
|
+
}
|
|
51880
|
+
readSession(ref) {
|
|
51881
|
+
const stat = fs36.statSync(ref.filePath);
|
|
51882
|
+
const events = [];
|
|
51883
|
+
const inlineRefs = [];
|
|
51884
|
+
let meta;
|
|
51885
|
+
for (const line of fs36.readFileSync(ref.filePath, "utf8").split(`
|
|
51886
|
+
`).filter(Boolean)) {
|
|
51887
|
+
let entry;
|
|
51888
|
+
try {
|
|
51889
|
+
entry = JSON.parse(line);
|
|
51890
|
+
} catch {
|
|
51891
|
+
continue;
|
|
51892
|
+
}
|
|
51893
|
+
meta ??= parseSessionMeta(entry);
|
|
51894
|
+
const parsed = parseCodexRecord(entry, ref.sessionId, ref.filePath, stat.mtimeMs);
|
|
51895
|
+
if (!parsed)
|
|
51896
|
+
continue;
|
|
51897
|
+
events.push(parsed);
|
|
51898
|
+
inlineRefs.push(...extractInlineRefMentions(parsed.text, parsed.ts));
|
|
51899
|
+
}
|
|
51900
|
+
return {
|
|
51901
|
+
ref: this.sessionRef({
|
|
51902
|
+
sessionId: ref.sessionId,
|
|
51903
|
+
filePath: ref.filePath,
|
|
51904
|
+
startedAt: meta?.startedAt ?? events[0]?.ts ?? stat.ctimeMs,
|
|
51905
|
+
endedAt: events[events.length - 1]?.ts ?? stat.mtimeMs,
|
|
51906
|
+
projectHint: meta?.cwd
|
|
51907
|
+
}),
|
|
51908
|
+
events,
|
|
51909
|
+
inlineRefs
|
|
51910
|
+
};
|
|
51911
|
+
}
|
|
51912
|
+
#peekMeta(filePath) {
|
|
51913
|
+
try {
|
|
51914
|
+
const fd = fs36.openSync(filePath, "r");
|
|
51915
|
+
try {
|
|
51916
|
+
const head = Buffer.alloc(META_PEEK_BYTES);
|
|
51917
|
+
const firstLine = head.toString("utf8", 0, fs36.readSync(fd, head, 0, head.length, 0)).split(`
|
|
51918
|
+
`, 1)[0] ?? "";
|
|
51919
|
+
return parseSessionMeta(JSON.parse(firstLine));
|
|
51920
|
+
} finally {
|
|
51921
|
+
fs36.closeSync(fd);
|
|
51922
|
+
}
|
|
51923
|
+
} catch {
|
|
51924
|
+
return;
|
|
51925
|
+
}
|
|
51926
|
+
}
|
|
51927
|
+
}
|
|
51928
|
+
|
|
51765
51929
|
// src/integrations/harnesses/codex/index.ts
|
|
51766
51930
|
class CodexHarness extends BaseHarness {
|
|
51767
51931
|
id = "codex";
|
|
@@ -51769,7 +51933,9 @@ class CodexHarness extends BaseHarness {
|
|
|
51769
51933
|
agentBuilder = codexBuilder;
|
|
51770
51934
|
resultExtractor = codexResultExtractor;
|
|
51771
51935
|
presenceEnv = ["CODEX_SANDBOX"];
|
|
51936
|
+
sessionLogProvider = () => new CodexProvider;
|
|
51772
51937
|
capabilities = caps({
|
|
51938
|
+
sessionLogs: true,
|
|
51773
51939
|
agentDispatch: true,
|
|
51774
51940
|
detection: true
|
|
51775
51941
|
});
|
|
@@ -52090,7 +52256,7 @@ function opencodeInferenceConfig(inference, modelWork) {
|
|
|
52090
52256
|
}
|
|
52091
52257
|
|
|
52092
52258
|
// src/integrations/harnesses/opencode/model-work-agent.ts
|
|
52093
|
-
import
|
|
52259
|
+
import path44 from "path";
|
|
52094
52260
|
var MODEL_WORK_OPENCODE_AGENT = "akm-model-work";
|
|
52095
52261
|
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.";
|
|
52096
52262
|
function modelWorkPermission(stash) {
|
|
@@ -52127,7 +52293,7 @@ function modelWorkPluginEnv() {
|
|
|
52127
52293
|
AKM_AUTO_LEARNING: "0",
|
|
52128
52294
|
AKM_AUTO_SKILL_PROPOSALS: "0",
|
|
52129
52295
|
AKM_WRITE_GATE: "off",
|
|
52130
|
-
XDG_STATE_HOME:
|
|
52296
|
+
XDG_STATE_HOME: path44.join(getStateDir(), "opencode-model-work"),
|
|
52131
52297
|
...process.platform === "win32" ? {} : { AKM_OPENCODE_CLI: "/bin/true" }
|
|
52132
52298
|
};
|
|
52133
52299
|
}
|
|
@@ -52210,15 +52376,15 @@ var opencodeBuilder = {
|
|
|
52210
52376
|
};
|
|
52211
52377
|
|
|
52212
52378
|
// src/integrations/harnesses/opencode/session-log.ts
|
|
52213
|
-
import
|
|
52214
|
-
import
|
|
52215
|
-
import
|
|
52379
|
+
import fs38 from "fs";
|
|
52380
|
+
import os7 from "os";
|
|
52381
|
+
import path46 from "path";
|
|
52216
52382
|
|
|
52217
52383
|
// src/storage/sqlite-read-snapshot.ts
|
|
52218
52384
|
import { spawnSync as spawnSync5 } from "child_process";
|
|
52219
|
-
import
|
|
52220
|
-
import
|
|
52221
|
-
import
|
|
52385
|
+
import fs37 from "fs";
|
|
52386
|
+
import os6 from "os";
|
|
52387
|
+
import path45 from "path";
|
|
52222
52388
|
var SNAPSHOT_MAX_ATTEMPTS = 8;
|
|
52223
52389
|
var SNAPSHOT_BACKOFF_MS = 25;
|
|
52224
52390
|
|
|
@@ -52230,7 +52396,7 @@ class SqliteReadSnapshotUnavailableError extends Error {
|
|
|
52230
52396
|
}
|
|
52231
52397
|
function pathExists(filePath) {
|
|
52232
52398
|
try {
|
|
52233
|
-
|
|
52399
|
+
fs37.lstatSync(filePath);
|
|
52234
52400
|
return true;
|
|
52235
52401
|
} catch (error2) {
|
|
52236
52402
|
if (error2.code === "ENOENT")
|
|
@@ -52240,7 +52406,7 @@ function pathExists(filePath) {
|
|
|
52240
52406
|
}
|
|
52241
52407
|
function fileFingerprint(filePath) {
|
|
52242
52408
|
try {
|
|
52243
|
-
const stat =
|
|
52409
|
+
const stat = fs37.statSync(filePath, { bigint: true });
|
|
52244
52410
|
return { size: stat.size, mtimeNs: stat.mtimeNs, ctimeNs: stat.ctimeNs };
|
|
52245
52411
|
} catch (error2) {
|
|
52246
52412
|
if (error2.code === "ENOENT")
|
|
@@ -52262,7 +52428,7 @@ function fingerprintsEqual(left, right) {
|
|
|
52262
52428
|
}
|
|
52263
52429
|
function copyFileOutsideThisProcess(source, destination) {
|
|
52264
52430
|
if (process.platform === "win32") {
|
|
52265
|
-
|
|
52431
|
+
fs37.copyFileSync(source, destination);
|
|
52266
52432
|
return;
|
|
52267
52433
|
}
|
|
52268
52434
|
const result = spawnSync5("cp", ["--", source, destination], {
|
|
@@ -52283,8 +52449,8 @@ function copyFileOutsideThisProcess(source, destination) {
|
|
|
52283
52449
|
function openSqliteReadSnapshot(dbPath) {
|
|
52284
52450
|
if (!pathExists(dbPath))
|
|
52285
52451
|
return;
|
|
52286
|
-
const snapshotDir =
|
|
52287
|
-
const snapshotPath =
|
|
52452
|
+
const snapshotDir = fs37.mkdtempSync(path45.join(os6.tmpdir(), "akm-sqlite-read-"));
|
|
52453
|
+
const snapshotPath = path45.join(snapshotDir, "snapshot.db");
|
|
52288
52454
|
let db;
|
|
52289
52455
|
try {
|
|
52290
52456
|
let copied = false;
|
|
@@ -52299,7 +52465,7 @@ function openSqliteReadSnapshot(dbPath) {
|
|
|
52299
52465
|
if (before.wal)
|
|
52300
52466
|
copyFileOutsideThisProcess(`${dbPath}-wal`, `${snapshotPath}-wal`);
|
|
52301
52467
|
else
|
|
52302
|
-
|
|
52468
|
+
fs37.rmSync(`${snapshotPath}-wal`, { force: true });
|
|
52303
52469
|
const after = databaseFingerprint(dbPath);
|
|
52304
52470
|
if (fingerprintsEqual(before, after) && !pathExists(`${dbPath}-journal`)) {
|
|
52305
52471
|
copied = true;
|
|
@@ -52327,14 +52493,14 @@ function openSqliteReadSnapshot(dbPath) {
|
|
|
52327
52493
|
closeSnapshot();
|
|
52328
52494
|
} catch {}
|
|
52329
52495
|
try {
|
|
52330
|
-
|
|
52496
|
+
fs37.rmSync(snapshotDir, { recursive: true, force: true });
|
|
52331
52497
|
} catch {}
|
|
52332
52498
|
return;
|
|
52333
52499
|
}
|
|
52334
52500
|
try {
|
|
52335
52501
|
closeSnapshot();
|
|
52336
52502
|
} finally {
|
|
52337
|
-
|
|
52503
|
+
fs37.rmSync(snapshotDir, { recursive: true, force: true });
|
|
52338
52504
|
}
|
|
52339
52505
|
};
|
|
52340
52506
|
const cleanupOnExit = () => cleanup(true);
|
|
@@ -52345,7 +52511,7 @@ function openSqliteReadSnapshot(dbPath) {
|
|
|
52345
52511
|
try {
|
|
52346
52512
|
db?.close();
|
|
52347
52513
|
} finally {
|
|
52348
|
-
|
|
52514
|
+
fs37.rmSync(snapshotDir, { recursive: true, force: true });
|
|
52349
52515
|
}
|
|
52350
52516
|
throw error2;
|
|
52351
52517
|
}
|
|
@@ -52354,9 +52520,9 @@ function openSqliteReadSnapshot(dbPath) {
|
|
|
52354
52520
|
// src/integrations/harnesses/opencode/session-log.ts
|
|
52355
52521
|
function getOpenCodeBaseDir() {
|
|
52356
52522
|
if (process.platform === "darwin") {
|
|
52357
|
-
return
|
|
52523
|
+
return path46.join(os7.homedir(), "Library", "Application Support", "opencode");
|
|
52358
52524
|
}
|
|
52359
|
-
return
|
|
52525
|
+
return path46.join(os7.homedir(), ".local", "share", "opencode");
|
|
52360
52526
|
}
|
|
52361
52527
|
var OPENCODE_DB_FILENAME = "opencode.db";
|
|
52362
52528
|
|
|
@@ -52367,13 +52533,13 @@ class OpenCodeProvider extends AbstractSessionLogProvider {
|
|
|
52367
52533
|
return this.#dbPath(this.#baseDir);
|
|
52368
52534
|
}
|
|
52369
52535
|
#dbPath(base) {
|
|
52370
|
-
return
|
|
52536
|
+
return path46.join(base, OPENCODE_DB_FILENAME);
|
|
52371
52537
|
}
|
|
52372
52538
|
listSessions(input = {}) {
|
|
52373
52539
|
const base = input.location ?? this.#baseDir;
|
|
52374
52540
|
const sinceMs = input.sinceMs ?? 0;
|
|
52375
52541
|
const dbPath = this.#dbPath(base);
|
|
52376
|
-
if (!
|
|
52542
|
+
if (!fs38.existsSync(dbPath))
|
|
52377
52543
|
return [];
|
|
52378
52544
|
return this.#listSessionsFromDb(dbPath, sinceMs, input.isolatedSnapshot ?? false);
|
|
52379
52545
|
}
|
|
@@ -53245,8 +53411,8 @@ Commands:
|
|
|
53245
53411
|
`;
|
|
53246
53412
|
|
|
53247
53413
|
// scripts/akm-migrate/migrate/dead-residue.ts
|
|
53248
|
-
import
|
|
53249
|
-
import
|
|
53414
|
+
import fs39 from "fs";
|
|
53415
|
+
import path47 from "path";
|
|
53250
53416
|
var DEAD_RESIDUE_PATHS = [
|
|
53251
53417
|
{ name: "proposals", reason: "superseded by the `proposals` table in $DATA/state.db (0.9.0)" },
|
|
53252
53418
|
{ prefix: "runs.archived-", reason: "orphaned archive of a directory that no longer exists" },
|
|
@@ -53263,43 +53429,43 @@ function dirSizeBytes(target) {
|
|
|
53263
53429
|
let total = 0;
|
|
53264
53430
|
let entries;
|
|
53265
53431
|
try {
|
|
53266
|
-
entries =
|
|
53432
|
+
entries = fs39.readdirSync(target, { withFileTypes: true });
|
|
53267
53433
|
} catch {
|
|
53268
53434
|
return 0;
|
|
53269
53435
|
}
|
|
53270
53436
|
for (const entry of entries) {
|
|
53271
|
-
const entryPath =
|
|
53437
|
+
const entryPath = path47.join(target, entry.name);
|
|
53272
53438
|
if (entry.isDirectory()) {
|
|
53273
53439
|
total += dirSizeBytes(entryPath);
|
|
53274
53440
|
} else if (entry.isFile()) {
|
|
53275
53441
|
try {
|
|
53276
|
-
total +=
|
|
53442
|
+
total += fs39.statSync(entryPath).size;
|
|
53277
53443
|
} catch {}
|
|
53278
53444
|
}
|
|
53279
53445
|
}
|
|
53280
53446
|
return total;
|
|
53281
53447
|
}
|
|
53282
53448
|
function sizeOf(target) {
|
|
53283
|
-
const st =
|
|
53449
|
+
const st = fs39.statSync(target);
|
|
53284
53450
|
return st.isDirectory() ? dirSizeBytes(target) : st.size;
|
|
53285
53451
|
}
|
|
53286
53452
|
function hostResidue() {
|
|
53287
53453
|
const data = getDataDir();
|
|
53288
53454
|
const state = getStateDir();
|
|
53289
|
-
const configDir =
|
|
53455
|
+
const configDir = path47.dirname(getConfigPath());
|
|
53290
53456
|
const named = [
|
|
53291
|
-
{ absolutePath:
|
|
53292
|
-
{ absolutePath:
|
|
53293
|
-
{ absolutePath:
|
|
53294
|
-
{ absolutePath:
|
|
53295
|
-
{ absolutePath:
|
|
53296
|
-
{ absolutePath:
|
|
53297
|
-
{ absolutePath:
|
|
53457
|
+
{ absolutePath: path47.join(data, "txn"), reason: "filesystem transaction journals (removed in 0.9.17)" },
|
|
53458
|
+
{ absolutePath: path47.join(data, "txn-quarantine"), reason: "quarantined transaction journals (removed in 0.9.17)" },
|
|
53459
|
+
{ absolutePath: path47.join(data, "maintenance.barrier.lock"), reason: "maintenance barrier (removed in 0.9.17)" },
|
|
53460
|
+
{ absolutePath: path47.join(data, "maintenance-activities"), reason: "per-process activity registry (removed in 0.9.17)" },
|
|
53461
|
+
{ absolutePath: path47.join(state, "maintenance-activities"), reason: "per-process activity registry (removed in 0.9.17)" },
|
|
53462
|
+
{ absolutePath: path47.join(state, "version-reconcile.json"), reason: "startup reconcile stamp (removed in 0.9.17)" },
|
|
53463
|
+
{ absolutePath: path47.join(state, "locks", "version-reconcile.lock"), reason: "startup reconcile lock (removed in 0.9.17)" }
|
|
53298
53464
|
];
|
|
53299
53465
|
const found = [];
|
|
53300
53466
|
const claimed = new Set;
|
|
53301
53467
|
for (const entry of named) {
|
|
53302
|
-
if (claimed.has(entry.absolutePath) || !
|
|
53468
|
+
if (claimed.has(entry.absolutePath) || !fs39.existsSync(entry.absolutePath))
|
|
53303
53469
|
continue;
|
|
53304
53470
|
try {
|
|
53305
53471
|
found.push({ ...entry, relativePath: entry.absolutePath, sizeBytes: sizeOf(entry.absolutePath) });
|
|
@@ -53323,13 +53489,13 @@ function hostResidue() {
|
|
|
53323
53489
|
function findSidecars(root2, depth, skip) {
|
|
53324
53490
|
let entries;
|
|
53325
53491
|
try {
|
|
53326
|
-
entries =
|
|
53492
|
+
entries = fs39.readdirSync(root2, { withFileTypes: true });
|
|
53327
53493
|
} catch {
|
|
53328
53494
|
return [];
|
|
53329
53495
|
}
|
|
53330
53496
|
const found = [];
|
|
53331
53497
|
for (const entry of entries) {
|
|
53332
|
-
const entryPath =
|
|
53498
|
+
const entryPath = path47.join(root2, entry.name);
|
|
53333
53499
|
if (entry.isFile() && entry.name.endsWith(".operations.sensitive"))
|
|
53334
53500
|
found.push(entryPath);
|
|
53335
53501
|
else if (entry.isDirectory() && depth > 0 && !skip.has(entryPath)) {
|
|
@@ -53342,10 +53508,10 @@ function findDeadResidueEntries(stashDir) {
|
|
|
53342
53508
|
const host = hostResidue();
|
|
53343
53509
|
if (stashDir === undefined)
|
|
53344
53510
|
return host;
|
|
53345
|
-
const akmDir =
|
|
53511
|
+
const akmDir = path47.join(stashDir, ".akm");
|
|
53346
53512
|
let names;
|
|
53347
53513
|
try {
|
|
53348
|
-
names =
|
|
53514
|
+
names = fs39.readdirSync(akmDir);
|
|
53349
53515
|
} catch {
|
|
53350
53516
|
return [];
|
|
53351
53517
|
}
|
|
@@ -53355,14 +53521,14 @@ function findDeadResidueEntries(stashDir) {
|
|
|
53355
53521
|
for (const name of matches) {
|
|
53356
53522
|
if (!names.includes(name))
|
|
53357
53523
|
continue;
|
|
53358
|
-
const absolutePath =
|
|
53524
|
+
const absolutePath = path47.join(akmDir, name);
|
|
53359
53525
|
let sizeBytes;
|
|
53360
53526
|
try {
|
|
53361
53527
|
sizeBytes = sizeOf(absolutePath);
|
|
53362
53528
|
} catch {
|
|
53363
53529
|
continue;
|
|
53364
53530
|
}
|
|
53365
|
-
found.push({ relativePath:
|
|
53531
|
+
found.push({ relativePath: path47.join(".akm", name), absolutePath, sizeBytes, reason: spec.reason });
|
|
53366
53532
|
}
|
|
53367
53533
|
}
|
|
53368
53534
|
return found;
|
|
@@ -53371,7 +53537,7 @@ function removeDeadResidue(stashDir) {
|
|
|
53371
53537
|
const entries = findDeadResidueEntries(stashDir);
|
|
53372
53538
|
return entries.map((entry) => {
|
|
53373
53539
|
try {
|
|
53374
|
-
|
|
53540
|
+
fs39.rmSync(entry.absolutePath, { recursive: true, force: true });
|
|
53375
53541
|
return { relativePath: entry.relativePath, sizeBytes: entry.sizeBytes, removed: true };
|
|
53376
53542
|
} catch (error2) {
|
|
53377
53543
|
return {
|
|
@@ -53386,18 +53552,18 @@ function removeDeadResidue(stashDir) {
|
|
|
53386
53552
|
|
|
53387
53553
|
// scripts/akm-migrate/task-migrate.ts
|
|
53388
53554
|
import { randomUUID as randomUUID3 } from "crypto";
|
|
53389
|
-
import
|
|
53390
|
-
import
|
|
53391
|
-
import
|
|
53555
|
+
import fs41 from "fs";
|
|
53556
|
+
import os8 from "os";
|
|
53557
|
+
import path50 from "path";
|
|
53392
53558
|
|
|
53393
53559
|
// scripts/akm-migrate/migrate/task-files.ts
|
|
53394
53560
|
import crypto4 from "crypto";
|
|
53395
|
-
import
|
|
53396
|
-
import
|
|
53561
|
+
import fs40 from "fs";
|
|
53562
|
+
import path49 from "path";
|
|
53397
53563
|
|
|
53398
53564
|
// src/tasks/source/task-to-v4.ts
|
|
53399
53565
|
import crypto3 from "crypto";
|
|
53400
|
-
import
|
|
53566
|
+
import path48 from "path";
|
|
53401
53567
|
|
|
53402
53568
|
// src/tasks/task-id.ts
|
|
53403
53569
|
var VALID_TASK_ID_RE = /^[A-Za-z0-9][A-Za-z0-9._-]*$/;
|
|
@@ -54206,7 +54372,7 @@ function addSharedNonPromptOverrides(data, akm) {
|
|
|
54206
54372
|
}
|
|
54207
54373
|
function promptSourceKind(raw) {
|
|
54208
54374
|
const trimmed = raw.trim();
|
|
54209
|
-
if (trimmed.startsWith("./") || trimmed.startsWith("../") ||
|
|
54375
|
+
if (trimmed.startsWith("./") || trimmed.startsWith("../") || path48.isAbsolute(trimmed) || /^[A-Za-z]:[\\/]/.test(trimmed)) {
|
|
54210
54376
|
return "file";
|
|
54211
54377
|
}
|
|
54212
54378
|
try {
|
|
@@ -54310,7 +54476,7 @@ function planV2DataToV4(input, data) {
|
|
|
54310
54476
|
return blocked(input, "read-only-source", !input.writable ? "the owning source is not writable" : "the source file or publication directory is read-only");
|
|
54311
54477
|
}
|
|
54312
54478
|
try {
|
|
54313
|
-
validateTaskId(
|
|
54479
|
+
validateTaskId(path48.basename(input.filePath, ".yml"));
|
|
54314
54480
|
} catch (cause) {
|
|
54315
54481
|
return blocked(input, "invalid-v2-task", causeMessage(cause));
|
|
54316
54482
|
}
|
|
@@ -54455,7 +54621,7 @@ function taskToV4PlanFromOutcomes(outcomes) {
|
|
|
54455
54621
|
for (let index = 1;index < files.length; index += 1) {
|
|
54456
54622
|
const previous = files[index - 1];
|
|
54457
54623
|
const current = files[index];
|
|
54458
|
-
if (previous && current &&
|
|
54624
|
+
if (previous && current && path48.resolve(previous.filePath) === path48.resolve(current.filePath)) {
|
|
54459
54625
|
throw new Error(`duplicate task migration file path: ${current.filePath}`);
|
|
54460
54626
|
}
|
|
54461
54627
|
}
|
|
@@ -54467,18 +54633,18 @@ function migrationError(detail) {
|
|
|
54467
54633
|
return new ConfigError(`Task migration failed: ${detail}`, "INVALID_CONFIG_FILE");
|
|
54468
54634
|
}
|
|
54469
54635
|
function contained2(root2, candidate) {
|
|
54470
|
-
const relative =
|
|
54471
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
54636
|
+
const relative = path49.relative(root2, candidate);
|
|
54637
|
+
return relative === "" || !relative.startsWith("..") && !path49.isAbsolute(relative);
|
|
54472
54638
|
}
|
|
54473
54639
|
function realDirectory(filePath) {
|
|
54474
|
-
const stat =
|
|
54640
|
+
const stat = fs40.lstatSync(filePath);
|
|
54475
54641
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
54476
54642
|
throw migrationError(`${filePath} must be a real directory.`);
|
|
54477
|
-
return
|
|
54643
|
+
return fs40.realpathSync(filePath);
|
|
54478
54644
|
}
|
|
54479
54645
|
function isWritable(filePath) {
|
|
54480
54646
|
try {
|
|
54481
|
-
|
|
54647
|
+
fs40.accessSync(filePath, fs40.constants.W_OK);
|
|
54482
54648
|
return true;
|
|
54483
54649
|
} catch {
|
|
54484
54650
|
return false;
|
|
@@ -54491,12 +54657,12 @@ function walkTasks(root2, tasksDir, out) {
|
|
|
54491
54657
|
throw migrationError(`${root2.root} resolves outside bundle ${root2.bundleId}.`);
|
|
54492
54658
|
}
|
|
54493
54659
|
const visit2 = (directory) => {
|
|
54494
|
-
const physicalDirectory =
|
|
54660
|
+
const physicalDirectory = fs40.realpathSync(directory);
|
|
54495
54661
|
if (!contained2(physicalRoot, physicalDirectory)) {
|
|
54496
54662
|
throw migrationError(`${directory} resolves outside bundle ${root2.bundleId}.`);
|
|
54497
54663
|
}
|
|
54498
|
-
for (const entry of
|
|
54499
|
-
const candidate =
|
|
54664
|
+
for (const entry of fs40.readdirSync(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
54665
|
+
const candidate = path49.join(directory, entry.name);
|
|
54500
54666
|
if (entry.isSymbolicLink())
|
|
54501
54667
|
throw migrationError(`task migration does not follow symbolic link ${candidate}.`);
|
|
54502
54668
|
if (entry.isDirectory()) {
|
|
@@ -54505,11 +54671,11 @@ function walkTasks(root2, tasksDir, out) {
|
|
|
54505
54671
|
}
|
|
54506
54672
|
if (!entry.isFile() || !entry.name.endsWith(".yml"))
|
|
54507
54673
|
continue;
|
|
54508
|
-
const stat =
|
|
54674
|
+
const stat = fs40.lstatSync(candidate);
|
|
54509
54675
|
const mode = stat.mode & 511;
|
|
54510
54676
|
out.push({
|
|
54511
54677
|
filePath: candidate,
|
|
54512
|
-
bytes:
|
|
54678
|
+
bytes: fs40.readFileSync(candidate),
|
|
54513
54679
|
mode,
|
|
54514
54680
|
writable: root2.writable,
|
|
54515
54681
|
onDiskWritable: isWritable(candidate) && isWritable(directory) && (mode & 146) !== 0,
|
|
@@ -54522,9 +54688,9 @@ function walkTasks(root2, tasksDir, out) {
|
|
|
54522
54688
|
function inspectTaskFiles(roots) {
|
|
54523
54689
|
const files = [];
|
|
54524
54690
|
for (const root2 of [...roots].sort((a, b) => a.bundleId.localeCompare(b.bundleId))) {
|
|
54525
|
-
const tasksDir = root2.layout === "akm-task" ? root2.root :
|
|
54691
|
+
const tasksDir = root2.layout === "akm-task" ? root2.root : path49.join(root2.root, "tasks");
|
|
54526
54692
|
try {
|
|
54527
|
-
const stat =
|
|
54693
|
+
const stat = fs40.lstatSync(tasksDir);
|
|
54528
54694
|
if (stat.isSymbolicLink())
|
|
54529
54695
|
throw migrationError(`task migration does not follow symbolic link ${tasksDir}.`);
|
|
54530
54696
|
if (!stat.isDirectory())
|
|
@@ -54542,18 +54708,18 @@ function planTaskFilesMigration(inputs) {
|
|
|
54542
54708
|
return taskToV4PlanFromOutcomes(inputs.map(planTaskToV4File));
|
|
54543
54709
|
}
|
|
54544
54710
|
function taskFileBackupPath(backupRoot, filePath) {
|
|
54545
|
-
const digest = crypto4.createHash("sha256").update(
|
|
54546
|
-
return
|
|
54711
|
+
const digest = crypto4.createHash("sha256").update(path49.resolve(filePath)).digest("hex").slice(0, 16);
|
|
54712
|
+
return path49.join(backupRoot, "files", `${digest}-${path49.basename(filePath)}`);
|
|
54547
54713
|
}
|
|
54548
54714
|
function fsyncDirectory(directory) {
|
|
54549
54715
|
if (process.platform === "win32")
|
|
54550
54716
|
return;
|
|
54551
54717
|
try {
|
|
54552
|
-
const fd =
|
|
54718
|
+
const fd = fs40.openSync(directory, "r");
|
|
54553
54719
|
try {
|
|
54554
|
-
|
|
54720
|
+
fs40.fsyncSync(fd);
|
|
54555
54721
|
} finally {
|
|
54556
|
-
|
|
54722
|
+
fs40.closeSync(fd);
|
|
54557
54723
|
}
|
|
54558
54724
|
} catch (cause) {
|
|
54559
54725
|
const code = cause.code;
|
|
@@ -54562,25 +54728,25 @@ function fsyncDirectory(directory) {
|
|
|
54562
54728
|
}
|
|
54563
54729
|
}
|
|
54564
54730
|
function writeDurable(filePath, bytes, mode, exclusive = false) {
|
|
54565
|
-
|
|
54566
|
-
const fd =
|
|
54731
|
+
fs40.mkdirSync(path49.dirname(filePath), { recursive: true });
|
|
54732
|
+
const fd = fs40.openSync(filePath, exclusive ? "wx" : "w", mode);
|
|
54567
54733
|
try {
|
|
54568
|
-
|
|
54569
|
-
|
|
54734
|
+
fs40.writeFileSync(fd, bytes);
|
|
54735
|
+
fs40.fsyncSync(fd);
|
|
54570
54736
|
} finally {
|
|
54571
|
-
|
|
54737
|
+
fs40.closeSync(fd);
|
|
54572
54738
|
}
|
|
54573
|
-
|
|
54574
|
-
fsyncDirectory(
|
|
54739
|
+
fs40.chmodSync(filePath, mode);
|
|
54740
|
+
fsyncDirectory(path49.dirname(filePath));
|
|
54575
54741
|
}
|
|
54576
54742
|
function replaceAtomically(filePath, bytes, mode) {
|
|
54577
|
-
const temporary =
|
|
54743
|
+
const temporary = path49.join(path49.dirname(filePath), `.${path49.basename(filePath)}.migrate-${crypto4.randomUUID()}`);
|
|
54578
54744
|
try {
|
|
54579
54745
|
writeDurable(temporary, bytes, mode, true);
|
|
54580
|
-
|
|
54581
|
-
fsyncDirectory(
|
|
54746
|
+
fs40.renameSync(temporary, filePath);
|
|
54747
|
+
fsyncDirectory(path49.dirname(filePath));
|
|
54582
54748
|
} finally {
|
|
54583
|
-
|
|
54749
|
+
fs40.rmSync(temporary, { force: true });
|
|
54584
54750
|
}
|
|
54585
54751
|
}
|
|
54586
54752
|
function applyTaskFilesPlan(plan, options) {
|
|
@@ -54603,7 +54769,7 @@ function applyTaskFilesPlan(plan, options) {
|
|
|
54603
54769
|
}
|
|
54604
54770
|
} catch (cause) {
|
|
54605
54771
|
for (const change of [...replaced].reverse()) {
|
|
54606
|
-
replaceAtomically(change.filePath,
|
|
54772
|
+
replaceAtomically(change.filePath, fs40.readFileSync(taskFileBackupPath(options.backupRoot, change.filePath)), change.mode);
|
|
54607
54773
|
}
|
|
54608
54774
|
throw cause;
|
|
54609
54775
|
}
|
|
@@ -54613,14 +54779,14 @@ function applyTaskFilesPlan(plan, options) {
|
|
|
54613
54779
|
// scripts/akm-migrate/task-migrate.ts
|
|
54614
54780
|
function expandTilde(value) {
|
|
54615
54781
|
if (value === "~")
|
|
54616
|
-
return
|
|
54782
|
+
return os8.homedir();
|
|
54617
54783
|
if (value.startsWith("~/") || value.startsWith("~\\"))
|
|
54618
|
-
return
|
|
54784
|
+
return path50.join(os8.homedir(), value.slice(2));
|
|
54619
54785
|
return value;
|
|
54620
54786
|
}
|
|
54621
54787
|
function existingDirectory(target) {
|
|
54622
54788
|
try {
|
|
54623
|
-
return
|
|
54789
|
+
return fs41.statSync(target).isDirectory();
|
|
54624
54790
|
} catch (cause) {
|
|
54625
54791
|
if (cause.code === "ENOENT")
|
|
54626
54792
|
return false;
|
|
@@ -54641,14 +54807,14 @@ function taskRoots(config, resolutionBase = process.cwd()) {
|
|
|
54641
54807
|
const source = sources.get(bundleId);
|
|
54642
54808
|
if (!source)
|
|
54643
54809
|
continue;
|
|
54644
|
-
const configuredRoot = source.type === "filesystem" && source.path ?
|
|
54810
|
+
const configuredRoot = source.type === "filesystem" && source.path ? path50.resolve(resolutionBase, expandTilde(source.path)) : lockContentRootFor(bundleId, source.type);
|
|
54645
54811
|
if (!configuredRoot || !existingDirectory(configuredRoot))
|
|
54646
54812
|
continue;
|
|
54647
|
-
const bundleRoot =
|
|
54813
|
+
const bundleRoot = path50.resolve(configuredRoot);
|
|
54648
54814
|
const component = bundleComponentConfig(bundle);
|
|
54649
|
-
const componentRoot =
|
|
54650
|
-
const relative =
|
|
54651
|
-
if (relative === ".." || relative.startsWith(`..${
|
|
54815
|
+
const componentRoot = path50.resolve(bundleRoot, component?.root ?? ".");
|
|
54816
|
+
const relative = path50.relative(bundleRoot, componentRoot);
|
|
54817
|
+
if (relative === ".." || relative.startsWith(`..${path50.sep}`) || path50.isAbsolute(relative)) {
|
|
54652
54818
|
throw new ConfigError(`Task migration component root ${componentRoot} escapes bundle ${bundleId} at ${bundleRoot}.`, "INVALID_CONFIG_FILE");
|
|
54653
54819
|
}
|
|
54654
54820
|
if (!existingDirectory(componentRoot))
|
|
@@ -54665,7 +54831,7 @@ function taskRoots(config, resolutionBase = process.cwd()) {
|
|
|
54665
54831
|
}
|
|
54666
54832
|
const envStash = process.env.AKM_BUNDLE_DIR?.trim();
|
|
54667
54833
|
if (envStash && existingDirectory(envStash)) {
|
|
54668
|
-
const stashRoot =
|
|
54834
|
+
const stashRoot = path50.resolve(envStash);
|
|
54669
54835
|
if (!rootsByPath.has(stashRoot)) {
|
|
54670
54836
|
const bundleId = deriveBundleId(undefined, stashRoot, new Set(Object.keys(config.bundles ?? {})));
|
|
54671
54837
|
const candidate = taskRoot(bundleId, stashRoot, stashRoot, detectAdapterId(stashRoot), () => true);
|
|
@@ -54678,7 +54844,7 @@ function taskRoots(config, resolutionBase = process.cwd()) {
|
|
|
54678
54844
|
function taskRoot(bundleId, bundleRoot, componentRoot, configuredAdapter, writable) {
|
|
54679
54845
|
const adapter = configuredAdapter ?? detectAdapterId(componentRoot, "");
|
|
54680
54846
|
if (!configuredAdapter && adapter === "") {
|
|
54681
|
-
const flatTasks =
|
|
54847
|
+
const flatTasks = fs41.readdirSync(componentRoot, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".yml")).map((entry) => entry.name).sort();
|
|
54682
54848
|
if (flatTasks.length > 0) {
|
|
54683
54849
|
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");
|
|
54684
54850
|
}
|
|
@@ -54734,7 +54900,7 @@ function applyTaskFilesMigration() {
|
|
|
54734
54900
|
const before = inspectCurrent();
|
|
54735
54901
|
if (before.result.taskFiles.changed === 0)
|
|
54736
54902
|
return before.result;
|
|
54737
|
-
const backupPath =
|
|
54903
|
+
const backupPath = path50.join(getDataDir(), "backups", "tasks", `${Date.now()}-${randomUUID3()}`);
|
|
54738
54904
|
const applied = applyTaskFilesPlan(before.plan, { backupRoot: backupPath });
|
|
54739
54905
|
return { ...inspectCurrent().result, backupPath, applied: applied.changed.length };
|
|
54740
54906
|
});
|