akm-cli 0.9.4 → 0.9.5
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 +160 -0
- package/dist/commands/improve/anti-collapse.js +4 -91
- package/dist/commands/proposal/validators/proposal-validators.js +12 -0
- package/dist/commands/read/search.js +14 -24
- package/dist/commands/tasks/tasks-cli.js +56 -3
- package/dist/commands/tasks/tasks.js +89 -2
- package/dist/core/adapter/adapters/akm-adapter.js +2 -0
- package/dist/core/config/config-version-shim.js +101 -0
- package/dist/core/config/config.js +6 -6
- package/dist/core/improve-result.js +35 -14
- package/dist/execution/guarded-source.js +0 -10
- package/dist/indexer/passes/metadata.js +12 -4
- package/dist/indexer/scan/doc-to-entry.js +2 -0
- package/dist/indexer/search/search-fields.js +16 -1
- package/dist/output/shapes/passthrough.js +17 -5
- package/dist/scripts/akm-migrate-node.js +120 -112
- package/dist/scripts/akm-migrate.js +120 -112
- package/dist/storage/repositories/proposals-repository.js +32 -6
- package/dist/tasks/scheduler-binding.js +15 -5
- package/dist/tasks/scheduler-sync-preview.js +4 -2
- package/dist/tasks/scheduler-sync.js +77 -42
- package/dist/tasks/source/task-to-v3.js +24 -12
- package/dist/tasks/source/task-to-v4.js +0 -10
- package/docs/reference/cli.md +25 -3
- package/docs/reference/configuration.md +27 -6
- package/docs/reference/tasks.md +10 -0
- package/package.json +1 -1
|
@@ -10067,11 +10067,13 @@ function makeStampHandler(command) {
|
|
|
10067
10067
|
if (typeof result !== "object" || Array.isArray(result))
|
|
10068
10068
|
return result;
|
|
10069
10069
|
const obj = result;
|
|
10070
|
-
if (obj.shape
|
|
10071
|
-
obj
|
|
10072
|
-
|
|
10073
|
-
obj
|
|
10074
|
-
|
|
10070
|
+
if (obj.shape !== undefined && obj.schemaVersion !== undefined)
|
|
10071
|
+
return obj;
|
|
10072
|
+
return {
|
|
10073
|
+
...obj,
|
|
10074
|
+
shape: obj.shape ?? command,
|
|
10075
|
+
schemaVersion: obj.schemaVersion ?? 1
|
|
10076
|
+
};
|
|
10075
10077
|
};
|
|
10076
10078
|
}
|
|
10077
10079
|
var PASSTHROUGH_COMMANDS = [
|
|
@@ -10111,6 +10113,7 @@ var PASSTHROUGH_COMMANDS = [
|
|
|
10111
10113
|
"task-doctor",
|
|
10112
10114
|
"task-explain",
|
|
10113
10115
|
"task-history",
|
|
10116
|
+
"task-prune",
|
|
10114
10117
|
"task-run",
|
|
10115
10118
|
"task-sync",
|
|
10116
10119
|
"task-sync-dry-run",
|
|
@@ -13024,8 +13027,17 @@ import path8 from "node:path";
|
|
|
13024
13027
|
// src/core/warn.ts
|
|
13025
13028
|
import fs4 from "node:fs";
|
|
13026
13029
|
var quiet = false;
|
|
13030
|
+
var verbose = false;
|
|
13027
13031
|
var logFilePath;
|
|
13028
13032
|
var sinkOverride;
|
|
13033
|
+
function isVerbose() {
|
|
13034
|
+
const env = process.env.AKM_VERBOSE?.trim().toLowerCase();
|
|
13035
|
+
if (env === "1" || env === "true" || env === "yes" || env === "on")
|
|
13036
|
+
return true;
|
|
13037
|
+
if (env === "0" || env === "false" || env === "no" || env === "off")
|
|
13038
|
+
return false;
|
|
13039
|
+
return verbose;
|
|
13040
|
+
}
|
|
13029
13041
|
function appendToLogFile(level, args) {
|
|
13030
13042
|
if (!logFilePath)
|
|
13031
13043
|
return;
|
|
@@ -13051,6 +13063,15 @@ function warn(...args) {
|
|
|
13051
13063
|
console.warn(...args);
|
|
13052
13064
|
}
|
|
13053
13065
|
}
|
|
13066
|
+
function warnVerbose(...args) {
|
|
13067
|
+
if (sinkOverride) {
|
|
13068
|
+
sinkOverride("warnVerbose", args);
|
|
13069
|
+
return;
|
|
13070
|
+
}
|
|
13071
|
+
if (isVerbose()) {
|
|
13072
|
+
warn(...args);
|
|
13073
|
+
}
|
|
13074
|
+
}
|
|
13054
13075
|
|
|
13055
13076
|
// src/indexer/passes/metadata.ts
|
|
13056
13077
|
var SCOPE_KEYS = ["user", "agent", "run", "channel"];
|
|
@@ -13766,7 +13787,7 @@ function stripMarkdownLinkDestinations(text, nesting = 0) {
|
|
|
13766
13787
|
}
|
|
13767
13788
|
return visible;
|
|
13768
13789
|
}
|
|
13769
|
-
function projectMarkdownContent(body) {
|
|
13790
|
+
function projectMarkdownContent(body, truncationInfo) {
|
|
13770
13791
|
const lines = body.split(/\r?\n/);
|
|
13771
13792
|
const innerBlock = findInnerFrontmatterBlock(lines);
|
|
13772
13793
|
const start = innerBlock && isFrontmatterShaped(lines, innerBlock) ? innerBlock.close + 1 : 0;
|
|
@@ -13812,6 +13833,8 @@ function projectMarkdownContent(body) {
|
|
|
13812
13833
|
const text = projected.join(" ").replace(/\s+/g, " ").trim();
|
|
13813
13834
|
if (!text)
|
|
13814
13835
|
return;
|
|
13836
|
+
if (truncationInfo)
|
|
13837
|
+
truncationInfo.truncated = text.length > MARKDOWN_CONTENT_MAX_CHARS;
|
|
13815
13838
|
return truncateUnicodeSafe(text, MARKDOWN_CONTENT_MAX_CHARS);
|
|
13816
13839
|
}
|
|
13817
13840
|
function applyPreContributorFields(entry, file, ctx, pkgMeta) {
|
|
@@ -13835,9 +13858,15 @@ function applyPreContributorFields(entry, file, ctx, pkgMeta) {
|
|
|
13835
13858
|
applyWikiFrontmatter(entry, parsed.data);
|
|
13836
13859
|
applyProvenanceFrontmatter(entry, parsed.data);
|
|
13837
13860
|
if (entry.type !== "env" && entry.type !== "session" && !hasSessionMemoryMarker(parsed.data, parsed.content)) {
|
|
13838
|
-
const
|
|
13839
|
-
|
|
13861
|
+
const truncationInfo = { truncated: false };
|
|
13862
|
+
const contentProjection = projectMarkdownContent(parsed.content, truncationInfo);
|
|
13863
|
+
if (contentProjection) {
|
|
13840
13864
|
entry.content = contentProjection;
|
|
13865
|
+
if (truncationInfo.truncated) {
|
|
13866
|
+
entry.contentTruncated = true;
|
|
13867
|
+
warnVerbose(`${file}: indexed content truncated to ${MARKDOWN_CONTENT_MAX_CHARS} chars`);
|
|
13868
|
+
}
|
|
13869
|
+
}
|
|
13841
13870
|
}
|
|
13842
13871
|
if (entry.type === "command") {
|
|
13843
13872
|
const cmdParams = extractCommandParameters(parsed.content);
|
|
@@ -16800,6 +16829,16 @@ var SHELL_ASSIGNMENT_WORD = /^[A-Za-z_][A-Za-z0-9_]*=/;
|
|
|
16800
16829
|
function shellStableV2Executable(executable) {
|
|
16801
16830
|
return executable === "akm" || executable.includes("/");
|
|
16802
16831
|
}
|
|
16832
|
+
function skipEnvAssignmentPrefix(tokens) {
|
|
16833
|
+
if (tokens[0] !== "env")
|
|
16834
|
+
return { tokens, envWrapped: false };
|
|
16835
|
+
let index = 1;
|
|
16836
|
+
while (index < tokens.length && SHELL_ASSIGNMENT_WORD.test(tokens[index]))
|
|
16837
|
+
index += 1;
|
|
16838
|
+
if (index >= tokens.length)
|
|
16839
|
+
return { tokens, envWrapped: false };
|
|
16840
|
+
return { tokens: tokens.slice(index), envWrapped: true };
|
|
16841
|
+
}
|
|
16803
16842
|
var KNOWN_PROMPT_REF_FAMILIES = new Set([
|
|
16804
16843
|
"agents",
|
|
16805
16844
|
"commands",
|
|
@@ -16820,11 +16859,6 @@ function hash(bytes) {
|
|
|
16820
16859
|
return crypto.createHash("sha256").update(bytes).digest("hex");
|
|
16821
16860
|
}
|
|
16822
16861
|
function base(input) {
|
|
16823
|
-
const inspectionIdentity = input.inspectionIdentity ? Object.freeze({
|
|
16824
|
-
file: Object.freeze({ ...input.inspectionIdentity.file }),
|
|
16825
|
-
root: Object.freeze({ ...input.inspectionIdentity.root }),
|
|
16826
|
-
...input.inspectionIdentity.bundleRoot ? { bundleRoot: Object.freeze({ ...input.inspectionIdentity.bundleRoot }) } : {}
|
|
16827
|
-
}) : undefined;
|
|
16828
16862
|
return {
|
|
16829
16863
|
filePath: input.filePath,
|
|
16830
16864
|
before: Buffer.from(input.bytes),
|
|
@@ -16832,8 +16866,7 @@ function base(input) {
|
|
|
16832
16866
|
mode: input.mode,
|
|
16833
16867
|
writable: input.writable,
|
|
16834
16868
|
...input.onDiskWritable !== undefined ? { onDiskWritable: input.onDiskWritable } : {},
|
|
16835
|
-
...input.containmentRoot ? { containmentRoot: input.containmentRoot } : {}
|
|
16836
|
-
...inspectionIdentity ? { inspectionIdentity } : {}
|
|
16869
|
+
...input.containmentRoot ? { containmentRoot: input.containmentRoot } : {}
|
|
16837
16870
|
};
|
|
16838
16871
|
}
|
|
16839
16872
|
function blocked(input, reason, detail) {
|
|
@@ -17069,8 +17102,9 @@ function migratedObject(data) {
|
|
|
17069
17102
|
if (tokens.length === 0 || tokens.some((token) => !SAFE_V2_COMMAND_TOKEN.test(token))) {
|
|
17070
17103
|
return "shell-operators-change-v2-literal-argv-semantics";
|
|
17071
17104
|
}
|
|
17072
|
-
const
|
|
17073
|
-
|
|
17105
|
+
const { tokens: targetTokens, envWrapped } = skipEnvAssignmentPrefix(tokens);
|
|
17106
|
+
const executable = targetTokens[0];
|
|
17107
|
+
if (SHELL_ASSIGNMENT_WORD.test(executable) || !envWrapped && !shellStableV2Executable(executable)) {
|
|
17074
17108
|
return "shell-command-resolution-changes-v2-literal-argv-semantics";
|
|
17075
17109
|
}
|
|
17076
17110
|
output.run = tokens.join(" ");
|
|
@@ -17264,11 +17298,6 @@ function causeMessage(cause) {
|
|
|
17264
17298
|
return cause instanceof Error ? cause.message : String(cause);
|
|
17265
17299
|
}
|
|
17266
17300
|
function base2(input) {
|
|
17267
|
-
const inspectionIdentity = input.inspectionIdentity ? Object.freeze({
|
|
17268
|
-
file: Object.freeze({ ...input.inspectionIdentity.file }),
|
|
17269
|
-
root: Object.freeze({ ...input.inspectionIdentity.root }),
|
|
17270
|
-
...input.inspectionIdentity.bundleRoot ? { bundleRoot: Object.freeze({ ...input.inspectionIdentity.bundleRoot }) } : {}
|
|
17271
|
-
}) : undefined;
|
|
17272
17301
|
return {
|
|
17273
17302
|
filePath: input.filePath,
|
|
17274
17303
|
before: Buffer.from(input.bytes),
|
|
@@ -17276,8 +17305,7 @@ function base2(input) {
|
|
|
17276
17305
|
mode: input.mode,
|
|
17277
17306
|
writable: input.writable,
|
|
17278
17307
|
...input.onDiskWritable !== undefined ? { onDiskWritable: input.onDiskWritable } : {},
|
|
17279
|
-
...input.containmentRoot ? { containmentRoot: input.containmentRoot } : {}
|
|
17280
|
-
...inspectionIdentity ? { inspectionIdentity } : {}
|
|
17308
|
+
...input.containmentRoot ? { containmentRoot: input.containmentRoot } : {}
|
|
17281
17309
|
};
|
|
17282
17310
|
}
|
|
17283
17311
|
function blocked2(input, reason, detail) {
|
|
@@ -21842,6 +21870,8 @@ function indexDocumentFromEntry(entry, base3, rendererName) {
|
|
|
21842
21870
|
doc.tags = entry.tags;
|
|
21843
21871
|
if (entry.content !== undefined)
|
|
21844
21872
|
doc.content = entry.content;
|
|
21873
|
+
if (entry.contentTruncated !== undefined)
|
|
21874
|
+
doc.contentTruncated = entry.contentTruncated;
|
|
21845
21875
|
if (entry.aliases !== undefined)
|
|
21846
21876
|
doc.aliases = entry.aliases;
|
|
21847
21877
|
if (entry.searchHints !== undefined)
|
|
@@ -28892,6 +28922,43 @@ var AkmConfigSchema = AkmConfigBaseSchema.superRefine((config, ctx) => {
|
|
|
28892
28922
|
}
|
|
28893
28923
|
});
|
|
28894
28924
|
|
|
28925
|
+
// src/core/config/config-version-shim.ts
|
|
28926
|
+
var KNOWN_OLD_CONFIG_VERSIONS = ["0.0.1"];
|
|
28927
|
+
function isKnownOldConfigVersion(value) {
|
|
28928
|
+
return typeof value === "string" && KNOWN_OLD_CONFIG_VERSIONS.includes(value);
|
|
28929
|
+
}
|
|
28930
|
+
function upgradeFrom080(raw) {
|
|
28931
|
+
const { defaultEngine, defaults, ...rest } = raw;
|
|
28932
|
+
if (typeof defaultEngine !== "string" || defaultEngine.length === 0) {
|
|
28933
|
+
return { ...rest, ...defaults !== undefined ? { defaults } : {}, configVersion: CURRENT_CONFIG_VERSION };
|
|
28934
|
+
}
|
|
28935
|
+
const existingDefaults = defaults !== null && typeof defaults === "object" ? defaults : {};
|
|
28936
|
+
return {
|
|
28937
|
+
...rest,
|
|
28938
|
+
configVersion: CURRENT_CONFIG_VERSION,
|
|
28939
|
+
defaults: { llmEngine: defaultEngine, ...existingDefaults }
|
|
28940
|
+
};
|
|
28941
|
+
}
|
|
28942
|
+
var CONFIG_VERSION_UPGRADES = {
|
|
28943
|
+
"0.0.1": upgradeFrom080
|
|
28944
|
+
};
|
|
28945
|
+
function unsupportedConfigVersionError(rawVersion, sourcePath) {
|
|
28946
|
+
const where = sourcePath ? ` at ${sourcePath}` : "";
|
|
28947
|
+
const supported = [CURRENT_CONFIG_VERSION, ...KNOWN_OLD_CONFIG_VERSIONS].map((v) => `"${v}"`).join(", ");
|
|
28948
|
+
return new ConfigError(`Unsupported configVersion${where}: got ${JSON.stringify(rawVersion)}, expected one of ${supported}.`, "UNSUPPORTED_CONFIG_VERSION", "Recreate engines and improve.strategies manually for AKM 0.9.0; profile-based configuration is not translated automatically.");
|
|
28949
|
+
}
|
|
28950
|
+
function upgradeConfigVersion(raw, sourcePath) {
|
|
28951
|
+
const version = raw.configVersion;
|
|
28952
|
+
if (version === CURRENT_CONFIG_VERSION)
|
|
28953
|
+
return raw;
|
|
28954
|
+
if (isKnownOldConfigVersion(version)) {
|
|
28955
|
+
const upgraded = CONFIG_VERSION_UPGRADES[version](raw);
|
|
28956
|
+
warn(`Config${sourcePath ? ` at ${sourcePath}` : ""} uses configVersion "${version}" — auto-upgraded to ${CURRENT_CONFIG_VERSION} in memory; the next config write (e.g. \`akm config set\`) persists this and silences the warning.`);
|
|
28957
|
+
return upgraded;
|
|
28958
|
+
}
|
|
28959
|
+
throw unsupportedConfigVersionError(version, sourcePath);
|
|
28960
|
+
}
|
|
28961
|
+
|
|
28895
28962
|
// src/core/config/deep-merge.ts
|
|
28896
28963
|
var UNSAFE_KEYS3 = new Set(["__proto__", "constructor", "prototype"]);
|
|
28897
28964
|
function isPlainObject4(value) {
|
|
@@ -28982,10 +29049,7 @@ function loadUserConfig() {
|
|
|
28982
29049
|
return finalConfig;
|
|
28983
29050
|
}
|
|
28984
29051
|
function parseAndValidateConfigText(text, sourcePath) {
|
|
28985
|
-
const parsedRaw = parseConfigText(text, sourcePath);
|
|
28986
|
-
if (parsedRaw.configVersion !== CURRENT_CONFIG_VERSION) {
|
|
28987
|
-
throw new ConfigError(`Unsupported configVersion${sourcePath ? ` at ${sourcePath}` : ""}: expected "${CURRENT_CONFIG_VERSION}".`, "UNSUPPORTED_CONFIG_VERSION", "Recreate engines and improve.strategies manually for AKM 0.9.0; profile-based configuration is not translated automatically.");
|
|
28988
|
-
}
|
|
29052
|
+
const parsedRaw = upgradeConfigVersion(parseConfigText(text, sourcePath), sourcePath);
|
|
28989
29053
|
const { config: raw, lifted, conflicts } = liftLegacyEngineExtraParams(parsedRaw);
|
|
28990
29054
|
const where = sourcePath ? ` at ${sourcePath}` : "";
|
|
28991
29055
|
if (conflicts.length > 0) {
|
|
@@ -29538,32 +29602,18 @@ function contained2(root, candidate) {
|
|
|
29538
29602
|
const relative = path31.relative(root, candidate);
|
|
29539
29603
|
return relative === "" || !relative.startsWith("..") && !path31.isAbsolute(relative);
|
|
29540
29604
|
}
|
|
29541
|
-
function
|
|
29542
|
-
const stat = fs26.lstatSync(filePath
|
|
29543
|
-
|
|
29544
|
-
|
|
29545
|
-
|
|
29546
|
-
if (kind === "file" && stat.nlink !== 1n)
|
|
29547
|
-
throw migrationError(`${filePath} must not be hard-linked.`);
|
|
29548
|
-
return Object.freeze({
|
|
29549
|
-
realPath: fs26.realpathSync(filePath),
|
|
29550
|
-
device: stat.dev.toString(),
|
|
29551
|
-
inode: stat.ino.toString(),
|
|
29552
|
-
linkCount: stat.nlink.toString(),
|
|
29553
|
-
changeTimeNs: stat.ctimeNs.toString()
|
|
29554
|
-
});
|
|
29555
|
-
}
|
|
29556
|
-
function sameIdentity2(left, right) {
|
|
29557
|
-
return left.realPath === right.realPath && left.device === right.device && left.inode === right.inode && left.linkCount === right.linkCount && left.changeTimeNs === right.changeTimeNs;
|
|
29605
|
+
function realDirectory(filePath) {
|
|
29606
|
+
const stat = fs26.lstatSync(filePath);
|
|
29607
|
+
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
29608
|
+
throw migrationError(`${filePath} must be a real directory.`);
|
|
29609
|
+
return fs26.realpathSync(filePath);
|
|
29558
29610
|
}
|
|
29559
29611
|
function snapshot(filePath) {
|
|
29560
|
-
const before = identity3(filePath, "file");
|
|
29561
29612
|
const stat = fs26.lstatSync(filePath);
|
|
29613
|
+
if (stat.isSymbolicLink() || !stat.isFile())
|
|
29614
|
+
throw migrationError(`${filePath} must be a real file.`);
|
|
29562
29615
|
const bytes = fs26.readFileSync(filePath);
|
|
29563
|
-
|
|
29564
|
-
if (!sameIdentity2(before, after))
|
|
29565
|
-
throw migrationError(`${filePath} changed while it was read.`);
|
|
29566
|
-
return Object.freeze({ bytes, mode: stat.mode & 511, identity: after });
|
|
29616
|
+
return Object.freeze({ bytes, mode: stat.mode & 511 });
|
|
29567
29617
|
}
|
|
29568
29618
|
function writable(filePath) {
|
|
29569
29619
|
try {
|
|
@@ -29574,10 +29624,9 @@ function writable(filePath) {
|
|
|
29574
29624
|
}
|
|
29575
29625
|
}
|
|
29576
29626
|
function walkTasks(root, tasksDir, out) {
|
|
29577
|
-
const
|
|
29578
|
-
const
|
|
29579
|
-
|
|
29580
|
-
if (!contained2(bundleIdentity.realPath, physicalRoot)) {
|
|
29627
|
+
const physicalRoot = realDirectory(root.root);
|
|
29628
|
+
const physicalBundleRoot = realDirectory(root.bundleRoot ?? root.root);
|
|
29629
|
+
if (!contained2(physicalBundleRoot, physicalRoot)) {
|
|
29581
29630
|
throw migrationError(`${root.root} resolves outside bundle ${root.bundleId}.`);
|
|
29582
29631
|
}
|
|
29583
29632
|
const visit2 = (directory) => {
|
|
@@ -29603,12 +29652,7 @@ function walkTasks(root, tasksDir, out) {
|
|
|
29603
29652
|
mode: current.mode,
|
|
29604
29653
|
writable: root.writable,
|
|
29605
29654
|
onDiskWritable: writable(candidate) && writable(parent) && (current.mode & 146) !== 0,
|
|
29606
|
-
containmentRoot: physicalRoot
|
|
29607
|
-
inspectionIdentity: Object.freeze({
|
|
29608
|
-
file: current.identity,
|
|
29609
|
-
root: rootIdentity,
|
|
29610
|
-
bundleRoot: bundleIdentity
|
|
29611
|
-
})
|
|
29655
|
+
containmentRoot: physicalRoot
|
|
29612
29656
|
});
|
|
29613
29657
|
}
|
|
29614
29658
|
};
|
|
@@ -29672,17 +29716,9 @@ function assertUnchanged(change) {
|
|
|
29672
29716
|
if (!current.bytes.equals(change.before) || current.mode !== change.mode) {
|
|
29673
29717
|
throw migrationError(`${change.filePath} changed after preview; no task files were replaced.`);
|
|
29674
29718
|
}
|
|
29675
|
-
const planned = change.inspectionIdentity?.file;
|
|
29676
|
-
if (planned && !sameIdentity2(planned, current.identity)) {
|
|
29677
|
-
throw migrationError(`${change.filePath} identity changed after preview; no task files were replaced.`);
|
|
29678
|
-
}
|
|
29679
29719
|
return current;
|
|
29680
29720
|
}
|
|
29681
29721
|
function applyTaskToV3MigrationPlan(plan, options) {
|
|
29682
|
-
const blocked3 = plan.files.filter((file) => file.status === "blocked");
|
|
29683
|
-
if (blocked3.length > 0) {
|
|
29684
|
-
throw migrationError(`plan is blocked: ${blocked3.map((file) => `${file.filePath} (${file.reason})`).join(", ")}. No files were written.`);
|
|
29685
|
-
}
|
|
29686
29722
|
const changes = plan.files.filter((file) => file.status === "changed");
|
|
29687
29723
|
for (const change of changes) {
|
|
29688
29724
|
assertUnchanged(change);
|
|
@@ -29725,32 +29761,18 @@ function contained3(root, candidate) {
|
|
|
29725
29761
|
const relative = path32.relative(root, candidate);
|
|
29726
29762
|
return relative === "" || !relative.startsWith("..") && !path32.isAbsolute(relative);
|
|
29727
29763
|
}
|
|
29728
|
-
function
|
|
29729
|
-
const stat = fs27.lstatSync(filePath
|
|
29730
|
-
|
|
29731
|
-
|
|
29732
|
-
|
|
29733
|
-
if (kind === "file" && stat.nlink !== 1n)
|
|
29734
|
-
throw migrationError2(`${filePath} must not be hard-linked.`);
|
|
29735
|
-
return Object.freeze({
|
|
29736
|
-
realPath: fs27.realpathSync(filePath),
|
|
29737
|
-
device: stat.dev.toString(),
|
|
29738
|
-
inode: stat.ino.toString(),
|
|
29739
|
-
linkCount: stat.nlink.toString(),
|
|
29740
|
-
changeTimeNs: stat.ctimeNs.toString()
|
|
29741
|
-
});
|
|
29742
|
-
}
|
|
29743
|
-
function sameIdentity3(left, right) {
|
|
29744
|
-
return left.realPath === right.realPath && left.device === right.device && left.inode === right.inode && left.linkCount === right.linkCount && left.changeTimeNs === right.changeTimeNs;
|
|
29764
|
+
function realDirectory2(filePath) {
|
|
29765
|
+
const stat = fs27.lstatSync(filePath);
|
|
29766
|
+
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
29767
|
+
throw migrationError2(`${filePath} must be a real directory.`);
|
|
29768
|
+
return fs27.realpathSync(filePath);
|
|
29745
29769
|
}
|
|
29746
29770
|
function snapshot2(filePath) {
|
|
29747
|
-
const before = identity4(filePath, "file");
|
|
29748
29771
|
const stat = fs27.lstatSync(filePath);
|
|
29772
|
+
if (stat.isSymbolicLink() || !stat.isFile())
|
|
29773
|
+
throw migrationError2(`${filePath} must be a real file.`);
|
|
29749
29774
|
const bytes = fs27.readFileSync(filePath);
|
|
29750
|
-
|
|
29751
|
-
if (!sameIdentity3(before, after))
|
|
29752
|
-
throw migrationError2(`${filePath} changed while it was read.`);
|
|
29753
|
-
return Object.freeze({ bytes, mode: stat.mode & 511, identity: after });
|
|
29775
|
+
return Object.freeze({ bytes, mode: stat.mode & 511 });
|
|
29754
29776
|
}
|
|
29755
29777
|
function writable2(filePath) {
|
|
29756
29778
|
try {
|
|
@@ -29761,10 +29783,9 @@ function writable2(filePath) {
|
|
|
29761
29783
|
}
|
|
29762
29784
|
}
|
|
29763
29785
|
function walkTasks2(root, tasksDir, out) {
|
|
29764
|
-
const
|
|
29765
|
-
const
|
|
29766
|
-
|
|
29767
|
-
if (!contained3(bundleIdentity.realPath, physicalRoot)) {
|
|
29786
|
+
const physicalRoot = realDirectory2(root.root);
|
|
29787
|
+
const physicalBundleRoot = realDirectory2(root.bundleRoot ?? root.root);
|
|
29788
|
+
if (!contained3(physicalBundleRoot, physicalRoot)) {
|
|
29768
29789
|
throw migrationError2(`${root.root} resolves outside bundle ${root.bundleId}.`);
|
|
29769
29790
|
}
|
|
29770
29791
|
const visit2 = (directory) => {
|
|
@@ -29790,12 +29811,7 @@ function walkTasks2(root, tasksDir, out) {
|
|
|
29790
29811
|
mode: current.mode,
|
|
29791
29812
|
writable: root.writable,
|
|
29792
29813
|
onDiskWritable: writable2(candidate) && writable2(parent) && (current.mode & 146) !== 0,
|
|
29793
|
-
containmentRoot: physicalRoot
|
|
29794
|
-
inspectionIdentity: Object.freeze({
|
|
29795
|
-
file: current.identity,
|
|
29796
|
-
root: rootIdentity,
|
|
29797
|
-
bundleRoot: bundleIdentity
|
|
29798
|
-
})
|
|
29814
|
+
containmentRoot: physicalRoot
|
|
29799
29815
|
});
|
|
29800
29816
|
}
|
|
29801
29817
|
};
|
|
@@ -29859,17 +29875,9 @@ function assertUnchanged2(change) {
|
|
|
29859
29875
|
if (!current.bytes.equals(change.before) || current.mode !== change.mode) {
|
|
29860
29876
|
throw migrationError2(`${change.filePath} changed after preview; no task files were replaced.`);
|
|
29861
29877
|
}
|
|
29862
|
-
const planned = change.inspectionIdentity?.file;
|
|
29863
|
-
if (planned && !sameIdentity3(planned, current.identity)) {
|
|
29864
|
-
throw migrationError2(`${change.filePath} identity changed after preview; no task files were replaced.`);
|
|
29865
|
-
}
|
|
29866
29878
|
return current;
|
|
29867
29879
|
}
|
|
29868
29880
|
function applyTaskToV4MigrationPlan(plan, options) {
|
|
29869
|
-
const blocked3 = plan.files.filter((file) => file.status === "blocked");
|
|
29870
|
-
if (blocked3.length > 0) {
|
|
29871
|
-
throw migrationError2(`plan is blocked: ${blocked3.map((file) => `${file.filePath} (${file.reason})`).join(", ")}. No files were written.`);
|
|
29872
|
-
}
|
|
29873
29881
|
const changes = plan.files.filter((file) => file.status === "changed");
|
|
29874
29882
|
for (const change of changes) {
|
|
29875
29883
|
assertUnchanged2(change);
|
|
@@ -30013,12 +30021,12 @@ async function runMigrationApply(options = {}) {
|
|
|
30013
30021
|
}
|
|
30014
30022
|
const result = withConfigLock(() => withMaintenanceStartBarrier(() => {
|
|
30015
30023
|
const before = inspectCurrentTaskPlan();
|
|
30016
|
-
if (before.result.
|
|
30024
|
+
if (before.result.taskV3Migration.changed === 0)
|
|
30017
30025
|
return before.result;
|
|
30018
30026
|
const backupPath = path33.join(getDataDir(), "backups", "task-v3", `${Date.now()}-${randomUUID2()}`);
|
|
30019
30027
|
const applied = applyTaskToV3MigrationPlan(before.plan, { backupRoot: backupPath });
|
|
30020
30028
|
const after = inspectCurrentTaskPlan().result;
|
|
30021
|
-
if (after.
|
|
30029
|
+
if (after.taskV3Migration.changed > 0) {
|
|
30022
30030
|
throw new ConfigError("Task migration did not converge to task v3.", "INVALID_CONFIG_FILE");
|
|
30023
30031
|
}
|
|
30024
30032
|
return { ...after, backupPath, applied: applied.changed.length };
|
|
@@ -30076,12 +30084,12 @@ async function runTaskV4MigrationApply(options = {}) {
|
|
|
30076
30084
|
}
|
|
30077
30085
|
const result = withConfigLock(() => withMaintenanceStartBarrier(() => {
|
|
30078
30086
|
const before = inspectCurrentTaskV4Plan();
|
|
30079
|
-
if (before.result.
|
|
30087
|
+
if (before.result.taskV4Migration.changed === 0)
|
|
30080
30088
|
return before.result;
|
|
30081
30089
|
const backupPath = path33.join(getDataDir(), "backups", "task-v4", `${Date.now()}-${randomUUID2()}`);
|
|
30082
30090
|
const applied = applyTaskToV4MigrationPlan(before.plan, { backupRoot: backupPath });
|
|
30083
30091
|
const after = inspectCurrentTaskV4Plan().result;
|
|
30084
|
-
if (after.
|
|
30092
|
+
if (after.taskV4Migration.changed > 0) {
|
|
30085
30093
|
throw new ConfigError("Task migration did not converge to task source v4.", "INVALID_CONFIG_FILE");
|
|
30086
30094
|
}
|
|
30087
30095
|
return { ...after, backupPath, applied: applied.changed.length };
|