@skein-code/cli 0.3.15 → 0.3.16

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/dist/cli.js CHANGED
@@ -220,7 +220,7 @@ function isSqliteBusy(error) {
220
220
  // package.json
221
221
  var package_default = {
222
222
  name: "@skein-code/cli",
223
- version: "0.3.15",
223
+ version: "0.3.16",
224
224
  description: "A context-first, model-agnostic coding agent with an auditable terminal workspace.",
225
225
  type: "module",
226
226
  license: "MIT",
@@ -236,6 +236,9 @@ var package_default = {
236
236
  },
237
237
  skein: {
238
238
  releaseNotes: [
239
+ "Duplication warnings now aggregate into the single completion receipt without changing verified status",
240
+ "Exact match ids support bounded, reason-coded suppression with audit and credential/code-block safeguards",
241
+ "Duplication audit tools are disclosed only when active warnings exist and repaired paths clear stale matches",
239
242
  "Warning-only TS/JS duplication audit compares new functions with the pre-write index generation",
240
243
  "Deterministic Type-1/2 and Type-3 receipts retain only hashes, locations, scores, and bounded counts",
241
244
  "Ordinary edits, renames, moves, deletions, small functions, tests, generated paths, and failed writes stay quiet",
@@ -5673,6 +5676,15 @@ var reuseReceiptSchema = z5.object({
5673
5676
  status: z5.enum(["warning", "skipped", "unresolved"]),
5674
5677
  warningOnly: z5.literal(true)
5675
5678
  }).strict();
5679
+ var duplicationMatchSchema = z5.object({
5680
+ matchId: z5.string().regex(/^[a-f0-9]{24}$/u).optional(),
5681
+ changedPath: z5.string(),
5682
+ changedSymbol: z5.string(),
5683
+ candidatePath: z5.string(),
5684
+ candidateSymbol: z5.string(),
5685
+ kind: z5.enum(["type-1-or-2", "type-3"]),
5686
+ similarity: z5.number().min(0).max(1)
5687
+ }).strict();
5676
5688
  var duplicationAuditSchema = z5.object({
5677
5689
  baselineGeneration: z5.string().min(1),
5678
5690
  changeSequence: z5.number().int().nonnegative(),
@@ -5680,16 +5692,16 @@ var duplicationAuditSchema = z5.object({
5680
5692
  warningOnly: z5.literal(true),
5681
5693
  checkedFunctions: z5.number().int().nonnegative(),
5682
5694
  skippedSmallFunctions: z5.number().int().nonnegative(),
5683
- matches: z5.array(z5.object({
5684
- changedPath: z5.string(),
5685
- changedSymbol: z5.string(),
5686
- candidatePath: z5.string(),
5687
- candidateSymbol: z5.string(),
5688
- kind: z5.enum(["type-1-or-2", "type-3"]),
5689
- similarity: z5.number().min(0).max(1)
5690
- }).strict()).max(8),
5695
+ matches: z5.array(duplicationMatchSchema).max(8),
5691
5696
  rationale: z5.string().max(500)
5692
5697
  }).strict();
5698
+ var duplicationSuppressionSchema = z5.object({
5699
+ matchId: z5.string().regex(/^[a-f0-9]{24}$/u),
5700
+ reasonCode: z5.enum(["separate-boundary", "protocol-required", "generated-contract", "false-positive", "other"]),
5701
+ reason: z5.string().min(12).max(240),
5702
+ createdAt: z5.string().datetime(),
5703
+ toolCallId: z5.string().min(1).max(512)
5704
+ }).strict();
5693
5705
  var auditMetadataSchema = z5.record(z5.string(), z5.unknown()).superRefine((metadata, ctx) => {
5694
5706
  const receipt = metadata.reuseReceipt;
5695
5707
  if (receipt !== void 0 && !reuseReceiptSchema.safeParse(receipt).success) {
@@ -5699,6 +5711,14 @@ var auditMetadataSchema = z5.record(z5.string(), z5.unknown()).superRefine((meta
5699
5711
  if (duplication !== void 0 && !duplicationAuditSchema.safeParse(duplication).success) {
5700
5712
  ctx.addIssue({ code: "custom", message: "Invalid duplication audit receipt" });
5701
5713
  }
5714
+ const suppression = metadata.duplicationSuppression;
5715
+ if (suppression !== void 0 && !duplicationSuppressionSchema.safeParse(suppression).success) {
5716
+ ctx.addIssue({ code: "custom", message: "Invalid duplication suppression receipt" });
5717
+ }
5718
+ const activeMatches = metadata.activeDuplicationMatches;
5719
+ if (activeMatches !== void 0 && !z5.array(z5.string().regex(/^[a-f0-9]{24}$/u)).max(8).safeParse(activeMatches).success) {
5720
+ ctx.addIssue({ code: "custom", message: "Invalid active duplication matches" });
5721
+ }
5702
5722
  });
5703
5723
  var auditSchema = z5.object({
5704
5724
  id: z5.string(),
@@ -5738,6 +5758,16 @@ var lastRunSchema = z5.object({
5738
5758
  checks: z5.array(verificationEvidenceSchema),
5739
5759
  detail: z5.string(),
5740
5760
  mutationTracking: z5.enum(["complete", "unknown"]).optional(),
5761
+ duplication: z5.object({
5762
+ enforcement: z5.literal("warning"),
5763
+ status: z5.enum(["clear", "warning", "unresolved", "suppressed"]),
5764
+ warningCount: z5.number().int().nonnegative(),
5765
+ unresolvedCount: z5.number().int().nonnegative(),
5766
+ suppressedCount: z5.number().int().nonnegative(),
5767
+ matches: z5.array(duplicationMatchSchema.extend({
5768
+ matchId: z5.string().regex(/^[a-f0-9]{24}$/u)
5769
+ })).max(8)
5770
+ }).strict().optional(),
5741
5771
  acceptance: z5.object({
5742
5772
  state: z5.enum(["draft", "active", "satisfied", "blocked"]),
5743
5773
  total: z5.number().int().nonnegative(),
@@ -5803,6 +5833,7 @@ var sessionSchema = z5.object({
5803
5833
  contextSources: z5.array(contextSourceSchema).max(64).optional(),
5804
5834
  toolArtifacts: z5.array(toolArtifactSchema).max(200).optional(),
5805
5835
  taskContract: taskContractSchema.optional(),
5836
+ duplicationSuppressions: z5.array(duplicationSuppressionSchema).max(64).optional(),
5806
5837
  lastRun: lastRunSchema.optional(),
5807
5838
  usage: z5.object({
5808
5839
  inputTokens: z5.number().nonnegative(),
@@ -8332,7 +8363,7 @@ function captureVerification(call, result, changeSequence, configuredCommands) {
8332
8363
  commandKey: createHash11("sha256").update(normalized).digest("hex")
8333
8364
  };
8334
8365
  }
8335
- function buildRunCompletion(changedFiles, evidence, currentChangeSequence, mutationTracking = "complete", taskContract, audit = []) {
8366
+ function buildRunCompletion(changedFiles, evidence, currentChangeSequence, mutationTracking = "complete", taskContract, audit = [], duplication) {
8336
8367
  const files = [...new Set(changedFiles)];
8337
8368
  const acceptance = taskContract ? buildAcceptance(taskContract, audit, evidence, currentChangeSequence) : void 0;
8338
8369
  if (mutationTracking === "unknown") {
@@ -8342,6 +8373,7 @@ function buildRunCompletion(changedFiles, evidence, currentChangeSequence, mutat
8342
8373
  checks: [],
8343
8374
  detail: files.length ? `Workspace changes were observed, but a dynamic shell command prevented complete mutation tracking for ${fileCount(files.length)}.` : "A dynamic shell command may have changed workspace files, but reliable mutation tracking was unavailable.",
8344
8375
  mutationTracking,
8376
+ ...duplication ? { duplication } : {},
8345
8377
  ...acceptance ? { acceptance: acceptanceForCompletion(acceptance, "unverified") } : {}
8346
8378
  };
8347
8379
  }
@@ -8352,7 +8384,8 @@ function buildRunCompletion(changedFiles, evidence, currentChangeSequence, mutat
8352
8384
  changedFiles: [],
8353
8385
  checks: [],
8354
8386
  detail: acceptanceDetail(acceptance),
8355
- acceptance: acceptanceForCompletion(acceptance, "unverified")
8387
+ acceptance: acceptanceForCompletion(acceptance, "unverified"),
8388
+ ...duplication ? { duplication } : {}
8356
8389
  };
8357
8390
  }
8358
8391
  return {
@@ -8360,7 +8393,8 @@ function buildRunCompletion(changedFiles, evidence, currentChangeSequence, mutat
8360
8393
  changedFiles: [],
8361
8394
  checks: [],
8362
8395
  detail: "No workspace files changed in this run.",
8363
- ...acceptance ? { acceptance: acceptanceForCompletion(acceptance, "no_changes") } : {}
8396
+ ...acceptance ? { acceptance: acceptanceForCompletion(acceptance, "no_changes") } : {},
8397
+ ...duplication ? { duplication } : {}
8364
8398
  };
8365
8399
  }
8366
8400
  const latestByCommand = /* @__PURE__ */ new Map();
@@ -8376,7 +8410,8 @@ function buildRunCompletion(changedFiles, evidence, currentChangeSequence, mutat
8376
8410
  changedFiles: files,
8377
8411
  checks,
8378
8412
  detail: `No successful verification was recorded after the last change to ${fileCount(files.length)}.`,
8379
- ...acceptance ? { acceptance: acceptanceForCompletion(acceptance, "unverified") } : {}
8413
+ ...acceptance ? { acceptance: acceptanceForCompletion(acceptance, "unverified") } : {},
8414
+ ...duplication ? { duplication } : {}
8380
8415
  };
8381
8416
  }
8382
8417
  const failures = checks.filter((check) => !check.ok);
@@ -8386,7 +8421,8 @@ function buildRunCompletion(changedFiles, evidence, currentChangeSequence, mutat
8386
8421
  changedFiles: files,
8387
8422
  checks,
8388
8423
  detail: `${failures.length} of ${checks.length} current verification ${checks.length === 1 ? "check" : "checks"} failed.`,
8389
- ...acceptance ? { acceptance: acceptanceForCompletion(acceptance, "verification_failed") } : {}
8424
+ ...acceptance ? { acceptance: acceptanceForCompletion(acceptance, "verification_failed") } : {},
8425
+ ...duplication ? { duplication } : {}
8390
8426
  };
8391
8427
  }
8392
8428
  if (acceptance && acceptanceUnresolved(acceptance)) {
@@ -8395,7 +8431,8 @@ function buildRunCompletion(changedFiles, evidence, currentChangeSequence, mutat
8395
8431
  changedFiles: files,
8396
8432
  checks,
8397
8433
  detail: acceptanceDetail(acceptance),
8398
- acceptance: acceptanceForCompletion(acceptance, "unverified")
8434
+ acceptance: acceptanceForCompletion(acceptance, "unverified"),
8435
+ ...duplication ? { duplication } : {}
8399
8436
  };
8400
8437
  }
8401
8438
  return {
@@ -8403,7 +8440,8 @@ function buildRunCompletion(changedFiles, evidence, currentChangeSequence, mutat
8403
8440
  changedFiles: files,
8404
8441
  checks,
8405
8442
  detail: `${checks.length} current verification ${checks.length === 1 ? "check" : "checks"} passed for ${fileCount(files.length)}.`,
8406
- ...acceptance ? { acceptance: acceptanceForCompletion(acceptance, "verified") } : {}
8443
+ ...acceptance ? { acceptance: acceptanceForCompletion(acceptance, "verified") } : {},
8444
+ ...duplication ? { duplication } : {}
8407
8445
  };
8408
8446
  }
8409
8447
  function completionRecoveryDirective(completion) {
@@ -8815,6 +8853,139 @@ function render(memory) {
8815
8853
  ].join("\n");
8816
8854
  }
8817
8855
 
8856
+ // src/tools/duplication.ts
8857
+ import { z as z17 } from "zod";
8858
+
8859
+ // src/agent/duplication-state.ts
8860
+ function buildDuplicationCompletion(audit, suppressions = [], runStartedAt) {
8861
+ const active = /* @__PURE__ */ new Map();
8862
+ const unresolved2 = /* @__PURE__ */ new Map();
8863
+ let sawCurrentReceipt = false;
8864
+ for (const event of audit) {
8865
+ if (runStartedAt && event.createdAt < runStartedAt) continue;
8866
+ const receipt = duplicationReceipt(event.metadata?.duplicationAudit);
8867
+ if (!receipt) continue;
8868
+ if (receipt.status === "clear" || receipt.status === "unresolved" || receipt.matches.some((match) => typeof match.matchId === "string")) sawCurrentReceipt = true;
8869
+ const changedPaths2 = changedPathsFor(event, receipt);
8870
+ for (const path of changedPaths2) {
8871
+ for (const [id, match] of active) if (match.changedPath === path) active.delete(id);
8872
+ unresolved2.delete(path);
8873
+ }
8874
+ if (receipt.status === "unresolved") {
8875
+ for (const path of changedPaths2) unresolved2.set(path, receipt.changeSequence);
8876
+ }
8877
+ for (const match of receipt.matches) {
8878
+ if (typeof match.matchId === "string") {
8879
+ active.set(match.matchId, match);
8880
+ }
8881
+ }
8882
+ }
8883
+ if (!active.size && !unresolved2.size && !sawCurrentReceipt) return void 0;
8884
+ const activeIds = new Set(active.keys());
8885
+ const suppressedIds = new Set(suppressions.filter((item) => activeIds.has(item.matchId)).map((item) => item.matchId));
8886
+ const warnings = [...active.values()].filter((match) => !suppressedIds.has(match.matchId));
8887
+ const suppressedCount = active.size - warnings.length;
8888
+ return {
8889
+ enforcement: "warning",
8890
+ status: unresolved2.size ? "unresolved" : warnings.length ? "warning" : suppressedCount ? "suppressed" : "clear",
8891
+ warningCount: warnings.length,
8892
+ unresolvedCount: unresolved2.size,
8893
+ suppressedCount,
8894
+ matches: warnings.slice(0, 8)
8895
+ };
8896
+ }
8897
+ function activeDuplicationMatchIds(audit, suppressions = []) {
8898
+ const completion = buildDuplicationCompletion(audit, suppressions);
8899
+ return new Set(completion?.matches.map((match) => match.matchId) ?? []);
8900
+ }
8901
+ function pruneDuplicationSuppressions(audit, suppressions = []) {
8902
+ if (!suppressions.length) return [];
8903
+ const active = new Set(buildDuplicationCompletion(audit, [])?.matches.map((match) => match.matchId) ?? []);
8904
+ return suppressions.filter((item) => active.has(item.matchId)).slice(-64);
8905
+ }
8906
+ function findActiveDuplicationMatches(audit, suppressions = []) {
8907
+ return buildDuplicationCompletion(audit, suppressions)?.matches ?? [];
8908
+ }
8909
+ function hasDuplicationActivity(audit, runStartedAt) {
8910
+ return audit.some(
8911
+ (event) => (!runStartedAt || event.createdAt >= runStartedAt) && (duplicationReceipt(event.metadata?.duplicationAudit) !== void 0 || event.metadata?.duplicationSuppression !== void 0 || event.metadata?.activeDuplicationMatches !== void 0)
8912
+ );
8913
+ }
8914
+ function duplicationReceipt(value) {
8915
+ if (!value || typeof value !== "object") return void 0;
8916
+ const receipt = value;
8917
+ if (!Array.isArray(receipt.matches) || typeof receipt.changeSequence !== "number" || !["clear", "warning", "unresolved"].includes(String(receipt.status))) return void 0;
8918
+ return receipt;
8919
+ }
8920
+ function changedPathsFor(event, receipt) {
8921
+ const metadataPaths = event.metadata?.changedFiles;
8922
+ const fromMetadata = Array.isArray(metadataPaths) ? metadataPaths.filter((path) => typeof path === "string") : [];
8923
+ return [.../* @__PURE__ */ new Set([...fromMetadata, ...receipt.matches.map((match) => match.changedPath)])];
8924
+ }
8925
+
8926
+ // src/tools/duplication.ts
8927
+ var inputSchema12 = z17.discriminatedUnion("action", [
8928
+ z17.object({ action: z17.literal("show") }).strict(),
8929
+ z17.object({
8930
+ action: z17.literal("suppress"),
8931
+ match_id: z17.string().regex(/^[a-f0-9]{24}$/u),
8932
+ reason_code: z17.enum(["separate-boundary", "protocol-required", "generated-contract", "false-positive", "other"]),
8933
+ reason: z17.string().trim().min(12).max(240)
8934
+ }).strict()
8935
+ ]);
8936
+ var duplicationTool = {
8937
+ definition: {
8938
+ name: "duplication_audit",
8939
+ description: "Inspect active duplicate-function warnings or suppress one exact match with an auditable reason. Suppression does not bypass correctness, security, accessibility, concurrency, or verification requirements.",
8940
+ category: "read",
8941
+ inputSchema: jsonSchema({
8942
+ action: { type: "string", enum: ["show", "suppress"] },
8943
+ match_id: { type: "string", description: "Exact 24-character match id from the current audit." },
8944
+ reason_code: { type: "string", enum: ["separate-boundary", "protocol-required", "generated-contract", "false-positive", "other"] },
8945
+ reason: { type: "string", description: "Specific 12-240 character explanation; code blocks and credentials are rejected." }
8946
+ }, ["action"])
8947
+ },
8948
+ async execute(arguments_, context) {
8949
+ const input2 = inputSchema12.parse(arguments_);
8950
+ const suppressions = pruneDuplicationSuppressions(
8951
+ context.session.audit ?? [],
8952
+ context.session.duplicationSuppressions ?? []
8953
+ );
8954
+ context.session.duplicationSuppressions = suppressions;
8955
+ const active = activeDuplicationMatchIds(context.session.audit ?? [], suppressions);
8956
+ if (input2.action === "suppress") {
8957
+ if (!active.has(input2.match_id)) {
8958
+ throw new Error(`Unknown, stale, or already suppressed duplication match: ${input2.match_id}`);
8959
+ }
8960
+ suppressions.push({
8961
+ matchId: input2.match_id,
8962
+ reasonCode: input2.reason_code,
8963
+ reason: cleanReason(input2.reason),
8964
+ createdAt: (/* @__PURE__ */ new Date()).toISOString(),
8965
+ toolCallId: context.toolCallId ?? "unavailable"
8966
+ });
8967
+ context.session.duplicationSuppressions = suppressions.slice(-64);
8968
+ return {
8969
+ content: `Suppressed duplication match ${input2.match_id}. This does not waive verification or safety requirements.`,
8970
+ metadata: { duplicationSuppression: context.session.duplicationSuppressions.at(-1) }
8971
+ };
8972
+ }
8973
+ const matches = findActiveDuplicationMatches(context.session.audit ?? [], suppressions);
8974
+ return {
8975
+ content: matches.length ? matches.map(
8976
+ (match) => `- ${match.matchId}: ${match.changedPath}#${match.changedSymbol} -> ${match.candidatePath}#${match.candidateSymbol} (${match.kind}, ${match.similarity.toFixed(3)})`
8977
+ ).join("\n") : "No unsuppressed duplication matches.",
8978
+ metadata: { activeDuplicationMatches: matches.map((match) => match.matchId) }
8979
+ };
8980
+ }
8981
+ };
8982
+ function cleanReason(value) {
8983
+ if (/```|~~~|\b(?:api[_-]?key|access[_-]?token|authorization|cookie|password|secret)\s*[:=]/iu.test(value) || /\b(?:sk-[A-Za-z0-9_-]{12,}|AIza[0-9A-Za-z_-]{20,})\b/u.test(value)) {
8984
+ throw new Error("Suppression reasons cannot contain code blocks or credentials.");
8985
+ }
8986
+ return value.replace(/[\u0000-\u001f\u007f-\u009f]/gu, " ").replace(/\s+/gu, " ").trim();
8987
+ }
8988
+
8818
8989
  // src/tools/index.ts
8819
8990
  function createDefaultToolRegistry(_options = {}) {
8820
8991
  return new ToolRegistry([
@@ -8828,6 +8999,7 @@ function createDefaultToolRegistry(_options = {}) {
8828
8999
  gitTool,
8829
9000
  taskTool,
8830
9001
  taskContractTool,
9002
+ duplicationTool,
8831
9003
  workingMemoryTool
8832
9004
  ]);
8833
9005
  }
@@ -9633,6 +9805,7 @@ function roundScore(value) {
9633
9805
  }
9634
9806
 
9635
9807
  // src/agent/duplication-audit.ts
9808
+ import { createHash as createHash14 } from "node:crypto";
9636
9809
  import { readFile as readFile15 } from "node:fs/promises";
9637
9810
  var NEAR_CLONE_THRESHOLD = 0.55;
9638
9811
  var MAX_MATCHES = 8;
@@ -9658,13 +9831,16 @@ async function auditChangedFunctions(input2) {
9658
9831
  return unresolved(input2.changeSequence, input2.baseline?.generation);
9659
9832
  }
9660
9833
  const currentFunctions = reports.flatMap((report) => report.functions.map(withoutTokens));
9661
- if (!currentFunctions.length) return void 0;
9834
+ if (!currentFunctions.length) {
9835
+ return auditableFiles.some((path) => input2.recheckPaths?.has(path)) && input2.baseline ? clear(input2.baseline.generation, input2.changeSequence, skippedSmallFunctions) : void 0;
9836
+ }
9662
9837
  if (!input2.baseline) return unresolved(input2.changeSequence);
9663
9838
  const lookup = createBaselineLookup(input2.baseline.functions);
9664
9839
  const previousByCurrent = matchCurrentFunctions(input2.baseline.functions, currentFunctions);
9665
9840
  const added = currentFunctions.flatMap((current) => {
9666
9841
  const previous = previousByCurrent.get(locationIdentity(current));
9667
- return !previous || current.tokenCount >= previous.tokenCount * 1.5 ? [{ current, previous }] : [];
9842
+ const recheck = input2.recheckFunctions?.has(identity(current)) || previous !== void 0 && input2.recheckFunctions?.has(identity(previous));
9843
+ return !previous || current.tokenCount >= previous.tokenCount * 1.5 || recheck ? [{ current, previous }] : [];
9668
9844
  });
9669
9845
  if (!added.length) return void 0;
9670
9846
  const matches = [];
@@ -9678,6 +9854,7 @@ async function auditChangedFunctions(input2) {
9678
9854
  }
9679
9855
  if (!best) continue;
9680
9856
  matches.push({
9857
+ matchId: matchId(input2.baseline.generation, input2.changeSequence, item, best.candidate, best.similarity),
9681
9858
  changedPath: item.path,
9682
9859
  changedSymbol: item.symbol,
9683
9860
  candidatePath: best.candidate.path,
@@ -9699,6 +9876,18 @@ async function auditChangedFunctions(input2) {
9699
9876
  rationale: bounded.length ? `${bounded.length} deterministic duplicate candidate${bounded.length === 1 ? "" : "s"} found; review for reuse.` : "No deterministic duplicate candidate exceeded the warning threshold."
9700
9877
  };
9701
9878
  }
9879
+ function clear(baselineGeneration, changeSequence, skippedSmallFunctions) {
9880
+ return {
9881
+ baselineGeneration,
9882
+ changeSequence,
9883
+ status: "clear",
9884
+ warningOnly: true,
9885
+ checkedFunctions: 0,
9886
+ skippedSmallFunctions,
9887
+ matches: [],
9888
+ rationale: "No active deterministic duplicate candidate remains on the rechecked path."
9889
+ };
9890
+ }
9702
9891
  function withoutTokens(value) {
9703
9892
  const { normalizedTokens: _tokens, ...fingerprint } = value;
9704
9893
  return fingerprint;
@@ -9782,6 +9971,17 @@ function unresolved(changeSequence, generation = "unavailable") {
9782
9971
  function round(value) {
9783
9972
  return Math.round(value * 1e3) / 1e3;
9784
9973
  }
9974
+ function matchId(generation, changeSequence, changed, candidate, similarity) {
9975
+ return createHash14("sha256").update([
9976
+ generation,
9977
+ String(changeSequence),
9978
+ changed.path,
9979
+ changed.symbol,
9980
+ candidate.path,
9981
+ candidate.symbol,
9982
+ similarity === 1 ? "type-1-or-2" : "type-3"
9983
+ ].join("\0")).digest("hex").slice(0, 24);
9984
+ }
9785
9985
 
9786
9986
  // src/agent/runner.ts
9787
9987
  var AgentRunner = class {
@@ -9853,6 +10053,7 @@ var AgentRunner = class {
9853
10053
  await options.onEvent?.(event);
9854
10054
  };
9855
10055
  const changeSequenceAtStart = this.changeSequence;
10056
+ const runStartedAt = (/* @__PURE__ */ new Date()).toISOString();
9856
10057
  const runChangedFiles = /* @__PURE__ */ new Set();
9857
10058
  const verificationEvidence = [];
9858
10059
  const toolRecovery = new ToolRecoveryController();
@@ -9882,7 +10083,11 @@ var AgentRunner = class {
9882
10083
  this.changeSequence,
9883
10084
  mutationTracking,
9884
10085
  activeRunContract,
9885
- this.session.audit ?? []
10086
+ this.session.audit ?? [],
10087
+ hasDuplicationActivity(this.session.audit ?? [], runStartedAt) ? buildDuplicationCompletion(
10088
+ this.session.audit ?? [],
10089
+ this.session.duplicationSuppressions ?? []
10090
+ ) : void 0
9886
10091
  );
9887
10092
  if (completion.acceptance && activeRunContract && activeRunContract.state !== "draft") {
9888
10093
  activeRunContract.state = completion.acceptance.state;
@@ -10008,7 +10213,11 @@ var AgentRunner = class {
10008
10213
  this.tools,
10009
10214
  options.askMode === true,
10010
10215
  contractEnabled,
10011
- this.hasReadableToolArtifact()
10216
+ this.hasReadableToolArtifact(),
10217
+ activeDuplicationMatchIds(
10218
+ this.session.audit ?? [],
10219
+ this.session.duplicationSuppressions ?? []
10220
+ ).size > 0
10012
10221
  );
10013
10222
  const estimatedInputTokens = estimateMessages2(messages) + estimateToolDefinitions(visibleTools);
10014
10223
  if (availableTokens <= 0 || estimatedInputTokens >= availableTokens) {
@@ -10293,7 +10502,8 @@ ${input2}`
10293
10502
  contextEngine: this.contextEngine,
10294
10503
  toolArtifactStore: this.toolArtifactStore,
10295
10504
  emit,
10296
- ...options.signal ? { signal: options.signal } : {}
10505
+ ...options.signal ? { signal: options.signal } : {},
10506
+ toolCallId: call.id
10297
10507
  };
10298
10508
  try {
10299
10509
  let reuseReceipt;
@@ -10343,10 +10553,21 @@ ${input2}`
10343
10553
  throwIfAborted(options.signal);
10344
10554
  const execution = await tool.execute(call.arguments, toolExecutionContext);
10345
10555
  const changedFiles = await this.acceptChangedFiles(execution.changedFiles ?? []);
10556
+ const activeDuplicateFunctions = new Set(
10557
+ buildDuplicationCompletion(
10558
+ this.session.audit ?? [],
10559
+ []
10560
+ )?.matches.map((match) => `${match.changedPath}\0${match.changedSymbol}`) ?? []
10561
+ );
10562
+ const activeDuplicatePaths = new Set(
10563
+ buildDuplicationCompletion(this.session.audit ?? [], [])?.matches.map((match) => match.changedPath) ?? []
10564
+ );
10346
10565
  const duplicationAudit = duplicationAuditEnabled ? await auditChangedFunctions({
10347
10566
  ...duplicationBaseline ? { baseline: duplicationBaseline } : {},
10348
10567
  changedFiles,
10349
- changeSequence: this.changeSequence
10568
+ changeSequence: this.changeSequence,
10569
+ recheckFunctions: activeDuplicateFunctions,
10570
+ recheckPaths: activeDuplicatePaths
10350
10571
  }) : void 0;
10351
10572
  const tasksBefore = JSON.stringify(this.session.tasks);
10352
10573
  let afterHookError;
@@ -10826,9 +11047,9 @@ ${content}` : content,
10826
11047
  ...failure ? { metadata: { failure } } : {}
10827
11048
  };
10828
11049
  }
10829
- function visibleToolDefinitions(tools, askMode, contractEnabled, artifactReadAvailable) {
11050
+ function visibleToolDefinitions(tools, askMode, contractEnabled, artifactReadAvailable, duplicationAvailable) {
10830
11051
  return tools.definitions().filter(
10831
- (tool) => (!askMode || tool.category === "read") && (contractEnabled || tool.name !== "task_contract") && (artifactReadAvailable || tool.name !== "read_tool_artifact")
11052
+ (tool) => (!askMode || tool.category === "read") && (contractEnabled || tool.name !== "task_contract") && (artifactReadAvailable || tool.name !== "read_tool_artifact") && (duplicationAvailable || tool.name !== "duplication_audit")
10832
11053
  );
10833
11054
  }
10834
11055
  function formatToolError(error) {
@@ -11020,7 +11241,7 @@ function integer(value, fallback, min, max) {
11020
11241
  // src/agent/delegation.ts
11021
11242
  import { randomUUID as randomUUID14 } from "node:crypto";
11022
11243
  import { join as join18 } from "node:path";
11023
- import { z as z18 } from "zod";
11244
+ import { z as z19 } from "zod";
11024
11245
 
11025
11246
  // src/agent/external-runtime.ts
11026
11247
  async function runExternalAgent(request) {
@@ -11147,86 +11368,86 @@ function numeric(...values) {
11147
11368
  }
11148
11369
 
11149
11370
  // src/agent/team-store.ts
11150
- import { createHash as createHash14, randomUUID as randomUUID13 } from "node:crypto";
11371
+ import { createHash as createHash15, randomUUID as randomUUID13 } from "node:crypto";
11151
11372
  import { lstat as lstat18, readFile as readFile17, readdir as readdir7, rm as rm3 } from "node:fs/promises";
11152
11373
  import { join as join16, resolve as resolve16 } from "node:path";
11153
- import { z as z17 } from "zod";
11154
- var runIdSchema = z17.string().uuid();
11155
- var hashSchema = z17.string().regex(/^[a-f0-9]{64}$/u);
11156
- var artifactSchema2 = z17.object({
11374
+ import { z as z18 } from "zod";
11375
+ var runIdSchema = z18.string().uuid();
11376
+ var hashSchema = z18.string().regex(/^[a-f0-9]{64}$/u);
11377
+ var artifactSchema2 = z18.object({
11157
11378
  sha256: hashSchema,
11158
- bytes: z17.number().int().nonnegative().max(5e5)
11379
+ bytes: z18.number().int().nonnegative().max(5e5)
11159
11380
  }).strict();
11160
- var phaseSchema = z17.enum(["work", "review", "revision", "write"]);
11161
- var agentRecordSchema = z17.object({
11162
- id: z17.string().uuid(),
11163
- profile: z17.string(),
11164
- provider: z17.string(),
11165
- model: z17.string(),
11381
+ var phaseSchema = z18.enum(["work", "review", "revision", "write"]);
11382
+ var agentRecordSchema = z18.object({
11383
+ id: z18.string().uuid(),
11384
+ profile: z18.string(),
11385
+ provider: z18.string(),
11386
+ model: z18.string(),
11166
11387
  phase: phaseSchema,
11167
- ok: z17.boolean(),
11168
- createdAt: z17.string(),
11169
- startedAt: z17.string().optional(),
11170
- endedAt: z17.string().optional(),
11171
- durationMs: z17.number().int().nonnegative().optional(),
11172
- toolCalls: z17.number().int().nonnegative().optional(),
11173
- usage: z17.object({
11174
- inputTokens: z17.number().int().nonnegative(),
11175
- outputTokens: z17.number().int().nonnegative()
11388
+ ok: z18.boolean(),
11389
+ createdAt: z18.string(),
11390
+ startedAt: z18.string().optional(),
11391
+ endedAt: z18.string().optional(),
11392
+ durationMs: z18.number().int().nonnegative().optional(),
11393
+ toolCalls: z18.number().int().nonnegative().optional(),
11394
+ usage: z18.object({
11395
+ inputTokens: z18.number().int().nonnegative(),
11396
+ outputTokens: z18.number().int().nonnegative()
11176
11397
  }).strict().optional(),
11177
11398
  report: artifactSchema2
11178
11399
  }).strict();
11179
- var messageRecordSchema = z17.object({
11180
- id: z17.string().uuid(),
11181
- from: z17.string(),
11182
- to: z17.string(),
11183
- createdAt: z17.string(),
11400
+ var messageRecordSchema = z18.object({
11401
+ id: z18.string().uuid(),
11402
+ from: z18.string(),
11403
+ to: z18.string(),
11404
+ createdAt: z18.string(),
11184
11405
  content: artifactSchema2
11185
11406
  }).strict();
11186
- var writerIntegrationSchema = z17.object({
11187
- status: z17.enum(["ready", "conflict", "integrated"]),
11188
- checkedAt: z17.string(),
11189
- detail: z17.string().max(2e4),
11190
- checkpoint: z17.object({
11191
- sessionId: z17.string(),
11192
- checkpointId: z17.string()
11407
+ var writerIntegrationSchema = z18.object({
11408
+ status: z18.enum(["ready", "conflict", "integrated"]),
11409
+ checkedAt: z18.string(),
11410
+ detail: z18.string().max(2e4),
11411
+ checkpoint: z18.object({
11412
+ sessionId: z18.string(),
11413
+ checkpointId: z18.string()
11193
11414
  }).strict().optional(),
11194
- integratedAt: z17.string().optional()
11415
+ integratedAt: z18.string().optional()
11195
11416
  }).strict();
11196
- var writerLaneSchema = z17.object({
11197
- profile: z17.string(),
11198
- reviewer: z17.string(),
11199
- baseCommit: z17.string().regex(/^[a-f0-9]{40,64}$/u),
11200
- outcome: z17.enum(["accepted", "rejected", "failed", "cancelled"]),
11417
+ var writerLaneSchema = z18.object({
11418
+ profile: z18.string(),
11419
+ reviewer: z18.string(),
11420
+ baseCommit: z18.string().regex(/^[a-f0-9]{40,64}$/u),
11421
+ outcome: z18.enum(["accepted", "rejected", "failed", "cancelled"]),
11201
11422
  patch: artifactSchema2,
11202
- files: z17.array(z17.string().min(1).max(4e3)).max(2e3),
11203
- worktreeCleaned: z17.boolean(),
11423
+ files: z18.array(z18.string().min(1).max(4e3)).max(2e3),
11424
+ worktreeCleaned: z18.boolean(),
11204
11425
  review: artifactSchema2.optional(),
11205
11426
  integration: writerIntegrationSchema.optional()
11206
11427
  }).strict();
11207
11428
  var manifestFields = {
11208
11429
  id: runIdSchema,
11209
- workspace: z17.string(),
11210
- objective: z17.string().max(3e4),
11211
- reviewer: z17.string(),
11212
- createdAt: z17.string(),
11213
- updatedAt: z17.string(),
11214
- status: z17.enum(["running", "accepted", "rejected", "failed"]),
11215
- maxReviewRounds: z17.number().int().min(0).max(3),
11216
- reviewRounds: z17.number().int().min(0).max(3),
11217
- agents: z17.array(agentRecordSchema).max(256),
11218
- messages: z17.array(messageRecordSchema).max(512)
11430
+ workspace: z18.string(),
11431
+ objective: z18.string().max(3e4),
11432
+ reviewer: z18.string(),
11433
+ createdAt: z18.string(),
11434
+ updatedAt: z18.string(),
11435
+ status: z18.enum(["running", "accepted", "rejected", "failed"]),
11436
+ maxReviewRounds: z18.number().int().min(0).max(3),
11437
+ reviewRounds: z18.number().int().min(0).max(3),
11438
+ agents: z18.array(agentRecordSchema).max(256),
11439
+ messages: z18.array(messageRecordSchema).max(512)
11219
11440
  };
11220
- var manifestV1Schema = z17.object({
11221
- version: z17.literal(1),
11441
+ var manifestV1Schema = z18.object({
11442
+ version: z18.literal(1),
11222
11443
  ...manifestFields
11223
11444
  }).strict();
11224
- var manifestV2Schema = z17.object({
11225
- version: z17.literal(2),
11445
+ var manifestV2Schema = z18.object({
11446
+ version: z18.literal(2),
11226
11447
  ...manifestFields,
11227
11448
  writer: writerLaneSchema.optional()
11228
11449
  }).strict();
11229
- var manifestSchema2 = z17.discriminatedUnion("version", [manifestV1Schema, manifestV2Schema]);
11450
+ var manifestSchema2 = z18.discriminatedUnion("version", [manifestV1Schema, manifestV2Schema]);
11230
11451
  var TeamRunStore = class {
11231
11452
  workspace;
11232
11453
  directory;
@@ -11405,7 +11626,7 @@ var TeamRunStore = class {
11405
11626
  async writeArtifact(runId, content, truncate = true) {
11406
11627
  const data = boundedArtifactText(content, 5e5, truncate);
11407
11628
  const bytes = Buffer.byteLength(data);
11408
- const sha256 = createHash14("sha256").update(data).digest("hex");
11629
+ const sha256 = createHash15("sha256").update(data).digest("hex");
11409
11630
  const directory = join16(this.runDirectory(runId), "blobs");
11410
11631
  await ensureWorkspaceStorageDirectory(this.workspace, directory, {
11411
11632
  requireActiveNamespace: this.managedDirectory
@@ -11414,7 +11635,7 @@ var TeamRunStore = class {
11414
11635
  try {
11415
11636
  await this.assertRegularFile(path);
11416
11637
  const existing = await readFile17(path);
11417
- if (createHash14("sha256").update(existing).digest("hex") !== sha256) {
11638
+ if (createHash15("sha256").update(existing).digest("hex") !== sha256) {
11418
11639
  throw new Error(`Team artifact hash collision or corruption: ${sha256}`);
11419
11640
  }
11420
11641
  } catch (error) {
@@ -11435,7 +11656,7 @@ var TeamRunStore = class {
11435
11656
  const path = this.artifactPath(runId, artifact.sha256);
11436
11657
  await this.assertRegularFile(path);
11437
11658
  const data = await readFile17(path);
11438
- const hash4 = createHash14("sha256").update(data).digest("hex");
11659
+ const hash4 = createHash15("sha256").update(data).digest("hex");
11439
11660
  if (hash4 !== artifact.sha256 || data.byteLength !== artifact.bytes) {
11440
11661
  throw new Error(`Team artifact integrity check failed: ${artifact.sha256}`);
11441
11662
  }
@@ -11498,7 +11719,7 @@ function resolveAgentModelRoute(team, parent, profile) {
11498
11719
  }
11499
11720
 
11500
11721
  // src/agent/writer-lane.ts
11501
- import { createHash as createHash15 } from "node:crypto";
11722
+ import { createHash as createHash16 } from "node:crypto";
11502
11723
  import { lstat as lstat19, mkdtemp, realpath as realpath7, rm as rm4 } from "node:fs/promises";
11503
11724
  import { tmpdir as tmpdir2 } from "node:os";
11504
11725
  import { isAbsolute as isAbsolute6, join as join17, resolve as resolve17 } from "node:path";
@@ -11596,7 +11817,7 @@ var WriterLane = class {
11596
11817
  return {
11597
11818
  baseCommit,
11598
11819
  patch,
11599
- patchSha256: createHash15("sha256").update(patch).digest("hex"),
11820
+ patchSha256: createHash16("sha256").update(patch).digest("hex"),
11600
11821
  files,
11601
11822
  worktreeCleaned,
11602
11823
  value
@@ -11826,14 +12047,14 @@ async function pathExists2(path) {
11826
12047
  }
11827
12048
 
11828
12049
  // src/agent/delegation.ts
11829
- var writerRunInputSchema = z18.object({
11830
- task: z18.string().min(1).max(2e4),
11831
- profile: z18.string().max(64).optional(),
11832
- reviewer: z18.string().max(64).optional()
12050
+ var writerRunInputSchema = z19.object({
12051
+ task: z19.string().min(1).max(2e4),
12052
+ profile: z19.string().max(64).optional(),
12053
+ reviewer: z19.string().max(64).optional()
11833
12054
  }).strict();
11834
- var writerIntegrateInputSchema = z18.object({
11835
- run_id: z18.string().uuid(),
11836
- patch_sha256: z18.string().regex(/^[a-f0-9]{64}$/u)
12055
+ var writerIntegrateInputSchema = z19.object({
12056
+ run_id: z19.string().uuid(),
12057
+ patch_sha256: z19.string().regex(/^[a-f0-9]{64}$/u)
11837
12058
  }).strict();
11838
12059
  var DelegationManager = class {
11839
12060
  constructor(options) {
@@ -11894,10 +12115,10 @@ var DelegationManager = class {
11894
12115
  },
11895
12116
  async execute(arguments_, context) {
11896
12117
  if (!manager.team.enabled) return { ok: false, content: "Multi-agent delegation is disabled." };
11897
- const input2 = z18.object({
11898
- tasks: z18.array(z18.object({
11899
- profile: z18.string().max(64).optional(),
11900
- task: z18.string().min(1).max(2e4)
12118
+ const input2 = z19.object({
12119
+ tasks: z19.array(z19.object({
12120
+ profile: z19.string().max(64).optional(),
12121
+ task: z19.string().min(1).max(2e4)
11901
12122
  })).min(1).max(manager.team.maxDelegations)
11902
12123
  }).parse(arguments_);
11903
12124
  const tasks = input2.tasks.map((task) => ({
@@ -11943,13 +12164,13 @@ var DelegationManager = class {
11943
12164
  },
11944
12165
  async execute(arguments_, context) {
11945
12166
  if (!manager.team.enabled) return { ok: false, content: "Multi-agent teams are disabled." };
11946
- const input2 = z18.object({
11947
- objective: z18.string().min(1).max(3e4),
11948
- tasks: z18.array(z18.object({
11949
- profile: z18.string().max(64).optional(),
11950
- task: z18.string().min(1).max(2e4)
12167
+ const input2 = z19.object({
12168
+ objective: z19.string().min(1).max(3e4),
12169
+ tasks: z19.array(z19.object({
12170
+ profile: z19.string().max(64).optional(),
12171
+ task: z19.string().min(1).max(2e4)
11951
12172
  })).min(1).max(manager.team.maxDelegations),
11952
- reviewer: z18.string().max(64).optional()
12173
+ reviewer: z19.string().max(64).optional()
11953
12174
  }).parse(arguments_);
11954
12175
  const tasks = input2.tasks.map((task) => ({
11955
12176
  profile: task.profile ?? manager.team.defaultProfile,
@@ -13597,22 +13818,24 @@ ${this.glyphs.meta} ${session.changedFiles.length} changed files ${this.glyphs.s
13597
13818
  if (!completion || completion.status === "no_changes") return;
13598
13819
  const checks = completion.checks.map((check) => check.command).join(", ");
13599
13820
  const suffix = checks ? ` ${this.glyphs.separator} ${checks}` : "";
13821
+ const duplication = completion.duplication;
13822
+ const duplicateSuffix = duplication ? ` ${this.glyphs.separator} duplication ${duplication.status} (${duplication.warningCount} warning, ${duplication.unresolvedCount} incomplete, ${duplication.suppressedCount} suppressed)` : "";
13600
13823
  if (completion.status === "verified") {
13601
13824
  process.stderr.write(this.paint.green(
13602
- `${this.glyphs.success} verified ${this.glyphs.separator} ${completion.detail}${suffix}
13825
+ `${this.glyphs.success} verified ${this.glyphs.separator} ${completion.detail}${suffix}${duplicateSuffix}
13603
13826
  `
13604
13827
  ));
13605
13828
  return;
13606
13829
  }
13607
13830
  if (completion.status === "verification_failed") {
13608
13831
  process.stderr.write(this.paint.red(
13609
- `${this.glyphs.error} verification failed ${this.glyphs.separator} ${completion.detail}${suffix}
13832
+ `${this.glyphs.error} verification failed ${this.glyphs.separator} ${completion.detail}${suffix}${duplicateSuffix}
13610
13833
  `
13611
13834
  ));
13612
13835
  return;
13613
13836
  }
13614
13837
  process.stderr.write(this.paint.yellow(
13615
- `${this.glyphs.warning} unverified ${this.glyphs.separator} ${completion.detail}
13838
+ `${this.glyphs.warning} unverified ${this.glyphs.separator} ${completion.detail}${duplicateSuffix}
13616
13839
  `
13617
13840
  ));
13618
13841
  }
@@ -16231,6 +16454,11 @@ function toolMetaSummary(metadata) {
16231
16454
  if (status === "warning") parts.push(`duplicates ${matches} (warning)`);
16232
16455
  else if (status === "unresolved") parts.push("duplicates incomplete");
16233
16456
  }
16457
+ const suppression = metadata.duplicationSuppression;
16458
+ if (suppression && typeof suppression === "object") {
16459
+ const matchId2 = suppression.matchId;
16460
+ if (typeof matchId2 === "string") parts.push(`duplicate ${matchId2.slice(0, 8)} suppressed`);
16461
+ }
16234
16462
  const hooks = metadata.hooks;
16235
16463
  if (hooks && typeof hooks === "object") {
16236
16464
  const before = Number(hooks.before ?? 0);
@@ -16690,12 +16918,14 @@ function SkeinApp({ runner, config, extensions, initialPrompt, askMode = false,
16690
16918
  refreshSession();
16691
16919
  if (event.completion && event.completion.status !== "no_changes") {
16692
16920
  const checks = event.completion.checks.map((check) => check.command).join(` ${separator} `);
16921
+ const duplication = event.completion.duplication;
16922
+ const duplicateDetail = duplication ? `${separator} duplication ${duplication.status} (${duplication.warningCount} warning, ${duplication.unresolvedCount} incomplete, ${duplication.suppressedCount} suppressed)` : "";
16693
16923
  append({
16694
16924
  id: nextId(),
16695
16925
  kind: "notice",
16696
16926
  wrapWidth: contentWidth,
16697
16927
  tone: event.completion.status === "verified" ? "success" : event.completion.status === "unverified" ? "warning" : "error",
16698
- text: event.completion.status === "verified" ? `Verified${separator}${event.completion.detail}${checks ? `${separator}${checks}` : ""}` : event.completion.status === "verification_failed" ? `Verification failed${separator}${event.completion.detail}${checks ? `${separator}${checks}` : ""}` : `Unverified${separator}${event.completion.detail}`
16928
+ text: event.completion.status === "verified" ? `Verified${separator}${event.completion.detail}${checks ? `${separator}${checks}` : ""}${duplicateDetail}` : event.completion.status === "verification_failed" ? `Verification failed${separator}${event.completion.detail}${checks ? `${separator}${checks}` : ""}${duplicateDetail}` : `Unverified${separator}${event.completion.detail}${duplicateDetail}`
16699
16929
  });
16700
16930
  }
16701
16931
  if (event.reason !== "completed" && event.reason !== "unverified" && event.reason !== "verification_failed") {
@@ -18717,7 +18947,7 @@ import { StreamableHTTPClientTransport } from "@modelcontextprotocol/sdk/client/
18717
18947
  import stripAnsi5 from "strip-ansi";
18718
18948
 
18719
18949
  // src/mcp/tool.ts
18720
- import { createHash as createHash16 } from "node:crypto";
18950
+ import { createHash as createHash17 } from "node:crypto";
18721
18951
  import stripAnsi4 from "strip-ansi";
18722
18952
  var MAX_ARGUMENT_BYTES = 256e3;
18723
18953
  var MAX_DESCRIPTION_LENGTH = 4e3;
@@ -18725,7 +18955,7 @@ var MAX_RESULT_BYTES = 5 * 1024 * 1024;
18725
18955
  var MAX_SCHEMA_BYTES = 1e5;
18726
18956
  function createMcpToolAdapter(options) {
18727
18957
  const { remoteTool } = options;
18728
- const inputSchema12 = copyInputSchema(remoteTool.inputSchema);
18958
+ const inputSchema13 = copyInputSchema(remoteTool.inputSchema);
18729
18959
  return {
18730
18960
  definition: {
18731
18961
  name: options.exposedName,
@@ -18733,7 +18963,7 @@ function createMcpToolAdapter(options) {
18733
18963
  // MCP servers are an external trust boundary. Read-only annotations are
18734
18964
  // hints from that server and must not lower the local permission level.
18735
18965
  category: "network",
18736
- inputSchema: inputSchema12
18966
+ inputSchema: inputSchema13
18737
18967
  },
18738
18968
  permissionCategories: () => ["network"],
18739
18969
  async execute(arguments_, context) {
@@ -18887,7 +19117,7 @@ function fitToolName(name, identity2) {
18887
19117
  return `${name.slice(0, 64 - suffix.length).replace(/_+$/g, "")}${suffix}`;
18888
19118
  }
18889
19119
  function shortHash(value) {
18890
- return createHash16("sha256").update(value).digest("hex").slice(0, 8);
19120
+ return createHash17("sha256").update(value).digest("hex").slice(0, 8);
18891
19121
  }
18892
19122
  function sanitizeOutputText(value) {
18893
19123
  return stripAnsi4(value).replace(/[\u0000-\u0008\u000b\u000c\u000e-\u001f\u007f]/g, "");
@@ -19517,9 +19747,9 @@ async function closeTransportQuietly(transport) {
19517
19747
  }
19518
19748
 
19519
19749
  // src/memory/tools.ts
19520
- import { z as z19 } from "zod";
19521
- var scopeSchema = z19.enum(["user", "workspace", "session", "agent"]);
19522
- var kindSchema = z19.enum(["semantic", "episodic", "procedural"]);
19750
+ import { z as z20 } from "zod";
19751
+ var scopeSchema = z20.enum(["user", "workspace", "session", "agent"]);
19752
+ var kindSchema = z20.enum(["semantic", "episodic", "procedural"]);
19523
19753
  function createMemoryTools(store) {
19524
19754
  return [
19525
19755
  {
@@ -19534,10 +19764,10 @@ function createMemoryTools(store) {
19534
19764
  }, ["query"])
19535
19765
  },
19536
19766
  async execute(arguments_, context) {
19537
- const input2 = z19.object({
19538
- query: z19.string().max(4e3),
19767
+ const input2 = z20.object({
19768
+ query: z20.string().max(4e3),
19539
19769
  scope: scopeSchema.optional(),
19540
- limit: z19.number().int().min(1).max(20).optional()
19770
+ limit: z20.number().int().min(1).max(20).optional()
19541
19771
  }).parse(arguments_);
19542
19772
  const scopes = input2.scope ? [{ scope: input2.scope, scopeKey: scopeKey(input2.scope, context) }] : availableScopes(context);
19543
19773
  const records = store.search(input2.query, { scopes, limit: input2.limit ?? 8 });
@@ -19569,17 +19799,17 @@ ${record.content}`
19569
19799
  }, ["content", "rationale"])
19570
19800
  },
19571
19801
  async execute(arguments_, context) {
19572
- const input2 = z19.object({
19573
- content: z19.string().min(1).max(12e3),
19574
- rationale: z19.string().min(1).max(1e3),
19802
+ const input2 = z20.object({
19803
+ content: z20.string().min(1).max(12e3),
19804
+ rationale: z20.string().min(1).max(1e3),
19575
19805
  scope: scopeSchema.optional(),
19576
19806
  kind: kindSchema.optional(),
19577
- tags: z19.array(z19.string()).max(24).optional(),
19578
- importance: z19.number().min(0).max(1).optional(),
19579
- confidence: z19.number().min(0).max(1).optional(),
19580
- agent: z19.string().max(64).optional(),
19581
- revision: z19.string().max(240).optional(),
19582
- conflictKey: z19.string().max(240).optional()
19807
+ tags: z20.array(z20.string()).max(24).optional(),
19808
+ importance: z20.number().min(0).max(1).optional(),
19809
+ confidence: z20.number().min(0).max(1).optional(),
19810
+ agent: z20.string().max(64).optional(),
19811
+ revision: z20.string().max(240).optional(),
19812
+ conflictKey: z20.string().max(240).optional()
19583
19813
  }).strict().parse(arguments_);
19584
19814
  const scope = input2.scope ?? "workspace";
19585
19815
  const candidate = store.propose({
@@ -19617,9 +19847,9 @@ ${record.content}`
19617
19847
  }, ["id"])
19618
19848
  },
19619
19849
  async execute(arguments_) {
19620
- const input2 = z19.object({
19621
- id: z19.string().uuid(),
19622
- permanent: z19.boolean().optional()
19850
+ const input2 = z20.object({
19851
+ id: z20.string().uuid(),
19852
+ permanent: z20.boolean().optional()
19623
19853
  }).parse(arguments_);
19624
19854
  const changed = input2.permanent ? store.remove(input2.id) : store.archive(input2.id);
19625
19855
  return {
@@ -19823,7 +20053,7 @@ function escapeAttribute6(value) {
19823
20053
  }
19824
20054
 
19825
20055
  // src/workflows/catalog.ts
19826
- import { z as z20 } from "zod";
20056
+ import { z as z21 } from "zod";
19827
20057
  var builtInWorkflows = [
19828
20058
  {
19829
20059
  name: "implement",
@@ -19914,7 +20144,7 @@ function createWorkflowTool(catalog) {
19914
20144
  }, ["name", "task"])
19915
20145
  },
19916
20146
  async execute(arguments_) {
19917
- const input2 = z20.object({ name: z20.string(), task: z20.string().min(1).max(2e4) }).parse(arguments_);
20147
+ const input2 = z21.object({ name: z21.string(), task: z21.string().min(1).max(2e4) }).parse(arguments_);
19918
20148
  const workflow = catalog.get(input2.name);
19919
20149
  if (!workflow) return { ok: false, content: `Unknown workflow: ${input2.name}` };
19920
20150
  return {