@tangle-network/agent-knowledge 11.0.0 → 12.0.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.
@@ -797,16 +797,19 @@ var KnowledgeLockLostError = class extends Error {
797
797
  this.name = "KnowledgeLockLostError";
798
798
  }
799
799
  };
800
+ /**
801
+ * Whether the current async context already holds the store lock for `root`.
802
+ *
803
+ * A caller that must decide between taking the lock and joining the one it is inside reads this
804
+ * rather than guessing; taking a held lock from inside its own scope would block against itself.
805
+ */
806
+ function isKnowledgeMutationHeld(root) {
807
+ return activeRoots.getStore()?.get(resolve(root))?.active === true;
808
+ }
800
809
  async function withKnowledgeMutation(root, mutate, options = {}) {
801
810
  const resolvedRoot = resolve(root);
802
- const active = activeRoots.getStore();
803
- const existing = active?.get(resolvedRoot);
804
- if (existing?.active) {
805
- existing.lock.assertOwned();
806
- const result = await mutate(existing.lock);
807
- existing.lock.assertOwned();
808
- return result;
809
- }
811
+ const existing = activeRoots.getStore()?.get(resolvedRoot);
812
+ if (existing?.active) return await runInlineMutation(existing.lock, mutate);
810
813
  return withSafeDirectory(resolvedRoot, ".agent-knowledge", true, async (cacheDir) => {
811
814
  const acquired = await acquireDurableFileLock(resolvedRoot, {
812
815
  lockfilePath: join(cacheDir, "mutation.lock.durable"),
@@ -819,77 +822,110 @@ async function withKnowledgeMutation(root, mutate, options = {}) {
819
822
  randomize: true
820
823
  }
821
824
  });
822
- let recovery;
823
- const mutationLock = {
824
- transactionRoot: join(cacheDir, "file-transactions"),
825
- get recovery() {
826
- return recovery;
827
- },
828
- assertOwned: acquired.assertOwned
829
- };
830
- const scope = {
831
- active: true,
832
- lock: mutationLock
833
- };
834
825
  try {
835
- const pendingState = await inspectKnowledgeFileTransaction({
836
- root: resolvedRoot,
837
- transactionRoot: mutationLock.transactionRoot
838
- });
839
- const pending = pendingState?.transaction ?? null;
840
- const resume = pending ? assertKnowledgeTransactionResume(pending, options.resumeTransaction) : void 0;
841
- const locks = new Map(active);
842
- locks.set(resolvedRoot, scope);
843
- return await activeRoots.run(locks, async () => {
844
- const epoch = await beginMutationEpoch(cacheDir);
845
- const finishEpoch = async (completed) => {
846
- mutationLock.assertOwned();
847
- const stillPending = await loadKnowledgeFileTransaction({
848
- root: resolvedRoot,
849
- transactionRoot: mutationLock.transactionRoot
850
- });
851
- if (completed && stillPending) throw new Error("knowledge mutation returned with an unfinished transaction");
852
- if (!stillPending) await finishMutationEpoch(cacheDir, epoch);
853
- };
854
- try {
855
- if (pending) {
856
- if (!resume) throw new Error(`knowledge transaction '${pending.purpose}' requires its owner to resume`);
857
- await recoverKnowledgeFileTransaction({
858
- root: resolvedRoot,
859
- transactionRoot: mutationLock.transactionRoot,
860
- expectedPurpose: resume.purpose,
861
- direction: resume.direction,
862
- finish: resume.deferFinish !== true,
863
- validate: resume.validate,
864
- assertOwned: acquired.assertOwned
865
- });
866
- recovery = Object.freeze({
867
- transactionId: pending.transactionId,
868
- purpose: pending.purpose,
869
- direction: resume.direction ?? pendingState?.direction ?? "apply",
870
- transaction: pending
871
- });
872
- }
873
- mutationLock.assertOwned();
874
- const result = await mutate(mutationLock);
875
- mutationLock.assertOwned();
876
- await finishEpoch(true);
877
- return result;
878
- } catch (error) {
879
- try {
880
- await finishEpoch(false);
881
- } catch (finishError) {
882
- throw new AggregateError([error, finishError], "knowledge mutation failed and its durable state could not be inspected");
883
- }
884
- throw error;
885
- }
886
- });
826
+ return await runOwnedMutation(resolvedRoot, cacheDir, acquired, options, mutate);
887
827
  } finally {
888
- scope.active = false;
889
828
  await acquired.release();
890
829
  }
891
830
  });
892
831
  }
832
+ /**
833
+ * Run `body` inside this package's mutation scope for `root`, on a lock the caller already holds.
834
+ *
835
+ * The caller owns acquiring and releasing that lock; this package owns the scope, the file
836
+ * transaction it opens, and the epoch a concurrent reader watches. Inside `body`, every
837
+ * lock-taking function in this package sees the root as held and runs inline, which is what makes
838
+ * a consumer's own read-modify-write composable with this package instead of exclusive of it.
839
+ *
840
+ * The hold is asked `assertOwned()` at the same points a lock this package acquired is asked, so
841
+ * an externally held lock carries the same guarantee and not a weaker one. Entering a scope for a
842
+ * lock the caller does not actually hold is the one way to defeat the store's single-writer rule;
843
+ * the hold is required, rather than assumed, so that is a statement the caller has to make.
844
+ */
845
+ async function runInKnowledgeMutationScope(root, hold, body, options = {}) {
846
+ const resolvedRoot = resolve(root);
847
+ const existing = activeRoots.getStore()?.get(resolvedRoot);
848
+ if (existing?.active) return await runInlineMutation(existing.lock, body);
849
+ return withSafeDirectory(resolvedRoot, ".agent-knowledge", true, (cacheDir) => runOwnedMutation(resolvedRoot, cacheDir, hold, options, body));
850
+ }
851
+ /** The reentrant path: the root is already held in this async context, so no lock is taken. */
852
+ async function runInlineMutation(lock, mutate) {
853
+ lock.assertOwned();
854
+ const result = await mutate(lock);
855
+ lock.assertOwned();
856
+ return result;
857
+ }
858
+ /** The owning path, shared by a lock this package acquired and a lock the caller supplies. */
859
+ async function runOwnedMutation(resolvedRoot, cacheDir, hold, options, mutate) {
860
+ let recovery;
861
+ const mutationLock = {
862
+ transactionRoot: join(cacheDir, "file-transactions"),
863
+ get recovery() {
864
+ return recovery;
865
+ },
866
+ assertOwned: () => hold.assertOwned()
867
+ };
868
+ const scope = {
869
+ active: true,
870
+ lock: mutationLock
871
+ };
872
+ try {
873
+ const pendingState = await inspectKnowledgeFileTransaction({
874
+ root: resolvedRoot,
875
+ transactionRoot: mutationLock.transactionRoot
876
+ });
877
+ const pending = pendingState?.transaction ?? null;
878
+ const resume = pending ? assertKnowledgeTransactionResume(pending, options.resumeTransaction) : void 0;
879
+ const locks = new Map(activeRoots.getStore());
880
+ locks.set(resolvedRoot, scope);
881
+ return await activeRoots.run(locks, async () => {
882
+ const epoch = await beginMutationEpoch(cacheDir);
883
+ const finishEpoch = async (completed) => {
884
+ mutationLock.assertOwned();
885
+ const stillPending = await loadKnowledgeFileTransaction({
886
+ root: resolvedRoot,
887
+ transactionRoot: mutationLock.transactionRoot
888
+ });
889
+ if (completed && stillPending) throw new Error("knowledge mutation returned with an unfinished transaction");
890
+ if (!stillPending) await finishMutationEpoch(cacheDir, epoch);
891
+ };
892
+ try {
893
+ if (pending) {
894
+ if (!resume) throw new Error(`knowledge transaction '${pending.purpose}' requires its owner to resume`);
895
+ await recoverKnowledgeFileTransaction({
896
+ root: resolvedRoot,
897
+ transactionRoot: mutationLock.transactionRoot,
898
+ expectedPurpose: resume.purpose,
899
+ direction: resume.direction,
900
+ finish: resume.deferFinish !== true,
901
+ validate: resume.validate,
902
+ assertOwned: mutationLock.assertOwned
903
+ });
904
+ recovery = Object.freeze({
905
+ transactionId: pending.transactionId,
906
+ purpose: pending.purpose,
907
+ direction: resume.direction ?? pendingState?.direction ?? "apply",
908
+ transaction: pending
909
+ });
910
+ }
911
+ mutationLock.assertOwned();
912
+ const result = await mutate(mutationLock);
913
+ mutationLock.assertOwned();
914
+ await finishEpoch(true);
915
+ return result;
916
+ } catch (error) {
917
+ try {
918
+ await finishEpoch(false);
919
+ } catch (finishError) {
920
+ throw new AggregateError([error, finishError], "knowledge mutation failed and its durable state could not be inspected");
921
+ }
922
+ throw error;
923
+ }
924
+ });
925
+ } finally {
926
+ scope.active = false;
927
+ }
928
+ }
893
929
  async function inspectPendingKnowledgeMutation(root) {
894
930
  const resolvedRoot = resolve(root);
895
931
  const pending = await inspectKnowledgeFileTransaction({
@@ -1146,8 +1182,23 @@ function stringNeedsJsonEncoding(value) {
1146
1182
  if (value === "true" || value === "false" || /^-?\d+(?:\.\d+)?$/.test(value)) return true;
1147
1183
  return /^[[{"']/.test(value) || /["']$/.test(value);
1148
1184
  }
1185
+ /**
1186
+ * Strip a MATCHED surrounding quote pair, and nothing else.
1187
+ *
1188
+ * The previous rule stripped a leading or a trailing quote independently, so a bare scalar that
1189
+ * merely ended in one lost its last character: `check: python3 -c "print(1)"` read back as
1190
+ * `python3 -c "print(1)` — an unterminated shell quote that no longer runs. Measured on one
1191
+ * corpus, 1,378 of 3,655 pages carried that shape, 1,376 of them in a `check` field.
1192
+ *
1193
+ * `formatYamlScalar` already refuses to WRITE the shape (`stringNeedsJsonEncoding` returns true
1194
+ * for a value matching /["']$/), so no page this writer produced was ever affected; the loss fell
1195
+ * on frontmatter written by any other hand.
1196
+ */
1149
1197
  function unquote(value) {
1150
- return value.replace(/^['"]|['"]$/g, "");
1198
+ if (value.length < 2) return value;
1199
+ const first = value[0];
1200
+ if ((first === "\"" || first === "'") && value.endsWith(first)) return value.slice(1, -1);
1201
+ return value;
1151
1202
  }
1152
1203
  //#endregion
1153
1204
  //#region src/claim-ledger.ts
@@ -2811,7 +2862,7 @@ const NO_CHECK_NOTE = "a claim at this rung asserts that a command reproduces a
2811
2862
  const NO_EXPECTATION_NOTE = "exit code alone cannot verify a claim at this rung — record the value the check must print";
2812
2863
  const CONSTANT_EMITTER_NOTE = "the check is a constant emitter: it prints a fixed string and exits zero whatever the claim describes, so it can never fail — record a command that reads the artifact the claim is about";
2813
2864
  const MULTILINE_EXPECTATION_NOTE = "the expected value spans multiple lines, but the grader performs one contiguous-substring comparison — record one decisive single-line value per claim";
2814
- const MULTI_VALUE_EXPECTATION_NOTE = "the expected value carries three or more key=value tokens, so any extra token in the check output breaks an otherwise correct claim — record one decisive value per claim";
2865
+ const SELF_CERTIFYING_NOTE = "the check text contains the expected value, so the check carries the answer it is graded against and prints a value the claim did not have to produce — record a command that reads the artifact and prints the value it finds there";
2815
2866
  const LONG_FIRST_WORD_NOTE = "the check begins with a shell word longer than 200 characters; this is the escaped-newline failure shape where \\n text was recorded instead of real line breaks — write the script to a file or record a real heredoc and a short invocation";
2816
2867
  const INVALID_SHELL_SYNTAX_NOTE = "the recorded check does not parse under bash and would fail independently of the claim — record the exact command only after bash -n accepts it";
2817
2868
  /**
@@ -2841,28 +2892,56 @@ var UncheckableClaimError = class extends Error {
2841
2892
  * `gradeFor` grades `uncheckable`: no check, a check that cannot fail, an unusable expectation,
2842
2893
  * or the escaped-newline command shape. Below the threshold nothing is refused.
2843
2894
  *
2844
- * Four additional rules are calibrated on downstream losses, not taste: four correct claims died
2845
- * from multiline expectations, two from brittle multi-value expectations, one campaign recorded
2846
- * an enormous first word made of literal `\\n` sequences, and a 299-run fleet autopsy reduced ten
2847
- * reported grader failures to checks that were never executed before their authors disappeared.
2848
- * The dynamic half of that last rule is `verifyGradeableEvidence` below.
2895
+ * Three additional rules are calibrated on downstream losses, not taste: four correct claims
2896
+ * died from multiline expectations, one campaign recorded an enormous first word made of literal
2897
+ * `\\n` sequences, and a 299-run fleet autopsy reduced ten reported grader failures to checks that
2898
+ * were never executed before their authors disappeared. The dynamic half of that last rule is
2899
+ * `verifyGradeableEvidence` below.
2849
2900
  */
2850
2901
  function assertGradeableEvidence(evidence) {
2851
2902
  if (evidence.rung < 4) return evidence;
2852
- const note = checkRefusalNote(evidence.check) ?? expectationRefusalNote(evidence.expect);
2903
+ const note = checkRefusalNote(evidence.check) ?? selfCertifyingNote(evidence) ?? expectationRefusalNote(evidence.expect);
2853
2904
  if (note) throw new UncheckableClaimError(evidence.rung, note);
2854
2905
  return evidence;
2855
2906
  }
2856
- /** The error signatures that mean the check could not run, as opposed to ran and failed. */
2857
- const UNRUNNABLE_SIGNATURES = /No such file|FileNotFoundError|ModuleNotFoundError|command not found|ENOENT|AbortError|timed out|ERR_CHILD_PROCESS_STDIO_MAXBUFFER/;
2907
+ /**
2908
+ * The output signatures that mean the check never reached what the claim is about.
2909
+ *
2910
+ * Matched case-insensitively, because a tool that prints its own diagnostic chooses its own case,
2911
+ * and read from the OUTPUT rather than from the exit status. A shell pipeline exits with the
2912
+ * status of its last stage, so `sha256sum <missing path> | cut -d' ' -f1` prints
2913
+ * "No such file or directory" and exits 0; reading only the status calls that a refutation of
2914
+ * research that was never run. Swept over 272 grade files, 29 of 61 recorded refutations were
2915
+ * this shape: 7 a malformed check body, 7 a shell that could not parse the check, 6 a solver that
2916
+ * could not open its problem file, 5 `Permission denied`, 4 `cannot create directory`.
2917
+ */
2918
+ const UNRUNNABLE_SIGNATURES = /No such file|FileNotFoundError|ModuleNotFoundError|command not found|ENOENT|AbortError|timed out|ERR_CHILD_PROCESS_STDIO_MAXBUFFER|Permission denied|EACCES|cannot create directory|cannot open|SyntaxError|unexpected EOF while looking for matching|syntax error near unexpected token/i;
2919
+ /**
2920
+ * The exit status a deadline kill reports: `timeout(1)`'s status, and the one a bounded process
2921
+ * runner forces so a killed child that closes with 0 cannot read as a pass. A grader that has
2922
+ * only an exit status reports this one; a grader that knows it killed the process sets
2923
+ * `CheckExecution.timedOut` instead, which is unambiguous.
2924
+ */
2925
+ const DEADLINE_EXIT_CODE = 124;
2926
+ const DEADLINE_NOTE = "the check was killed at its deadline, so it never tested the claim — a deadline is a budget, not a verdict; raise the budget or record a check that decides within it";
2927
+ const UNREACHED_INPUT_NOTE = "the check never reached what the claim is about, so this is a verdict on the environment and not on the claim";
2858
2928
  /**
2859
2929
  * The calibrated verdict function, pure so every grader shares one semantics. Callers execute the
2860
2930
  * check however their environment requires and pass the observation; this function only judges.
2931
+ *
2932
+ * Three rules decide a verdict before the expectation is compared, and each one exists because
2933
+ * comparing first blamed the claim for something the claim did not do:
2934
+ *
2935
+ * - a check that carries its own expected value is refused, because its output is authored
2936
+ * rather than measured;
2937
+ * - a check killed at its deadline is `unrunnable`, because a budget is not a verdict;
2938
+ * - a check whose output says it never reached its input is `unrunnable` whatever its exit
2939
+ * status, because a pipeline hides the failing stage's status behind its last stage.
2861
2940
  */
2862
2941
  function gradeFor(evidence, execution) {
2863
2942
  const mustBeCheckable = evidence.rung >= 4;
2864
2943
  if (mustBeCheckable) {
2865
- const note = checkRefusalNote(evidence.check);
2944
+ const note = checkRefusalNote(evidence.check) ?? selfCertifyingNote(evidence);
2866
2945
  if (note) return {
2867
2946
  verdict: "uncheckable",
2868
2947
  note
@@ -2870,7 +2949,11 @@ function gradeFor(evidence, execution) {
2870
2949
  }
2871
2950
  if (!execution) return { verdict: "unrunnable" };
2872
2951
  const output = `${execution.stdout}\n${execution.stderr}`.trim();
2873
- if (execution.exitCode !== 0) return { verdict: UNRUNNABLE_SIGNATURES.test(output) ? "unrunnable" : "contradicted" };
2952
+ if (execution.timedOut || execution.exitCode === 124) return {
2953
+ verdict: "unrunnable",
2954
+ note: DEADLINE_NOTE
2955
+ };
2956
+ if (execution.exitCode !== 0) return refutation(output, evidence.expect);
2874
2957
  if (mustBeCheckable) {
2875
2958
  const note = expectationRefusalNote(evidence.expect);
2876
2959
  if (note) return {
@@ -2878,9 +2961,88 @@ function gradeFor(evidence, execution) {
2878
2961
  note
2879
2962
  };
2880
2963
  }
2881
- if (evidence.expect && !output.includes(evidence.expect)) return { verdict: output === "" ? "silent-check" : "contradicted" };
2964
+ if (evidence.expect && !output.includes(evidence.expect)) {
2965
+ if (output === "") return { verdict: "silent-check" };
2966
+ return refutation(output, evidence.expect);
2967
+ }
2882
2968
  return { verdict: "verified" };
2883
2969
  }
2970
+ /**
2971
+ * Decide between a claim verdict and an environment verdict for output that failed to establish
2972
+ * the claim. The signature list only ever downgrades a refutation to `unrunnable`: it can turn a
2973
+ * measurement that did not happen into an honest "not measured", and it can never turn a real
2974
+ * failure into a pass.
2975
+ *
2976
+ * The expectation is consulted first. A claim that PREDICTED the error is genuinely contradicted
2977
+ * when the error does not appear, so an expectation naming a signature switches this guard off
2978
+ * for that claim rather than letting it hide the one case it would grade backwards.
2979
+ */
2980
+ function refutation(output, expect) {
2981
+ if (expect && UNRUNNABLE_SIGNATURES.test(expect)) return { verdict: "contradicted" };
2982
+ const hit = UNRUNNABLE_SIGNATURES.exec(output);
2983
+ if (!hit) return { verdict: "contradicted" };
2984
+ return {
2985
+ verdict: "unrunnable",
2986
+ note: `${UNREACHED_INPUT_NOTE} (${hit[0]})`
2987
+ };
2988
+ }
2989
+ /**
2990
+ * Grade one pass of claims and flag the repeats within it.
2991
+ *
2992
+ * `gradeFor` judges one claim and cannot see a second claim carrying the same check, so a run
2993
+ * that recorded one verification under several titles reports as several independent
2994
+ * verifications. This function grades each claim exactly as `gradeFor` does and marks the later
2995
+ * claim with `duplicateOf`, leaving the verdict and the count untouched: the flag is for a reader
2996
+ * deciding how much evidence a run really produced.
2997
+ */
2998
+ function gradeClaims(claims) {
2999
+ const firstSeen = /* @__PURE__ */ new Map();
3000
+ return claims.map((claim) => {
3001
+ const grade = gradeFor(claim.evidence, claim.execution);
3002
+ const key = claimCheckKey({
3003
+ ...claim.evidence,
3004
+ title: claim.title
3005
+ });
3006
+ if (!key) return {
3007
+ id: claim.id,
3008
+ ...grade
3009
+ };
3010
+ const seenAt = `${key}\u0000${grade.verdict}`;
3011
+ const canonical = firstSeen.get(seenAt);
3012
+ if (canonical === void 0) {
3013
+ firstSeen.set(seenAt, claim.id);
3014
+ return {
3015
+ id: claim.id,
3016
+ ...grade
3017
+ };
3018
+ }
3019
+ return {
3020
+ id: claim.id,
3021
+ ...grade,
3022
+ duplicateOf: canonical
3023
+ };
3024
+ });
3025
+ }
3026
+ /**
3027
+ * The identity two claims must share to be one verification counted twice: the same command, the
3028
+ * same expectation, and the same sentence. A check shared across claims that say different things
3029
+ * is one instrument used several times, which is not a duplicate.
3030
+ *
3031
+ * Returns `undefined` when the claim cannot be keyed at all — no check, or no title to compare —
3032
+ * so an unkeyable claim is never flagged as a repeat of another unkeyable one. The key is JSON
3033
+ * rather than a joined string, so no separator can collide with text inside a check.
3034
+ */
3035
+ function claimCheckKey(claim) {
3036
+ const check = claim.check?.trim();
3037
+ if (!check) return void 0;
3038
+ const title = claim.title?.trim().replace(/\s+/g, " ").toLowerCase().replace(/\.md$/, "");
3039
+ if (!title) return void 0;
3040
+ return JSON.stringify([
3041
+ check,
3042
+ claim.expect?.trim() ?? "",
3043
+ title
3044
+ ]);
3045
+ }
2884
3046
  /** The verdict alone, for graders that report a lattice member and not a reason. */
2885
3047
  function verdictFor(evidence, execution) {
2886
3048
  return gradeFor(evidence, execution).verdict;
@@ -2914,6 +3076,35 @@ async function verifyGradeableEvidence(evidence, options) {
2914
3076
  grade: gradeFor(accepted, execution)
2915
3077
  };
2916
3078
  }
3079
+ const WORD_CHARACTER = /[A-Za-z0-9_]/;
3080
+ /**
3081
+ * Whether the check text carries the value it is graded against.
3082
+ *
3083
+ * A check that contains its own expectation prints a value the claim's subject did not have to
3084
+ * produce, so the comparison that follows tests the author's typing rather than the artifact.
3085
+ * The test is the whole trimmed expectation appearing verbatim in the command, which is narrow
3086
+ * on purpose: it costs an author only a rewrite of the command, and it catches the shape
3087
+ * `isConstantEmitter` cannot, where a real command's arguments already spell the answer.
3088
+ *
3089
+ * An occurrence glued to a word character on a side where the expectation is itself a word
3090
+ * character does not count. Without that, a short expectation refuses the check that reads it:
3091
+ * `expect: 6` appears inside `node report6.mjs`, and refusing a correct claim is the cost this
3092
+ * file's rules are calibrated to avoid.
3093
+ */
3094
+ function selfCertifyingNote(evidence) {
3095
+ const wanted = evidence.expect?.trim();
3096
+ const check = evidence.check;
3097
+ if (!check || !wanted) return void 0;
3098
+ const startsInsideWord = WORD_CHARACTER.test(wanted[0]);
3099
+ const endsInsideWord = WORD_CHARACTER.test(wanted[wanted.length - 1]);
3100
+ for (let at = check.indexOf(wanted); at !== -1; at = check.indexOf(wanted, at + 1)) {
3101
+ const before = check[at - 1];
3102
+ const after = check[at + wanted.length];
3103
+ if (startsInsideWord && before !== void 0 && WORD_CHARACTER.test(before)) continue;
3104
+ if (endsInsideWord && after !== void 0 && WORD_CHARACTER.test(after)) continue;
3105
+ return SELF_CERTIFYING_NOTE;
3106
+ }
3107
+ }
2917
3108
  function checkRefusalNote(check) {
2918
3109
  if (!check) return NO_CHECK_NOTE;
2919
3110
  if (isConstantEmitter(check)) return CONSTANT_EMITTER_NOTE;
@@ -2922,7 +3113,6 @@ function checkRefusalNote(check) {
2922
3113
  function expectationRefusalNote(expect) {
2923
3114
  if (!expect?.trim()) return NO_EXPECTATION_NOTE;
2924
3115
  if (expect.includes("\n") || expect.includes("\r")) return MULTILINE_EXPECTATION_NOTE;
2925
- if (expect.trim().split(/\s+/).filter((token) => token.includes("=")).length >= 3) return MULTI_VALUE_EXPECTATION_NOTE;
2926
3116
  }
2927
3117
  async function runBash(args, options) {
2928
3118
  const { execFile } = await import("node:child_process");
@@ -2936,10 +3126,12 @@ async function runBash(args, options) {
2936
3126
  encoding: "utf8"
2937
3127
  }, (error, stdout, stderr) => {
2938
3128
  const diagnostic = error && typeof error.code !== "number" ? `${stderr}\n${error}` : stderr;
3129
+ const timedOut = error?.killed === true && error.name !== "AbortError";
2939
3130
  resolve({
2940
3131
  exitCode: typeof error?.code === "number" ? error.code : error ? 127 : 0,
2941
3132
  stdout: String(stdout ?? ""),
2942
- stderr: String(diagnostic ?? "")
3133
+ stderr: String(diagnostic ?? ""),
3134
+ ...timedOut ? { timedOut: true } : {}
2943
3135
  });
2944
3136
  });
2945
3137
  });
@@ -3794,6 +3986,6 @@ function explainKnowledgeTarget(index, target) {
3794
3986
  };
3795
3987
  }
3796
3988
  //#endregion
3797
- export { resolveKnowledgeCitations as $, withKnowledgeRead as $t, sourceRegistryPath as A, KNOWLEDGE_EVENT_TYPES as At, buildKnowledgeGraph as B, emptyClaimLedger as Bt, verifyGradeableEvidence as C, writeFileDurableWithinRoot as Cn, KnowledgeRelationSchema as Ct, addSourceText as D, textSourceAdapter as Dn, ResearchSourceVersionSchema as Dt, addSourcePath as E, mediaTypeFor$1 as En, ResearchClaimRecordSchema as Et, KB_EVENTS_PATH as F, assertTrackedClaimIntegrity as Ft, assertKnowledgeCitationAudit as G, normalizeClaimText as Gt, KnowledgeCitationAuditError as H, materializeRegisteredClaimEvidence as Ht, KB_INDEX_PATH as I, claimEvidenceId as It, auditCurrentRunCitations as J, parseFrontmatter as Jt, assertKnowledgeCitationsResolved as K, researchSourceVersionKey as Kt, KB_STORE_DIR as L, claimId as Lt, ClaimLedgerMigrationRequiredError as M, assertDeepQuestionIntegrity as Mt, FileSystemKbStore as N, assertResearchClaimEvidenceIntegrity as Nt, loadSourceRegistry as O, SourceAnchorSchema as Ot, KB_CLAIM_LEDGER_DIR as P, assertResearchClaimLedgerIntegrity as Pt, resolveKnowledgeCitation as Q, withKnowledgeMutation as Qt, MemoryKbStore as R, claimSourceHost as Rt, verdictFor as S, writeFileDurable as Sn, KnowledgeRelationNodeSchema as St, writeKnowledgeIndex as T, writeJsonDurableWithinRoot as Tn, ResearchClaimLedgerSchema as Tt, KnowledgeCitationResolutionError as U, mergeClaimLedgers as Ut, knowledgePageRelations as V, linkClaimContradictions as Vt, assertCurrentRunCitationsResolved as W, mergeTrackedClaims as Wt, formatKnowledgeCitationReference as X, inspectPendingKnowledgeMutation as Xt, auditKnowledgeCitations as Y, acquireDurableFileLock as Yt, parseKnowledgeCitationReference as Z, recoverPendingKnowledgeMutation as Zt, lintKnowledgeIndex as _, removeDurable as _n, KnowledgeGraphNodeSchema as _t, applyKnowledgeWriteBlocksFile as a, prepareKnowledgeFileTransaction as an, isScaffoldPath as at, assertGradeableEvidence as b, withSafeDescendant as bn, KnowledgePageSchema as bt, KnowledgeDuplicateIntakeError as c, normalizePagesDirectory as cn, loadKnowledgePages as ct, createFileRunLineageAuthority as d, isKernelAnchoredPath as dn, extractWikilinks as dt, applyKnowledgeFileTransaction as en, resolveRunScopedCitation as et, createRunScopedStores as f, isMissingFile as fn, normalizeLinkTarget as ft, validateKnowledgeIndex as g, relativeWithinRoot as gn, KnowledgeGraphEdgeSchema as gt, normalizePageText as h, readRegularFileWithinRoot as hn, KnowledgeEventSchema as ht, applyKnowledgeWriteBlocks as i, knowledgeFileTransactionPlanHash as in, isKnowledgePagePath as it, writeSourceRegistry as j, ClaimLedgerGoalConflictError as jt, snapshotSourceTextInput as k, SourceRecordSchema as kt, assertKnowledgeWriteIntake as l, canonicalPathsEqual as ln, writeJson as lt, detectNearDuplicatePages as m, readRegularFileNoFollow as mn, KnowledgeBaseCandidateSchema as mt, inspectKnowledgeIndex as n, commitKnowledgeFileMutations as nn, SCAFFOLD_PAGE_BASENAMES as nt, isSafeKnowledgePath as o, rollbackKnowledgeFileTransaction as on, knowledgePageFromMarkdown as ot, originatedPages as p, listRegularFilesWithinRoot as pn, DeepQuestionSchema as pt, assertRunScopedCitationsResolved as q, formatFrontmatter as qt, stringMetadata as r, finishKnowledgeFileTransaction as rn, initKnowledgeBase as rt, parseKnowledgeWriteBlocks as s, DEFAULT_PAGES_DIRECTORY as sn, layoutFor as st, explainKnowledgeTarget as t, assertKnowledgeMutationPath as tn, resolveRunScopedCitations as tt, RUN_LINEAGE_BASENAME as u, canonicalRelativeWithinRoot as un, WIKILINK_REGEX as ut, CHECKABLE_RUNG_THRESHOLD as v, renameDurable as vn, KnowledgeIndexSchema as vt, buildKnowledgeIndex as w, writeJsonDurable as wn, ResearchClaimEvidenceSchema as wt, gradeFor as x, withSafeDirectory as xn, KnowledgeRelationGraphSchema as xt, UncheckableClaimError as y, syncDirectory as yn, KnowledgePageInvalidationSchema as yt, assertClaimLedgerId as z, deepQuestionId as zt };
3989
+ export { formatKnowledgeCitationReference as $, inspectPendingKnowledgeMutation as $t, addSourceText as A, writeJsonDurableWithinRoot as An, ResearchSourceVersionSchema as At, KB_STORE_DIR as B, claimId as Bt, gradeClaims as C, renameDurable as Cn, KnowledgePageSchema as Ct, buildKnowledgeIndex as D, writeFileDurable as Dn, ResearchClaimEvidenceSchema as Dt, verifyGradeableEvidence as E, withSafeDirectory as En, KnowledgeRelationSchema as Et, ClaimLedgerMigrationRequiredError as F, assertDeepQuestionIntegrity as Ft, KnowledgeCitationAuditError as G, materializeRegisteredClaimEvidence as Gt, assertClaimLedgerId as H, deepQuestionId as Ht, FileSystemKbStore as I, assertResearchClaimEvidenceIntegrity as It, assertKnowledgeCitationAudit as J, normalizeClaimText as Jt, KnowledgeCitationResolutionError as K, mergeClaimLedgers as Kt, KB_CLAIM_LEDGER_DIR as L, assertResearchClaimLedgerIntegrity as Lt, snapshotSourceTextInput as M, textSourceAdapter as Mn, SourceRecordSchema as Mt, sourceRegistryPath as N, KNOWLEDGE_EVENT_TYPES as Nt, writeKnowledgeIndex as O, writeFileDurableWithinRoot as On, ResearchClaimLedgerSchema as Ot, writeSourceRegistry as P, ClaimLedgerGoalConflictError as Pt, auditKnowledgeCitations as Q, acquireDurableFileLock as Qt, KB_EVENTS_PATH as R, assertTrackedClaimIntegrity as Rt, claimCheckKey as S, removeDurable as Sn, KnowledgePageInvalidationSchema as St, verdictFor as T, withSafeDescendant as Tn, KnowledgeRelationNodeSchema as Tt, buildKnowledgeGraph as U, emptyClaimLedger as Ut, MemoryKbStore as V, claimSourceHost as Vt, knowledgePageRelations as W, linkClaimContradictions as Wt, assertRunScopedCitationsResolved as X, formatFrontmatter as Xt, assertKnowledgeCitationsResolved as Y, researchSourceVersionKey as Yt, auditCurrentRunCitations as Z, parseFrontmatter as Zt, lintKnowledgeIndex as _, isMissingFile as _n, KnowledgeBaseCandidateSchema as _t, applyKnowledgeWriteBlocksFile as a, applyKnowledgeFileTransaction as an, SCAFFOLD_PAGE_BASENAMES as at, UncheckableClaimError as b, readRegularFileWithinRoot as bn, KnowledgeGraphNodeSchema as bt, KnowledgeDuplicateIntakeError as c, finishKnowledgeFileTransaction as cn, isScaffoldPath as ct, createFileRunLineageAuthority as d, rollbackKnowledgeFileTransaction as dn, loadKnowledgePages as dt, isKnowledgeMutationHeld as en, parseKnowledgeCitationReference as et, createRunScopedStores as f, DEFAULT_PAGES_DIRECTORY as fn, writeJson as ft, validateKnowledgeIndex as g, isKernelAnchoredPath as gn, DeepQuestionSchema as gt, normalizePageText as h, canonicalRelativeWithinRoot as hn, normalizeLinkTarget as ht, applyKnowledgeWriteBlocks as i, withKnowledgeRead as in, resolveRunScopedCitations as it, loadSourceRegistry as j, mediaTypeFor$1 as jn, SourceAnchorSchema as jt, addSourcePath as k, writeJsonDurable as kn, ResearchClaimRecordSchema as kt, assertKnowledgeWriteIntake as l, knowledgeFileTransactionPlanHash as ln, knowledgePageFromMarkdown as lt, detectNearDuplicatePages as m, canonicalPathsEqual as mn, extractWikilinks as mt, inspectKnowledgeIndex as n, runInKnowledgeMutationScope as nn, resolveKnowledgeCitations as nt, isSafeKnowledgePath as o, assertKnowledgeMutationPath as on, initKnowledgeBase as ot, originatedPages as p, normalizePagesDirectory as pn, WIKILINK_REGEX as pt, assertCurrentRunCitationsResolved as q, mergeTrackedClaims as qt, stringMetadata as r, withKnowledgeMutation as rn, resolveRunScopedCitation as rt, parseKnowledgeWriteBlocks as s, commitKnowledgeFileMutations as sn, isKnowledgePagePath as st, explainKnowledgeTarget as t, recoverPendingKnowledgeMutation as tn, resolveKnowledgeCitation as tt, RUN_LINEAGE_BASENAME as u, prepareKnowledgeFileTransaction as un, layoutFor as ut, CHECKABLE_RUNG_THRESHOLD as v, listRegularFilesWithinRoot as vn, KnowledgeEventSchema as vt, gradeFor as w, syncDirectory as wn, KnowledgeRelationGraphSchema as wt, assertGradeableEvidence as x, relativeWithinRoot as xn, KnowledgeIndexSchema as xt, DEADLINE_EXIT_CODE as y, readRegularFileNoFollow as yn, KnowledgeGraphEdgeSchema as yt, KB_INDEX_PATH as z, claimEvidenceId as zt };
3798
3990
 
3799
- //# sourceMappingURL=inspect-yYqLQuM4.js.map
3991
+ //# sourceMappingURL=inspect-QU0p2LuS.js.map