akm-cli 0.9.12 → 0.9.14-beta.1
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 +100 -0
- package/dist/assets/workflows/workflow-template.md +4 -0
- package/dist/commands/improve/eligibility.js +27 -15
- package/dist/commands/improve/improve.js +1 -0
- package/dist/commands/lint/base-linter.js +10 -0
- package/dist/commands/proposal/drain.js +48 -6
- package/dist/commands/proposal/proposal-cli.js +1 -0
- package/dist/commands/read/curate.js +3 -2
- package/dist/commands/read/show.js +26 -9
- package/dist/core/adapter/adapters/akm-adapter.js +5 -1
- package/dist/core/asset/markdown-fragments.js +146 -0
- package/dist/core/config/config-walker.js +7 -3
- package/dist/core/config/config.js +21 -12
- package/dist/core/config/schema/primitives.js +8 -2
- package/dist/core/errors.js +2 -0
- package/dist/core/lexical-score.js +25 -0
- package/dist/core/type-presentation.js +36 -4
- package/dist/indexer/index-written-assets.js +4 -0
- package/dist/indexer/indexer.js +5 -2
- package/dist/indexer/passes/metadata.js +64 -1
- package/dist/indexer/scan/doc-to-entry.js +3 -0
- package/dist/indexer/scan/drain-dir.js +33 -22
- package/dist/indexer/search/db-search.js +72 -14
- package/dist/indexer/search/name-match.js +35 -0
- package/dist/indexer/search/ranking-contributors.js +15 -12
- package/dist/indexer/search/ranking.js +42 -18
- package/dist/indexer/usage/show-usage.js +14 -2
- package/dist/llm/client.js +12 -8
- package/dist/llm/embedders/remote.js +3 -2
- package/dist/llm/graph-extract.js +18 -67
- package/dist/output/shapes.js +46 -1
- package/dist/output/text/proposal-format.js +5 -0
- package/dist/scripts/akm-migrate-node.js +648 -253
- package/dist/scripts/akm-migrate.js +648 -253
- package/dist/storage/repositories/index-connection.js +23 -8
- package/dist/storage/repositories/index-entries-repository.js +3 -2
- package/dist/storage/repositories/index-entry-schema.js +43 -3
- package/dist/storage/repositories/index-fts-repository.js +160 -14
- package/dist/storage/repositories/index-schema.js +8 -18
- package/dist/storage/repositories/workflow-runs-repository.js +118 -10
- package/dist/workflows/exec/run-workflow.js +1 -1
- package/dist/workflows/exec/step-work.js +41 -0
- package/dist/workflows/parser.js +1 -1
- package/dist/workflows/runtime/runs.js +29 -5
- package/docs/migration/release-notes/0.9.14.md +26 -0
- package/docs/migration/release-notes/README.md +2 -0
- package/docs/reference/cli.md +18 -0
- package/package.json +1 -1
|
@@ -7042,7 +7042,8 @@ var init_errors = __esm(() => {
|
|
|
7042
7042
|
TEST_ISOLATION_MISSING: "Under bun test, when AKM_BUNDLE_DIR is set you MUST also set XDG_DATA_HOME (or AKM_DATA_DIR) and XDG_STATE_HOME (or AKM_STATE_DIR) to temp directories so the test does not touch the developer's real ~/.local/share/akm or ~/.local/state/akm.",
|
|
7043
7043
|
UNSAFE_STASH_DIR: "Choose a path inside your home directory (e.g. ~/akm) or another empty workspace. The bundle directory cannot be the filesystem root, your home directory itself, or a sensitive system path like /etc, /var, ~/.config, or ~/.ssh.",
|
|
7044
7044
|
UNKNOWN_IMPROVE_STRATEGY: "Pass one of the listed strategy names to `--strategy`, or define it under `improve.strategies`. Names are case-sensitive.",
|
|
7045
|
-
EXECUTION_NOT_AUTHORIZED: "Change the selected tools or update the machine/user execution policy, then retry."
|
|
7045
|
+
EXECUTION_NOT_AUTHORIZED: "Change the selected tools or update the machine/user execution policy, then retry.",
|
|
7046
|
+
SECRET_REFERENCE_UNRESOLVED: "Check the secret exists (`akm secret list`) and the name after `secret://` matches, or run `akm secret set <name> <value>` to store it."
|
|
7046
7047
|
};
|
|
7047
7048
|
COMPOSITION_INVALID_MULTI_JOB_HINT = "AKM workflows support exactly one job per source, with no needs: between jobs. Split the extra job(s) into " + "their own workflow file, and compose them with uses: workflows/<ref> instead.";
|
|
7048
7049
|
USAGE_HINTS = {
|
|
@@ -7064,7 +7065,8 @@ var init_errors = __esm(() => {
|
|
|
7064
7065
|
INPUT_BINDING_INVALID: "Check the step's with: keys against the target's declared inputs.",
|
|
7065
7066
|
TASK_TARGET_UNSUPPORTED: "Task definitions support command, script, workflow, and shell (run:) targets; akm/command is layered by callers.",
|
|
7066
7067
|
WORKFLOW_IR_VERSION_UNSUPPORTED: "Abandon the run with `akm workflow abandon <id>`, then start it again from the workflow source \u2014 a frozen plan this akm cannot execute is not re-executable in place.",
|
|
7067
|
-
WORKFLOW_OUTPUT_INVALID: "Check each `outputs:` entry's `from:` against the step artifact it names, and its `schema:` against the value that step actually promotes."
|
|
7068
|
+
WORKFLOW_OUTPUT_INVALID: "Check each `outputs:` entry's `from:` against the step artifact it names, and its `schema:` against the value that step actually promotes.",
|
|
7069
|
+
RUN_LEASE_HELD: "Wait for the named engine invocation to finish or for the lease to expire, then retry. `akm workflow status <id>` shows the current lease."
|
|
7068
7070
|
};
|
|
7069
7071
|
NOT_FOUND_HINTS = {
|
|
7070
7072
|
ASSET_NOT_FOUND: "Run `akm search <query>` or `akm index` to refresh the index.",
|
|
@@ -8388,6 +8390,17 @@ function parseRefInput(raw) {
|
|
|
8388
8390
|
}
|
|
8389
8391
|
return { type: parts.type, name: parts.name, origin: ref.bundle };
|
|
8390
8392
|
}
|
|
8393
|
+
function isFullRefInput(raw) {
|
|
8394
|
+
const trimmed = raw.trim();
|
|
8395
|
+
if (!trimmed)
|
|
8396
|
+
return false;
|
|
8397
|
+
try {
|
|
8398
|
+
const parsed = parseBundleRef(trimmed);
|
|
8399
|
+
return parsed.bundle !== undefined || typeNameFromConceptId(parsed.conceptId) !== undefined;
|
|
8400
|
+
} catch {
|
|
8401
|
+
return false;
|
|
8402
|
+
}
|
|
8403
|
+
}
|
|
8391
8404
|
var init_resolve_ref = __esm(() => {
|
|
8392
8405
|
init_errors();
|
|
8393
8406
|
init_asset_placement();
|
|
@@ -9453,6 +9466,53 @@ function projectMarkdownContent(body, truncationInfo) {
|
|
|
9453
9466
|
truncationInfo.truncated = text.length > MARKDOWN_CONTENT_MAX_CHARS;
|
|
9454
9467
|
return truncateUnicodeSafe(text, MARKDOWN_CONTENT_MAX_CHARS);
|
|
9455
9468
|
}
|
|
9469
|
+
function setMarkdownFragmentContent(entry, content) {
|
|
9470
|
+
markdownFragmentProjectionEntries.add(entry);
|
|
9471
|
+
if (content)
|
|
9472
|
+
markdownFragmentContentByEntry.set(entry, content);
|
|
9473
|
+
}
|
|
9474
|
+
function getMarkdownFragmentContent(entry) {
|
|
9475
|
+
return markdownFragmentContentByEntry.get(entry);
|
|
9476
|
+
}
|
|
9477
|
+
function hasMarkdownFragmentContent(entry) {
|
|
9478
|
+
return markdownFragmentProjectionEntries.has(entry);
|
|
9479
|
+
}
|
|
9480
|
+
function projectMarkdownFragmentContent(raw) {
|
|
9481
|
+
const lines = raw.split(/\r?\n/);
|
|
9482
|
+
const parsed = parseFrontmatter(raw);
|
|
9483
|
+
const start = parsed.frontmatter ? parsed.bodyStartLine - 1 : 0;
|
|
9484
|
+
const projected = lines.map(() => "");
|
|
9485
|
+
let fence;
|
|
9486
|
+
const htmlComment = { inComment: false };
|
|
9487
|
+
for (let index = start;index < lines.length; index++) {
|
|
9488
|
+
const rawLine = lines[index];
|
|
9489
|
+
if (fence) {
|
|
9490
|
+
if (isMarkdownFenceClosing(rawLine, fence))
|
|
9491
|
+
fence = undefined;
|
|
9492
|
+
continue;
|
|
9493
|
+
}
|
|
9494
|
+
if (!htmlComment.inComment) {
|
|
9495
|
+
const opening2 = parseMarkdownFenceOpening(rawLine);
|
|
9496
|
+
if (opening2) {
|
|
9497
|
+
fence = opening2;
|
|
9498
|
+
continue;
|
|
9499
|
+
}
|
|
9500
|
+
}
|
|
9501
|
+
let safe = stripMarkdownHtmlComments(rawLine, htmlComment);
|
|
9502
|
+
const opening = parseMarkdownFenceOpening(safe.trim());
|
|
9503
|
+
if (opening) {
|
|
9504
|
+
fence = opening;
|
|
9505
|
+
continue;
|
|
9506
|
+
}
|
|
9507
|
+
if (/^\s*\[[^\]]+\]:\s*\S+/.test(safe) || /^\s*<[^>]+>\s*$/.test(safe))
|
|
9508
|
+
continue;
|
|
9509
|
+
safe = stripMarkdownLinkDestinations(safe).replace(/<[^>]+>/g, " ");
|
|
9510
|
+
projected[index] = safe.replace(/[ \t]+$/g, "");
|
|
9511
|
+
}
|
|
9512
|
+
const text = projected.join(`
|
|
9513
|
+
`);
|
|
9514
|
+
return text.trim() ? text : undefined;
|
|
9515
|
+
}
|
|
9456
9516
|
function applyPreContributorFields(entry, file, ctx, pkgMeta) {
|
|
9457
9517
|
const ext = path19.extname(file).toLowerCase();
|
|
9458
9518
|
if (pkgMeta) {
|
|
@@ -9473,7 +9533,9 @@ function applyPreContributorFields(entry, file, ctx, pkgMeta) {
|
|
|
9473
9533
|
entry.parameters = fmParams;
|
|
9474
9534
|
applyWikiFrontmatter(entry, parsed.data);
|
|
9475
9535
|
applyProvenanceFrontmatter(entry, parsed.data);
|
|
9476
|
-
|
|
9536
|
+
const safeForFragments = entry.type !== "env" && entry.type !== "session" && !hasSessionMemoryMarker(parsed.data, parsed.content);
|
|
9537
|
+
setMarkdownFragmentContent(entry, safeForFragments ? projectMarkdownFragmentContent(content) : undefined);
|
|
9538
|
+
if (safeForFragments) {
|
|
9477
9539
|
const truncationInfo = { truncated: false };
|
|
9478
9540
|
const contentProjection = projectMarkdownContent(parsed.content, truncationInfo);
|
|
9479
9541
|
if (contentProjection) {
|
|
@@ -9591,7 +9653,7 @@ function extractDirTagsFromName(name) {
|
|
|
9591
9653
|
}
|
|
9592
9654
|
return Array.from(tags);
|
|
9593
9655
|
}
|
|
9594
|
-
var SCOPE_KEYS, KNOWN_QUALITY_VALUES, warnedUnknownQualityValues, MARKDOWN_CONTENT_MAX_CHARS = 1e6, MAX_MARKDOWN_LINK_NESTING = 32;
|
|
9656
|
+
var SCOPE_KEYS, KNOWN_QUALITY_VALUES, warnedUnknownQualityValues, MARKDOWN_CONTENT_MAX_CHARS = 1e6, MAX_MARKDOWN_LINK_NESTING = 32, markdownFragmentContentByEntry, markdownFragmentProjectionEntries;
|
|
9595
9657
|
var init_metadata = __esm(() => {
|
|
9596
9658
|
init_asset_ref();
|
|
9597
9659
|
init_frontmatter();
|
|
@@ -9600,6 +9662,8 @@ var init_metadata = __esm(() => {
|
|
|
9600
9662
|
SCOPE_KEYS = ["user", "agent", "run", "channel"];
|
|
9601
9663
|
KNOWN_QUALITY_VALUES = new Set(["generated", "curated", "enriched", "proposed"]);
|
|
9602
9664
|
warnedUnknownQualityValues = new Set;
|
|
9665
|
+
markdownFragmentContentByEntry = new WeakMap;
|
|
9666
|
+
markdownFragmentProjectionEntries = new WeakSet;
|
|
9603
9667
|
});
|
|
9604
9668
|
|
|
9605
9669
|
// src/execution/record.ts
|
|
@@ -12173,6 +12237,9 @@ var init_schema2 = __esm(() => {
|
|
|
12173
12237
|
});
|
|
12174
12238
|
|
|
12175
12239
|
// src/core/asset/markdown.ts
|
|
12240
|
+
function markdownHeadingSlug(heading) {
|
|
12241
|
+
return heading.trim().toLowerCase().replace(/<[^>]*>/g, "").replace(/[^\p{L}\p{N}\s_-]+/gu, "-").replace(/[\s_]+/g, "-").replace(/-+/g, "-").replace(/^-|-$/g, "");
|
|
12242
|
+
}
|
|
12176
12243
|
function parseMarkdownToc(content) {
|
|
12177
12244
|
const lines = content.split(/\r?\n/);
|
|
12178
12245
|
const headings = [];
|
|
@@ -12414,7 +12481,7 @@ function bindStepSections(headings, lines, bodyStartLine, totalLines, path24, de
|
|
|
12414
12481
|
if (!declaredIds.has(h.text)) {
|
|
12415
12482
|
errors3.push({
|
|
12416
12483
|
line: h.line,
|
|
12417
|
-
message: `Unexpected level-2 heading "## ${h.text}" on line ${h.line} \u2014 no step "${h.text}" is declared in frontmatter "steps:". Level-2 headings must exactly match a declared step id.`
|
|
12484
|
+
message: `Unexpected level-2 heading "## ${h.text}" on line ${h.line} \u2014 no step "${h.text}" is declared in frontmatter "steps:". Level-2 headings must exactly match a declared step id. To document something that is not a step, use a level-3 heading.`
|
|
12418
12485
|
});
|
|
12419
12486
|
continue;
|
|
12420
12487
|
}
|
|
@@ -35607,7 +35674,7 @@ var require_libvips = __commonJS((exports, module) => {
|
|
|
35607
35674
|
SPDX-License-Identifier: Apache-2.0
|
|
35608
35675
|
*/
|
|
35609
35676
|
var { spawnSync: spawnSync6 } = __require("child_process");
|
|
35610
|
-
var { createHash:
|
|
35677
|
+
var { createHash: createHash10 } = __require("crypto");
|
|
35611
35678
|
var semverCoerce = require_coerce2();
|
|
35612
35679
|
var semverGreaterThanOrEqualTo = require_gte2();
|
|
35613
35680
|
var semverSatisfies = require_satisfies2();
|
|
@@ -35695,7 +35762,7 @@ var require_libvips = __commonJS((exports, module) => {
|
|
|
35695
35762
|
}
|
|
35696
35763
|
return false;
|
|
35697
35764
|
};
|
|
35698
|
-
var sha512 = (s) =>
|
|
35765
|
+
var sha512 = (s) => createHash10("sha512").update(s).digest("hex");
|
|
35699
35766
|
var yarnLocator = () => {
|
|
35700
35767
|
try {
|
|
35701
35768
|
const identHash = sha512(`imgsharp-libvips-${buildPlatformArch()}`);
|
|
@@ -49987,10 +50054,10 @@ var import_sharp, __dirname = "/home/runner/work/akm/akm/node_modules/@huggingfa
|
|
|
49987
50054
|
if (cached) {
|
|
49988
50055
|
return cached.text();
|
|
49989
50056
|
}
|
|
49990
|
-
const
|
|
49991
|
-
if (
|
|
49992
|
-
await hashCache.put(url2, new Response(
|
|
49993
|
-
return
|
|
50057
|
+
const hash4 = await this._getLfsFileHash(url2);
|
|
50058
|
+
if (hash4) {
|
|
50059
|
+
await hashCache.put(url2, new Response(hash4));
|
|
50060
|
+
return hash4;
|
|
49994
50061
|
}
|
|
49995
50062
|
return null;
|
|
49996
50063
|
} catch {
|
|
@@ -68087,15 +68154,15 @@ ${this.boa_token}${this.audio_token.repeat(this._compute_audio_num_tokens(audio_
|
|
|
68087
68154
|
});
|
|
68088
68155
|
|
|
68089
68156
|
// src/indexer/walk/file-context.ts
|
|
68090
|
-
import
|
|
68091
|
-
import
|
|
68157
|
+
import fs47 from "fs";
|
|
68158
|
+
import path56 from "path";
|
|
68092
68159
|
function buildFileContext(stashRoot, absPath) {
|
|
68093
|
-
const relPath = toPosix(
|
|
68094
|
-
const ext =
|
|
68095
|
-
const fileName =
|
|
68096
|
-
const parentDirAbs =
|
|
68097
|
-
const parentDir =
|
|
68098
|
-
const relDir = toPosix(
|
|
68160
|
+
const relPath = toPosix(path56.relative(stashRoot, absPath));
|
|
68161
|
+
const ext = path56.extname(absPath).toLowerCase();
|
|
68162
|
+
const fileName = path56.basename(absPath);
|
|
68163
|
+
const parentDirAbs = path56.dirname(absPath);
|
|
68164
|
+
const parentDir = path56.basename(parentDirAbs);
|
|
68165
|
+
const relDir = toPosix(path56.dirname(relPath));
|
|
68099
68166
|
const ancestorDirs = relDir === "." ? [] : relDir.split("/").filter((seg) => seg.length > 0);
|
|
68100
68167
|
let cachedContent;
|
|
68101
68168
|
let cachedFrontmatter;
|
|
@@ -68112,7 +68179,7 @@ function buildFileContext(stashRoot, absPath) {
|
|
|
68112
68179
|
stashRoot,
|
|
68113
68180
|
content() {
|
|
68114
68181
|
if (cachedContent === undefined) {
|
|
68115
|
-
cachedContent =
|
|
68182
|
+
cachedContent = fs47.readFileSync(absPath, "utf8");
|
|
68116
68183
|
}
|
|
68117
68184
|
return cachedContent;
|
|
68118
68185
|
},
|
|
@@ -68127,7 +68194,7 @@ function buildFileContext(stashRoot, absPath) {
|
|
|
68127
68194
|
},
|
|
68128
68195
|
stat() {
|
|
68129
68196
|
if (cachedStat === undefined) {
|
|
68130
|
-
cachedStat =
|
|
68197
|
+
cachedStat = fs47.statSync(absPath);
|
|
68131
68198
|
}
|
|
68132
68199
|
return cachedStat;
|
|
68133
68200
|
}
|
|
@@ -70250,6 +70317,7 @@ function formatProposalDrainPlain(r) {
|
|
|
70250
70317
|
const deferred = Array.isArray(r.deferred) ? r.deferred : [];
|
|
70251
70318
|
const skippedByCap = Array.isArray(r.skippedByCap) ? r.skippedByCap : [];
|
|
70252
70319
|
const staged = Array.isArray(r.staged) ? r.staged : [];
|
|
70320
|
+
const failed = Array.isArray(r.failed) ? r.failed : [];
|
|
70253
70321
|
const prefix = r.dryRun === true ? "[dry-run] " : "";
|
|
70254
70322
|
const lines = [
|
|
70255
70323
|
`${prefix}Drained proposal queue (strategy=${String(r.strategy ?? "?")}, policy=${policy}, applyMode=${applyMode})`,
|
|
@@ -70257,11 +70325,15 @@ function formatProposalDrainPlain(r) {
|
|
|
70257
70325
|
` rejected: ${rejected.length}`,
|
|
70258
70326
|
` deferred: ${deferred.length}`,
|
|
70259
70327
|
` skippedByCap: ${skippedByCap.length}`,
|
|
70260
|
-
` staged: ${staged.length}
|
|
70328
|
+
` staged: ${staged.length}`,
|
|
70329
|
+
` failed: ${failed.length}`
|
|
70261
70330
|
];
|
|
70262
70331
|
for (const d of deferred) {
|
|
70263
70332
|
lines.push(` - ${String(d.id ?? "?")} (${String(d.reason ?? "?")})`);
|
|
70264
70333
|
}
|
|
70334
|
+
for (const f of failed) {
|
|
70335
|
+
lines.push(` ! ${String(f.id ?? "?")} (${String(f.reason ?? "?")}): ${String(f.detail ?? "?")}`);
|
|
70336
|
+
}
|
|
70265
70337
|
appendLoweringNotices(lines, r);
|
|
70266
70338
|
return lines.join(`
|
|
70267
70339
|
`).trimEnd();
|
|
@@ -75483,12 +75555,16 @@ var httpUrl = exports_external.string().refine((v) => v.startsWith("http://") ||
|
|
|
75483
75555
|
});
|
|
75484
75556
|
var ENGINE_NAME_PATTERN = new RegExp(ENGINE_NAME_PATTERN_SOURCE);
|
|
75485
75557
|
var ENV_REFERENCE_PATTERN = /^\$[A-Za-z_][A-Za-z0-9_]*$|^\$\{[A-Za-z_][A-Za-z0-9_]*\}$/;
|
|
75558
|
+
var SECRET_STORE_REFERENCE_PATTERN = /^secret:\/\/(.+)$/;
|
|
75486
75559
|
var engineName = exports_external.string().max(63).regex(ENGINE_NAME_PATTERN, "names must be lowercase kebab-case and must not begin with reserved akm-");
|
|
75560
|
+
function isApiKeyReference(value) {
|
|
75561
|
+
return ENV_REFERENCE_PATTERN.test(value) || SECRET_STORE_REFERENCE_PATTERN.test(value);
|
|
75562
|
+
}
|
|
75487
75563
|
function symbolicOrWarnApiKey(label) {
|
|
75488
75564
|
return exports_external.string().superRefine((value) => {
|
|
75489
|
-
if (
|
|
75565
|
+
if (isApiKeyReference(value))
|
|
75490
75566
|
return;
|
|
75491
|
-
warnOnce(`config:literal-api-key:${label}`, `A ${label} in config.json is a literal API key, not a $VAR/\${VAR} reference; using it as configured. Prefer \`akm config set ...apiKey '$VAR'\` (with the corresponding env var set) \u2014 see docs/reference/data-and-telemetry.md.`);
|
|
75567
|
+
warnOnce(`config:literal-api-key:${label}`, `A ${label} in config.json is a literal API key, not a $VAR/\${VAR}/secret:// reference; using it as configured. Prefer \`akm config set ...apiKey '$VAR'\` (with the corresponding env var set) or \`secret://<name>\` (with \`akm secret set <name> ...\`) \u2014 see docs/reference/data-and-telemetry.md.`);
|
|
75492
75568
|
});
|
|
75493
75569
|
}
|
|
75494
75570
|
var chatCompletionsEndpoint = exports_external.string().superRefine((value, ctx) => {
|
|
@@ -76656,11 +76732,19 @@ function getSources(config) {
|
|
|
76656
76732
|
function loadConfig() {
|
|
76657
76733
|
return loadUserConfig();
|
|
76658
76734
|
}
|
|
76659
|
-
function resolveSecret(value) {
|
|
76735
|
+
function resolveSecret(value, resolveFromStore) {
|
|
76660
76736
|
if (value === undefined)
|
|
76661
76737
|
return;
|
|
76662
76738
|
if (typeof value !== "string")
|
|
76663
76739
|
return value;
|
|
76740
|
+
const storeRef = SECRET_STORE_REFERENCE_PATTERN.exec(value)?.[1];
|
|
76741
|
+
if (storeRef !== undefined) {
|
|
76742
|
+
const resolved = resolveFromStore?.(storeRef) ?? null;
|
|
76743
|
+
if (resolved === null) {
|
|
76744
|
+
throw new ConfigError(`Secret store reference "${value}" did not resolve to a stored value.`, "SECRET_REFERENCE_UNRESOLVED");
|
|
76745
|
+
}
|
|
76746
|
+
return resolved;
|
|
76747
|
+
}
|
|
76664
76748
|
if (!value.includes("$"))
|
|
76665
76749
|
return value;
|
|
76666
76750
|
return value.replace(/\$\{([A-Za-z_][A-Za-z0-9_]*)\}|\$([A-Za-z_][A-Za-z0-9_]*)/g, (_match, braced, bare) => {
|
|
@@ -78544,10 +78628,10 @@ function listTxnJournalsTolerant(predicate) {
|
|
|
78544
78628
|
}
|
|
78545
78629
|
|
|
78546
78630
|
// src/commands/proposal/repository.ts
|
|
78547
|
-
import { createHash as
|
|
78548
|
-
import
|
|
78631
|
+
import { createHash as createHash10, randomUUID as randomUUID6 } from "crypto";
|
|
78632
|
+
import fs49 from "fs";
|
|
78549
78633
|
init_dist();
|
|
78550
|
-
import
|
|
78634
|
+
import path61 from "path";
|
|
78551
78635
|
|
|
78552
78636
|
// src/core/adapter/adapters/agent-skills-adapter.ts
|
|
78553
78637
|
init_frontmatter();
|
|
@@ -79452,20 +79536,41 @@ function buildWorkflowAction(ref) {
|
|
|
79452
79536
|
return `Start or resume execution with \`akm workflow run ${shellQuote(ref)}\`.`;
|
|
79453
79537
|
}
|
|
79454
79538
|
var TYPE_PRESENTATION = {
|
|
79455
|
-
skill: {
|
|
79539
|
+
skill: {
|
|
79540
|
+
label: "Skill",
|
|
79541
|
+
renderer: "skill-md",
|
|
79542
|
+
action: (ref) => `akm show ${ref} -> follow the instructions`,
|
|
79543
|
+
fragmentRef: false
|
|
79544
|
+
},
|
|
79456
79545
|
command: {
|
|
79457
79546
|
label: "Command",
|
|
79458
79547
|
renderer: "command-md",
|
|
79459
|
-
action: (ref) => `akm show ${ref} -> fill placeholders and dispatch
|
|
79548
|
+
action: (ref) => `akm show ${ref} -> fill placeholders and dispatch`,
|
|
79549
|
+
fragmentRef: false
|
|
79550
|
+
},
|
|
79551
|
+
agent: {
|
|
79552
|
+
label: "Agent",
|
|
79553
|
+
renderer: "agent-md",
|
|
79554
|
+
action: (ref) => `akm show ${ref} -> dispatch with full prompt`,
|
|
79555
|
+
fragmentRef: false
|
|
79460
79556
|
},
|
|
79461
|
-
agent: { label: "Agent", renderer: "agent-md", action: (ref) => `akm show ${ref} -> dispatch with full prompt` },
|
|
79462
79557
|
knowledge: {
|
|
79463
79558
|
label: "Knowledge",
|
|
79464
79559
|
renderer: "knowledge-md",
|
|
79465
79560
|
action: (ref) => `akm show ${ref} -> read reference material`
|
|
79466
79561
|
},
|
|
79467
|
-
workflow: {
|
|
79468
|
-
|
|
79562
|
+
workflow: {
|
|
79563
|
+
label: "Workflow",
|
|
79564
|
+
renderer: "workflow-md",
|
|
79565
|
+
action: (ref) => buildWorkflowAction(ref),
|
|
79566
|
+
fragmentRef: false
|
|
79567
|
+
},
|
|
79568
|
+
script: {
|
|
79569
|
+
label: "Script",
|
|
79570
|
+
renderer: "script-source",
|
|
79571
|
+
action: (ref) => `akm show ${ref} -> execute the run command`,
|
|
79572
|
+
fragmentRef: false
|
|
79573
|
+
},
|
|
79469
79574
|
memory: { label: "Memory", renderer: "memory-md", action: (ref) => `akm show ${ref} -> recall context` },
|
|
79470
79575
|
env: {
|
|
79471
79576
|
label: "Env",
|
|
@@ -79485,7 +79590,8 @@ var TYPE_PRESENTATION = {
|
|
|
79485
79590
|
task: {
|
|
79486
79591
|
label: "Task",
|
|
79487
79592
|
renderer: "task-yaml",
|
|
79488
|
-
action: (ref) => `akm show ${ref} -> inspect; akm task run <id> -> run now; edit the file + akm task sync -> unschedule
|
|
79593
|
+
action: (ref) => `akm show ${ref} -> inspect; akm task run <id> -> run now; edit the file + akm task sync -> unschedule`,
|
|
79594
|
+
fragmentRef: false
|
|
79489
79595
|
},
|
|
79490
79596
|
session: {
|
|
79491
79597
|
label: "Session",
|
|
@@ -79500,7 +79606,8 @@ var TYPE_PRESENTATION = {
|
|
|
79500
79606
|
instruction: {
|
|
79501
79607
|
label: "Instruction",
|
|
79502
79608
|
renderer: "knowledge-md",
|
|
79503
|
-
action: (ref) => `akm show ${ref} -> read the project instructions
|
|
79609
|
+
action: (ref) => `akm show ${ref} -> read the project instructions`,
|
|
79610
|
+
fragmentRef: false
|
|
79504
79611
|
}
|
|
79505
79612
|
};
|
|
79506
79613
|
var DEFAULT_PRESENTATION = { label: "Asset" };
|
|
@@ -82426,6 +82533,8 @@ function indexDocumentFromEntry(entry, base3, rendererName) {
|
|
|
82426
82533
|
doc.lessonStrength = entry.lessonStrength;
|
|
82427
82534
|
if (entry.derivedFrom !== undefined)
|
|
82428
82535
|
doc.derivedFrom = entry.derivedFrom;
|
|
82536
|
+
if (hasMarkdownFragmentContent(entry))
|
|
82537
|
+
setMarkdownFragmentContent(doc, getMarkdownFragmentContent(entry));
|
|
82429
82538
|
return doc;
|
|
82430
82539
|
}
|
|
82431
82540
|
function conceptIdForRecognizedType(root, filePath, type) {
|
|
@@ -92631,8 +92740,8 @@ init_warn();
|
|
|
92631
92740
|
init_write_provenance();
|
|
92632
92741
|
|
|
92633
92742
|
// src/indexer/index-written-assets.ts
|
|
92634
|
-
import
|
|
92635
|
-
import
|
|
92743
|
+
import fs48 from "fs";
|
|
92744
|
+
import path59 from "path";
|
|
92636
92745
|
init_errors();
|
|
92637
92746
|
init_paths();
|
|
92638
92747
|
init_warn();
|
|
@@ -92643,7 +92752,7 @@ init_paths();
|
|
|
92643
92752
|
init_warn();
|
|
92644
92753
|
|
|
92645
92754
|
// src/storage/repositories/index-entry-schema.ts
|
|
92646
|
-
var CANONICAL_INDEX_DB_VERSION =
|
|
92755
|
+
var CANONICAL_INDEX_DB_VERSION = 23;
|
|
92647
92756
|
var CANONICAL_ENTRY_SCHEMA_FINGERPRINT = {
|
|
92648
92757
|
tableSql: "CREATE TABLE entries ( id INTEGER PRIMARY KEY AUTOINCREMENT, item_ref TEXT NOT NULL UNIQUE, bundle_id TEXT NOT NULL, component_id TEXT NOT NULL, concept_id TEXT NOT NULL, adapter_id TEXT NOT NULL, type TEXT NOT NULL, file_path TEXT NOT NULL, content_hash TEXT, document_json TEXT NOT NULL, search_text TEXT NOT NULL, derived_from TEXT )",
|
|
92649
92758
|
sqliteSequenceTable: true,
|
|
@@ -92793,7 +92902,12 @@ var CANONICAL_ENTRY_SCHEMA_FINGERPRINT = {
|
|
|
92793
92902
|
{ sequence: 1, cid: -1, name: null, descending: 0, collation: "BINARY", key: 0 }
|
|
92794
92903
|
]
|
|
92795
92904
|
}
|
|
92796
|
-
]
|
|
92905
|
+
],
|
|
92906
|
+
searchSurfaces: {
|
|
92907
|
+
entriesFtsSql: "CREATE VIRTUAL TABLE entries_fts USING fts5( entry_id UNINDEXED, name, description, tags, hints, content, tokenize='porter unicode61' )",
|
|
92908
|
+
fragmentSourceSql: "CREATE TABLE entry_fragments ( entry_id INTEGER PRIMARY KEY REFERENCES entries(id) ON DELETE CASCADE, safe_markdown TEXT NOT NULL )",
|
|
92909
|
+
fragmentsFtsSql: "CREATE VIRTUAL TABLE entry_fragments_fts USING fts5( entry_id UNINDEXED, fragment_id UNINDEXED, fragment_ordinal UNINDEXED, content, tokenize='porter unicode61' )"
|
|
92910
|
+
}
|
|
92797
92911
|
};
|
|
92798
92912
|
function sqlString(value) {
|
|
92799
92913
|
return `'${value.replaceAll("'", "''")}'`;
|
|
@@ -92803,8 +92917,11 @@ function normalizeSchemaSql(value) {
|
|
|
92803
92917
|
return null;
|
|
92804
92918
|
return value.replace(/\s+/g, " ").trim();
|
|
92805
92919
|
}
|
|
92920
|
+
function readNamedTableSql(db, name) {
|
|
92921
|
+
const row = db.prepare(`SELECT sql FROM sqlite_master WHERE type = 'table' AND name = ${sqlString(name)}`).get();
|
|
92922
|
+
return normalizeSchemaSql(row?.sql);
|
|
92923
|
+
}
|
|
92806
92924
|
function readEntrySchemaFingerprint(db) {
|
|
92807
|
-
const tableRow = db.prepare("SELECT sql FROM sqlite_master WHERE type = 'table' AND name = 'entries'").get();
|
|
92808
92925
|
const sqliteSequenceTable = db.prepare("SELECT 1 AS present FROM sqlite_master WHERE type = 'table' AND name = 'sqlite_sequence'").get() != null;
|
|
92809
92926
|
const maxId = Number(db.prepare("SELECT COALESCE(MAX(id), 0) AS maxId FROM entries").get().maxId);
|
|
92810
92927
|
const sequenceRow = sqliteSequenceTable ? db.prepare("SELECT seq FROM sqlite_sequence WHERE name = 'entries'").get() : undefined;
|
|
@@ -92833,11 +92950,16 @@ function readEntrySchemaFingerprint(db) {
|
|
|
92833
92950
|
}))
|
|
92834
92951
|
})).sort((left, right) => left.name.localeCompare(right.name));
|
|
92835
92952
|
return {
|
|
92836
|
-
tableSql:
|
|
92953
|
+
tableSql: readNamedTableSql(db, "entries"),
|
|
92837
92954
|
sqliteSequenceTable,
|
|
92838
92955
|
sqliteSequenceValid,
|
|
92839
92956
|
columns,
|
|
92840
|
-
indexes
|
|
92957
|
+
indexes,
|
|
92958
|
+
searchSurfaces: {
|
|
92959
|
+
entriesFtsSql: readNamedTableSql(db, "entries_fts"),
|
|
92960
|
+
fragmentSourceSql: readNamedTableSql(db, "entry_fragments"),
|
|
92961
|
+
fragmentsFtsSql: readNamedTableSql(db, "entry_fragments_fts")
|
|
92962
|
+
}
|
|
92841
92963
|
};
|
|
92842
92964
|
}
|
|
92843
92965
|
function hasCanonicalEntrySchema(db) {
|
|
@@ -93040,20 +93162,30 @@ function openExistingDatabase(dbPath) {
|
|
|
93040
93162
|
if (classifyPathAccess(resolvedPath).access === "absent") {
|
|
93041
93163
|
throw new Error(`Index database not found at ${resolvedPath}. Run 'akm index' to build it.`);
|
|
93042
93164
|
}
|
|
93043
|
-
|
|
93165
|
+
const db = openManagedDatabase({
|
|
93044
93166
|
path: resolvedPath,
|
|
93045
|
-
init: (
|
|
93046
|
-
loadVecExtension(
|
|
93047
|
-
warnIfNonCanonicalIndexGeneration(db, resolvedPath);
|
|
93167
|
+
init: (db2) => {
|
|
93168
|
+
loadVecExtension(db2);
|
|
93048
93169
|
},
|
|
93049
93170
|
create: false
|
|
93050
93171
|
});
|
|
93172
|
+
try {
|
|
93173
|
+
assertCanonicalIndexGeneration(db, resolvedPath);
|
|
93174
|
+
return db;
|
|
93175
|
+
} catch (error2) {
|
|
93176
|
+
db.close();
|
|
93177
|
+
throw error2;
|
|
93178
|
+
}
|
|
93051
93179
|
}
|
|
93052
|
-
function
|
|
93180
|
+
function assertCanonicalIndexGeneration(db, resolvedPath) {
|
|
93053
93181
|
if (isCanonicalIndexGeneration(db))
|
|
93054
93182
|
return;
|
|
93055
93183
|
const classification = classifyIndexGeneration(db);
|
|
93056
|
-
|
|
93184
|
+
const stored = classification.storedVersion ?? "unknown";
|
|
93185
|
+
if (classification.status === "newer") {
|
|
93186
|
+
throw new ConfigError(`Index database at ${resolvedPath} was built by a newer akm (stored generation ${stored}; ` + `this binary understands ${CANONICAL_INDEX_DB_VERSION}). Upgrade akm to use this index.`, "INDEX_SCHEMA_INCOMPATIBLE", "Upgrade akm to a version that understands this index generation.");
|
|
93187
|
+
}
|
|
93188
|
+
throw new ConfigError(`Index database at ${resolvedPath} is not usable with this akm's derived schema (stored generation ${stored}; ` + `this binary understands ${CANONICAL_INDEX_DB_VERSION}). Run 'akm index' to rebuild it.`, "INDEX_SCHEMA_INCOMPATIBLE", "Run `akm index` to rebuild the derived index from the currently materialized sources.");
|
|
93057
93189
|
}
|
|
93058
93190
|
function assertIndexPathReadable(resolvedPath) {
|
|
93059
93191
|
const { access, code } = classifyPathAccess(resolvedPath);
|
|
@@ -93070,6 +93202,7 @@ import fs40 from "fs";
|
|
|
93070
93202
|
init_asset_ref();
|
|
93071
93203
|
init_resolve_ref();
|
|
93072
93204
|
init_warn();
|
|
93205
|
+
init_metadata();
|
|
93073
93206
|
|
|
93074
93207
|
// src/indexer/search/search-fields.ts
|
|
93075
93208
|
function buildSearchFields(entry) {
|
|
@@ -93133,9 +93266,129 @@ function buildSearchText(entry) {
|
|
|
93133
93266
|
// src/storage/repositories/index-entry-mapper.ts
|
|
93134
93267
|
init_warn();
|
|
93135
93268
|
|
|
93269
|
+
// src/core/asset/markdown-fragments.ts
|
|
93270
|
+
init_markdown();
|
|
93271
|
+
import { createHash as createHash9 } from "crypto";
|
|
93272
|
+
var MARKDOWN_FRAGMENT_MAX_CHARS = 1600;
|
|
93273
|
+
var MARKDOWN_FRAGMENT_PREFIX = "akm-fragment-";
|
|
93274
|
+
function hash3(text) {
|
|
93275
|
+
return createHash9("sha256").update(text).digest("hex");
|
|
93276
|
+
}
|
|
93277
|
+
function uniqueSlugs(body) {
|
|
93278
|
+
const out = new Map;
|
|
93279
|
+
const seen = new Set;
|
|
93280
|
+
for (const heading of parseMarkdownToc(body).headings) {
|
|
93281
|
+
const base3 = markdownHeadingSlug(heading.text);
|
|
93282
|
+
if (!base3)
|
|
93283
|
+
continue;
|
|
93284
|
+
let slug = base3;
|
|
93285
|
+
for (let suffix = 1;seen.has(slug); suffix++)
|
|
93286
|
+
slug = `${base3}-${suffix}`;
|
|
93287
|
+
seen.add(slug);
|
|
93288
|
+
out.set(heading.line, slug);
|
|
93289
|
+
}
|
|
93290
|
+
return out;
|
|
93291
|
+
}
|
|
93292
|
+
function textOf(lines) {
|
|
93293
|
+
return lines.join(`
|
|
93294
|
+
`).trim();
|
|
93295
|
+
}
|
|
93296
|
+
function splitPiece(piece, maxChars) {
|
|
93297
|
+
if (textOf(piece.lines).length <= maxChars)
|
|
93298
|
+
return [piece];
|
|
93299
|
+
const pieces = [];
|
|
93300
|
+
let start = 0;
|
|
93301
|
+
while (start < piece.lines.length) {
|
|
93302
|
+
let end = start;
|
|
93303
|
+
let chars = 0;
|
|
93304
|
+
while (end < piece.lines.length) {
|
|
93305
|
+
const next2 = piece.lines[end];
|
|
93306
|
+
if (end === start && next2.length > maxChars)
|
|
93307
|
+
break;
|
|
93308
|
+
if (end > start && chars + next2.length + 1 > maxChars)
|
|
93309
|
+
break;
|
|
93310
|
+
chars += next2.length + (end > start ? 1 : 0);
|
|
93311
|
+
end++;
|
|
93312
|
+
}
|
|
93313
|
+
if (end === start) {
|
|
93314
|
+
const line = piece.lines[start];
|
|
93315
|
+
let offset = 0;
|
|
93316
|
+
while (offset < line.length) {
|
|
93317
|
+
let cut = Math.min(offset + maxChars, line.length);
|
|
93318
|
+
if (cut < line.length) {
|
|
93319
|
+
const space = line.lastIndexOf(" ", cut);
|
|
93320
|
+
if (space > offset + Math.floor(maxChars * 0.55))
|
|
93321
|
+
cut = space;
|
|
93322
|
+
}
|
|
93323
|
+
pieces.push({ lines: [line.slice(offset, cut).trim()], startLine: piece.startLine + start });
|
|
93324
|
+
offset = cut;
|
|
93325
|
+
while (line[offset] === " ")
|
|
93326
|
+
offset++;
|
|
93327
|
+
}
|
|
93328
|
+
start++;
|
|
93329
|
+
continue;
|
|
93330
|
+
}
|
|
93331
|
+
let preferred = -1;
|
|
93332
|
+
for (let i = start + 1;i < end; i++)
|
|
93333
|
+
if (!piece.lines[i].trim())
|
|
93334
|
+
preferred = i;
|
|
93335
|
+
if (preferred > start)
|
|
93336
|
+
end = preferred;
|
|
93337
|
+
pieces.push({ lines: piece.lines.slice(start, end), startLine: piece.startLine + start });
|
|
93338
|
+
start = end;
|
|
93339
|
+
while (start < piece.lines.length && !piece.lines[start].trim())
|
|
93340
|
+
start++;
|
|
93341
|
+
}
|
|
93342
|
+
return pieces.filter((candidate) => textOf(candidate.lines));
|
|
93343
|
+
}
|
|
93344
|
+
function splitMarkdownFragmentStats(body, maxChars = MARKDOWN_FRAGMENT_MAX_CHARS) {
|
|
93345
|
+
const lines = body.split(/\r?\n/);
|
|
93346
|
+
const headings = parseMarkdownToc(body).headings;
|
|
93347
|
+
const boundaries = [1, ...headings.map((heading) => heading.line), lines.length + 1].filter((line, index, all) => index === 0 || line !== all[index - 1]).sort((left, right) => left - right);
|
|
93348
|
+
const slugs = uniqueSlugs(body);
|
|
93349
|
+
const pieces = [];
|
|
93350
|
+
let sectionCount = 0;
|
|
93351
|
+
for (let i = 0;i < boundaries.length - 1; i++) {
|
|
93352
|
+
const startLine = boundaries[i];
|
|
93353
|
+
const end = boundaries[i + 1] - 1;
|
|
93354
|
+
const section = { lines: lines.slice(startLine - 1, end), startLine, headingSlug: slugs.get(startLine) };
|
|
93355
|
+
if (textOf(section.lines)) {
|
|
93356
|
+
sectionCount++;
|
|
93357
|
+
pieces.push(...splitPiece(section, maxChars));
|
|
93358
|
+
}
|
|
93359
|
+
}
|
|
93360
|
+
const piecesPerHeading = new Map;
|
|
93361
|
+
for (const piece of pieces) {
|
|
93362
|
+
if (piece.headingSlug)
|
|
93363
|
+
piecesPerHeading.set(piece.headingSlug, (piecesPerHeading.get(piece.headingSlug) ?? 0) + 1);
|
|
93364
|
+
}
|
|
93365
|
+
const fragments = pieces.map((piece, ordinal) => {
|
|
93366
|
+
const text = textOf(piece.lines);
|
|
93367
|
+
const contentLines = piece.lines.map((line, index) => ({ line, index })).filter(({ line }) => line.trim());
|
|
93368
|
+
const first = contentLines[0]?.index ?? 0;
|
|
93369
|
+
const last = contentLines.at(-1)?.index ?? 0;
|
|
93370
|
+
const digest = hash3(text);
|
|
93371
|
+
const unsplitHeading = piece.headingSlug && piecesPerHeading.get(piece.headingSlug) === 1;
|
|
93372
|
+
return {
|
|
93373
|
+
fragmentId: `${MARKDOWN_FRAGMENT_PREFIX}${ordinal + 1}-${digest.slice(0, 12)}`,
|
|
93374
|
+
ordinal,
|
|
93375
|
+
startLine: piece.startLine + first,
|
|
93376
|
+
endLine: piece.startLine + last,
|
|
93377
|
+
...unsplitHeading ? { headingSlug: piece.headingSlug } : {},
|
|
93378
|
+
text,
|
|
93379
|
+
hash: digest
|
|
93380
|
+
};
|
|
93381
|
+
});
|
|
93382
|
+
return { fragments, hardSplitCount: Math.max(0, pieces.length - sectionCount) };
|
|
93383
|
+
}
|
|
93384
|
+
function splitMarkdownFragments(body, maxChars = MARKDOWN_FRAGMENT_MAX_CHARS) {
|
|
93385
|
+
return splitMarkdownFragmentStats(body, maxChars).fragments;
|
|
93386
|
+
}
|
|
93387
|
+
|
|
93136
93388
|
// src/storage/repositories/index-fts-repository.ts
|
|
93137
93389
|
init_warn();
|
|
93138
93390
|
var INSERT_FTS_SQL = "INSERT INTO entries_fts (entry_id, name, description, tags, hints, content) VALUES (?, ?, ?, ?, ?, ?)";
|
|
93391
|
+
var INSERT_FRAGMENT_SQL = "INSERT INTO entry_fragments_fts (entry_id, fragment_id, fragment_ordinal, content) VALUES (?, ?, ?, ?)";
|
|
93139
93392
|
var ftsMutationStatementsByDb = new WeakMap;
|
|
93140
93393
|
function getFtsMutationStatements(db) {
|
|
93141
93394
|
const existing = ftsMutationStatementsByDb.get(db);
|
|
@@ -93143,22 +93396,39 @@ function getFtsMutationStatements(db) {
|
|
|
93143
93396
|
return existing;
|
|
93144
93397
|
const statements = {
|
|
93145
93398
|
deleteOne: db.prepare("DELETE FROM entries_fts WHERE entry_id = ?"),
|
|
93146
|
-
insert: db.prepare(INSERT_FTS_SQL)
|
|
93399
|
+
insert: db.prepare(INSERT_FTS_SQL),
|
|
93400
|
+
deleteFragments: db.prepare("DELETE FROM entry_fragments_fts WHERE entry_id = ?"),
|
|
93401
|
+
upsertFragmentSource: db.prepare("INSERT INTO entry_fragments (entry_id, safe_markdown) VALUES (?, ?) ON CONFLICT(entry_id) DO UPDATE SET safe_markdown = excluded.safe_markdown"),
|
|
93402
|
+
deleteFragmentSource: db.prepare("DELETE FROM entry_fragments WHERE entry_id = ?"),
|
|
93403
|
+
insertFragment: db.prepare(INSERT_FRAGMENT_SQL)
|
|
93147
93404
|
};
|
|
93148
93405
|
ftsMutationStatementsByDb.set(db, statements);
|
|
93149
93406
|
return statements;
|
|
93150
93407
|
}
|
|
93151
|
-
function replaceFtsEntry(db, entryId, entry) {
|
|
93408
|
+
function replaceFtsEntry(db, entryId, entry, fragmentContent) {
|
|
93152
93409
|
const fields = buildSearchFields(entry);
|
|
93153
93410
|
const statements = getFtsMutationStatements(db);
|
|
93154
93411
|
statements.deleteOne.run(entryId);
|
|
93155
93412
|
statements.insert.run(entryId, fields.name, fields.description, fields.tags, fields.hints, fields.content);
|
|
93413
|
+
if (fragmentContent === undefined) {
|
|
93414
|
+
return;
|
|
93415
|
+
}
|
|
93416
|
+
statements.deleteFragments.run(entryId);
|
|
93417
|
+
statements.deleteFragmentSource.run(entryId);
|
|
93418
|
+
if (!fragmentContent)
|
|
93419
|
+
return;
|
|
93420
|
+
statements.upsertFragmentSource.run(entryId, fragmentContent);
|
|
93421
|
+
for (const fragment of splitMarkdownFragments(fragmentContent)) {
|
|
93422
|
+
statements.insertFragment.run(entryId, fragment.fragmentId, fragment.ordinal, fragment.text.toLowerCase());
|
|
93423
|
+
}
|
|
93156
93424
|
}
|
|
93157
93425
|
function deleteFtsEntries(db, entryIds) {
|
|
93158
93426
|
for (let i = 0;i < entryIds.length; i += SQLITE_CHUNK_SIZE) {
|
|
93159
93427
|
const chunk = entryIds.slice(i, i + SQLITE_CHUNK_SIZE);
|
|
93160
93428
|
const placeholders = chunk.map(() => "?").join(",");
|
|
93161
93429
|
db.prepare(`DELETE FROM entries_fts WHERE entry_id IN (${placeholders})`).run(...chunk);
|
|
93430
|
+
db.prepare(`DELETE FROM entry_fragments_fts WHERE entry_id IN (${placeholders})`).run(...chunk);
|
|
93431
|
+
db.prepare(`DELETE FROM entry_fragments WHERE entry_id IN (${placeholders})`).run(...chunk);
|
|
93162
93432
|
}
|
|
93163
93433
|
}
|
|
93164
93434
|
|
|
@@ -93173,7 +93443,7 @@ function upsertEntry(db, filePath, entry, searchText, provenance, contentHash) {
|
|
|
93173
93443
|
throw new Error("upsertEntry: item_ref not found after upsert");
|
|
93174
93444
|
if (previous?.id === result.id && previous.search_text !== searchText)
|
|
93175
93445
|
deleteEntryVectors(db, result.id);
|
|
93176
|
-
replaceFtsEntry(db, result.id, entry);
|
|
93446
|
+
replaceFtsEntry(db, result.id, entry, hasMarkdownFragmentContent(entry) ? getMarkdownFragmentContent(entry) ?? null : undefined);
|
|
93177
93447
|
return result.id;
|
|
93178
93448
|
};
|
|
93179
93449
|
return db.transaction(apply)();
|
|
@@ -93669,6 +93939,127 @@ function redactSensitiveText(text, sensitiveValues) {
|
|
|
93669
93939
|
|
|
93670
93940
|
// src/llm/embedders/remote.ts
|
|
93671
93941
|
init_warn();
|
|
93942
|
+
|
|
93943
|
+
// src/sources/snapshot-fetchers/secret-seam.ts
|
|
93944
|
+
import fs45 from "fs";
|
|
93945
|
+
|
|
93946
|
+
// src/core/env-secret-ref.ts
|
|
93947
|
+
import fs43 from "fs";
|
|
93948
|
+
import path54 from "path";
|
|
93949
|
+
|
|
93950
|
+
// src/registry/origin-resolve.ts
|
|
93951
|
+
init_asset_ref();
|
|
93952
|
+
function resolveSourcesForOrigin(origin, allSources) {
|
|
93953
|
+
if (!origin)
|
|
93954
|
+
return allSources;
|
|
93955
|
+
const installations = deriveInstallations(allSources);
|
|
93956
|
+
return allSources.filter((_, index) => installations[index]?.id === origin);
|
|
93957
|
+
}
|
|
93958
|
+
|
|
93959
|
+
// src/core/asset/asset-create.ts
|
|
93960
|
+
init_errors();
|
|
93961
|
+
function normalizeCreateSubPath(subPath) {
|
|
93962
|
+
if (subPath === undefined)
|
|
93963
|
+
return "";
|
|
93964
|
+
const trimmed = subPath.trim().replace(/\\/g, "/").replace(/^\/+|\/+$/g, "");
|
|
93965
|
+
if (!trimmed)
|
|
93966
|
+
return "";
|
|
93967
|
+
if (trimmed.split("/").some((segment) => !segment || segment === "." || segment === "..")) {
|
|
93968
|
+
throw new UsageError("--path must be a relative directory without '.' or '..' segments.");
|
|
93969
|
+
}
|
|
93970
|
+
return trimmed;
|
|
93971
|
+
}
|
|
93972
|
+
function assertFlatAssetName(name) {
|
|
93973
|
+
if (name?.replace(/\\/g, "/").replace(/\.md$/i, "").includes("/")) {
|
|
93974
|
+
throw new UsageError("Asset --name must be a flat name without '/'. Use --path to choose a subdirectory " + "(e.g. --path personal --name grocery-list).");
|
|
93975
|
+
}
|
|
93976
|
+
}
|
|
93977
|
+
function combineCreatePath(subPath, baseName) {
|
|
93978
|
+
return subPath ? `${subPath}/${baseName}` : baseName;
|
|
93979
|
+
}
|
|
93980
|
+
|
|
93981
|
+
// src/core/env-secret-ref.ts
|
|
93982
|
+
init_asset_placement();
|
|
93983
|
+
init_resolve_ref();
|
|
93984
|
+
init_common();
|
|
93985
|
+
init_errors();
|
|
93986
|
+
function assertNotRemovedVaultRef(ref) {
|
|
93987
|
+
const boundary = ref.indexOf("//");
|
|
93988
|
+
const bare = boundary >= 0 ? ref.slice(boundary + 2) : ref;
|
|
93989
|
+
if (/^vault[:/]/.test(bare.trim())) {
|
|
93990
|
+
throw new UsageError("The `vault` asset type was removed in 0.9.0 \u2014 use `env/` (whole .env config) or `secrets/` (a single value).", "INVALID_FLAG_VALUE");
|
|
93991
|
+
}
|
|
93992
|
+
}
|
|
93993
|
+
function assertNotColonRef(ref, aliases, replacement) {
|
|
93994
|
+
const boundary = ref.indexOf("//");
|
|
93995
|
+
const bare = (boundary >= 0 ? ref.slice(boundary + 2) : ref).trim();
|
|
93996
|
+
const colon = bare.indexOf(":");
|
|
93997
|
+
if (colon <= 0)
|
|
93998
|
+
return;
|
|
93999
|
+
const head = bare.slice(0, colon).toLowerCase();
|
|
94000
|
+
if (!aliases.includes(head))
|
|
94001
|
+
return;
|
|
94002
|
+
const name = bare.slice(colon + 1);
|
|
94003
|
+
throw new UsageError(`The \`${head}:\` ref spelling was removed in 0.9.0 \u2014 use the slash form instead: \`${replacement}${name}\`.`, "INVALID_FLAG_VALUE");
|
|
94004
|
+
}
|
|
94005
|
+
function findEnvSource(origin, type, name) {
|
|
94006
|
+
const sources = resolveSourceEntries(undefined, loadConfig());
|
|
94007
|
+
if (sources.length === 0) {
|
|
94008
|
+
throw new UsageError("No bundles configured. Run `akm bundle create` to create your working bundle.");
|
|
94009
|
+
}
|
|
94010
|
+
const candidates = origin ? resolveSourcesForOrigin(origin, sources) : sources;
|
|
94011
|
+
const typeDir = type === "env" ? "env" : "secrets";
|
|
94012
|
+
const member = candidates.find((source) => fs43.existsSync(assetPathForName(type, path54.join(source.path, typeDir), name)));
|
|
94013
|
+
if (member)
|
|
94014
|
+
return member;
|
|
94015
|
+
if (!origin) {
|
|
94016
|
+
const fallback = candidates[0];
|
|
94017
|
+
if (fallback)
|
|
94018
|
+
return fallback;
|
|
94019
|
+
throw new UsageError("No bundles configured. Run `akm bundle create` to create your working bundle.");
|
|
94020
|
+
}
|
|
94021
|
+
const named = candidates[0];
|
|
94022
|
+
if (!named) {
|
|
94023
|
+
throw new NotFoundError(`Source not found for origin: ${origin}`);
|
|
94024
|
+
}
|
|
94025
|
+
return named;
|
|
94026
|
+
}
|
|
94027
|
+
function parseSecretRef(ref) {
|
|
94028
|
+
assertNotRemovedVaultRef(ref);
|
|
94029
|
+
assertNotColonRef(ref, ["secret", "secrets"], "secrets/");
|
|
94030
|
+
return parseRefInput(isFullRefInput(ref) ? ref : `secrets/${ref}`);
|
|
94031
|
+
}
|
|
94032
|
+
function resolveSecretPath(ref, create) {
|
|
94033
|
+
const parsed = parseSecretRef(ref);
|
|
94034
|
+
if (parsed.type !== "secret") {
|
|
94035
|
+
throw new UsageError(`Expected a secret ref (secrets/<name>); got "${ref}".`);
|
|
94036
|
+
}
|
|
94037
|
+
if (create) {
|
|
94038
|
+
assertFlatAssetName(parsed.name);
|
|
94039
|
+
parsed.name = combineCreatePath(normalizeCreateSubPath(create.subPath), parsed.name);
|
|
94040
|
+
}
|
|
94041
|
+
const source = findEnvSource(parsed.origin, "secret", parsed.name);
|
|
94042
|
+
const typeRoot = path54.join(source.path, "secrets");
|
|
94043
|
+
const absPath = assetPathForName("secret", typeRoot, parsed.name);
|
|
94044
|
+
if (!isWithin(absPath, typeRoot)) {
|
|
94045
|
+
throw new UsageError(`Secret name "${parsed.name}" escapes the secrets directory.`);
|
|
94046
|
+
}
|
|
94047
|
+
return { name: parsed.name, absPath, source };
|
|
94048
|
+
}
|
|
94049
|
+
|
|
94050
|
+
// src/sources/snapshot-fetchers/secret-seam.ts
|
|
94051
|
+
function resolveSecretFromStore(ref) {
|
|
94052
|
+
try {
|
|
94053
|
+
const { absPath } = resolveSecretPath(ref);
|
|
94054
|
+
if (!fs45.existsSync(absPath))
|
|
94055
|
+
return null;
|
|
94056
|
+
return fs45.readFileSync(absPath, "utf8").trim() || null;
|
|
94057
|
+
} catch {
|
|
94058
|
+
return null;
|
|
94059
|
+
}
|
|
94060
|
+
}
|
|
94061
|
+
|
|
94062
|
+
// src/llm/embedders/remote.ts
|
|
93672
94063
|
var DEFAULT_REMOTE_BATCH_SIZE = 100;
|
|
93673
94064
|
var DEFAULT_TOKEN_BUDGET = 8000;
|
|
93674
94065
|
function estimateTokenCount(text) {
|
|
@@ -93824,14 +94215,14 @@ class RemoteEmbedder {
|
|
|
93824
94215
|
}
|
|
93825
94216
|
buildHeaders() {
|
|
93826
94217
|
const headers = { "Content-Type": "application/json" };
|
|
93827
|
-
const resolvedKey = resolveSecret(this.config.apiKey);
|
|
94218
|
+
const resolvedKey = resolveSecret(this.config.apiKey, resolveSecretFromStore);
|
|
93828
94219
|
if (resolvedKey) {
|
|
93829
94220
|
headers.Authorization = `Bearer ${resolvedKey}`;
|
|
93830
94221
|
}
|
|
93831
94222
|
return headers;
|
|
93832
94223
|
}
|
|
93833
94224
|
safeErrorBody(body) {
|
|
93834
|
-
const resolvedKey = resolveSecret(this.config.apiKey);
|
|
94225
|
+
const resolvedKey = resolveSecret(this.config.apiKey, resolveSecretFromStore);
|
|
93835
94226
|
return redactSensitiveText(redactErrorBody(body), resolvedKey ? [resolvedKey] : []);
|
|
93836
94227
|
}
|
|
93837
94228
|
}
|
|
@@ -94066,8 +94457,11 @@ function publishTargetedEmbeddingMeta(db, config) {
|
|
|
94066
94457
|
setMeta(db, "hasEmbeddings", ready ? "1" : "0");
|
|
94067
94458
|
}
|
|
94068
94459
|
|
|
94460
|
+
// src/indexer/index-written-assets.ts
|
|
94461
|
+
init_metadata();
|
|
94462
|
+
|
|
94069
94463
|
// src/indexer/scan/drain-dir.ts
|
|
94070
|
-
import
|
|
94464
|
+
import path58 from "path";
|
|
94071
94465
|
init_common();
|
|
94072
94466
|
init_recognition_util();
|
|
94073
94467
|
|
|
@@ -94076,8 +94470,8 @@ init_common();
|
|
|
94076
94470
|
init_errors();
|
|
94077
94471
|
init_recognition_util();
|
|
94078
94472
|
init_warn();
|
|
94079
|
-
import
|
|
94080
|
-
import
|
|
94473
|
+
import fs46 from "fs";
|
|
94474
|
+
import path55 from "path";
|
|
94081
94475
|
|
|
94082
94476
|
class WorkflowSourceRejectionError extends UsageError {
|
|
94083
94477
|
sourcePaths;
|
|
@@ -94117,63 +94511,67 @@ class WorkflowSourcePathIdentityError extends WorkflowSourceRejectionError {
|
|
|
94117
94511
|
function workflowNameForSourcePath(sourceRoot, adapterId, sourcePath) {
|
|
94118
94512
|
if (adapterId !== "akm" && adapterId !== "akm-workflow")
|
|
94119
94513
|
return;
|
|
94120
|
-
const relativePath = toPosix(
|
|
94514
|
+
const relativePath = toPosix(path55.relative(path55.resolve(sourceRoot), path55.resolve(sourcePath)));
|
|
94121
94515
|
if (!isSafeRelativeName(relativePath))
|
|
94122
94516
|
return;
|
|
94123
94517
|
const ownedPath = adapterId === "akm" ? relativePath.replace(/^workflows\//, "") : relativePath;
|
|
94124
94518
|
if (adapterId === "akm" && ownedPath === relativePath)
|
|
94125
94519
|
return;
|
|
94126
|
-
const extension =
|
|
94520
|
+
const extension = path55.posix.extname(ownedPath);
|
|
94127
94521
|
if (!WORKFLOW_EXTENSIONS.includes(extension.toLowerCase()))
|
|
94128
94522
|
return;
|
|
94129
94523
|
return ownedPath;
|
|
94130
94524
|
}
|
|
94131
|
-
function
|
|
94525
|
+
function resolveWorkflowSourceDomains(sourceRoot, adapterId, sourcePaths) {
|
|
94132
94526
|
if (adapterId !== "akm" && adapterId !== "akm-workflow")
|
|
94133
94527
|
return [];
|
|
94134
|
-
const
|
|
94135
|
-
if (!isSafeRelativeName(canonicalName)) {
|
|
94136
|
-
throw new UsageError("Workflow ref resolves outside the bundle root.", "PATH_ESCAPE_VIOLATION");
|
|
94137
|
-
}
|
|
94528
|
+
const authoredRoot = path55.resolve(sourceRoot);
|
|
94138
94529
|
let realRoot;
|
|
94139
|
-
const authoredRoot = path54.resolve(sourceRoot);
|
|
94140
94530
|
try {
|
|
94141
|
-
realRoot =
|
|
94531
|
+
realRoot = fs46.realpathSync(authoredRoot);
|
|
94142
94532
|
} catch {
|
|
94143
94533
|
return [];
|
|
94144
94534
|
}
|
|
94145
|
-
const
|
|
94146
|
-
const
|
|
94147
|
-
|
|
94148
|
-
|
|
94149
|
-
|
|
94150
|
-
let entries;
|
|
94151
|
-
try {
|
|
94152
|
-
entries = fs43.readdirSync(parent, { withFileTypes: true });
|
|
94153
|
-
} catch {
|
|
94154
|
-
return [];
|
|
94155
|
-
}
|
|
94156
|
-
const basename = path54.basename(canonicalName);
|
|
94157
|
-
const candidates = [];
|
|
94158
|
-
for (const entry of entries) {
|
|
94159
|
-
if (!entry.isFile() && !entry.isSymbolicLink())
|
|
94535
|
+
const candidatesByName = new Map;
|
|
94536
|
+
const seenAuthoredPaths = new Set;
|
|
94537
|
+
for (const sourcePath of sourcePaths) {
|
|
94538
|
+
const normalizedSourcePath = path55.resolve(sourcePath);
|
|
94539
|
+
if (seenAuthoredPaths.has(normalizedSourcePath))
|
|
94160
94540
|
continue;
|
|
94161
|
-
|
|
94541
|
+
seenAuthoredPaths.add(normalizedSourcePath);
|
|
94542
|
+
const authoredName = workflowNameForSourcePath(authoredRoot, adapterId, normalizedSourcePath);
|
|
94543
|
+
if (authoredName === undefined)
|
|
94544
|
+
continue;
|
|
94545
|
+
const canonicalName = canonicalizeWorkflowName(authoredName);
|
|
94546
|
+
if (!isSafeRelativeName(canonicalName))
|
|
94547
|
+
continue;
|
|
94548
|
+
const extension = path55.extname(normalizedSourcePath);
|
|
94162
94549
|
const lowerExtension = extension.toLowerCase();
|
|
94163
94550
|
if (!WORKFLOW_EXTENSIONS.includes(lowerExtension))
|
|
94164
94551
|
continue;
|
|
94165
|
-
|
|
94166
|
-
|
|
94167
|
-
|
|
94168
|
-
candidates.push({
|
|
94169
|
-
path: candidatePath,
|
|
94170
|
-
relativePath: toPosix(path54.relative(authoredRoot, candidatePath)),
|
|
94552
|
+
const candidate = {
|
|
94553
|
+
path: normalizedSourcePath,
|
|
94554
|
+
relativePath: toPosix(path55.relative(authoredRoot, normalizedSourcePath)),
|
|
94171
94555
|
lowerExtension,
|
|
94172
|
-
extensionlessStem:
|
|
94556
|
+
extensionlessStem: path55.basename(normalizedSourcePath).slice(0, -extension.length)
|
|
94557
|
+
};
|
|
94558
|
+
const domain = candidatesByName.get(canonicalName) ?? [];
|
|
94559
|
+
domain.push(candidate);
|
|
94560
|
+
candidatesByName.set(canonicalName, domain);
|
|
94561
|
+
}
|
|
94562
|
+
const resolutions = [];
|
|
94563
|
+
for (const canonicalName of [...candidatesByName.keys()].sort(compareCodePoints)) {
|
|
94564
|
+
const candidates = candidatesByName.get(canonicalName) ?? [];
|
|
94565
|
+
candidates.sort((left, right) => compareCodePoints(left.relativePath, right.relativePath));
|
|
94566
|
+
const sources = inspectWorkflowSourceDomain(candidates, canonicalName, realRoot);
|
|
94567
|
+
const sourcePaths2 = candidates.map((candidate) => candidate.relativePath);
|
|
94568
|
+
resolutions.push({
|
|
94569
|
+
canonicalName,
|
|
94570
|
+
sourcePaths: sourcePaths2,
|
|
94571
|
+
source: pickWorkflowSource(adapterId, canonicalName, sources)
|
|
94173
94572
|
});
|
|
94174
94573
|
}
|
|
94175
|
-
|
|
94176
|
-
return inspectWorkflowSourceDomain(candidates, canonicalName, realRoot);
|
|
94574
|
+
return resolutions;
|
|
94177
94575
|
}
|
|
94178
94576
|
function inspectWorkflowSourceDomain(candidates, canonicalName, realRoot) {
|
|
94179
94577
|
const sources = [];
|
|
@@ -94202,7 +94600,7 @@ function inspectWorkflowSourceCandidate(candidate, canonicalName, realRoot) {
|
|
|
94202
94600
|
const issues = [];
|
|
94203
94601
|
let authoredStat;
|
|
94204
94602
|
try {
|
|
94205
|
-
authoredStat =
|
|
94603
|
+
authoredStat = fs46.lstatSync(candidate.path);
|
|
94206
94604
|
} catch {
|
|
94207
94605
|
issues.push(new WorkflowSourceLinkResolutionError(candidate.relativePath));
|
|
94208
94606
|
return { issues };
|
|
@@ -94214,21 +94612,21 @@ function inspectWorkflowSourceCandidate(candidate, canonicalName, realRoot) {
|
|
|
94214
94612
|
}
|
|
94215
94613
|
let realPath;
|
|
94216
94614
|
try {
|
|
94217
|
-
realPath =
|
|
94615
|
+
realPath = fs46.realpathSync(candidate.path);
|
|
94218
94616
|
} catch {
|
|
94219
94617
|
issues.push(new WorkflowSourceLinkResolutionError(candidate.relativePath));
|
|
94220
94618
|
return { issues };
|
|
94221
94619
|
}
|
|
94222
|
-
const targetPath = toPosix(
|
|
94620
|
+
const targetPath = toPosix(path55.relative(realRoot, realPath));
|
|
94223
94621
|
const contained2 = isWithinResolved(realPath, realRoot);
|
|
94224
94622
|
if (!contained2)
|
|
94225
94623
|
issues.push(new WorkflowSourcePathIdentityError(candidate.relativePath, targetPath));
|
|
94226
|
-
if (isLink &&
|
|
94624
|
+
if (isLink && path55.extname(realPath).toLowerCase() !== candidate.lowerExtension) {
|
|
94227
94625
|
issues.push(new WorkflowSourceLinkIdentityError(candidate.relativePath, targetPath));
|
|
94228
94626
|
}
|
|
94229
94627
|
if (contained2) {
|
|
94230
94628
|
try {
|
|
94231
|
-
if (!
|
|
94629
|
+
if (!fs46.statSync(realPath).isFile())
|
|
94232
94630
|
issues.push(new WorkflowSourceLinkResolutionError(candidate.relativePath));
|
|
94233
94631
|
} catch {
|
|
94234
94632
|
issues.push(new WorkflowSourceLinkResolutionError(candidate.relativePath));
|
|
@@ -94247,20 +94645,12 @@ function inspectWorkflowSourceCandidate(candidate, canonicalName, realRoot) {
|
|
|
94247
94645
|
}
|
|
94248
94646
|
};
|
|
94249
94647
|
}
|
|
94250
|
-
function resolveUniqueWorkflowSource(sourceRoot, adapterId, name) {
|
|
94251
|
-
const sources = listWorkflowSourceFiles(sourceRoot, adapterId, name);
|
|
94252
|
-
const canonicalName = sources[0]?.canonicalName ?? canonicalizeWorkflowName(normalizeName2(name));
|
|
94253
|
-
return pickWorkflowSource(adapterId, canonicalName, sources);
|
|
94254
|
-
}
|
|
94255
|
-
function normalizeName2(name) {
|
|
94256
|
-
return name.replaceAll("\\", "/");
|
|
94257
|
-
}
|
|
94258
94648
|
function isSafeRelativeName(name) {
|
|
94259
|
-
return name.length > 0 && !
|
|
94649
|
+
return name.length > 0 && !path55.posix.isAbsolute(name) && name !== ".." && !name.startsWith("../") && path55.posix.normalize(name) === name;
|
|
94260
94650
|
}
|
|
94261
94651
|
function isWithinResolved(candidate, root2) {
|
|
94262
|
-
const relative =
|
|
94263
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
94652
|
+
const relative = path55.relative(root2, path55.resolve(candidate));
|
|
94653
|
+
return relative === "" || !relative.startsWith("..") && !path55.isAbsolute(relative);
|
|
94264
94654
|
}
|
|
94265
94655
|
|
|
94266
94656
|
// src/indexer/scan/drain-dir.ts
|
|
@@ -94269,13 +94659,14 @@ init_metadata();
|
|
|
94269
94659
|
init_file_context();
|
|
94270
94660
|
|
|
94271
94661
|
// src/indexer/scan/doc-to-entry.ts
|
|
94272
|
-
|
|
94662
|
+
init_metadata();
|
|
94663
|
+
import path57 from "path";
|
|
94273
94664
|
function indexDocumentToStashEntry(doc) {
|
|
94274
94665
|
const dj = doc.documentJson ?? {};
|
|
94275
94666
|
const entry = {
|
|
94276
94667
|
name: doc.name,
|
|
94277
94668
|
type: doc.type,
|
|
94278
|
-
filename:
|
|
94669
|
+
filename: path57.basename(doc.path ?? "")
|
|
94279
94670
|
};
|
|
94280
94671
|
if (doc.description !== undefined)
|
|
94281
94672
|
entry.description = doc.description;
|
|
@@ -94285,6 +94676,8 @@ function indexDocumentToStashEntry(doc) {
|
|
|
94285
94676
|
entry.content = doc.content;
|
|
94286
94677
|
if (doc.contentTruncated !== undefined)
|
|
94287
94678
|
entry.contentTruncated = doc.contentTruncated;
|
|
94679
|
+
if (hasMarkdownFragmentContent(doc))
|
|
94680
|
+
setMarkdownFragmentContent(entry, getMarkdownFragmentContent(doc));
|
|
94288
94681
|
if (doc.ownsPresentation !== undefined)
|
|
94289
94682
|
entry.ownsPresentation = doc.ownsPresentation;
|
|
94290
94683
|
if (doc.updated !== undefined)
|
|
@@ -94378,31 +94771,28 @@ function drainDirDocuments(adapter, component, fileContexts) {
|
|
|
94378
94771
|
const conceptIdByFile = new Map;
|
|
94379
94772
|
const rejectedPaths = new Set;
|
|
94380
94773
|
const rejectedConceptIds = new Set;
|
|
94381
|
-
const
|
|
94382
|
-
|
|
94774
|
+
const workflowOwnerPathByCanonicalName = new Map(resolveWorkflowSourceDomains(component.root, adapter.id, fileContexts.map((file) => file.absPath)).filter((resolution) => resolution.source !== undefined).map((resolution) => [resolution.canonicalName, path58.resolve(resolution.source.path)]));
|
|
94775
|
+
const invalidWorkflowOwnerNames = new Set;
|
|
94776
|
+
const orderedFileContexts = [...fileContexts].sort((left, right) => {
|
|
94777
|
+
const leftName = workflowNameForSourcePath(component.root, adapter.id, left.absPath);
|
|
94778
|
+
const rightName = workflowNameForSourcePath(component.root, adapter.id, right.absPath);
|
|
94779
|
+
const leftOwner = leftName !== undefined && workflowOwnerPathByCanonicalName.get(canonicalizeWorkflowName(leftName)) === path58.resolve(left.absPath);
|
|
94780
|
+
const rightOwner = rightName !== undefined && workflowOwnerPathByCanonicalName.get(canonicalizeWorkflowName(rightName)) === path58.resolve(right.absPath);
|
|
94781
|
+
if (leftOwner !== rightOwner)
|
|
94782
|
+
return leftOwner ? -1 : 1;
|
|
94783
|
+
return compareCodePoints(left.absPath, right.absPath);
|
|
94784
|
+
});
|
|
94785
|
+
for (const file of orderedFileContexts) {
|
|
94786
|
+
if (rejectedPaths.has(file.absPath))
|
|
94787
|
+
continue;
|
|
94383
94788
|
const workflowName = workflowNameForSourcePath(component.root, adapter.id, file.absPath);
|
|
94384
94789
|
if (workflowName !== undefined) {
|
|
94385
94790
|
const canonicalName = canonicalizeWorkflowName(workflowName);
|
|
94386
|
-
|
|
94387
|
-
|
|
94388
|
-
|
|
94389
|
-
}
|
|
94390
|
-
for (const [canonicalName, workflowName] of [...workflowLookups].sort(([left], [right]) => compareCodePoints(left, right))) {
|
|
94391
|
-
try {
|
|
94392
|
-
resolveUniqueWorkflowSource(component.root, adapter.id, workflowName);
|
|
94393
|
-
} catch (error2) {
|
|
94394
|
-
if (!(error2 instanceof WorkflowSourceRejectionError))
|
|
94395
|
-
throw error2;
|
|
94396
|
-
rejectedConceptIds.add(adapter.id === "akm" ? `workflows/${canonicalName}` : canonicalName);
|
|
94397
|
-
for (const relativePath of error2.sourcePaths) {
|
|
94398
|
-
rejectedPaths.add(path57.join(component.root, relativePath));
|
|
94791
|
+
const ownerPath = workflowOwnerPathByCanonicalName.get(canonicalName);
|
|
94792
|
+
if (ownerPath !== undefined && ownerPath !== path58.resolve(file.absPath) && !invalidWorkflowOwnerNames.has(canonicalName)) {
|
|
94793
|
+
continue;
|
|
94399
94794
|
}
|
|
94400
|
-
warnings.push(error2.message);
|
|
94401
94795
|
}
|
|
94402
|
-
}
|
|
94403
|
-
for (const file of fileContexts) {
|
|
94404
|
-
if (rejectedPaths.has(file.absPath))
|
|
94405
|
-
continue;
|
|
94406
94796
|
const doc = adapter.recognize(component, file);
|
|
94407
94797
|
if (doc === null)
|
|
94408
94798
|
continue;
|
|
@@ -94414,6 +94804,8 @@ function drainDirDocuments(adapter, component, fileContexts) {
|
|
|
94414
94804
|
const dropWarning = handleWorkflowDoc(doc, file, component.root);
|
|
94415
94805
|
if (dropWarning !== null) {
|
|
94416
94806
|
warnings.push(dropWarning);
|
|
94807
|
+
if (workflowName !== undefined)
|
|
94808
|
+
invalidWorkflowOwnerNames.add(canonicalizeWorkflowName(workflowName));
|
|
94417
94809
|
continue;
|
|
94418
94810
|
}
|
|
94419
94811
|
if (doc.hash !== undefined)
|
|
@@ -94457,7 +94849,7 @@ async function indexWrittenAssets(stashDir, filePaths, options = {}) {
|
|
|
94457
94849
|
if (isPathAbsent(dbPath))
|
|
94458
94850
|
return true;
|
|
94459
94851
|
const files = filePaths.filter((f) => {
|
|
94460
|
-
const rel =
|
|
94852
|
+
const rel = path59.relative(stashDir, f);
|
|
94461
94853
|
return !rel.split(/[\\/]+/).some((segment) => segment.startsWith("."));
|
|
94462
94854
|
});
|
|
94463
94855
|
if (files.length === 0)
|
|
@@ -94471,10 +94863,10 @@ async function indexWrittenAssets(stashDir, filePaths, options = {}) {
|
|
|
94471
94863
|
const unindexable = new Set;
|
|
94472
94864
|
const rejectedConceptIds = new Set;
|
|
94473
94865
|
for (const file of files) {
|
|
94474
|
-
if (!
|
|
94866
|
+
if (!fs48.existsSync(file)) {
|
|
94475
94867
|
let authoredDanglingSymlink = false;
|
|
94476
94868
|
try {
|
|
94477
|
-
authoredDanglingSymlink =
|
|
94869
|
+
authoredDanglingSymlink = fs48.lstatSync(file).isSymbolicLink();
|
|
94478
94870
|
} catch {}
|
|
94479
94871
|
if (!authoredDanglingSymlink) {
|
|
94480
94872
|
unindexable.add(file);
|
|
@@ -94525,7 +94917,10 @@ async function indexWrittenAssets(stashDir, filePaths, options = {}) {
|
|
|
94525
94917
|
for (const { file, entry, conceptId, contentHash } of pairs) {
|
|
94526
94918
|
let entryWithSize = entry;
|
|
94527
94919
|
try {
|
|
94528
|
-
entryWithSize = { ...entry, fileSize:
|
|
94920
|
+
entryWithSize = { ...entry, fileSize: fs48.statSync(file).size };
|
|
94921
|
+
if (hasMarkdownFragmentContent(entry)) {
|
|
94922
|
+
setMarkdownFragmentContent(entryWithSize, getMarkdownFragmentContent(entry));
|
|
94923
|
+
}
|
|
94529
94924
|
} catch {}
|
|
94530
94925
|
const provenance = deriveEntryProvenance({ bundleId: component.id, componentId: component.id, adapterId: component.adapter }, entry.type, entry.name, conceptId);
|
|
94531
94926
|
const supersededIds = db.prepare("SELECT id FROM entries WHERE file_path = ? AND item_ref <> ?").all(file, provenance.itemRef);
|
|
@@ -94558,7 +94953,7 @@ async function indexWrittenAssets(stashDir, filePaths, options = {}) {
|
|
|
94558
94953
|
init_asset_placement();
|
|
94559
94954
|
init_asset_ref();
|
|
94560
94955
|
init_warn();
|
|
94561
|
-
import
|
|
94956
|
+
import path60 from "path";
|
|
94562
94957
|
function changesToStored(changes) {
|
|
94563
94958
|
return changes.map((c, i) => ({
|
|
94564
94959
|
path: c.path,
|
|
@@ -94611,10 +95006,10 @@ function currentProposalTarget(value) {
|
|
|
94611
95006
|
if (typeof value !== "object" || value === null)
|
|
94612
95007
|
throw new Error("Proposal metadata has an invalid proposedTarget.");
|
|
94613
95008
|
const target = value;
|
|
94614
|
-
if (typeof target.source !== "string" || !isBundleSlug(target.source) || typeof target.root !== "string" || !
|
|
95009
|
+
if (typeof target.source !== "string" || !isBundleSlug(target.source) || typeof target.root !== "string" || !path60.isAbsolute(target.root)) {
|
|
94615
95010
|
throw new Error("Proposal metadata has an invalid proposedTarget.");
|
|
94616
95011
|
}
|
|
94617
|
-
return { source: target.source, root:
|
|
95012
|
+
return { source: target.source, root: path60.resolve(target.root) };
|
|
94618
95013
|
}
|
|
94619
95014
|
function invalidPresentField(name) {
|
|
94620
95015
|
throw new Error(`Proposal metadata has an invalid ${name}.`);
|
|
@@ -94654,7 +95049,7 @@ function validatePresentMetadata(meta) {
|
|
|
94654
95049
|
}
|
|
94655
95050
|
if (Object.hasOwn(meta, "acceptedTarget")) {
|
|
94656
95051
|
const target = meta.acceptedTarget;
|
|
94657
|
-
if (typeof target !== "object" || target === null || typeof target.source !== "string" || !isBundleSlug(target.source) || typeof target.root !== "string" || !
|
|
95052
|
+
if (typeof target !== "object" || target === null || typeof target.source !== "string" || !isBundleSlug(target.source) || typeof target.root !== "string" || !path60.isAbsolute(target.root) || typeof target.path !== "string" || !path60.isAbsolute(target.path) || typeof target.contentHash !== "string") {
|
|
94658
95053
|
invalidPresentField("acceptedTarget");
|
|
94659
95054
|
}
|
|
94660
95055
|
}
|
|
@@ -95385,15 +95780,15 @@ var PROPOSAL_TXN_PHASES = [
|
|
|
95385
95780
|
"committed"
|
|
95386
95781
|
];
|
|
95387
95782
|
function proposalHash(content) {
|
|
95388
|
-
return
|
|
95783
|
+
return createHash10("sha256").update(content).digest("hex");
|
|
95389
95784
|
}
|
|
95390
95785
|
function proposalFileHash(filePath) {
|
|
95391
|
-
return proposalHash(
|
|
95786
|
+
return proposalHash(fs49.readFileSync(filePath));
|
|
95392
95787
|
}
|
|
95393
95788
|
function sameProposalFile(left, right) {
|
|
95394
95789
|
try {
|
|
95395
|
-
const leftStat =
|
|
95396
|
-
const rightStat =
|
|
95790
|
+
const leftStat = fs49.statSync(left);
|
|
95791
|
+
const rightStat = fs49.statSync(right);
|
|
95397
95792
|
return leftStat.dev === rightStat.dev && leftStat.ino === rightStat.ino;
|
|
95398
95793
|
} catch {
|
|
95399
95794
|
return false;
|
|
@@ -95402,20 +95797,20 @@ function sameProposalFile(left, right) {
|
|
|
95402
95797
|
function cleanupProposalPublication(p) {
|
|
95403
95798
|
for (const filePath of [p.publishPath, p.displacedPath]) {
|
|
95404
95799
|
try {
|
|
95405
|
-
|
|
95800
|
+
fs49.rmSync(filePath, { force: true });
|
|
95406
95801
|
} catch (error2) {
|
|
95407
95802
|
warn(`[proposals] transaction publication cleanup failed at ${filePath}: ${error2 instanceof Error ? error2.message : String(error2)}`);
|
|
95408
95803
|
}
|
|
95409
95804
|
}
|
|
95410
|
-
fsyncTxnDir(
|
|
95805
|
+
fsyncTxnDir(path61.dirname(p.assetPath));
|
|
95411
95806
|
}
|
|
95412
95807
|
function rollbackPreparedProposalTransaction(txn) {
|
|
95413
95808
|
const p = txn.journal.payload;
|
|
95414
|
-
const currentHash =
|
|
95415
|
-
if (!
|
|
95809
|
+
const currentHash = fs49.existsSync(p.assetPath) ? proposalFileHash(p.assetPath) : null;
|
|
95810
|
+
if (!fs49.existsSync(p.displacedPath)) {
|
|
95416
95811
|
if (p.originalHash === null) {
|
|
95417
95812
|
if (currentHash === p.publishedHash && sameProposalFile(p.assetPath, p.publishPath)) {
|
|
95418
|
-
|
|
95813
|
+
fs49.unlinkSync(p.assetPath);
|
|
95419
95814
|
recordWrittenPath(p.assetPath);
|
|
95420
95815
|
} else if (currentHash !== null) {
|
|
95421
95816
|
throw new Error(`Cannot roll back proposal transaction: target was created externally.`);
|
|
@@ -95427,30 +95822,30 @@ function rollbackPreparedProposalTransaction(txn) {
|
|
|
95427
95822
|
return;
|
|
95428
95823
|
}
|
|
95429
95824
|
if (currentHash === p.publishedHash) {
|
|
95430
|
-
|
|
95825
|
+
fs49.unlinkSync(p.assetPath);
|
|
95431
95826
|
recordWrittenPath(p.assetPath);
|
|
95432
95827
|
} else if (currentHash !== null && currentHash !== p.originalHash) {
|
|
95433
95828
|
throw new Error(`Cannot roll back proposal transaction: ${p.assetPath} diverged.`);
|
|
95434
95829
|
}
|
|
95435
|
-
if (
|
|
95436
|
-
if (
|
|
95830
|
+
if (fs49.existsSync(p.displacedPath)) {
|
|
95831
|
+
if (fs49.existsSync(p.assetPath)) {
|
|
95437
95832
|
throw new Error(`Cannot restore proposal backup: ${p.assetPath} is occupied.`);
|
|
95438
95833
|
}
|
|
95439
|
-
|
|
95834
|
+
fs49.linkSync(p.displacedPath, p.assetPath);
|
|
95440
95835
|
recordWrittenPath(p.assetPath);
|
|
95441
95836
|
}
|
|
95442
95837
|
cleanupProposalPublication(p);
|
|
95443
95838
|
}
|
|
95444
95839
|
function validatePublishedProposal(p) {
|
|
95445
|
-
if (!
|
|
95840
|
+
if (!fs49.existsSync(p.assetPath) || proposalFileHash(p.assetPath) !== p.publishedHash) {
|
|
95446
95841
|
throw new Error(`Cannot recover proposal ${p.proposalId}: published asset diverged.`);
|
|
95447
95842
|
}
|
|
95448
95843
|
}
|
|
95449
95844
|
function persistProposalTransactionState(txn, proposal, ctx) {
|
|
95450
95845
|
const p = txn.journal.payload;
|
|
95451
95846
|
const decidedAt = txn.journal.decidedAt;
|
|
95452
|
-
const backupContent = p.backupPath ?
|
|
95453
|
-
const publishedContent =
|
|
95847
|
+
const backupContent = p.backupPath ? fs49.readFileSync(p.backupPath, "utf8") : undefined;
|
|
95848
|
+
const publishedContent = fs49.readFileSync(p.contentPath, "utf8");
|
|
95454
95849
|
return withProposalsDb(p.stashDir, ctx, (db) => withImmediateTransaction(db, () => {
|
|
95455
95850
|
const current = requireProposal(db, p.stashDir, p.proposalId);
|
|
95456
95851
|
if (p.operation === "accept") {
|
|
@@ -95468,7 +95863,7 @@ function persistProposalTransactionState(txn, proposal, ctx) {
|
|
|
95468
95863
|
payload: { ...proposal.payload, content: publishedContent },
|
|
95469
95864
|
changes: [
|
|
95470
95865
|
{
|
|
95471
|
-
path:
|
|
95866
|
+
path: path61.relative(txn.journal.root, p.assetPath),
|
|
95472
95867
|
op: p.originalHash === null ? "create" : "update",
|
|
95473
95868
|
after: publishedContent
|
|
95474
95869
|
}
|
|
@@ -95539,7 +95934,7 @@ async function finalizeProposalTransaction(txn, target, proposal, ctx) {
|
|
|
95539
95934
|
cleanupProposalPublication(p);
|
|
95540
95935
|
if (txn.journal.phase === "asset-published") {
|
|
95541
95936
|
const commitRoot = target.source.repoPath ?? target.source.path;
|
|
95542
|
-
const commitPath =
|
|
95937
|
+
const commitPath = path61.relative(commitRoot, p.assetPath).replaceAll(path61.sep, "/");
|
|
95543
95938
|
publishWriteTargetTransaction(target, p.gitPublication, {
|
|
95544
95939
|
transactionId: txn.journal.transactionId,
|
|
95545
95940
|
message: `${p.operation === "accept" ? "Update" : "Revert"} ${p.ref}`,
|
|
@@ -95576,8 +95971,8 @@ async function finalizeProposalTransaction(txn, target, proposal, ctx) {
|
|
|
95576
95971
|
function fenceProposalTxnJournal(journal, txnDir, root2) {
|
|
95577
95972
|
const p = journal.payload;
|
|
95578
95973
|
const refIdentity = proposalRefIdentity(p.ref);
|
|
95579
|
-
if (!["accept", "revert"].includes(p.operation) || !p.targetSource || !p.targetKind || refIdentity?.bundle === undefined || !isWithin(p.assetPath, root2) || ![p.contentPath, p.backupPath].filter((candidate) => candidate !== null).every((candidate) => isWithin(candidate, txnDir)) || ![p.publishPath, p.displacedPath].every((candidate) => isWithin(candidate, root2) &&
|
|
95580
|
-
throw new Error(`Refusing unsafe proposal transaction journal at ${
|
|
95974
|
+
if (!["accept", "revert"].includes(p.operation) || !p.targetSource || !p.targetKind || refIdentity?.bundle === undefined || !isWithin(p.assetPath, root2) || ![p.contentPath, p.backupPath].filter((candidate) => candidate !== null).every((candidate) => isWithin(candidate, txnDir)) || ![p.publishPath, p.displacedPath].every((candidate) => isWithin(candidate, root2) && path61.dirname(candidate) === path61.dirname(p.assetPath))) {
|
|
95975
|
+
throw new Error(`Refusing unsafe proposal transaction journal at ${path61.join(txnDir, "journal.json")}.`);
|
|
95581
95976
|
}
|
|
95582
95977
|
}
|
|
95583
95978
|
function resolveProposalRecoveryTarget(config, journal) {
|
|
@@ -95677,8 +96072,8 @@ async function recoverStaleTxns(stashDir) {
|
|
|
95677
96072
|
}
|
|
95678
96073
|
|
|
95679
96074
|
// scripts/akm-migrate/migrate/writer-relocation.ts
|
|
95680
|
-
import
|
|
95681
|
-
import
|
|
96075
|
+
import fs50 from "fs";
|
|
96076
|
+
import path62 from "path";
|
|
95682
96077
|
init_paths();
|
|
95683
96078
|
function relocationSpecs(stashDir) {
|
|
95684
96079
|
return [
|
|
@@ -95698,7 +96093,7 @@ function mutexSiblingName(lockName) {
|
|
|
95698
96093
|
function fileCountIfExists(dir) {
|
|
95699
96094
|
let entries;
|
|
95700
96095
|
try {
|
|
95701
|
-
entries =
|
|
96096
|
+
entries = fs50.readdirSync(dir, { withFileTypes: true });
|
|
95702
96097
|
} catch {
|
|
95703
96098
|
return;
|
|
95704
96099
|
}
|
|
@@ -95706,7 +96101,7 @@ function fileCountIfExists(dir) {
|
|
|
95706
96101
|
}
|
|
95707
96102
|
function statFileIfExists(filePath) {
|
|
95708
96103
|
try {
|
|
95709
|
-
const stat =
|
|
96104
|
+
const stat = fs50.statSync(filePath);
|
|
95710
96105
|
return stat.isFile() ? stat : undefined;
|
|
95711
96106
|
} catch {
|
|
95712
96107
|
return;
|
|
@@ -95716,8 +96111,8 @@ function classifyLockArtifacts(akmDir) {
|
|
|
95716
96111
|
const removable = [];
|
|
95717
96112
|
const skipped = [];
|
|
95718
96113
|
for (const lockName of LOCK_NAMES) {
|
|
95719
|
-
const lockPath =
|
|
95720
|
-
const mutexPath =
|
|
96114
|
+
const lockPath = path62.join(akmDir, lockName);
|
|
96115
|
+
const mutexPath = path62.join(akmDir, mutexSiblingName(lockName));
|
|
95721
96116
|
const lockStat = statFileIfExists(lockPath);
|
|
95722
96117
|
const mutexStat = statFileIfExists(mutexPath);
|
|
95723
96118
|
if (!lockStat) {
|
|
@@ -95743,11 +96138,11 @@ function classifyLockArtifacts(akmDir) {
|
|
|
95743
96138
|
return { removable, skipped };
|
|
95744
96139
|
}
|
|
95745
96140
|
function findWriterRelocationEntries(stashDir) {
|
|
95746
|
-
const akmDir =
|
|
96141
|
+
const akmDir = path62.join(stashDir, ".akm");
|
|
95747
96142
|
const directories = [];
|
|
95748
96143
|
for (const spec of relocationSpecs(stashDir)) {
|
|
95749
96144
|
const relativeParts = Array.isArray(spec.oldRelative) ? spec.oldRelative : [spec.oldRelative];
|
|
95750
|
-
const oldPath =
|
|
96145
|
+
const oldPath = path62.join(akmDir, ...relativeParts);
|
|
95751
96146
|
const fileCount = fileCountIfExists(oldPath);
|
|
95752
96147
|
if (fileCount === undefined || fileCount === 0)
|
|
95753
96148
|
continue;
|
|
@@ -95758,36 +96153,36 @@ function findWriterRelocationEntries(stashDir) {
|
|
|
95758
96153
|
}
|
|
95759
96154
|
function moveFile(oldFilePath, newFilePath) {
|
|
95760
96155
|
try {
|
|
95761
|
-
|
|
96156
|
+
fs50.renameSync(oldFilePath, newFilePath);
|
|
95762
96157
|
} catch (error2) {
|
|
95763
96158
|
if (error2.code !== "EXDEV")
|
|
95764
96159
|
throw error2;
|
|
95765
|
-
|
|
95766
|
-
|
|
96160
|
+
fs50.copyFileSync(oldFilePath, newFilePath);
|
|
96161
|
+
fs50.rmSync(oldFilePath, { force: true });
|
|
95767
96162
|
}
|
|
95768
96163
|
}
|
|
95769
96164
|
function moveDirectoryContents(entry) {
|
|
95770
96165
|
const errors3 = [];
|
|
95771
96166
|
let moved = 0;
|
|
95772
|
-
|
|
96167
|
+
fs50.mkdirSync(entry.newPath, { recursive: true });
|
|
95773
96168
|
let names;
|
|
95774
96169
|
try {
|
|
95775
|
-
names =
|
|
96170
|
+
names = fs50.readdirSync(entry.oldPath).sort();
|
|
95776
96171
|
} catch {
|
|
95777
96172
|
return { key: entry.key, oldPath: entry.oldPath, newPath: entry.newPath, moved: 0, errors: [] };
|
|
95778
96173
|
}
|
|
95779
96174
|
for (const name of names) {
|
|
95780
|
-
const oldFilePath =
|
|
95781
|
-
const newFilePath =
|
|
96175
|
+
const oldFilePath = path62.join(entry.oldPath, name);
|
|
96176
|
+
const newFilePath = path62.join(entry.newPath, name);
|
|
95782
96177
|
let oldStat;
|
|
95783
96178
|
try {
|
|
95784
|
-
oldStat =
|
|
96179
|
+
oldStat = fs50.lstatSync(oldFilePath);
|
|
95785
96180
|
} catch {
|
|
95786
96181
|
continue;
|
|
95787
96182
|
}
|
|
95788
96183
|
if (!oldStat.isFile())
|
|
95789
96184
|
continue;
|
|
95790
|
-
if (
|
|
96185
|
+
if (fs50.existsSync(newFilePath))
|
|
95791
96186
|
continue;
|
|
95792
96187
|
try {
|
|
95793
96188
|
moveFile(oldFilePath, newFilePath);
|
|
@@ -95800,13 +96195,13 @@ function moveDirectoryContents(entry) {
|
|
|
95800
96195
|
}
|
|
95801
96196
|
function removeIfEmptyDir(dir) {
|
|
95802
96197
|
try {
|
|
95803
|
-
if (
|
|
95804
|
-
|
|
96198
|
+
if (fs50.readdirSync(dir).length === 0)
|
|
96199
|
+
fs50.rmdirSync(dir);
|
|
95805
96200
|
} catch {}
|
|
95806
96201
|
}
|
|
95807
96202
|
function removeLockArtifact(entry) {
|
|
95808
96203
|
try {
|
|
95809
|
-
|
|
96204
|
+
fs50.rmSync(entry.path, { force: true });
|
|
95810
96205
|
return { path: entry.path, removed: true };
|
|
95811
96206
|
} catch (error2) {
|
|
95812
96207
|
return { path: entry.path, removed: false, error: error2 instanceof Error ? error2.message : String(error2) };
|
|
@@ -95818,36 +96213,36 @@ function applyWriterRelocation(stashDir) {
|
|
|
95818
96213
|
const lockResults = lockArtifacts.map(removeLockArtifact);
|
|
95819
96214
|
for (const spec of relocationSpecs(stashDir)) {
|
|
95820
96215
|
const relativeParts = Array.isArray(spec.oldRelative) ? spec.oldRelative : [spec.oldRelative];
|
|
95821
|
-
removeIfEmptyDir(
|
|
96216
|
+
removeIfEmptyDir(path62.join(stashDir, ".akm", ...relativeParts));
|
|
95822
96217
|
}
|
|
95823
96218
|
return { directories: directoryResults, lockArtifacts: lockResults, skippedLocks };
|
|
95824
96219
|
}
|
|
95825
96220
|
|
|
95826
96221
|
// scripts/akm-migrate/task-migrate.ts
|
|
95827
96222
|
import { randomUUID as randomUUID7 } from "crypto";
|
|
95828
|
-
import
|
|
96223
|
+
import fs56 from "fs";
|
|
95829
96224
|
import os5 from "os";
|
|
95830
|
-
import
|
|
96225
|
+
import path65 from "path";
|
|
95831
96226
|
init_errors();
|
|
95832
96227
|
init_paths();
|
|
95833
96228
|
|
|
95834
96229
|
// scripts/akm-migrate/migrate/task-files-to-v3.ts
|
|
95835
96230
|
init_errors();
|
|
95836
96231
|
import crypto6 from "crypto";
|
|
95837
|
-
import
|
|
95838
|
-
import
|
|
96232
|
+
import fs53 from "fs";
|
|
96233
|
+
import path63 from "path";
|
|
95839
96234
|
|
|
95840
96235
|
// scripts/akm-migrate/migrate/durable-fs.ts
|
|
95841
|
-
import
|
|
96236
|
+
import fs51 from "fs";
|
|
95842
96237
|
function fsyncDirectoryPortable(directory) {
|
|
95843
96238
|
if (process.platform === "win32")
|
|
95844
96239
|
return;
|
|
95845
96240
|
try {
|
|
95846
|
-
const fd =
|
|
96241
|
+
const fd = fs51.openSync(directory, "r");
|
|
95847
96242
|
try {
|
|
95848
|
-
|
|
96243
|
+
fs51.fsyncSync(fd);
|
|
95849
96244
|
} finally {
|
|
95850
|
-
|
|
96245
|
+
fs51.closeSync(fd);
|
|
95851
96246
|
}
|
|
95852
96247
|
} catch (cause) {
|
|
95853
96248
|
const code = cause.code;
|
|
@@ -95861,25 +96256,25 @@ function migrationError(detail) {
|
|
|
95861
96256
|
return new ConfigError(`Task migration to v3 failed: ${detail}`, "INVALID_CONFIG_FILE");
|
|
95862
96257
|
}
|
|
95863
96258
|
function contained2(root2, candidate) {
|
|
95864
|
-
const relative =
|
|
95865
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
96259
|
+
const relative = path63.relative(root2, candidate);
|
|
96260
|
+
return relative === "" || !relative.startsWith("..") && !path63.isAbsolute(relative);
|
|
95866
96261
|
}
|
|
95867
96262
|
function realDirectory(filePath) {
|
|
95868
|
-
const stat =
|
|
96263
|
+
const stat = fs53.lstatSync(filePath);
|
|
95869
96264
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
95870
96265
|
throw migrationError(`${filePath} must be a real directory.`);
|
|
95871
|
-
return
|
|
96266
|
+
return fs53.realpathSync(filePath);
|
|
95872
96267
|
}
|
|
95873
96268
|
function snapshot(filePath) {
|
|
95874
|
-
const stat =
|
|
96269
|
+
const stat = fs53.lstatSync(filePath);
|
|
95875
96270
|
if (stat.isSymbolicLink() || !stat.isFile())
|
|
95876
96271
|
throw migrationError(`${filePath} must be a real file.`);
|
|
95877
|
-
const bytes =
|
|
96272
|
+
const bytes = fs53.readFileSync(filePath);
|
|
95878
96273
|
return Object.freeze({ bytes, mode: stat.mode & 511 });
|
|
95879
96274
|
}
|
|
95880
96275
|
function writable(filePath) {
|
|
95881
96276
|
try {
|
|
95882
|
-
|
|
96277
|
+
fs53.accessSync(filePath, fs53.constants.W_OK);
|
|
95883
96278
|
return true;
|
|
95884
96279
|
} catch {
|
|
95885
96280
|
return false;
|
|
@@ -95892,12 +96287,12 @@ function walkTasks(root2, tasksDir, out) {
|
|
|
95892
96287
|
throw migrationError(`${root2.root} resolves outside bundle ${root2.bundleId}.`);
|
|
95893
96288
|
}
|
|
95894
96289
|
const visit2 = (directory) => {
|
|
95895
|
-
const physicalDirectory =
|
|
96290
|
+
const physicalDirectory = fs53.realpathSync(directory);
|
|
95896
96291
|
if (!contained2(physicalRoot, physicalDirectory)) {
|
|
95897
96292
|
throw migrationError(`${directory} resolves outside bundle ${root2.bundleId}.`);
|
|
95898
96293
|
}
|
|
95899
|
-
for (const entry of
|
|
95900
|
-
const candidate =
|
|
96294
|
+
for (const entry of fs53.readdirSync(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
96295
|
+
const candidate = path63.join(directory, entry.name);
|
|
95901
96296
|
if (entry.isSymbolicLink())
|
|
95902
96297
|
throw migrationError(`task migration does not follow symbolic link ${candidate}.`);
|
|
95903
96298
|
if (entry.isDirectory()) {
|
|
@@ -95907,7 +96302,7 @@ function walkTasks(root2, tasksDir, out) {
|
|
|
95907
96302
|
if (!entry.isFile() || !entry.name.endsWith(".yml"))
|
|
95908
96303
|
continue;
|
|
95909
96304
|
const current = snapshot(candidate);
|
|
95910
|
-
const parent =
|
|
96305
|
+
const parent = path63.dirname(candidate);
|
|
95911
96306
|
out.push({
|
|
95912
96307
|
filePath: candidate,
|
|
95913
96308
|
bytes: current.bytes,
|
|
@@ -95923,9 +96318,9 @@ function walkTasks(root2, tasksDir, out) {
|
|
|
95923
96318
|
function inspectTaskToV3Files(roots) {
|
|
95924
96319
|
const files = [];
|
|
95925
96320
|
for (const root2 of [...roots].sort((a, b) => a.bundleId.localeCompare(b.bundleId))) {
|
|
95926
|
-
const tasksDir = root2.layout === "akm-task" ? root2.root :
|
|
96321
|
+
const tasksDir = root2.layout === "akm-task" ? root2.root : path63.join(root2.root, "tasks");
|
|
95927
96322
|
try {
|
|
95928
|
-
const stat =
|
|
96323
|
+
const stat = fs53.lstatSync(tasksDir);
|
|
95929
96324
|
if (stat.isSymbolicLink())
|
|
95930
96325
|
throw migrationError(`task migration does not follow symbolic link ${tasksDir}.`);
|
|
95931
96326
|
if (!stat.isDirectory())
|
|
@@ -95940,33 +96335,33 @@ function inspectTaskToV3Files(roots) {
|
|
|
95940
96335
|
return files.sort((a, b) => a.filePath.localeCompare(b.filePath));
|
|
95941
96336
|
}
|
|
95942
96337
|
function hashPath(filePath) {
|
|
95943
|
-
return crypto6.createHash("sha256").update(
|
|
96338
|
+
return crypto6.createHash("sha256").update(path63.resolve(filePath)).digest("hex").slice(0, 16);
|
|
95944
96339
|
}
|
|
95945
96340
|
function taskMigrationBackupPath(backupRoot, filePath) {
|
|
95946
|
-
return
|
|
96341
|
+
return path63.join(backupRoot, "files", `${hashPath(filePath)}-${path63.basename(filePath)}`);
|
|
95947
96342
|
}
|
|
95948
96343
|
function writeDurable(filePath, bytes, mode, exclusive = false) {
|
|
95949
|
-
|
|
96344
|
+
fs53.mkdirSync(path63.dirname(filePath), { recursive: true });
|
|
95950
96345
|
const flags = exclusive ? "wx" : "w";
|
|
95951
|
-
const fd =
|
|
96346
|
+
const fd = fs53.openSync(filePath, flags, mode);
|
|
95952
96347
|
try {
|
|
95953
|
-
|
|
95954
|
-
|
|
96348
|
+
fs53.writeFileSync(fd, bytes);
|
|
96349
|
+
fs53.fsyncSync(fd);
|
|
95955
96350
|
} finally {
|
|
95956
|
-
|
|
96351
|
+
fs53.closeSync(fd);
|
|
95957
96352
|
}
|
|
95958
|
-
|
|
95959
|
-
fsyncDirectoryPortable(
|
|
96353
|
+
fs53.chmodSync(filePath, mode);
|
|
96354
|
+
fsyncDirectoryPortable(path63.dirname(filePath));
|
|
95960
96355
|
}
|
|
95961
96356
|
function replaceAtomically(filePath, bytes, mode) {
|
|
95962
|
-
const temporary =
|
|
96357
|
+
const temporary = path63.join(path63.dirname(filePath), `.${path63.basename(filePath)}.migrate-${crypto6.randomUUID()}`);
|
|
95963
96358
|
try {
|
|
95964
96359
|
writeDurable(temporary, bytes, mode, true);
|
|
95965
|
-
|
|
95966
|
-
fsyncDirectoryPortable(
|
|
96360
|
+
fs53.renameSync(temporary, filePath);
|
|
96361
|
+
fsyncDirectoryPortable(path63.dirname(filePath));
|
|
95967
96362
|
} finally {
|
|
95968
96363
|
try {
|
|
95969
|
-
|
|
96364
|
+
fs53.unlinkSync(temporary);
|
|
95970
96365
|
} catch (cause) {
|
|
95971
96366
|
if (cause.code !== "ENOENT")
|
|
95972
96367
|
throw cause;
|
|
@@ -96005,7 +96400,7 @@ function applyTaskToV3MigrationPlan(plan, options) {
|
|
|
96005
96400
|
const current = snapshot(change.filePath);
|
|
96006
96401
|
if (!current.bytes.equals(change.after))
|
|
96007
96402
|
continue;
|
|
96008
|
-
replaceAtomically(change.filePath,
|
|
96403
|
+
replaceAtomically(change.filePath, fs53.readFileSync(taskMigrationBackupPath(options.backupRoot, change.filePath)), change.mode);
|
|
96009
96404
|
}
|
|
96010
96405
|
throw cause;
|
|
96011
96406
|
}
|
|
@@ -96015,31 +96410,31 @@ function applyTaskToV3MigrationPlan(plan, options) {
|
|
|
96015
96410
|
// scripts/akm-migrate/migrate/task-files-to-v4.ts
|
|
96016
96411
|
init_errors();
|
|
96017
96412
|
import crypto7 from "crypto";
|
|
96018
|
-
import
|
|
96019
|
-
import
|
|
96413
|
+
import fs55 from "fs";
|
|
96414
|
+
import path64 from "path";
|
|
96020
96415
|
function migrationError2(detail) {
|
|
96021
96416
|
return new ConfigError(`Task migration to v4 failed: ${detail}`, "INVALID_CONFIG_FILE");
|
|
96022
96417
|
}
|
|
96023
96418
|
function contained3(root2, candidate) {
|
|
96024
|
-
const relative =
|
|
96025
|
-
return relative === "" || !relative.startsWith("..") && !
|
|
96419
|
+
const relative = path64.relative(root2, candidate);
|
|
96420
|
+
return relative === "" || !relative.startsWith("..") && !path64.isAbsolute(relative);
|
|
96026
96421
|
}
|
|
96027
96422
|
function realDirectory2(filePath) {
|
|
96028
|
-
const stat =
|
|
96423
|
+
const stat = fs55.lstatSync(filePath);
|
|
96029
96424
|
if (stat.isSymbolicLink() || !stat.isDirectory())
|
|
96030
96425
|
throw migrationError2(`${filePath} must be a real directory.`);
|
|
96031
|
-
return
|
|
96426
|
+
return fs55.realpathSync(filePath);
|
|
96032
96427
|
}
|
|
96033
96428
|
function snapshot2(filePath) {
|
|
96034
|
-
const stat =
|
|
96429
|
+
const stat = fs55.lstatSync(filePath);
|
|
96035
96430
|
if (stat.isSymbolicLink() || !stat.isFile())
|
|
96036
96431
|
throw migrationError2(`${filePath} must be a real file.`);
|
|
96037
|
-
const bytes =
|
|
96432
|
+
const bytes = fs55.readFileSync(filePath);
|
|
96038
96433
|
return Object.freeze({ bytes, mode: stat.mode & 511 });
|
|
96039
96434
|
}
|
|
96040
96435
|
function writable2(filePath) {
|
|
96041
96436
|
try {
|
|
96042
|
-
|
|
96437
|
+
fs55.accessSync(filePath, fs55.constants.W_OK);
|
|
96043
96438
|
return true;
|
|
96044
96439
|
} catch {
|
|
96045
96440
|
return false;
|
|
@@ -96052,12 +96447,12 @@ function walkTasks2(root2, tasksDir, out) {
|
|
|
96052
96447
|
throw migrationError2(`${root2.root} resolves outside bundle ${root2.bundleId}.`);
|
|
96053
96448
|
}
|
|
96054
96449
|
const visit2 = (directory) => {
|
|
96055
|
-
const physicalDirectory =
|
|
96450
|
+
const physicalDirectory = fs55.realpathSync(directory);
|
|
96056
96451
|
if (!contained3(physicalRoot, physicalDirectory)) {
|
|
96057
96452
|
throw migrationError2(`${directory} resolves outside bundle ${root2.bundleId}.`);
|
|
96058
96453
|
}
|
|
96059
|
-
for (const entry of
|
|
96060
|
-
const candidate =
|
|
96454
|
+
for (const entry of fs55.readdirSync(directory, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
|
|
96455
|
+
const candidate = path64.join(directory, entry.name);
|
|
96061
96456
|
if (entry.isSymbolicLink())
|
|
96062
96457
|
throw migrationError2(`task migration does not follow symbolic link ${candidate}.`);
|
|
96063
96458
|
if (entry.isDirectory()) {
|
|
@@ -96067,7 +96462,7 @@ function walkTasks2(root2, tasksDir, out) {
|
|
|
96067
96462
|
if (!entry.isFile() || !entry.name.endsWith(".yml"))
|
|
96068
96463
|
continue;
|
|
96069
96464
|
const current = snapshot2(candidate);
|
|
96070
|
-
const parent =
|
|
96465
|
+
const parent = path64.dirname(candidate);
|
|
96071
96466
|
out.push({
|
|
96072
96467
|
filePath: candidate,
|
|
96073
96468
|
bytes: current.bytes,
|
|
@@ -96083,9 +96478,9 @@ function walkTasks2(root2, tasksDir, out) {
|
|
|
96083
96478
|
function inspectTaskToV4Files(roots) {
|
|
96084
96479
|
const files = [];
|
|
96085
96480
|
for (const root2 of [...roots].sort((a, b) => a.bundleId.localeCompare(b.bundleId))) {
|
|
96086
|
-
const tasksDir = root2.layout === "akm-task" ? root2.root :
|
|
96481
|
+
const tasksDir = root2.layout === "akm-task" ? root2.root : path64.join(root2.root, "tasks");
|
|
96087
96482
|
try {
|
|
96088
|
-
const stat =
|
|
96483
|
+
const stat = fs55.lstatSync(tasksDir);
|
|
96089
96484
|
if (stat.isSymbolicLink())
|
|
96090
96485
|
throw migrationError2(`task migration does not follow symbolic link ${tasksDir}.`);
|
|
96091
96486
|
if (!stat.isDirectory())
|
|
@@ -96100,33 +96495,33 @@ function inspectTaskToV4Files(roots) {
|
|
|
96100
96495
|
return files.sort((a, b) => a.filePath.localeCompare(b.filePath));
|
|
96101
96496
|
}
|
|
96102
96497
|
function hashPath2(filePath) {
|
|
96103
|
-
return crypto7.createHash("sha256").update(
|
|
96498
|
+
return crypto7.createHash("sha256").update(path64.resolve(filePath)).digest("hex").slice(0, 16);
|
|
96104
96499
|
}
|
|
96105
96500
|
function taskMigrationBackupPathV4(backupRoot, filePath) {
|
|
96106
|
-
return
|
|
96501
|
+
return path64.join(backupRoot, "files", `${hashPath2(filePath)}-${path64.basename(filePath)}`);
|
|
96107
96502
|
}
|
|
96108
96503
|
function writeDurable2(filePath, bytes, mode, exclusive = false) {
|
|
96109
|
-
|
|
96504
|
+
fs55.mkdirSync(path64.dirname(filePath), { recursive: true });
|
|
96110
96505
|
const flags = exclusive ? "wx" : "w";
|
|
96111
|
-
const fd =
|
|
96506
|
+
const fd = fs55.openSync(filePath, flags, mode);
|
|
96112
96507
|
try {
|
|
96113
|
-
|
|
96114
|
-
|
|
96508
|
+
fs55.writeFileSync(fd, bytes);
|
|
96509
|
+
fs55.fsyncSync(fd);
|
|
96115
96510
|
} finally {
|
|
96116
|
-
|
|
96511
|
+
fs55.closeSync(fd);
|
|
96117
96512
|
}
|
|
96118
|
-
|
|
96119
|
-
fsyncDirectoryPortable(
|
|
96513
|
+
fs55.chmodSync(filePath, mode);
|
|
96514
|
+
fsyncDirectoryPortable(path64.dirname(filePath));
|
|
96120
96515
|
}
|
|
96121
96516
|
function replaceAtomically2(filePath, bytes, mode) {
|
|
96122
|
-
const temporary =
|
|
96517
|
+
const temporary = path64.join(path64.dirname(filePath), `.${path64.basename(filePath)}.migrate-${crypto7.randomUUID()}`);
|
|
96123
96518
|
try {
|
|
96124
96519
|
writeDurable2(temporary, bytes, mode, true);
|
|
96125
|
-
|
|
96126
|
-
fsyncDirectoryPortable(
|
|
96520
|
+
fs55.renameSync(temporary, filePath);
|
|
96521
|
+
fsyncDirectoryPortable(path64.dirname(filePath));
|
|
96127
96522
|
} finally {
|
|
96128
96523
|
try {
|
|
96129
|
-
|
|
96524
|
+
fs55.unlinkSync(temporary);
|
|
96130
96525
|
} catch (cause) {
|
|
96131
96526
|
if (cause.code !== "ENOENT")
|
|
96132
96527
|
throw cause;
|
|
@@ -96165,7 +96560,7 @@ function applyTaskToV4MigrationPlan(plan, options) {
|
|
|
96165
96560
|
const current = snapshot2(change.filePath);
|
|
96166
96561
|
if (!current.bytes.equals(change.after))
|
|
96167
96562
|
continue;
|
|
96168
|
-
replaceAtomically2(change.filePath,
|
|
96563
|
+
replaceAtomically2(change.filePath, fs55.readFileSync(taskMigrationBackupPathV4(options.backupRoot, change.filePath)), change.mode);
|
|
96169
96564
|
}
|
|
96170
96565
|
throw cause;
|
|
96171
96566
|
}
|
|
@@ -96177,12 +96572,12 @@ function expandTilde(value) {
|
|
|
96177
96572
|
if (value === "~")
|
|
96178
96573
|
return os5.homedir();
|
|
96179
96574
|
if (value.startsWith("~/") || value.startsWith("~\\"))
|
|
96180
|
-
return
|
|
96575
|
+
return path65.join(os5.homedir(), value.slice(2));
|
|
96181
96576
|
return value;
|
|
96182
96577
|
}
|
|
96183
96578
|
function existingDirectory(target) {
|
|
96184
96579
|
try {
|
|
96185
|
-
return
|
|
96580
|
+
return fs56.statSync(target).isDirectory();
|
|
96186
96581
|
} catch (cause) {
|
|
96187
96582
|
if (cause.code === "ENOENT")
|
|
96188
96583
|
return false;
|
|
@@ -96203,21 +96598,21 @@ function taskRoots(config, resolutionBase = process.cwd()) {
|
|
|
96203
96598
|
const source = sources.get(bundleId);
|
|
96204
96599
|
if (!source)
|
|
96205
96600
|
continue;
|
|
96206
|
-
const configuredRoot = source.type === "filesystem" && source.path ?
|
|
96601
|
+
const configuredRoot = source.type === "filesystem" && source.path ? path65.resolve(resolutionBase, expandTilde(source.path)) : lockContentRootFor(bundleId, source.type);
|
|
96207
96602
|
if (!configuredRoot || !existingDirectory(configuredRoot))
|
|
96208
96603
|
continue;
|
|
96209
|
-
const bundleRoot =
|
|
96604
|
+
const bundleRoot = path65.resolve(configuredRoot);
|
|
96210
96605
|
const component = bundleComponentConfig(bundle);
|
|
96211
|
-
const componentRoot =
|
|
96212
|
-
const relative =
|
|
96213
|
-
if (relative === ".." || relative.startsWith(`..${
|
|
96606
|
+
const componentRoot = path65.resolve(bundleRoot, component?.root ?? ".");
|
|
96607
|
+
const relative = path65.relative(bundleRoot, componentRoot);
|
|
96608
|
+
if (relative === ".." || relative.startsWith(`..${path65.sep}`) || path65.isAbsolute(relative)) {
|
|
96214
96609
|
throw new ConfigError(`Task migration component root ${componentRoot} escapes bundle ${bundleId} at ${bundleRoot}.`, "INVALID_CONFIG_FILE");
|
|
96215
96610
|
}
|
|
96216
96611
|
if (!existingDirectory(componentRoot))
|
|
96217
96612
|
continue;
|
|
96218
96613
|
const adapter = component?.adapter ?? detectAdapterId(componentRoot, "");
|
|
96219
96614
|
if (!component?.adapter && adapter === "") {
|
|
96220
|
-
const flatTasks =
|
|
96615
|
+
const flatTasks = fs56.readdirSync(componentRoot, { withFileTypes: true }).filter((entry) => entry.isFile() && entry.name.endsWith(".yml")).map((entry) => entry.name).sort();
|
|
96221
96616
|
if (flatTasks.length > 0) {
|
|
96222
96617
|
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");
|
|
96223
96618
|
}
|
|
@@ -96289,8 +96684,8 @@ function applyTaskV3Migration() {
|
|
|
96289
96684
|
const before = inspectCurrentTaskPlan();
|
|
96290
96685
|
if (before.result.taskV3Migration.changed === 0)
|
|
96291
96686
|
return before.result;
|
|
96292
|
-
const backupRoot =
|
|
96293
|
-
const backupPath =
|
|
96687
|
+
const backupRoot = path65.join(getDataDir(), "backups", "task-v3");
|
|
96688
|
+
const backupPath = path65.join(backupRoot, `${Date.now()}-${randomUUID7()}`);
|
|
96294
96689
|
const applied = applyTaskToV3MigrationPlan(before.plan, { backupRoot: backupPath });
|
|
96295
96690
|
const after = inspectCurrentTaskPlan().result;
|
|
96296
96691
|
if (after.taskV3Migration.changed > 0) {
|
|
@@ -96346,8 +96741,8 @@ function applyTaskV4Migration() {
|
|
|
96346
96741
|
const before = inspectCurrentTaskV4Plan();
|
|
96347
96742
|
if (before.result.taskV4Migration.changed === 0)
|
|
96348
96743
|
return before.result;
|
|
96349
|
-
const backupRoot =
|
|
96350
|
-
const backupPath =
|
|
96744
|
+
const backupRoot = path65.join(getDataDir(), "backups", "task-v4");
|
|
96745
|
+
const backupPath = path65.join(backupRoot, `${Date.now()}-${randomUUID7()}`);
|
|
96351
96746
|
const applied = applyTaskToV4MigrationPlan(before.plan, { backupRoot: backupPath });
|
|
96352
96747
|
const after = inspectCurrentTaskV4Plan().result;
|
|
96353
96748
|
if (after.taskV4Migration.changed > 0) {
|