@wrongstack/core 0.307.0 → 0.307.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/dist/index.js CHANGED
@@ -1529,9 +1529,9 @@ __export(review_finding_store_exports, {
1529
1529
  });
1530
1530
  import { randomUUID as randomUUID40 } from "node:crypto";
1531
1531
  import * as fsp48 from "node:fs/promises";
1532
- import * as path104 from "node:path";
1532
+ import * as path105 from "node:path";
1533
1533
  function resolveFindingStorePath(projectDir) {
1534
- return path104.join(projectDir, FINDING_STORE_FILE);
1534
+ return path105.join(projectDir, FINDING_STORE_FILE);
1535
1535
  }
1536
1536
  var FINDING_RESOLVED_RETENTION_MS, FINDING_IGNORED_RETENTION_MS, FINDING_DEFAULT_PAGE_SIZE, NL2, LINE_SEPARATOR, FINDING_STORE_FILE, JsonlFindingStore;
1537
1537
  var init_review_finding_store = __esm({
@@ -10252,6 +10252,7 @@ var RUNTIME_CAPABILITY_MANIFEST = [
10252
10252
  "codebase-skeleton",
10253
10253
  "codebase-repo-map",
10254
10254
  "codebase-impact-analysis",
10255
+ "codebase-invariant-check",
10255
10256
  "dead-code-scan",
10256
10257
  "diff",
10257
10258
  "json",
@@ -23864,13 +23865,50 @@ var HEAVY_BUDGET = {
23864
23865
  maxIterations: 8e3,
23865
23866
  maxToolCalls: 2e4
23866
23867
  };
23868
+ var INDEX_READ = [
23869
+ "codebase-stats",
23870
+ "codebase-search",
23871
+ "codebase-skeleton",
23872
+ "codebase-repo-map",
23873
+ "codebase-incoming-calls",
23874
+ "codebase-outgoing-calls"
23875
+ ];
23867
23876
  var TOOLS = {
23877
+ /** Index-backed code discovery. Spread onto code-facing presets, not browser. */
23878
+ index: INDEX_READ,
23868
23879
  /** Pure read/inspect — safe for analysis and review agents. */
23869
23880
  read: ["read", "grep", "glob", "search", "tree", "mailbox"],
23870
23881
  /** Read + structured inspection (logs, diffs, json, dependency audit). */
23871
- inspect: ["read", "grep", "glob", "search", "tree", "json", "diff", "logs", "audit", "mailbox"],
23882
+ inspect: [
23883
+ "read",
23884
+ "grep",
23885
+ "glob",
23886
+ "search",
23887
+ "tree",
23888
+ ...INDEX_READ,
23889
+ "json",
23890
+ "diff",
23891
+ "logs",
23892
+ "audit",
23893
+ "mailbox"
23894
+ ],
23872
23895
  /** Read + edit (no shell). For agents that write code/docs but don't run it. */
23873
- write: ["read", "grep", "glob", "search", "tree", "write", "edit", "replace", "patch", "mailbox"],
23896
+ write: [
23897
+ "read",
23898
+ "grep",
23899
+ "glob",
23900
+ "search",
23901
+ "tree",
23902
+ ...INDEX_READ,
23903
+ "codebase-impact-analysis",
23904
+ "codebase-ast-replace",
23905
+ "codebase-invariant-check",
23906
+ "write",
23907
+ "edit",
23908
+ "replace",
23909
+ "patch",
23910
+ "mailbox"
23911
+ ],
23874
23912
  /** Full build loop: edit + run (lint/format/typecheck/test/bash). */
23875
23913
  build: [
23876
23914
  "read",
@@ -23878,6 +23916,11 @@ var TOOLS = {
23878
23916
  "glob",
23879
23917
  "search",
23880
23918
  "tree",
23919
+ ...INDEX_READ,
23920
+ "codebase-impact-analysis",
23921
+ "codebase-ast-replace",
23922
+ "codebase-invariant-check",
23923
+ "codebase-targeted-test",
23881
23924
  "diff",
23882
23925
  "write",
23883
23926
  "edit",
@@ -23904,7 +23947,18 @@ var TOOLS = {
23904
23947
  /** Dependency management + CVE audit. */
23905
23948
  deps: ["read", "grep", "glob", "install", "outdated", "audit", "json", "mailbox"],
23906
23949
  /** Documentation authoring. */
23907
- docs: ["read", "grep", "glob", "search", "tree", "write", "edit", "document", "mailbox"],
23950
+ docs: [
23951
+ "read",
23952
+ "grep",
23953
+ "glob",
23954
+ "search",
23955
+ "tree",
23956
+ ...INDEX_READ,
23957
+ "write",
23958
+ "edit",
23959
+ "document",
23960
+ "mailbox"
23961
+ ],
23908
23962
  /** Web research. */
23909
23963
  research: ["read", "grep", "glob", "search", "fetch", "mailbox"]
23910
23964
  };
@@ -23921,7 +23975,7 @@ var DISCOVERY_AGENTS = [
23921
23975
  id: "explore",
23922
23976
  name: "Explore",
23923
23977
  role: "explore",
23924
- tools: [...TOOLS.read],
23978
+ tools: [...TOOLS.read, ...TOOLS.index],
23925
23979
  prompt: agentPrompt("explore")
23926
23980
  },
23927
23981
  budget: MEDIUM_BUDGET,
@@ -23949,7 +24003,7 @@ var DISCOVERY_AGENTS = [
23949
24003
  id: "search",
23950
24004
  name: "Search",
23951
24005
  role: "search",
23952
- tools: [...TOOLS.read, "codebase-search"],
24006
+ tools: [...TOOLS.read, ...TOOLS.index],
23953
24007
  prompt: agentPrompt("search")
23954
24008
  },
23955
24009
  budget: MEDIUM_BUDGET,
@@ -24000,7 +24054,7 @@ var DISCOVERY_AGENTS = [
24000
24054
  ];
24001
24055
 
24002
24056
  // src/coordination/agents/phase2-planning.ts
24003
- var PLAN_TOOLS = [...TOOLS.read, "plan", "todo"];
24057
+ var PLAN_TOOLS = [...TOOLS.read, ...TOOLS.index, "plan", "todo"];
24004
24058
  var PLANNING_AGENTS = [
24005
24059
  {
24006
24060
  config: {
@@ -53753,6 +53807,274 @@ function requestLimitExtension(opts) {
53753
53807
  });
53754
53808
  }
53755
53809
 
53810
+ // src/prompts/prompt-journal.ts
53811
+ import * as fs31 from "node:fs/promises";
53812
+ import * as path77 from "node:path";
53813
+ var PROMPT_JOURNAL_RAW_MARKER = "promptJournal.raw";
53814
+ async function ensureGitignore(projectRoot) {
53815
+ const gitignorePath = path77.join(projectRoot, ".gitignore");
53816
+ try {
53817
+ let content = "";
53818
+ try {
53819
+ content = await fs31.readFile(gitignorePath, "utf8");
53820
+ } catch {
53821
+ content = "";
53822
+ }
53823
+ if (!content.includes(".wrongstack") && !content.includes(".wrongstack/")) {
53824
+ const addition = content.endsWith("\n") || content.length === 0 ? ".wrongstack/\n" : "\n.wrongstack/\n";
53825
+ await fs31.writeFile(gitignorePath, content + addition, "utf8");
53826
+ }
53827
+ } catch {
53828
+ }
53829
+ }
53830
+ function sessionFileId(sessionId) {
53831
+ const leaf = sessionId.split(/[\\/]/u).pop();
53832
+ return leaf && leaf.trim().length > 0 ? leaf : "general";
53833
+ }
53834
+ async function recordPromptJournalEntry(opts) {
53835
+ const now = /* @__PURE__ */ new Date();
53836
+ const timestamp = now.toISOString();
53837
+ const dateStr = timestamp.slice(0, 10);
53838
+ const monthStr = dateStr.slice(0, 7);
53839
+ const sessionId = opts.sessionId && opts.sessionId.trim() ? opts.sessionId.trim() : "general";
53840
+ const id = `pmt_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
53841
+ const content = opts.content ?? "";
53842
+ const lines = content.split("\n");
53843
+ const characterCount = content.length;
53844
+ const lineCount2 = lines.length;
53845
+ const tokenEstimate = Math.ceil(characterCount / 4);
53846
+ const entry = {
53847
+ id,
53848
+ timestamp,
53849
+ sessionId,
53850
+ projectRoot: opts.projectRoot,
53851
+ role: opts.role ?? (opts.category === "system_prompt" ? "system" : "user"),
53852
+ category: opts.category,
53853
+ content,
53854
+ rawContent: opts.rawContent,
53855
+ metadata: {
53856
+ model: opts.model,
53857
+ provider: opts.provider,
53858
+ iterationIndex: opts.iterationIndex,
53859
+ tokenEstimate,
53860
+ characterCount,
53861
+ lineCount: lineCount2,
53862
+ activeTools: opts.activeTools,
53863
+ contextFiles: opts.contextFiles,
53864
+ durationMs: opts.durationMs,
53865
+ decisionReason: opts.decisionReason,
53866
+ tags: opts.tags
53867
+ }
53868
+ };
53869
+ const basePromptsDir = path77.join(opts.projectRoot, ".wrongstack", "prompts");
53870
+ const dayDir = path77.join(basePromptsDir, monthStr, dateStr);
53871
+ try {
53872
+ await fs31.mkdir(dayDir, { recursive: true });
53873
+ await ensureGitignore(opts.projectRoot);
53874
+ const sessionJsonlFile = path77.join(dayDir, `session-${sessionFileId(sessionId)}.jsonl`);
53875
+ await fs31.appendFile(sessionJsonlFile, JSON.stringify(entry) + "\n", "utf8");
53876
+ const sessionMdFile = path77.join(dayDir, `session-${sessionFileId(sessionId)}.md`);
53877
+ const mdSection = formatEntryMarkdown(entry);
53878
+ await fs31.appendFile(sessionMdFile, mdSection, "utf8");
53879
+ const dailySummaryFile = path77.join(dayDir, "daily-summary.md");
53880
+ await updateDailySummary(dailySummaryFile, dateStr, entry);
53881
+ await updateRootCatalog(basePromptsDir, monthStr, dateStr, sessionId, entry);
53882
+ } catch (err) {
53883
+ console.error?.(`Failed to write hierarchical prompt journal: ${err}`);
53884
+ }
53885
+ return entry;
53886
+ }
53887
+ function formatEntryMarkdown(entry) {
53888
+ const tagList = [
53889
+ `**Category:** \`${entry.category}\``,
53890
+ `**Role:** \`${entry.role}\``,
53891
+ entry.metadata.model ? `**Model:** \`${entry.metadata.model}\`` : null,
53892
+ `**Tokens (est):** ~${entry.metadata.tokenEstimate}`,
53893
+ entry.metadata.iterationIndex !== void 0 ? `**Iteration:** #${entry.metadata.iterationIndex}` : null,
53894
+ `**Session:** \`${entry.sessionId}\``
53895
+ ].filter(Boolean).join(" | ");
53896
+ let md = `
53897
+ ### \u{1F4DD} [${entry.timestamp}] \`${entry.id}\`
53898
+ ${tagList}
53899
+
53900
+ `;
53901
+ if (entry.metadata.decisionReason) {
53902
+ md += `> **Rationale:** ${entry.metadata.decisionReason}
53903
+
53904
+ `;
53905
+ }
53906
+ if (entry.metadata.activeTools && entry.metadata.activeTools.length > 0) {
53907
+ md += `*Active Tools:* \`${entry.metadata.activeTools.join("`, `")}\`
53908
+
53909
+ `;
53910
+ }
53911
+ if (entry.rawContent && entry.rawContent !== entry.content) {
53912
+ md += `**Raw Input:**
53913
+ \`\`\`text
53914
+ ${entry.rawContent.trim()}
53915
+ \`\`\`
53916
+
53917
+ `;
53918
+ md += `**Refined / Injected Prompt:**
53919
+ \`\`\`text
53920
+ ${entry.content.trim()}
53921
+ \`\`\`
53922
+
53923
+ `;
53924
+ } else {
53925
+ md += `**Prompt Content:**
53926
+ \`\`\`text
53927
+ ${entry.content.trim()}
53928
+ \`\`\`
53929
+
53930
+ `;
53931
+ }
53932
+ md += `---
53933
+ `;
53934
+ return md;
53935
+ }
53936
+ async function updateDailySummary(summaryFile, dateStr, entry) {
53937
+ try {
53938
+ let content = "";
53939
+ try {
53940
+ content = await fs31.readFile(summaryFile, "utf8");
53941
+ } catch {
53942
+ content = `# \u{1F4C5} Daily Prompt Summary \u2014 ${dateStr}
53943
+
53944
+ | Time | ID | Session | Category | Model | Tokens | Rationale |
53945
+ | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
53946
+ `;
53947
+ }
53948
+ const time = entry.timestamp.slice(11, 19);
53949
+ const model = entry.metadata.model ?? "-";
53950
+ const reason = entry.metadata.decisionReason ? entry.metadata.decisionReason.slice(0, 40) : "-";
53951
+ const row = `| ${time} | [\`${entry.id}\`](session-${sessionFileId(entry.sessionId)}.md) | \`${entry.sessionId}\` | \`${entry.category}\` | ${model} | ~${entry.metadata.tokenEstimate} | ${reason} |
53952
+ `;
53953
+ await fs31.writeFile(summaryFile, content + row, "utf8");
53954
+ } catch {
53955
+ }
53956
+ }
53957
+ async function updateRootCatalog(baseDir2, monthStr, dateStr, sessionId, entry) {
53958
+ const indexJsonFile = path77.join(baseDir2, "index.json");
53959
+ const indexMdFile = path77.join(baseDir2, "index.md");
53960
+ let catalog;
53961
+ try {
53962
+ const raw = await fs31.readFile(indexJsonFile, "utf8");
53963
+ catalog = JSON.parse(raw);
53964
+ } catch {
53965
+ catalog = {
53966
+ updatedAt: entry.timestamp,
53967
+ totalPrompts: 0,
53968
+ totalTokensEstimated: 0,
53969
+ months: {}
53970
+ };
53971
+ }
53972
+ catalog.updatedAt = entry.timestamp;
53973
+ catalog.totalPrompts += 1;
53974
+ catalog.totalTokensEstimated += entry.metadata.tokenEstimate;
53975
+ if (!catalog.months[monthStr]) {
53976
+ catalog.months[monthStr] = { days: {} };
53977
+ }
53978
+ const monthData = catalog.months[monthStr];
53979
+ if (!monthData.days[dateStr]) {
53980
+ monthData.days[dateStr] = { sessions: {} };
53981
+ }
53982
+ const dayData = monthData.days[dateStr];
53983
+ if (!dayData.sessions[sessionId]) {
53984
+ dayData.sessions[sessionId] = {
53985
+ promptCount: 0,
53986
+ tokenEstimate: 0,
53987
+ lastTimestamp: entry.timestamp,
53988
+ categories: {}
53989
+ };
53990
+ }
53991
+ const sessionData = dayData.sessions[sessionId];
53992
+ sessionData.promptCount += 1;
53993
+ sessionData.tokenEstimate += entry.metadata.tokenEstimate;
53994
+ sessionData.lastTimestamp = entry.timestamp;
53995
+ sessionData.categories[entry.category] = (sessionData.categories[entry.category] ?? 0) + 1;
53996
+ try {
53997
+ await fs31.writeFile(indexJsonFile, JSON.stringify(catalog, null, 2), "utf8");
53998
+ let md = `# \u{1F5C2}\uFE0F Prompt Journal Navigation Index
53999
+
54000
+ `;
54001
+ md += `* **Total Prompts Logged:** ${catalog.totalPrompts}
54002
+ `;
54003
+ md += `* **Total Tokens (est):** ~${catalog.totalTokensEstimated.toLocaleString()}
54004
+ `;
54005
+ md += `* **Last Recorded Activity:** ${catalog.updatedAt}
54006
+
54007
+ `;
54008
+ md += `## \u{1F4C5} Recorded Dates & Sessions
54009
+
54010
+ `;
54011
+ md += `| Date | Session | Prompts | Tokens (est) | Daily Log | Session Log |
54012
+ `;
54013
+ md += `| :--- | :--- | :--- | :--- | :--- | :--- |
54014
+ `;
54015
+ for (const [m, mObj] of Object.entries(catalog.months).sort().reverse()) {
54016
+ for (const [d, dObj] of Object.entries(mObj.days).sort().reverse()) {
54017
+ for (const [sId, sData] of Object.entries(dObj.sessions)) {
54018
+ const dailyLink = `[daily-summary.md](./${m}/${d}/daily-summary.md)`;
54019
+ const sessionLink = `[session-${sessionFileId(sId)}.md](./${m}/${d}/session-${sessionFileId(sId)}.md)`;
54020
+ md += `| **${d}** | \`${sId}\` | ${sData.promptCount} | ~${sData.tokenEstimate.toLocaleString()} | ${dailyLink} | ${sessionLink} |
54021
+ `;
54022
+ }
54023
+ }
54024
+ }
54025
+ await fs31.writeFile(indexMdFile, md, "utf8");
54026
+ } catch {
54027
+ }
54028
+ }
54029
+ async function getPromptJournalEntries(projectRoot, filter = {}) {
54030
+ const basePromptsDir = path77.join(projectRoot, ".wrongstack", "prompts");
54031
+ const results = [];
54032
+ try {
54033
+ const months = await fs31.readdir(basePromptsDir);
54034
+ for (const month of months) {
54035
+ if (!/^\d{4}-\d{2}$/.test(month)) continue;
54036
+ if (filter.month && filter.month !== month) continue;
54037
+ const monthDir = path77.join(basePromptsDir, month);
54038
+ const days = await fs31.readdir(monthDir);
54039
+ for (const day of days) {
54040
+ if (!/^\d{4}-\d{2}-\d{2}$/.test(day)) continue;
54041
+ if (filter.date && filter.date !== day) continue;
54042
+ const dayDir = path77.join(monthDir, day);
54043
+ const files = await fs31.readdir(dayDir);
54044
+ const jsonlFiles = files.filter((f) => f.startsWith("session-") && f.endsWith(".jsonl"));
54045
+ for (const jsonlFile of jsonlFiles) {
54046
+ const sessionMatch = jsonlFile.match(/^session-(.+)\.jsonl$/);
54047
+ const sId = sessionMatch ? sessionMatch[1] : void 0;
54048
+ if (filter.sessionId && sId !== sessionFileId(filter.sessionId)) continue;
54049
+ const filePath = path77.join(dayDir, jsonlFile);
54050
+ const content = await fs31.readFile(filePath, "utf8");
54051
+ const lines = content.split("\n");
54052
+ for (const line of lines) {
54053
+ if (!line.trim()) continue;
54054
+ try {
54055
+ const entry = JSON.parse(line);
54056
+ if (filter.sessionId && sessionFileId(entry.sessionId) !== sessionFileId(filter.sessionId)) {
54057
+ continue;
54058
+ }
54059
+ if (filter.category && entry.category !== filter.category) continue;
54060
+ if (filter.since && entry.timestamp < filter.since) continue;
54061
+ results.push(entry);
54062
+ } catch {
54063
+ }
54064
+ }
54065
+ }
54066
+ }
54067
+ }
54068
+ } catch {
54069
+ return [];
54070
+ }
54071
+ results.sort((a, b) => a.timestamp.localeCompare(b.timestamp));
54072
+ if (filter.limit && results.length > filter.limit) {
54073
+ return results.slice(-filter.limit);
54074
+ }
54075
+ return results;
54076
+ }
54077
+
53756
54078
  // src/core/provider-runner.ts
53757
54079
  init_errors();
53758
54080
 
@@ -54471,6 +54793,36 @@ function buildQueuedMessagesBlock(items) {
54471
54793
  function toError(err) {
54472
54794
  return err instanceof Error ? err : new Error(String(err));
54473
54795
  }
54796
+ function recordSelfHealingRetry(a, err, reason) {
54797
+ const projectRoot = a.ctx.projectRoot;
54798
+ if (!projectRoot) return;
54799
+ void recordPromptJournalEntry({
54800
+ projectRoot,
54801
+ sessionId: resolveEventSessionId(a.ctx),
54802
+ category: "self_healing_retry",
54803
+ content: toErrorMessage(err),
54804
+ decisionReason: reason,
54805
+ model: a.ctx.model,
54806
+ provider: a.ctx.provider?.id,
54807
+ activeTools: a.ctx.tools?.map((tool) => tool.name) ?? []
54808
+ }).catch(() => {
54809
+ });
54810
+ }
54811
+ function recordAutonomousContinue(a, text2) {
54812
+ const projectRoot = a.ctx.projectRoot;
54813
+ if (!projectRoot) return;
54814
+ void recordPromptJournalEntry({
54815
+ projectRoot,
54816
+ sessionId: resolveEventSessionId(a.ctx),
54817
+ category: "autonomous_next_step",
54818
+ content: text2,
54819
+ decisionReason: "text-marker autonomous continue",
54820
+ model: a.ctx.model,
54821
+ provider: a.ctx.provider?.id,
54822
+ activeTools: a.ctx.tools?.map((tool) => tool.name) ?? []
54823
+ }).catch(() => {
54824
+ });
54825
+ }
54474
54826
  function signalAbortReason(signal) {
54475
54827
  const r = signal.reason;
54476
54828
  if (r instanceof Error) return r.message || r.name;
@@ -54761,6 +55113,7 @@ ${text2}` : text2;
54761
55113
  }
54762
55114
  if (extDecision.model) a.ctx.model = extDecision.model;
54763
55115
  a.logger.info("Extension requested retry; retrying turn");
55116
+ recordSelfHealingRetry(a, err, "extension-requested provider retry");
54764
55117
  continue;
54765
55118
  }
54766
55119
  }
@@ -54790,6 +55143,7 @@ ${text2}` : text2;
54790
55143
  }
54791
55144
  if (recovered.model) a.ctx.model = recovered.model;
54792
55145
  a.logger.info(`Recovered provider error via ${recovered.reason}; retrying turn`);
55146
+ recordSelfHealingRetry(a, err, recovered.reason);
54793
55147
  continue;
54794
55148
  }
54795
55149
  recoveryRetries = 0;
@@ -54849,6 +55203,7 @@ ${text2}` : text2;
54849
55203
  continue;
54850
55204
  }
54851
55205
  if (autonomousContinue && responseResult.directive === "continue") {
55206
+ recordAutonomousContinue(a, finalText);
54852
55207
  await a.extensions.runAfterIteration(a.ctx, i);
54853
55208
  continue;
54854
55209
  }
@@ -58463,8 +58818,8 @@ var KNOWN_TOKEN_NAMES = Object.values(KNOWN_TOKEN_GROUPS).flat();
58463
58818
 
58464
58819
  // src/execution/design-kit-loader.ts
58465
58820
  import { existsSync as existsSync10 } from "node:fs";
58466
- import * as fs31 from "node:fs/promises";
58467
- import * as path77 from "node:path";
58821
+ import * as fs32 from "node:fs/promises";
58822
+ import * as path78 from "node:path";
58468
58823
  import { fileURLToPath as fileURLToPath8 } from "node:url";
58469
58824
  var KIT_FILE = "KIT.md";
58470
58825
  var TOKENS_FILE = "tokens.json";
@@ -58564,15 +58919,15 @@ var DefaultDesignKitLoader = class {
58564
58919
  for (const { dir, source } of this.dirs) {
58565
58920
  let entries;
58566
58921
  try {
58567
- entries = await fs31.readdir(dir, { withFileTypes: true });
58922
+ entries = await fs32.readdir(dir, { withFileTypes: true });
58568
58923
  } catch {
58569
58924
  continue;
58570
58925
  }
58571
58926
  for (const e of entries) {
58572
58927
  if (!e.isDirectory()) continue;
58573
- const kitFile = path77.join(dir, e.name, KIT_FILE);
58928
+ const kitFile = path78.join(dir, e.name, KIT_FILE);
58574
58929
  try {
58575
- const raw = await fs31.readFile(kitFile, "utf8");
58930
+ const raw = await fs32.readFile(kitFile, "utf8");
58576
58931
  const fm = parseKitFrontmatter(raw);
58577
58932
  const id = fm.id ?? e.name;
58578
58933
  if (!fm.name) continue;
@@ -58633,7 +58988,7 @@ var DefaultDesignKitLoader = class {
58633
58988
  if (cached2 !== void 0) return cached2;
58634
58989
  const m = await this.find(id);
58635
58990
  if (!m) throw new Error(`Design kit "${id}" not found`);
58636
- const raw = await fs31.readFile(m.path, "utf8");
58991
+ const raw = await fs32.readFile(m.path, "utf8");
58637
58992
  const body = narrowStackSections(stripFrontmatter(raw), stack);
58638
58993
  this.bodyCache.set(key, body);
58639
58994
  return body;
@@ -58645,9 +59000,9 @@ var DefaultDesignKitLoader = class {
58645
59000
  const m = await this.find(id);
58646
59001
  let tokens;
58647
59002
  if (m) {
58648
- const tokensPath = path77.join(path77.dirname(m.path), TOKENS_FILE);
59003
+ const tokensPath = path78.join(path78.dirname(m.path), TOKENS_FILE);
58649
59004
  try {
58650
- const raw = await fs31.readFile(tokensPath, "utf8");
59005
+ const raw = await fs32.readFile(tokensPath, "utf8");
58651
59006
  tokens = JSON.parse(raw);
58652
59007
  } catch {
58653
59008
  tokens = void 0;
@@ -58707,12 +59062,12 @@ function mergeKitTokens(base, own) {
58707
59062
  }
58708
59063
  function resolveBundledDesignKitsDir() {
58709
59064
  try {
58710
- const here = path77.dirname(fileURLToPath8(import.meta.url));
59065
+ const here = path78.dirname(fileURLToPath8(import.meta.url));
58711
59066
  const candidates = [
58712
- path77.join(here, "design-kits"),
58713
- path77.join(here, "..", "design-kits"),
58714
- path77.join(here, "..", "..", "design-kits"),
58715
- path77.join(here, "..", "..", "..", "design-kits")
59067
+ path78.join(here, "design-kits"),
59068
+ path78.join(here, "..", "design-kits"),
59069
+ path78.join(here, "..", "..", "design-kits"),
59070
+ path78.join(here, "..", "..", "..", "design-kits")
58716
59071
  ];
58717
59072
  for (const c of candidates) {
58718
59073
  if (existsSync10(c)) return c;
@@ -58750,11 +59105,11 @@ function _resetDesignKitLoaderMemo() {
58750
59105
 
58751
59106
  // src/execution/design-project-store.ts
58752
59107
  import { existsSync as existsSync11 } from "node:fs";
58753
- import * as fs32 from "node:fs/promises";
58754
- import * as path78 from "node:path";
59108
+ import * as fs33 from "node:fs/promises";
59109
+ import * as path79 from "node:path";
58755
59110
  var DESIGN_DIR = ".design";
58756
59111
  function designProjectDir(projectRoot) {
58757
- return path78.join(projectRoot, DESIGN_DIR);
59112
+ return path79.join(projectRoot, DESIGN_DIR);
58758
59113
  }
58759
59114
  var RULE_FILES = ["rules.md", "RULES.md", "design.md"];
58760
59115
  var rulesCache = /* @__PURE__ */ new Map();
@@ -58769,7 +59124,7 @@ async function loadProjectDesignRules(projectRoot) {
58769
59124
  let rules;
58770
59125
  for (const name of RULE_FILES) {
58771
59126
  try {
58772
- const txt = await fs32.readFile(path78.join(designProjectDir(projectRoot), name), "utf8");
59127
+ const txt = await fs33.readFile(path79.join(designProjectDir(projectRoot), name), "utf8");
58773
59128
  if (txt.trim()) {
58774
59129
  rules = txt.trim();
58775
59130
  break;
@@ -58795,7 +59150,7 @@ function parseOverrides(value) {
58795
59150
  }
58796
59151
  async function loadActiveKit(projectRoot) {
58797
59152
  try {
58798
- const raw = await fs32.readFile(path78.join(designProjectDir(projectRoot), "active.json"), "utf8");
59153
+ const raw = await fs33.readFile(path79.join(designProjectDir(projectRoot), "active.json"), "utf8");
58799
59154
  const parsed = JSON.parse(raw);
58800
59155
  if (parsed && typeof parsed.kit === "string") {
58801
59156
  return {
@@ -58828,11 +59183,11 @@ function applyTokenOverrides(tokens, overrides) {
58828
59183
  }
58829
59184
  async function ensureDesignDir(projectRoot) {
58830
59185
  const dir = designProjectDir(projectRoot);
58831
- await fs32.mkdir(dir, { recursive: true });
58832
- const gi = path78.join(dir, ".gitignore");
59186
+ await fs33.mkdir(dir, { recursive: true });
59187
+ const gi = path79.join(dir, ".gitignore");
58833
59188
  if (!existsSync11(gi)) {
58834
59189
  try {
58835
- await fs32.writeFile(gi, "*\n");
59190
+ await fs33.writeFile(gi, "*\n");
58836
59191
  } catch {
58837
59192
  }
58838
59193
  }
@@ -58843,11 +59198,11 @@ async function recordKitChoice(projectRoot, kit, stack, source, isoTime, overrid
58843
59198
  const dir = await ensureDesignDir(projectRoot);
58844
59199
  const record = { kit, stack: stack ?? null };
58845
59200
  if (overrides && Object.keys(overrides).length > 0) record.overrides = overrides;
58846
- await fs32.writeFile(path78.join(dir, "active.json"), `${JSON.stringify(record, null, 2)}
59201
+ await fs33.writeFile(path79.join(dir, "active.json"), `${JSON.stringify(record, null, 2)}
58847
59202
  `);
58848
59203
  const line = `- ${isoTime} \xB7 kit=${kit}${stack ? ` stack=${stack}` : ""} \xB7 via=${source}
58849
59204
  `;
58850
- await fs32.appendFile(path78.join(dir, "decisions.md"), line);
59205
+ await fs33.appendFile(path79.join(dir, "decisions.md"), line);
58851
59206
  } catch {
58852
59207
  }
58853
59208
  }
@@ -58863,11 +59218,11 @@ async function recordOverrides(projectRoot, patch, isoTime) {
58863
59218
  const dir = await ensureDesignDir(projectRoot);
58864
59219
  const record = { kit: active.kit, stack: active.stack ?? null };
58865
59220
  if (Object.keys(merged).length > 0) record.overrides = merged;
58866
- await fs32.writeFile(path78.join(dir, "active.json"), `${JSON.stringify(record, null, 2)}
59221
+ await fs33.writeFile(path79.join(dir, "active.json"), `${JSON.stringify(record, null, 2)}
58867
59222
  `);
58868
59223
  const keys = Object.keys(patch).join(",");
58869
- await fs32.appendFile(
58870
- path78.join(dir, "decisions.md"),
59224
+ await fs33.appendFile(
59225
+ path79.join(dir, "decisions.md"),
58871
59226
  `- ${isoTime} \xB7 kit=${active.kit} \xB7 override=${keys} \xB7 via=set
58872
59227
  `
58873
59228
  );
@@ -58877,7 +59232,7 @@ async function recordOverrides(projectRoot, patch, isoTime) {
58877
59232
  }
58878
59233
  async function clearPersistedActiveKit(projectRoot) {
58879
59234
  try {
58880
- await fs32.rm(path78.join(designProjectDir(projectRoot), "active.json"), { force: true });
59235
+ await fs33.rm(path79.join(designProjectDir(projectRoot), "active.json"), { force: true });
58881
59236
  } catch {
58882
59237
  }
58883
59238
  }
@@ -62712,8 +63067,8 @@ Summarize the following message range:`;
62712
63067
  };
62713
63068
 
62714
63069
  // src/execution/skill-loader.ts
62715
- import * as fs33 from "node:fs/promises";
62716
- import * as path79 from "node:path";
63070
+ import * as fs34 from "node:fs/promises";
63071
+ import * as path80 from "node:path";
62717
63072
 
62718
63073
  // src/skills/foreign-sources.ts
62719
63074
  var FOREIGN_SKILL_TOOLS = [
@@ -62783,7 +63138,7 @@ async function entryIsDirectory(dir, entry) {
62783
63138
  if (entry.isDirectory()) return true;
62784
63139
  if (entry.isSymbolicLink()) {
62785
63140
  try {
62786
- return (await fs33.stat(path79.join(dir, entry.name))).isDirectory();
63141
+ return (await fs34.stat(path80.join(dir, entry.name))).isDirectory();
62787
63142
  } catch {
62788
63143
  return false;
62789
63144
  }
@@ -62807,7 +63162,7 @@ var DefaultSkillLoader = class {
62807
63162
  for (const tool of FOREIGN_SKILL_TOOLS) {
62808
63163
  if (!foreignIds.includes(tool.id)) continue;
62809
63164
  dirs.push({
62810
- dir: path79.join(root, "." + tool.id, tool.subdir),
63165
+ dir: path80.join(root, "." + tool.id, tool.subdir),
62811
63166
  source: "foreign",
62812
63167
  originTool: tool.id
62813
63168
  });
@@ -62832,15 +63187,15 @@ var DefaultSkillLoader = class {
62832
63187
  this.shadowed = [];
62833
63188
  for (const { dir, source, originTool } of this.dirs) {
62834
63189
  try {
62835
- const entries = (await fs33.readdir(dir, { withFileTypes: true })).sort(
63190
+ const entries = (await fs34.readdir(dir, { withFileTypes: true })).sort(
62836
63191
  (a, b) => a.name < b.name ? -1 : a.name > b.name ? 1 : 0
62837
63192
  );
62838
63193
  for (const e of entries) {
62839
63194
  if (!await entryIsDirectory(dir, e)) continue;
62840
- const skillFile = path79.join(dir, e.name, "SKILL.md");
63195
+ const skillFile = path80.join(dir, e.name, "SKILL.md");
62841
63196
  let raw;
62842
63197
  try {
62843
- raw = await fs33.readFile(skillFile, "utf8");
63198
+ raw = await fs34.readFile(skillFile, "utf8");
62844
63199
  } catch {
62845
63200
  continue;
62846
63201
  }
@@ -62959,7 +63314,7 @@ var DefaultSkillLoader = class {
62959
63314
  if (cached2 !== void 0) return cached2;
62960
63315
  const m = await this.find(name);
62961
63316
  if (!m) throw new Error(`Skill "${name}" not found`);
62962
- const body = await fs33.readFile(m.path, "utf8");
63317
+ const body = await fs34.readFile(m.path, "utf8");
62963
63318
  this.bodyCache.set(key, body);
62964
63319
  return body;
62965
63320
  }
@@ -62969,12 +63324,12 @@ var DefaultSkillLoader = class {
62969
63324
  if (cached2 !== void 0) return cached2;
62970
63325
  const m = await this.find(name);
62971
63326
  if (!m) throw new Error(`Skill "${name}" not found`);
62972
- const savePath = path79.join(path79.dirname(m.path), "SKILL.save.md");
63327
+ const savePath = path80.join(path80.dirname(m.path), "SKILL.save.md");
62973
63328
  let result;
62974
63329
  try {
62975
- result = await fs33.readFile(savePath, "utf8");
63330
+ result = await fs34.readFile(savePath, "utf8");
62976
63331
  } catch {
62977
- const full = await fs33.readFile(m.path, "utf8");
63332
+ const full = await fs34.readFile(m.path, "utf8");
62978
63333
  const body = stripFrontmatter(full);
62979
63334
  const compact = compactSkillBody(body);
62980
63335
  if (compact) {
@@ -63002,14 +63357,14 @@ function parseDescriptionFromText(desc) {
63002
63357
  }
63003
63358
 
63004
63359
  // src/execution/prompt-loader.ts
63005
- import * as fs35 from "node:fs/promises";
63006
- import * as path81 from "node:path";
63360
+ import * as fs36 from "node:fs/promises";
63361
+ import * as path82 from "node:path";
63007
63362
 
63008
63363
  // src/storage/prompt-store.ts
63009
63364
  init_atomic_write();
63010
63365
  import { createHash as createHash28 } from "node:crypto";
63011
- import * as fs34 from "node:fs/promises";
63012
- import * as path80 from "node:path";
63366
+ import * as fs35 from "node:fs/promises";
63367
+ import * as path81 from "node:path";
63013
63368
  var SCHEMA_VERSION3 = 2;
63014
63369
  function promptChecksum(content) {
63015
63370
  return createHash28("sha256").update(content, "utf8").digest("hex");
@@ -63073,12 +63428,12 @@ var DefaultPromptStore = class {
63073
63428
  await ensureDir(this.dir);
63074
63429
  const entries = [];
63075
63430
  try {
63076
- const files = await fs34.readdir(this.dir);
63431
+ const files = await fs35.readdir(this.dir);
63077
63432
  for (const file of files) {
63078
63433
  if (!file.endsWith(".json")) continue;
63079
63434
  try {
63080
63435
  const raw = JSON.parse(
63081
- await fs34.readFile(path80.join(this.dir, file), "utf8")
63436
+ await fs35.readFile(path81.join(this.dir, file), "utf8")
63082
63437
  );
63083
63438
  const migrated = migratePromptEntry(raw.entry);
63084
63439
  if (migrated) entries.push(migrated);
@@ -63092,9 +63447,9 @@ var DefaultPromptStore = class {
63092
63447
  );
63093
63448
  }
63094
63449
  async get(id) {
63095
- const file = path80.join(this.dir, `${id}.json`);
63450
+ const file = path81.join(this.dir, `${id}.json`);
63096
63451
  try {
63097
- const raw = JSON.parse(await fs34.readFile(file, "utf8"));
63452
+ const raw = JSON.parse(await fs35.readFile(file, "utf8"));
63098
63453
  return migratePromptEntry(raw.entry);
63099
63454
  } catch {
63100
63455
  return null;
@@ -63102,14 +63457,14 @@ var DefaultPromptStore = class {
63102
63457
  }
63103
63458
  async save(entry) {
63104
63459
  await ensureDir(this.dir);
63105
- const file = path80.join(this.dir, `${entry.id}.json`);
63460
+ const file = path81.join(this.dir, `${entry.id}.json`);
63106
63461
  const raw = { version: SCHEMA_VERSION3, entry };
63107
63462
  await atomicWrite(file, JSON.stringify(raw, null, 2));
63108
63463
  }
63109
63464
  async delete(id) {
63110
- const file = path80.join(this.dir, `${id}.json`);
63465
+ const file = path81.join(this.dir, `${id}.json`);
63111
63466
  try {
63112
- await fs34.unlink(file);
63467
+ await fs35.unlink(file);
63113
63468
  return true;
63114
63469
  } catch {
63115
63470
  return false;
@@ -63196,7 +63551,7 @@ var DefaultPromptLoader = class {
63196
63551
  constructor(opts) {
63197
63552
  this.projectStore = typeof opts.paths.inProjectPrompts === "string" ? new DefaultPromptStore(opts.paths.inProjectPrompts) : void 0;
63198
63553
  this.userStore = typeof opts.paths.globalPrompts === "string" ? new DefaultPromptStore(opts.paths.globalPrompts) : void 0;
63199
- this.builtinDir = opts.bundledDir ? path81.join(opts.bundledDir, "prompts") : void 0;
63554
+ this.builtinDir = opts.bundledDir ? path82.join(opts.bundledDir, "prompts") : void 0;
63200
63555
  }
63201
63556
  async list() {
63202
63557
  if (this.cache) return this.cache;
@@ -63309,7 +63664,7 @@ var DefaultPromptLoader = class {
63309
63664
  const files = await walkJson(dir);
63310
63665
  for (const file of files) {
63311
63666
  try {
63312
- const parsed = JSON.parse(await fs35.readFile(file, "utf8"));
63667
+ const parsed = JSON.parse(await fs36.readFile(file, "utf8"));
63313
63668
  const migrated = migratePromptEntry(parsed);
63314
63669
  if (migrated) out.push({ ...migrated, source: "builtin" });
63315
63670
  } catch {
@@ -63323,12 +63678,12 @@ async function walkJson(dir) {
63323
63678
  const out = [];
63324
63679
  let entries;
63325
63680
  try {
63326
- entries = await fs35.readdir(dir, { withFileTypes: true });
63681
+ entries = await fs36.readdir(dir, { withFileTypes: true });
63327
63682
  } catch {
63328
63683
  return out;
63329
63684
  }
63330
63685
  for (const e of entries) {
63331
- const full = path81.join(dir, e.name);
63686
+ const full = path82.join(dir, e.name);
63332
63687
  if (e.isDirectory()) {
63333
63688
  out.push(...await walkJson(full));
63334
63689
  } else if (e.name.endsWith(".json") && e.name !== "index.json" && e.name !== "schema.json") {
@@ -63516,8 +63871,8 @@ function readPolicy(ctx) {
63516
63871
 
63517
63872
  // src/execution/tool-executor.ts
63518
63873
  import { randomUUID as randomUUID37 } from "node:crypto";
63519
- import * as fs37 from "node:fs/promises";
63520
- import * as path84 from "node:path";
63874
+ import * as fs38 from "node:fs/promises";
63875
+ import * as path85 from "node:path";
63521
63876
  init_errors();
63522
63877
 
63523
63878
  // src/types/tool-executor.ts
@@ -63538,8 +63893,8 @@ var ToolErrorCategory = /* @__PURE__ */ ((ToolErrorCategory2) => {
63538
63893
 
63539
63894
  // src/execution/tool-executor-support.ts
63540
63895
  import { createHash as createHash29, randomUUID as randomUUID35 } from "node:crypto";
63541
- import * as fs36 from "node:fs/promises";
63542
- import * as path82 from "node:path";
63896
+ import * as fs37 from "node:fs/promises";
63897
+ import * as path83 from "node:path";
63543
63898
  init_errors();
63544
63899
 
63545
63900
  // src/types/tool-markers.ts
@@ -63665,12 +64020,12 @@ async function maybePersistLargeToolOutput(toolName, content, budget) {
63665
64020
  return content;
63666
64021
  }
63667
64022
  try {
63668
- const dir = path82.join(wstackGlobalRoot(), "tool-output");
63669
- await fs36.mkdir(dir, { recursive: true });
64023
+ const dir = path83.join(wstackGlobalRoot(), "tool-output");
64024
+ await fs37.mkdir(dir, { recursive: true });
63670
64025
  const safeTool = toolName.replace(/[^a-zA-Z0-9._-]+/g, "_").slice(0, 40) || "tool";
63671
64026
  const stamp = (/* @__PURE__ */ new Date()).toISOString().replace(/[:.]/g, "-");
63672
- const filePath = path82.join(dir, `${stamp}-${safeTool}-${randomUUID35()}.log`);
63673
- await fs36.writeFile(filePath, content, "utf8");
64027
+ const filePath = path83.join(dir, `${stamp}-${safeTool}-${randomUUID35()}.log`);
64028
+ await fs37.writeFile(filePath, content, "utf8");
63674
64029
  const marker = `[full tool output: ${bytes} bytes at ${filePath}; read/grep that file selectively instead of re-running or requesting more output]`;
63675
64030
  const fixedBytes = Buffer.byteLength(marker + TOOL_OUTPUT_ARTIFACT_OMISSION, "utf8");
63676
64031
  const previewBytes = Math.min(
@@ -63874,7 +64229,7 @@ import { isDeepStrictEqual } from "node:util";
63874
64229
 
63875
64230
  // src/security/kanban-boundary.ts
63876
64231
  import { realpath as realpath3 } from "node:fs/promises";
63877
- import * as path83 from "node:path";
64232
+ import * as path84 from "node:path";
63878
64233
  import {
63879
64234
  evaluateContractGraphReadiness,
63880
64235
  evaluateKanbanBoundaryOpaque,
@@ -64029,10 +64384,10 @@ function resolveKanbanIdentity(ctx) {
64029
64384
  async function extractCandidatePaths(toolName, input, ctx) {
64030
64385
  if (toolName === "patch" && typeof input["patch"] === "string") {
64031
64386
  const directoryInput = stringValue(input["directory"]) ?? ctx.workingDir;
64032
- const directory = path83.isAbsolute(directoryInput) ? directoryInput : path83.resolve(ctx.workingDir, directoryInput);
64387
+ const directory = path84.isAbsolute(directoryInput) ? directoryInput : path84.resolve(ctx.workingDir, directoryInput);
64033
64388
  const strip = Math.max(1, numericValue(input["strip"]) ?? 1);
64034
64389
  const targets = extractPatchTargets(input["patch"], strip).map(
64035
- (target) => relativeToProject(path83.resolve(directory, target), ctx.projectRoot)
64390
+ (target) => relativeToProject(path84.resolve(directory, target), ctx.projectRoot)
64036
64391
  );
64037
64392
  return Promise.all(targets.map((target) => canonicalizeCandidatePath(target, ctx)));
64038
64393
  }
@@ -64042,7 +64397,7 @@ async function extractCandidatePaths(toolName, input, ctx) {
64042
64397
  collectPathValues(input, values, pathKeys);
64043
64398
  if (toolName === "scaffold" && typeof input["name"] === "string") {
64044
64399
  const cwd = stringValue(input["cwd"]) ?? ctx.workingDir;
64045
- values.push(path83.join(cwd, input["name"]));
64400
+ values.push(path84.join(cwd, input["name"]));
64046
64401
  }
64047
64402
  const candidates = [
64048
64403
  ...new Set(values.flatMap(splitPathList).map((value) => resolveInputPath(value, ctx)))
@@ -64050,21 +64405,21 @@ async function extractCandidatePaths(toolName, input, ctx) {
64050
64405
  return Promise.all(candidates.map((candidate) => canonicalizeCandidatePath(candidate, ctx)));
64051
64406
  }
64052
64407
  async function canonicalizeCandidatePath(candidate, ctx) {
64053
- if (path83.isAbsolute(candidate)) return candidate;
64054
- const absolute = path83.resolve(ctx.projectRoot, candidate);
64408
+ if (path84.isAbsolute(candidate)) return candidate;
64409
+ const absolute = path84.resolve(ctx.projectRoot, candidate);
64055
64410
  const canonicalRoot = await realpath3(ctx.projectRoot).catch(() => ctx.projectRoot);
64056
64411
  let probe2 = absolute;
64057
64412
  const missingSegments = [];
64058
64413
  while (true) {
64059
64414
  try {
64060
- const canonical = path83.join(await realpath3(probe2), ...missingSegments);
64415
+ const canonical = path84.join(await realpath3(probe2), ...missingSegments);
64061
64416
  return relativeToProject(canonical, canonicalRoot);
64062
64417
  } catch (cause) {
64063
64418
  const code = cause.code;
64064
64419
  if (code !== "ENOENT" && code !== "ENOTDIR") return absolute;
64065
- const parent = path83.dirname(probe2);
64420
+ const parent = path84.dirname(probe2);
64066
64421
  if (parent === probe2) return absolute;
64067
- missingSegments.unshift(path83.basename(probe2));
64422
+ missingSegments.unshift(path84.basename(probe2));
64068
64423
  probe2 = parent;
64069
64424
  }
64070
64425
  }
@@ -64087,12 +64442,12 @@ function splitPathList(value) {
64087
64442
  return value.split(",").map((item) => item.trim()).filter(Boolean);
64088
64443
  }
64089
64444
  function resolveInputPath(value, ctx) {
64090
- const absolute = path83.isAbsolute(value) ? value : path83.resolve(ctx.workingDir, value);
64445
+ const absolute = path84.isAbsolute(value) ? value : path84.resolve(ctx.workingDir, value);
64091
64446
  return relativeToProject(absolute, ctx.projectRoot);
64092
64447
  }
64093
64448
  function relativeToProject(absolute, projectRoot) {
64094
- const relative21 = path83.relative(projectRoot, absolute).replace(/\\/g, "/");
64095
- return relative21.startsWith("../") || path83.isAbsolute(relative21) ? absolute : relative21 || ".";
64449
+ const relative21 = path84.relative(projectRoot, absolute).replace(/\\/g, "/");
64450
+ return relative21.startsWith("../") || path84.isAbsolute(relative21) ? absolute : relative21 || ".";
64096
64451
  }
64097
64452
  function extractPatchTargets(patchText, strip) {
64098
64453
  const targets = [];
@@ -64677,10 +65032,10 @@ var ToolExecutor = class _ToolExecutor {
64677
65032
  const inputPath = use.input && typeof use.input === "object" ? use.input.path : void 0;
64678
65033
  const caps = tool.capabilities ?? [];
64679
65034
  const hasFileCapability = caps.includes("fs.read") || caps.includes("fs.write");
64680
- const absPath = hasFileCapability && typeof inputPath === "string" ? path84.isAbsolute(inputPath) ? inputPath : path84.resolve(ctx.projectRoot, inputPath) : void 0;
65035
+ const absPath = hasFileCapability && typeof inputPath === "string" ? path85.isAbsolute(inputPath) ? inputPath : path85.resolve(ctx.projectRoot, inputPath) : void 0;
64681
65036
  let writeTargetExisted;
64682
65037
  if (tool.name === "write" && caps.includes("fs.write") && absPath) {
64683
- writeTargetExisted = await fs37.stat(absPath).then(
65038
+ writeTargetExisted = await fs38.stat(absPath).then(
64684
65039
  (stat40) => stat40.isFile(),
64685
65040
  (error2) => error2.code === "ENOENT" ? false : void 0
64686
65041
  );
@@ -65437,28 +65792,28 @@ function codexModelMeta(id) {
65437
65792
 
65438
65793
  // src/models/mode-store.ts
65439
65794
  init_atomic_write();
65440
- import * as fs38 from "node:fs/promises";
65441
- import * as path86 from "node:path";
65795
+ import * as fs39 from "node:fs/promises";
65796
+ import * as path87 from "node:path";
65442
65797
 
65443
65798
  // src/types/mode-prompts.ts
65444
65799
  import { readFileSync as readFileSync23, statSync as statSync9 } from "node:fs";
65445
- import * as path85 from "node:path";
65800
+ import * as path86 from "node:path";
65446
65801
  import { fileURLToPath as fileURLToPath9 } from "node:url";
65447
65802
  function modePrompt(id) {
65448
65803
  for (const dir of modePromptDirCandidates()) {
65449
65804
  try {
65450
- return readFileSync23(path85.join(dir, `${id}.md`), "utf8").trimEnd();
65805
+ return readFileSync23(path86.join(dir, `${id}.md`), "utf8").trimEnd();
65451
65806
  } catch {
65452
65807
  }
65453
65808
  }
65454
65809
  return "";
65455
65810
  }
65456
65811
  function modePromptDirCandidates() {
65457
- const here = path85.dirname(fileURLToPath9(import.meta.url));
65812
+ const here = path86.dirname(fileURLToPath9(import.meta.url));
65458
65813
  const candidates = [
65459
- path85.resolve(here, "../../instructions/modes"),
65460
- path85.resolve(here, "../instructions/modes"),
65461
- path85.resolve(here, "instructions/modes")
65814
+ path86.resolve(here, "../../instructions/modes"),
65815
+ path86.resolve(here, "../instructions/modes"),
65816
+ path86.resolve(here, "instructions/modes")
65462
65817
  ];
65463
65818
  return candidates.sort((a, b) => Number(!isDirectory4(a)) - Number(!isDirectory4(b)));
65464
65819
  }
@@ -65690,8 +66045,8 @@ var DefaultModeStore = class {
65690
66045
  }
65691
66046
  async loadActiveMode() {
65692
66047
  try {
65693
- const configPath = path86.join(this.configDir, "mode.json");
65694
- const content = await fs38.readFile(configPath, "utf8");
66048
+ const configPath = path87.join(this.configDir, "mode.json");
66049
+ const content = await fs39.readFile(configPath, "utf8");
65695
66050
  const data = JSON.parse(content);
65696
66051
  this.activeModeId = data.activeMode ?? null;
65697
66052
  } catch {
@@ -65700,8 +66055,8 @@ var DefaultModeStore = class {
65700
66055
  }
65701
66056
  async saveActiveMode() {
65702
66057
  try {
65703
- await fs38.mkdir(this.configDir, { recursive: true });
65704
- const configPath = path86.join(this.configDir, "mode.json");
66058
+ await fs39.mkdir(this.configDir, { recursive: true });
66059
+ const configPath = path87.join(this.configDir, "mode.json");
65705
66060
  await atomicWrite(
65706
66061
  configPath,
65707
66062
  JSON.stringify({ activeMode: this.activeModeId }, null, 2)
@@ -65713,14 +66068,14 @@ var DefaultModeStore = class {
65713
66068
  async function loadProjectModes(modesDir) {
65714
66069
  const modes = [];
65715
66070
  try {
65716
- const entries = await fs38.readdir(modesDir);
66071
+ const entries = await fs39.readdir(modesDir);
65717
66072
  for (const entry of entries) {
65718
66073
  if (!entry.endsWith(".md") && !entry.endsWith(".txt")) continue;
65719
- const filePath = path86.join(modesDir, entry);
65720
- const stat40 = await fs38.stat(filePath);
66074
+ const filePath = path87.join(modesDir, entry);
66075
+ const stat40 = await fs39.stat(filePath);
65721
66076
  if (!stat40.isFile()) continue;
65722
- const content = await fs38.readFile(filePath, "utf8");
65723
- const id = path86.basename(entry, path86.extname(entry));
66077
+ const content = await fs39.readFile(filePath, "utf8");
66078
+ const id = path87.basename(entry, path87.extname(entry));
65724
66079
  modes.push({
65725
66080
  id,
65726
66081
  name: id.replace(/[-_]/g, " ").replace(/\b\w/g, (c) => c.toUpperCase()),
@@ -65736,8 +66091,8 @@ async function loadProjectModes(modesDir) {
65736
66091
  async function loadUserModes(modesDir) {
65737
66092
  const modes = [];
65738
66093
  try {
65739
- const manifestPath = path86.join(modesDir, "modes.json");
65740
- const content = await fs38.readFile(manifestPath, "utf8");
66094
+ const manifestPath = path87.join(modesDir, "modes.json");
66095
+ const content = await fs39.readFile(manifestPath, "utf8");
65741
66096
  const manifest = JSON.parse(content);
65742
66097
  for (const mode of manifest.modes) {
65743
66098
  modes.push(mode);
@@ -65748,8 +66103,8 @@ async function loadUserModes(modesDir) {
65748
66103
  }
65749
66104
 
65750
66105
  // src/models/models-registry.ts
65751
- import * as fs39 from "node:fs/promises";
65752
- import * as path87 from "node:path";
66106
+ import * as fs40 from "node:fs/promises";
66107
+ import * as path88 from "node:path";
65753
66108
  init_atomic_write();
65754
66109
  init_error();
65755
66110
  init_errors();
@@ -65829,7 +66184,7 @@ var DefaultModelsRegistry = class {
65829
66184
  this.overlay = opts.overlay;
65830
66185
  this.overlayUrl = opts.overlayUrl;
65831
66186
  this.overlayFile = opts.overlayFile;
65832
- this.overlayCacheFile = opts.overlayCacheFile ?? (opts.overlayUrl ? path87.join(path87.dirname(opts.cacheFile), "models-overlay-cache.json") : void 0);
66187
+ this.overlayCacheFile = opts.overlayCacheFile ?? (opts.overlayUrl ? path88.join(path88.dirname(opts.cacheFile), "models-overlay-cache.json") : void 0);
65833
66188
  this.logger = opts.logger ?? noOpLogger;
65834
66189
  }
65835
66190
  async load(opts = {}) {
@@ -66017,7 +66372,7 @@ var DefaultModelsRegistry = class {
66017
66372
  async readOverlayFile() {
66018
66373
  if (!this.overlayFile) return void 0;
66019
66374
  try {
66020
- const raw = await fs39.readFile(this.overlayFile, "utf8");
66375
+ const raw = await fs40.readFile(this.overlayFile, "utf8");
66021
66376
  return JSON.parse(raw);
66022
66377
  } catch {
66023
66378
  return void 0;
@@ -66096,7 +66451,7 @@ var DefaultModelsRegistry = class {
66096
66451
  }
66097
66452
  async readCacheAt(file) {
66098
66453
  try {
66099
- const raw = await fs39.readFile(file, "utf8");
66454
+ const raw = await fs40.readFile(file, "utf8");
66100
66455
  return JSON.parse(raw);
66101
66456
  } catch {
66102
66457
  return void 0;
@@ -66104,7 +66459,7 @@ var DefaultModelsRegistry = class {
66104
66459
  }
66105
66460
  /** Used by `wstack models refresh` to expose where the cache lives. */
66106
66461
  cacheLocation() {
66107
- return path87.resolve(this.cacheFile);
66462
+ return path88.resolve(this.cacheFile);
66108
66463
  }
66109
66464
  };
66110
66465
  var REASONING_EFFORTS = /* @__PURE__ */ new Set([
@@ -67017,16 +67372,16 @@ function startOtlpTraceExporter(opts) {
67017
67372
 
67018
67373
  // src/security/permission-policy.ts
67019
67374
  init_atomic_write();
67020
- import * as fs40 from "node:fs/promises";
67021
- import * as path90 from "node:path";
67375
+ import * as fs41 from "node:fs/promises";
67376
+ import * as path91 from "node:path";
67022
67377
 
67023
67378
  // src/security/permission-helpers.ts
67024
67379
  import { realpathSync as realpathSync3 } from "node:fs";
67025
- import * as path89 from "node:path";
67380
+ import * as path90 from "node:path";
67026
67381
 
67027
67382
  // src/security/yolo-risk.ts
67028
67383
  import * as os11 from "node:os";
67029
- import * as path88 from "node:path";
67384
+ import * as path89 from "node:path";
67030
67385
  var PROTECTED_STATE_BASENAMES = /^(?:config\.json|config\.local\.json|trust\.json|auth\.json|\.key)$/i;
67031
67386
  var CATASTROPHIC_PATTERNS = [
67032
67387
  /\b(?:mkfs(?:\.[a-z0-9]+)?|mke2fs|newfs)\b/i,
@@ -67087,9 +67442,9 @@ function getInputString(input, key) {
67087
67442
  function pathLooksInsideProject(rawPath, projectRoot) {
67088
67443
  if (!projectRoot) return false;
67089
67444
  if (rawPath === "~" || rawPath.startsWith("~/") || rawPath.startsWith("~\\")) return false;
67090
- const resolved = path88.resolve(projectRoot, rawPath);
67091
- const relative21 = path88.relative(projectRoot, resolved);
67092
- return !!relative21 && !relative21.startsWith("..") && !path88.isAbsolute(relative21);
67445
+ const resolved = path89.resolve(projectRoot, rawPath);
67446
+ const relative21 = path89.relative(projectRoot, resolved);
67447
+ return !!relative21 && !relative21.startsWith("..") && !path89.isAbsolute(relative21);
67093
67448
  }
67094
67449
  function tokenizeShell(command) {
67095
67450
  return command.match(/"[^"]*"|'[^']*'|\S+/g)?.map((token) => token.replace(/^['"]|['"]$/g, "")) ?? [];
@@ -67296,14 +67651,14 @@ function hasWriteToAgentStateRoot(command) {
67296
67651
  }
67297
67652
  function looksLikeAgentStateTarget(rawPath) {
67298
67653
  const expanded = rawPath.replace(/^~([\\/])/, (_, sep10) => `${os11.homedir()}${sep10}`);
67299
- const resolved = path88.resolve(expanded);
67654
+ const resolved = path89.resolve(expanded);
67300
67655
  const rootStr = wstackGlobalRoot();
67301
67656
  const resolvedNorm = resolved.replace(/\\/g, "/").toLowerCase();
67302
- const rootNorm = path88.resolve(rootStr).replace(/\\/g, "/").toLowerCase();
67657
+ const rootNorm = path89.resolve(rootStr).replace(/\\/g, "/").toLowerCase();
67303
67658
  if (!resolvedNorm.startsWith(rootNorm) && !resolvedNorm.includes(".wrongstack")) {
67304
67659
  return false;
67305
67660
  }
67306
- return PROTECTED_STATE_BASENAMES.test(path88.basename(resolved));
67661
+ return PROTECTED_STATE_BASENAMES.test(path89.basename(resolved));
67307
67662
  }
67308
67663
  function isClearlyDestructiveBashCommand(command, projectRoot) {
67309
67664
  const trimmed = command.trim();
@@ -67403,24 +67758,24 @@ function realpathOfNearestExisting(p) {
67403
67758
  const tail = [];
67404
67759
  for (; ; ) {
67405
67760
  try {
67406
- return tail.length === 0 ? realpathSync3(probe2) : path89.join(realpathSync3(probe2), ...tail);
67761
+ return tail.length === 0 ? realpathSync3(probe2) : path90.join(realpathSync3(probe2), ...tail);
67407
67762
  } catch {
67408
- const parent = path89.dirname(probe2);
67763
+ const parent = path90.dirname(probe2);
67409
67764
  if (parent === probe2) return p;
67410
- tail.unshift(path89.basename(probe2));
67765
+ tail.unshift(path90.basename(probe2));
67411
67766
  probe2 = parent;
67412
67767
  }
67413
67768
  }
67414
67769
  }
67415
67770
  var agentStateRootRealCache = /* @__PURE__ */ new Map();
67416
67771
  function isInsideAgentStateRoot(absPath) {
67417
- const lexicalRoot = normalizeForCompare(path89.resolve(wstackGlobalRoot()));
67772
+ const lexicalRoot = normalizeForCompare(path90.resolve(wstackGlobalRoot()));
67418
67773
  if (!lexicalRoot) return false;
67419
67774
  const target = normalizeForCompare(absPath);
67420
67775
  if (target === lexicalRoot || target.startsWith(`${lexicalRoot}/`)) return true;
67421
67776
  let realRoot = agentStateRootRealCache.get(lexicalRoot);
67422
67777
  if (realRoot === void 0) {
67423
- realRoot = normalizeForCompare(realpathOfNearestExisting(path89.resolve(wstackGlobalRoot())));
67778
+ realRoot = normalizeForCompare(realpathOfNearestExisting(path90.resolve(wstackGlobalRoot())));
67424
67779
  agentStateRootRealCache.set(lexicalRoot, realRoot);
67425
67780
  }
67426
67781
  if (!realRoot || realRoot === lexicalRoot) return false;
@@ -67429,7 +67784,7 @@ function isInsideAgentStateRoot(absPath) {
67429
67784
  }
67430
67785
  function isProtectedAgentStatePath(absPath) {
67431
67786
  if (!isInsideAgentStateRoot(absPath)) return false;
67432
- return AGENT_STATE_SENSITIVE_BASENAMES.test(path89.basename(normalizeForCompare(absPath)));
67787
+ return AGENT_STATE_SENSITIVE_BASENAMES.test(path90.basename(normalizeForCompare(absPath)));
67433
67788
  }
67434
67789
  function pathLooksSensitive(rawPath) {
67435
67790
  const normalized = stripShellQuotes(rawPath).replace(/\\/g, "/");
@@ -68066,7 +68421,7 @@ var DefaultPermissionPolicy = class {
68066
68421
  if (!hasCapability(tool, ToolCapabilities.FS_WRITE)) return false;
68067
68422
  for (const targetPath of fsWriteTargetPaths(input)) {
68068
68423
  const base = ctx.workingDir ?? ctx.cwd;
68069
- const resolved = base ? path90.resolve(base, targetPath) : path90.resolve(targetPath);
68424
+ const resolved = base ? path91.resolve(base, targetPath) : path91.resolve(targetPath);
68070
68425
  if (isInsideAgentStateRoot(resolved)) return true;
68071
68426
  }
68072
68427
  return false;
@@ -68097,7 +68452,7 @@ var DefaultPermissionPolicy = class {
68097
68452
  this.policyDiagnostics = [];
68098
68453
  this.policyInvalid = false;
68099
68454
  try {
68100
- const raw = await fs40.readFile(this.trustFile, "utf8");
68455
+ const raw = await fs41.readFile(this.trustFile, "utf8");
68101
68456
  const parsed = safeParse(raw);
68102
68457
  if (!parsed.ok) {
68103
68458
  this.policy = {};
@@ -68417,7 +68772,7 @@ var DefaultPermissionPolicy = class {
68417
68772
  init_atomic_write();
68418
68773
  import { randomBytes as randomBytes6 } from "node:crypto";
68419
68774
  import * as fsp37 from "node:fs/promises";
68420
- import * as path91 from "node:path";
68775
+ import * as path92 from "node:path";
68421
68776
  var DEFAULT_SPOOL_THRESHOLD = 256 * 1024;
68422
68777
  var PLACEHOLDER_RE2 = /\[(pasted|image|file) #(\d+)[^\]]*\]|\[file:([^\]]+)\]/g;
68423
68778
  var DefaultAttachmentStore = class {
@@ -68438,7 +68793,7 @@ var DefaultAttachmentStore = class {
68438
68793
  let data = input.data;
68439
68794
  if (this.spoolDir && bytes >= this.spoolThreshold) {
68440
68795
  await fsp37.mkdir(this.spoolDir, { recursive: true });
68441
- spooledPath = path91.join(this.spoolDir, `${id}.bin`);
68796
+ spooledPath = path92.join(this.spoolDir, `${id}.bin`);
68442
68797
  await atomicWrite(spooledPath, input.data, {
68443
68798
  encoding: input.kind === "image" ? "base64" : "utf8"
68444
68799
  });
@@ -69027,7 +69382,7 @@ ${cat}:`);
69027
69382
  init_atomic_write();
69028
69383
  init_error();
69029
69384
  import * as fsp39 from "node:fs/promises";
69030
- import * as path92 from "node:path";
69385
+ import * as path93 from "node:path";
69031
69386
  var QUEUE_MAX_ITEMS = 100;
69032
69387
  var QUEUE_MAX_BYTES = 16 * 1024 * 1024;
69033
69388
  var QUEUE_MAX_ITEM_BYTES = 8 * 1024 * 1024;
@@ -69060,7 +69415,7 @@ var QueueStore = class {
69060
69415
  traceId;
69061
69416
  logger;
69062
69417
  constructor(opts) {
69063
- this.file = path92.join(opts.dir, "queue.json");
69418
+ this.file = path93.join(opts.dir, "queue.json");
69064
69419
  this.events = opts.events;
69065
69420
  this.traceId = opts.traceId;
69066
69421
  this.logger = opts.logger;
@@ -69277,7 +69632,7 @@ function isPersistedQueueItem(v) {
69277
69632
  init_atomic_write();
69278
69633
  import * as fsp40 from "node:fs/promises";
69279
69634
  import * as os12 from "node:os";
69280
- import * as path93 from "node:path";
69635
+ import * as path94 from "node:path";
69281
69636
  var LOCK_FILE = "active.json";
69282
69637
  var DEFAULT_MAX_AGE_MS = 24 * 60 * 60 * 1e3;
69283
69638
  var RecoveryLock = class {
@@ -69288,7 +69643,7 @@ var RecoveryLock = class {
69288
69643
  sessionStore;
69289
69644
  probe;
69290
69645
  constructor(opts) {
69291
- this.file = path93.join(opts.dir, LOCK_FILE);
69646
+ this.file = path94.join(opts.dir, LOCK_FILE);
69292
69647
  this.pid = opts.pid ?? process.pid;
69293
69648
  this.hostname = opts.hostname ?? os12.hostname();
69294
69649
  this.maxAgeMs = opts.maxAgeMs ?? DEFAULT_MAX_AGE_MS;
@@ -69362,7 +69717,7 @@ var RecoveryLock = class {
69362
69717
  * null return before calling this.
69363
69718
  */
69364
69719
  async write(sessionId) {
69365
- await ensureDir(path93.dirname(this.file));
69720
+ await ensureDir(path94.dirname(this.file));
69366
69721
  const lock = {
69367
69722
  v: 1,
69368
69723
  sessionId,
@@ -75718,7 +76073,7 @@ var PHASE_EVENT_NAMES = [
75718
76073
  // src/goal/phase-store.ts
75719
76074
  init_atomic_write();
75720
76075
  import * as fsp42 from "node:fs/promises";
75721
- import * as path94 from "node:path";
76076
+ import * as path95 from "node:path";
75722
76077
  var PHASE_STORE_VERSION = 1;
75723
76078
  var PhaseStore = class {
75724
76079
  baseDir;
@@ -75726,7 +76081,7 @@ var PhaseStore = class {
75726
76081
  constructor(opts) {
75727
76082
  this.baseDir = opts.baseDir;
75728
76083
  this.legacyBaseDirs = (opts.legacyBaseDirs ?? []).filter(
75729
- (dir) => path94.resolve(dir) !== path94.resolve(this.baseDir)
76084
+ (dir) => path95.resolve(dir) !== path95.resolve(this.baseDir)
75730
76085
  );
75731
76086
  }
75732
76087
  async save(graph) {
@@ -75741,7 +76096,7 @@ var PhaseStore = class {
75741
76096
  const current = await this.loadFromPath(filePath);
75742
76097
  if (current) return current;
75743
76098
  for (const legacyDir of this.legacyBaseDirs) {
75744
- const legacyPath = path94.join(legacyDir, `${graphId}.json`);
76099
+ const legacyPath = path95.join(legacyDir, `${graphId}.json`);
75745
76100
  const legacy = await this.loadFromPath(legacyPath);
75746
76101
  if (!legacy) continue;
75747
76102
  try {
@@ -75757,7 +76112,7 @@ var PhaseStore = class {
75757
76112
  async delete(graphId) {
75758
76113
  const paths = [
75759
76114
  this.getFilePath(graphId),
75760
- ...this.legacyBaseDirs.map((dir) => path94.join(dir, `${graphId}.json`))
76115
+ ...this.legacyBaseDirs.map((dir) => path95.join(dir, `${graphId}.json`))
75761
76116
  ];
75762
76117
  await Promise.all(paths.map((filePath) => fsp42.unlink(filePath).catch(() => void 0)));
75763
76118
  }
@@ -75769,7 +76124,7 @@ var PhaseStore = class {
75769
76124
  for (const entry of entries) {
75770
76125
  if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
75771
76126
  try {
75772
- const raw = await fsp42.readFile(path94.join(this.baseDir, entry.name), "utf8");
76127
+ const raw = await fsp42.readFile(path95.join(this.baseDir, entry.name), "utf8");
75773
76128
  const serialized = JSON.parse(raw);
75774
76129
  const done = serialized.completedPhaseIds.length;
75775
76130
  const total = serialized.phases.length;
@@ -75788,7 +76143,7 @@ var PhaseStore = class {
75788
76143
  }
75789
76144
  }
75790
76145
  getFilePath(graphId) {
75791
- return path94.join(this.baseDir, `${graphId}.json`);
76146
+ return path95.join(this.baseDir, `${graphId}.json`);
75792
76147
  }
75793
76148
  async loadFromPath(filePath) {
75794
76149
  try {
@@ -75804,8 +76159,8 @@ var PhaseStore = class {
75804
76159
  const entries = await fsp42.readdir(legacyDir, { withFileTypes: true }).catch(() => []);
75805
76160
  for (const entry of entries) {
75806
76161
  if (!entry.isFile() || !entry.name.endsWith(".json")) continue;
75807
- const legacyPath = path94.join(legacyDir, entry.name);
75808
- const currentPath = this.getFilePath(path94.basename(entry.name, ".json"));
76162
+ const legacyPath = path95.join(legacyDir, entry.name);
76163
+ const currentPath = this.getFilePath(path95.basename(entry.name, ".json"));
75809
76164
  if (await this.pathExists(currentPath)) {
75810
76165
  await this.removeMigratedLegacyFile(legacyDir, legacyPath);
75811
76166
  continue;
@@ -75956,7 +76311,7 @@ var PhaseStore = class {
75956
76311
  // src/goal/checkpoint.ts
75957
76312
  init_atomic_write();
75958
76313
  import * as fsp43 from "node:fs/promises";
75959
- import * as path95 from "node:path";
76314
+ import * as path96 from "node:path";
75960
76315
  var CheckpointManager = class {
75961
76316
  store;
75962
76317
  maxCheckpoints;
@@ -75967,7 +76322,7 @@ var CheckpointManager = class {
75967
76322
  this.store = opts.store;
75968
76323
  this.maxCheckpoints = opts.maxCheckpoints ?? 10;
75969
76324
  this.maxCheckpointAgeMs = opts.maxCheckpointAgeMs ?? 7 * 24 * 60 * 60 * 1e3;
75970
- this.baseDir = opts.baseDir ?? path95.join(opts.store.baseDir, ".checkpoints");
76325
+ this.baseDir = opts.baseDir ?? path96.join(opts.store.baseDir, ".checkpoints");
75971
76326
  }
75972
76327
  async initialize() {
75973
76328
  await fsp43.mkdir(this.baseDir, { recursive: true });
@@ -76033,7 +76388,7 @@ var CheckpointManager = class {
76033
76388
  return true;
76034
76389
  }
76035
76390
  async saveToDisk(checkpoint) {
76036
- const filePath = path95.join(this.baseDir, `${checkpoint.graphId}.json`);
76391
+ const filePath = path96.join(this.baseDir, `${checkpoint.graphId}.json`);
76037
76392
  const serialized = {
76038
76393
  ...checkpoint
76039
76394
  };
@@ -76060,7 +76415,7 @@ var CheckpointManager = class {
76060
76415
  }
76061
76416
  for (const filename of entries) {
76062
76417
  if (!filename.endsWith(".json")) continue;
76063
- const filePath = path95.join(this.baseDir, filename);
76418
+ const filePath = path96.join(this.baseDir, filename);
76064
76419
  try {
76065
76420
  await withFileLock(filePath, async () => {
76066
76421
  const raw = await fsp43.readFile(filePath, "utf8");
@@ -76089,7 +76444,7 @@ var CheckpointManager = class {
76089
76444
  }
76090
76445
  for (const filename of entries) {
76091
76446
  if (!filename.endsWith(".json")) continue;
76092
- const filePath = path95.join(this.baseDir, filename);
76447
+ const filePath = path96.join(this.baseDir, filename);
76093
76448
  try {
76094
76449
  const raw = await fsp43.readFile(filePath, "utf8");
76095
76450
  const parsed = JSON.parse(raw);
@@ -77012,7 +77367,7 @@ function countShellHooks(hooks) {
77012
77367
  }
77013
77368
 
77014
77369
  // src/hq/session-bridge.ts
77015
- import * as fs41 from "node:fs";
77370
+ import * as fs42 from "node:fs";
77016
77371
  import * as fsp44 from "node:fs/promises";
77017
77372
 
77018
77373
  // src/types/session-markers.ts
@@ -77456,7 +77811,7 @@ function startSessionTelemetryBridge(opts) {
77456
77811
  let setupWatcher2 = function() {
77457
77812
  if (disposed || watcher) return;
77458
77813
  try {
77459
- const nextWatcher = fs41.watch(sessionFile, () => {
77814
+ const nextWatcher = fs42.watch(sessionFile, () => {
77460
77815
  if (watchPending || disposed) return;
77461
77816
  watchPending = true;
77462
77817
  setTimeout(() => {
@@ -77934,8 +78289,8 @@ function startCostTelemetryBridge(opts) {
77934
78289
  // src/hq/kanban-store.ts
77935
78290
  init_atomic_write();
77936
78291
  import { createHash as createHash31 } from "node:crypto";
77937
- import * as fs42 from "node:fs/promises";
77938
- import * as path96 from "node:path";
78292
+ import * as fs43 from "node:fs/promises";
78293
+ import * as path97 from "node:path";
77939
78294
 
77940
78295
  // src/hq/write-queues.ts
77941
78296
  var BestEffortBatchQueue = class _BestEffortBatchQueue {
@@ -78030,7 +78385,7 @@ var HqKanbanStore = class {
78030
78385
  writers = /* @__PURE__ */ new Map();
78031
78386
  mergeChains = /* @__PURE__ */ new Map();
78032
78387
  constructor(dataDir) {
78033
- this.dirPath = path96.join(dataDir, "kanban");
78388
+ this.dirPath = path97.join(dataDir, "kanban");
78034
78389
  }
78035
78390
  async load(projectId) {
78036
78391
  const cached2 = this.cache.get(projectId);
@@ -78040,7 +78395,7 @@ var HqKanbanStore = class {
78040
78395
  return structuredClone(cached2);
78041
78396
  }
78042
78397
  try {
78043
- const content = await fs42.readFile(this.filePath(projectId), "utf8");
78398
+ const content = await fs43.readFile(this.filePath(projectId), "utf8");
78044
78399
  const snapshot = JSON.parse(content);
78045
78400
  if (!isHqKanbanSnapshotPayload(snapshot) || snapshot.projectId !== projectId) {
78046
78401
  return emptyKanbanSnapshot(projectId);
@@ -78114,7 +78469,7 @@ var HqKanbanStore = class {
78114
78469
  let writer = this.writers.get(projectId);
78115
78470
  if (writer === void 0) {
78116
78471
  writer = new BestEffortLatestQueue(async (snapshot) => {
78117
- await fs42.mkdir(this.dirPath, { recursive: true });
78472
+ await fs43.mkdir(this.dirPath, { recursive: true });
78118
78473
  await atomicWrite(this.filePath(projectId), JSON.stringify(snapshot), { mode: 384 });
78119
78474
  });
78120
78475
  this.writers.set(projectId, writer);
@@ -78138,7 +78493,7 @@ var HqKanbanStore = class {
78138
78493
  }
78139
78494
  filePath(projectId) {
78140
78495
  const safe = createHash31("sha256").update(projectId).digest("hex");
78141
- return path96.join(this.dirPath, `${safe}.json`);
78496
+ return path97.join(this.dirPath, `${safe}.json`);
78142
78497
  }
78143
78498
  };
78144
78499
  function emptyKanbanSnapshot(projectId) {
@@ -78156,17 +78511,17 @@ function compareKanbanRecord(a, b) {
78156
78511
  // src/hq/persistence/event-log.ts
78157
78512
  init_file_permissions();
78158
78513
  init_atomic_write();
78159
- import * as fs44 from "node:fs/promises";
78160
- import * as path97 from "node:path";
78514
+ import * as fs45 from "node:fs/promises";
78515
+ import * as path98 from "node:path";
78161
78516
 
78162
78517
  // src/hq/persistence/jsonl-io.ts
78163
- import * as fs43 from "node:fs/promises";
78518
+ import * as fs44 from "node:fs/promises";
78164
78519
  import { StringDecoder } from "node:string_decoder";
78165
78520
  var RECENT_READ_CHUNK_BYTES = 64 * 1024;
78166
78521
  var LINE_COUNT_CHUNK_BYTES = 256 * 1024;
78167
78522
  async function readTailNonEmptyLines(filePath, limit, estimatedLineCount) {
78168
78523
  if (!(limit > 0)) return [];
78169
- const handle = await fs43.open(filePath, "r");
78524
+ const handle = await fs44.open(filePath, "r");
78170
78525
  try {
78171
78526
  const size = (await handle.stat()).size;
78172
78527
  let position = size;
@@ -78213,7 +78568,7 @@ async function readTailNonEmptyLines(filePath, limit, estimatedLineCount) {
78213
78568
  }
78214
78569
  }
78215
78570
  async function findTailStartOffset(filePath, keepLines, maxBytes) {
78216
- const handle = await fs43.open(filePath, "r");
78571
+ const handle = await fs44.open(filePath, "r");
78217
78572
  try {
78218
78573
  const size = (await handle.stat()).size;
78219
78574
  if (size === 0) return { offset: 0, size };
@@ -78253,7 +78608,7 @@ async function findTailStartOffset(filePath, keepLines, maxBytes) {
78253
78608
  }
78254
78609
  }
78255
78610
  async function copyTailToHandle(sourcePath, offset, destination) {
78256
- const handle = await fs43.open(sourcePath, "r");
78611
+ const handle = await fs44.open(sourcePath, "r");
78257
78612
  try {
78258
78613
  const buffer = Buffer.allocUnsafe(LINE_COUNT_CHUNK_BYTES);
78259
78614
  let position = offset;
@@ -78283,7 +78638,7 @@ async function copyTailToHandle(sourcePath, offset, destination) {
78283
78638
  }
78284
78639
  }
78285
78640
  async function* readJsonlLines(filePath) {
78286
- const handle = await fs43.open(filePath, "r");
78641
+ const handle = await fs44.open(filePath, "r");
78287
78642
  try {
78288
78643
  const buffer = Buffer.allocUnsafe(LINE_COUNT_CHUNK_BYTES);
78289
78644
  const decoder = new StringDecoder("utf8");
@@ -78313,7 +78668,7 @@ async function* readJsonlLines(filePath) {
78313
78668
  async function countNonEmptyLines(filePath) {
78314
78669
  let handle;
78315
78670
  try {
78316
- handle = await fs43.open(filePath, "r");
78671
+ handle = await fs44.open(filePath, "r");
78317
78672
  } catch {
78318
78673
  return 0;
78319
78674
  }
@@ -78379,7 +78734,7 @@ var HqEventLog = class {
78379
78734
  counted = false;
78380
78735
  hydration;
78381
78736
  constructor(opts) {
78382
- this.filePath = path97.join(opts.dataDir, "events.jsonl");
78737
+ this.filePath = path98.join(opts.dataDir, "events.jsonl");
78383
78738
  this.maxLines = opts.maxLines ?? DEFAULT_EVENT_LOG_MAX_LINES;
78384
78739
  this.rotateKeep = opts.rotateKeep ?? DEFAULT_EVENT_LOG_ROTATE_KEEP;
78385
78740
  this.maxBytes = opts.maxBytes ?? DEFAULT_EVENT_LOG_MAX_BYTES;
@@ -78397,7 +78752,7 @@ var HqEventLog = class {
78397
78752
  async appendInternal(events) {
78398
78753
  await this.ensureLineCount();
78399
78754
  const lines = events.map((event) => JSON.stringify(event)).join("\n") + "\n";
78400
- await fs44.appendFile(this.filePath, lines, { encoding: "utf8", mode: SECRET_FILE_MODE });
78755
+ await fs45.appendFile(this.filePath, lines, { encoding: "utf8", mode: SECRET_FILE_MODE });
78401
78756
  this.lineCount += events.length;
78402
78757
  this.byteCount += Buffer.byteLength(lines, "utf8");
78403
78758
  if (this.lineCount >= this.maxLines || this.byteCount >= this.maxBytes) {
@@ -78443,7 +78798,7 @@ var HqEventLog = class {
78443
78798
  async countLines() {
78444
78799
  let handle;
78445
78800
  try {
78446
- handle = await fs44.open(this.filePath, "r");
78801
+ handle = await fs45.open(this.filePath, "r");
78447
78802
  } catch {
78448
78803
  return 0;
78449
78804
  }
@@ -78485,7 +78840,7 @@ var HqEventLog = class {
78485
78840
  if (this.counted) return;
78486
78841
  this.hydration ??= Promise.all([
78487
78842
  this.countLines(),
78488
- fs44.stat(this.filePath).then(
78843
+ fs45.stat(this.filePath).then(
78489
78844
  (stat40) => stat40.size,
78490
78845
  () => 0
78491
78846
  )
@@ -78523,7 +78878,7 @@ async function readRecentEvents(filePath, limit, typeFilter) {
78523
78878
  if (!(limit > 0)) return [];
78524
78879
  let handle;
78525
78880
  try {
78526
- handle = await fs44.open(filePath, "r");
78881
+ handle = await fs45.open(filePath, "r");
78527
78882
  } catch {
78528
78883
  return [];
78529
78884
  }
@@ -78604,8 +78959,8 @@ async function readRecentEvents(filePath, limit, typeFilter) {
78604
78959
 
78605
78960
  // src/hq/persistence/simple-log.ts
78606
78961
  init_atomic_write();
78607
- import * as fs45 from "node:fs/promises";
78608
- import * as path98 from "node:path";
78962
+ import * as fs46 from "node:fs/promises";
78963
+ import * as path99 from "node:path";
78609
78964
  var HqSimpleLog = class {
78610
78965
  filePath;
78611
78966
  maxLines;
@@ -78616,7 +78971,7 @@ var HqSimpleLog = class {
78616
78971
  counted = false;
78617
78972
  hydration;
78618
78973
  constructor(opts) {
78619
- this.filePath = path98.join(opts.dataDir, opts.filename);
78974
+ this.filePath = path99.join(opts.dataDir, opts.filename);
78620
78975
  this.maxLines = opts.maxLines ?? Infinity;
78621
78976
  this.rotateKeep = opts.rotateKeep ?? this.maxLines;
78622
78977
  this.readLimit = opts.readLimit ?? Infinity;
@@ -78632,7 +78987,7 @@ var HqSimpleLog = class {
78632
78987
  }
78633
78988
  async appendInternal(records) {
78634
78989
  if (Number.isFinite(this.maxLines)) await this.ensureLineCount();
78635
- await fs45.appendFile(
78990
+ await fs46.appendFile(
78636
78991
  this.filePath,
78637
78992
  records.map((record) => JSON.stringify(record)).join("\n") + "\n",
78638
78993
  { encoding: "utf8" }
@@ -78686,13 +79041,13 @@ var HqSimpleLog = class {
78686
79041
 
78687
79042
  // src/hq/persistence/snapshot-store.ts
78688
79043
  init_atomic_write();
78689
- import * as fs46 from "node:fs/promises";
78690
- import * as path99 from "node:path";
79044
+ import * as fs47 from "node:fs/promises";
79045
+ import * as path100 from "node:path";
78691
79046
  var HqSnapshotStore = class {
78692
79047
  filePath;
78693
79048
  writer;
78694
79049
  constructor(opts) {
78695
- this.filePath = path99.join(opts.dataDir, "snapshot.json");
79050
+ this.filePath = path100.join(opts.dataDir, "snapshot.json");
78696
79051
  this.writer = new BestEffortLatestQueue(
78697
79052
  (snapshot) => atomicWrite(this.filePath, JSON.stringify(snapshot), { mode: 384 })
78698
79053
  );
@@ -78708,7 +79063,7 @@ var HqSnapshotStore = class {
78708
79063
  /** Read the last persisted snapshot, or `null` if none. */
78709
79064
  async load() {
78710
79065
  try {
78711
- const content = await fs46.readFile(this.filePath, "utf8");
79066
+ const content = await fs47.readFile(this.filePath, "utf8");
78712
79067
  return JSON.parse(content);
78713
79068
  } catch {
78714
79069
  return null;
@@ -78719,8 +79074,8 @@ var HqSnapshotStore = class {
78719
79074
  // src/hq/persistence/timeseries-store.ts
78720
79075
  init_file_permissions();
78721
79076
  init_atomic_write();
78722
- import * as fs47 from "node:fs/promises";
78723
- import * as path100 from "node:path";
79077
+ import * as fs48 from "node:fs/promises";
79078
+ import * as path101 from "node:path";
78724
79079
  var HqTimeseriesStore = class {
78725
79080
  filePath;
78726
79081
  bucketMs;
@@ -78733,7 +79088,7 @@ var HqTimeseriesStore = class {
78733
79088
  loaded = false;
78734
79089
  loadPromise;
78735
79090
  constructor(opts) {
78736
- this.filePath = path100.join(opts.dataDir, "timeseries.jsonl");
79091
+ this.filePath = path101.join(opts.dataDir, "timeseries.jsonl");
78737
79092
  this.bucketMs = opts.bucketMs ?? 5 * 60 * 1e3;
78738
79093
  this.maxBuckets = opts.maxBuckets ?? 2016;
78739
79094
  this.writer = new BestEffortLatestQueue((snapshot) => this.flushInternal(snapshot));
@@ -78820,7 +79175,7 @@ var HqTimeseriesStore = class {
78820
79175
  const lines = snapshot.samples.map((bucket) => JSON.stringify(bucket)).join("\n") + "\n";
78821
79176
  await withFileLock(this.filePath, async () => {
78822
79177
  this.diskLineCount ??= await countNonEmptyLines(this.filePath);
78823
- await fs47.appendFile(this.filePath, lines, { encoding: "utf8", mode: SECRET_FILE_MODE });
79178
+ await fs48.appendFile(this.filePath, lines, { encoding: "utf8", mode: SECRET_FILE_MODE });
78824
79179
  this.diskLineCount += snapshot.samples.length;
78825
79180
  const compactAt = Math.max(this.maxBuckets + 1, this.maxBuckets * 4);
78826
79181
  if (this.diskLineCount >= compactAt) {
@@ -81051,7 +81406,7 @@ function definePlugin(metadata, factory) {
81051
81406
  // src/plugins/auto-review-plugin.ts
81052
81407
  init_error();
81053
81408
  import * as fsp47 from "node:fs/promises";
81054
- import * as path103 from "node:path";
81409
+ import * as path104 from "node:path";
81055
81410
 
81056
81411
  // src/plugins/auto-review-config.ts
81057
81412
  var DEFAULT_DEBOUNCE_MS = 15e3;
@@ -81228,7 +81583,7 @@ function shouldCascade(cascadeOn, severities) {
81228
81583
  import { spawn as spawn9 } from "node:child_process";
81229
81584
  import { createHash as createHash32 } from "node:crypto";
81230
81585
  import * as fsp45 from "node:fs/promises";
81231
- import * as path101 from "node:path";
81586
+ import * as path102 from "node:path";
81232
81587
  var MAX_SNAPSHOT_FILE_BYTES = 256 * 1024;
81233
81588
  var MAX_SNAPSHOT_TOTAL_BYTES = 8 * 1024 * 1024;
81234
81589
  async function runGit2(args, cwd) {
@@ -81286,9 +81641,9 @@ async function snapshotChangedFiles(cwd) {
81286
81641
  if (file.path.startsWith(".wrongstack/")) continue;
81287
81642
  if (budget <= 0) break;
81288
81643
  try {
81289
- const stat40 = await fsp45.stat(path101.join(cwd, file.path));
81644
+ const stat40 = await fsp45.stat(path102.join(cwd, file.path));
81290
81645
  if (!stat40.isFile() || stat40.size > MAX_SNAPSHOT_FILE_BYTES) continue;
81291
- const content = await fsp45.readFile(path101.join(cwd, file.path), "utf8");
81646
+ const content = await fsp45.readFile(path102.join(cwd, file.path), "utf8");
81292
81647
  budget -= content.length;
81293
81648
  snapshots.push({
81294
81649
  ...file,
@@ -81305,7 +81660,7 @@ async function snapshotChangedFiles(cwd) {
81305
81660
  import { createHash as createHash33, randomUUID as randomUUID39 } from "node:crypto";
81306
81661
  import * as fsp46 from "node:fs/promises";
81307
81662
  import { hostname as hostname5 } from "node:os";
81308
- import * as path102 from "node:path";
81663
+ import * as path103 from "node:path";
81309
81664
  var CLAIMS_FILE = "review-claims.jsonl";
81310
81665
  var DEFAULT_CLAIM_TTL_MS = 30 * 60 * 1e3;
81311
81666
  var LOCK_WAIT_MS = 5e3;
@@ -81441,16 +81796,16 @@ function claimKey(cwd, filePath) {
81441
81796
  }
81442
81797
  function resolveStore(opts, cwd) {
81443
81798
  return {
81444
- storeDir: opts?.storeDir ?? path102.join(cwd, ".wrongstack"),
81799
+ storeDir: opts?.storeDir ?? path103.join(cwd, ".wrongstack"),
81445
81800
  ttlMs: opts?.ttlMs ?? DEFAULT_CLAIM_TTL_MS,
81446
81801
  maxLedgerLines: opts?.maxLedgerLines ?? MAX_LEDGER_LINES
81447
81802
  };
81448
81803
  }
81449
81804
  function claimsFilePath(storeDir) {
81450
- return path102.join(storeDir, CLAIMS_FILE);
81805
+ return path103.join(storeDir, CLAIMS_FILE);
81451
81806
  }
81452
81807
  function lockFilePath(storeDir) {
81453
- return path102.join(storeDir, `${CLAIMS_FILE}.lock`);
81808
+ return path103.join(storeDir, `${CLAIMS_FILE}.lock`);
81454
81809
  }
81455
81810
  async function readLedger(storeDir, now) {
81456
81811
  const active = /* @__PURE__ */ new Map();
@@ -82306,7 +82661,7 @@ function createAutoReviewPlugin() {
82306
82661
  for (const f of allChanged) {
82307
82662
  if (f.path.startsWith(".wrongstack/")) continue;
82308
82663
  try {
82309
- await fsp47.access(path103.join(cwd, f.path));
82664
+ await fsp47.access(path104.join(cwd, f.path));
82310
82665
  existing.push(f);
82311
82666
  } catch {
82312
82667
  }
@@ -82316,7 +82671,7 @@ function createAutoReviewPlugin() {
82316
82671
  const filesWithContent = [];
82317
82672
  for (const f of toReview) {
82318
82673
  try {
82319
- const absPath = path103.join(cwd, f.path);
82674
+ const absPath = path104.join(cwd, f.path);
82320
82675
  const content = await fsp47.readFile(absPath, "utf8");
82321
82676
  filesWithContent.push({ path: f.path, status: f.status, content });
82322
82677
  } catch {
@@ -82428,7 +82783,7 @@ init_error();
82428
82783
  import { spawn as spawn11 } from "node:child_process";
82429
82784
  import * as fsp49 from "node:fs/promises";
82430
82785
  import * as os13 from "node:os";
82431
- import * as path105 from "node:path";
82786
+ import * as path106 from "node:path";
82432
82787
 
82433
82788
  // src/plugins/review-finding-commands.ts
82434
82789
  init_review_finding_store();
@@ -83423,8 +83778,8 @@ function buildReviewCommand(_getConfig) {
83423
83778
  async run(args) {
83424
83779
  const cwd = process.cwd();
83425
83780
  const slug = projectSlug(cwd);
83426
- const globalRoot = path105.join(os13.homedir(), ".wrongstack");
83427
- const projectDir = path105.join(globalRoot, "projects", slug);
83781
+ const globalRoot = path106.join(os13.homedir(), ".wrongstack");
83782
+ const projectDir = path106.join(globalRoot, "projects", slug);
83428
83783
  const trimmed = (args ?? "").trim();
83429
83784
  const parts = trimmed.split(/\s+/).filter(Boolean);
83430
83785
  return {
@@ -83486,7 +83841,7 @@ function createChimeraPlugin() {
83486
83841
  for (const f of allChanged) {
83487
83842
  if (f.path.startsWith(".wrongstack/")) continue;
83488
83843
  try {
83489
- await fsp49.access(path105.join(cwd, f.path));
83844
+ await fsp49.access(path106.join(cwd, f.path));
83490
83845
  existing.push(f);
83491
83846
  } catch {
83492
83847
  }
@@ -83504,7 +83859,7 @@ function createChimeraPlugin() {
83504
83859
  const filesWithContent = [];
83505
83860
  for (const f of toReview) {
83506
83861
  try {
83507
- const absPath = path105.join(cwd, f.path);
83862
+ const absPath = path106.join(cwd, f.path);
83508
83863
  const content = await fsp49.readFile(absPath, "utf8");
83509
83864
  filesWithContent.push({ path: f.path, status: f.status, content });
83510
83865
  } catch {
@@ -83549,13 +83904,13 @@ function createChimeraPlugin() {
83549
83904
  }
83550
83905
 
83551
83906
  // src/plugins/cloud-config-sync-plugin.ts
83552
- import * as path107 from "node:path";
83907
+ import * as path108 from "node:path";
83553
83908
 
83554
83909
  // src/storage/cloud-config-sync.ts
83555
83910
  init_atomic_write();
83556
83911
  import { createHash as createHash35, randomUUID as nodeRandomUUID } from "node:crypto";
83557
- import * as fs48 from "node:fs/promises";
83558
- import * as path106 from "node:path";
83912
+ import * as fs49 from "node:fs/promises";
83913
+ import * as path107 from "node:path";
83559
83914
 
83560
83915
  // src/storage/cloud-config-sync/sanitize.ts
83561
83916
  var SAGE_TREE = {
@@ -84276,7 +84631,7 @@ var CloudConfigSync = class {
84276
84631
  async loadState() {
84277
84632
  if (this.state) return this.state;
84278
84633
  try {
84279
- const raw = await fs48.readFile(this.deps.statePath, "utf8");
84634
+ const raw = await fs49.readFile(this.deps.statePath, "utf8");
84280
84635
  const parsed = JSON.parse(raw);
84281
84636
  this.state = {
84282
84637
  ...structuredClone(EMPTY_STATE),
@@ -84290,7 +84645,7 @@ var CloudConfigSync = class {
84290
84645
  }
84291
84646
  async saveState(state) {
84292
84647
  this.state = state;
84293
- await fs48.mkdir(path106.dirname(this.deps.statePath), { recursive: true });
84648
+ await fs49.mkdir(path107.dirname(this.deps.statePath), { recursive: true });
84294
84649
  await atomicWrite(this.deps.statePath, `${JSON.stringify(state, null, 2)}
84295
84650
  `, {
84296
84651
  mode: 384
@@ -84337,8 +84692,8 @@ function createCloudConfigSyncPlugin(opts) {
84337
84692
  );
84338
84693
  return;
84339
84694
  }
84340
- const profileConfigPath = path107.join(paths.configDir, "config.json");
84341
- const statePath = path107.join(paths.configDir, "cloud-sync-state.json");
84695
+ const profileConfigPath = path108.join(paths.configDir, "config.json");
84696
+ const statePath = path108.join(paths.configDir, "cloud-sync-state.json");
84342
84697
  const warn = (msg) => api.log.warn(msg);
84343
84698
  const readLocalConfig = async () => {
84344
84699
  const raw = await readJsonObjectFile(profileConfigPath).catch(() => ({}));
@@ -84512,12 +84867,12 @@ ${first}` };
84512
84867
  }
84513
84868
 
84514
84869
  // src/plugins/prompts-plugin.ts
84515
- import * as fs50 from "node:fs/promises";
84516
- import * as path108 from "node:path";
84870
+ import * as fs51 from "node:fs/promises";
84871
+ import * as path109 from "node:path";
84517
84872
 
84518
84873
  // src/storage/prompt-usage-store.ts
84519
84874
  init_atomic_write();
84520
- import * as fs49 from "node:fs/promises";
84875
+ import * as fs50 from "node:fs/promises";
84521
84876
  var PromptUsageStore = class {
84522
84877
  constructor(file) {
84523
84878
  this.file = file;
@@ -84537,7 +84892,7 @@ var PromptUsageStore = class {
84537
84892
  return this.cachedUsage;
84538
84893
  }
84539
84894
  try {
84540
- const raw = JSON.parse(await fs49.readFile(this.file, "utf8"));
84895
+ const raw = JSON.parse(await fs50.readFile(this.file, "utf8"));
84541
84896
  if (raw && typeof raw === "object" && raw.usage && typeof raw.usage === "object") {
84542
84897
  this.cachedUsage = raw.usage;
84543
84898
  this.cachedSignature = signature;
@@ -84617,7 +84972,7 @@ var PromptUsageStore = class {
84617
84972
  }
84618
84973
  async fileSignature() {
84619
84974
  try {
84620
- const stat40 = await fs49.stat(this.file);
84975
+ const stat40 = await fs50.stat(this.file);
84621
84976
  return { size: stat40.size, mtimeMs: stat40.mtimeMs, ctimeMs: stat40.ctimeMs };
84622
84977
  } catch {
84623
84978
  return null;
@@ -84804,7 +85159,7 @@ ${exact.content}` };
84804
85159
  2
84805
85160
  );
84806
85161
  try {
84807
- await fs50.writeFile(target, payload, "utf8");
85162
+ await fs51.writeFile(target, payload, "utf8");
84808
85163
  return { message: `Exported ${own.length} prompt(s) \u2192 ${target}` };
84809
85164
  } catch (err) {
84810
85165
  return { message: `Export failed: ${err instanceof Error ? err.message : String(err)}` };
@@ -84816,7 +85171,7 @@ ${exact.content}` };
84816
85171
  const src = resolveIoPath(restJoined, ctx);
84817
85172
  let raw;
84818
85173
  try {
84819
- raw = JSON.parse(await fs50.readFile(src, "utf8"));
85174
+ raw = JSON.parse(await fs51.readFile(src, "utf8"));
84820
85175
  } catch (err) {
84821
85176
  return { message: `Import failed: ${err instanceof Error ? err.message : String(err)}` };
84822
85177
  }
@@ -85022,9 +85377,9 @@ ${dim(`slug: ${entry.slug} | category: ${entry.category} | source: ${entry.sourc
85022
85377
  }
85023
85378
  function resolveIoPath(p, ctx) {
85024
85379
  const cleaned = p.trim().replace(/^["']|["']$/g, "");
85025
- if (path108.isAbsolute(cleaned)) return cleaned;
85380
+ if (path109.isAbsolute(cleaned)) return cleaned;
85026
85381
  const base = ctx.projectRoot ?? process.cwd();
85027
- return path108.resolve(base, cleaned);
85382
+ return path109.resolve(base, cleaned);
85028
85383
  }
85029
85384
  function sourceGlyph(e) {
85030
85385
  return e.source === "project" ? "\u{1F4C1}" : e.source === "user" ? "\u{1F464}" : e.source === "synced" ? "\u2601" : "\u{1F4E6}";
@@ -85107,7 +85462,7 @@ init_review_report_store();
85107
85462
 
85108
85463
  // src/plugins/skills-plugin.ts
85109
85464
  import * as os15 from "node:os";
85110
- import * as path113 from "node:path";
85465
+ import * as path114 from "node:path";
85111
85466
 
85112
85467
  // src/skills/registry/github-direct-adapter.ts
85113
85468
  var githubDirectAdapter = {
@@ -85264,8 +85619,8 @@ function numField(rec, key) {
85264
85619
  // src/skills/skill-generator.ts
85265
85620
  init_errors();
85266
85621
  import { spawn as spawn12 } from "node:child_process";
85267
- import * as fs51 from "node:fs/promises";
85268
- import * as path109 from "node:path";
85622
+ import * as fs52 from "node:fs/promises";
85623
+ import * as path110 from "node:path";
85269
85624
  async function validateSkillNameAvailable(name, loader) {
85270
85625
  const formatViolations = validateSkillName(name);
85271
85626
  const conflicts = loader ? (await loader.listEntries()).filter((e) => e.name === name) : [];
@@ -85389,11 +85744,11 @@ async function writeSkeletonSkill(skillsDir, body, opts = {}) {
85389
85744
  subsystem: "general"
85390
85745
  });
85391
85746
  }
85392
- const skillDir = path109.join(skillsDir, name);
85393
- const skillFile = path109.join(skillDir, "SKILL.md");
85747
+ const skillDir = path110.join(skillsDir, name);
85748
+ const skillFile = path110.join(skillDir, "SKILL.md");
85394
85749
  if (!opts.overwrite) {
85395
85750
  try {
85396
- await fs51.access(skillFile);
85751
+ await fs52.access(skillFile);
85397
85752
  throw new WrongStackError({
85398
85753
  message: `A skill already exists at ${skillFile}. Use --force to overwrite.`,
85399
85754
  code: ERROR_CODES.VALIDATION_ERROR,
@@ -85404,8 +85759,8 @@ async function writeSkeletonSkill(skillsDir, body, opts = {}) {
85404
85759
  if (err instanceof WrongStackError) throw err;
85405
85760
  }
85406
85761
  }
85407
- await fs51.mkdir(skillDir, { recursive: true });
85408
- await fs51.writeFile(skillFile, body, "utf8");
85762
+ await fs52.mkdir(skillDir, { recursive: true });
85763
+ await fs52.writeFile(skillFile, body, "utf8");
85409
85764
  return skillFile;
85410
85765
  }
85411
85766
  function bodyLineAdvisory(body) {
@@ -85448,15 +85803,15 @@ function defaultEditor() {
85448
85803
  // src/skills/skill-installer.ts
85449
85804
  init_errors();
85450
85805
  init_error();
85451
- import * as fs54 from "node:fs/promises";
85452
- import * as path112 from "node:path";
85806
+ import * as fs55 from "node:fs/promises";
85807
+ import * as path113 from "node:path";
85453
85808
 
85454
85809
  // src/skills/github-fetcher.ts
85455
85810
  init_errors();
85456
85811
  import { createWriteStream } from "node:fs";
85457
- import * as fs52 from "node:fs/promises";
85812
+ import * as fs53 from "node:fs/promises";
85458
85813
  import * as os14 from "node:os";
85459
- import * as path110 from "node:path";
85814
+ import * as path111 from "node:path";
85460
85815
  import { Readable } from "node:stream";
85461
85816
  import { pipeline } from "node:stream/promises";
85462
85817
  import { createGunzip } from "node:zlib";
@@ -85598,7 +85953,7 @@ async function downloadGitHubTarball(parsed) {
85598
85953
  }
85599
85954
  });
85600
85955
  }
85601
- const tempDir = await fs52.mkdtemp(path110.join(os14.tmpdir(), "wskill-"));
85956
+ const tempDir = await fs53.mkdtemp(path111.join(os14.tmpdir(), "wskill-"));
85602
85957
  try {
85603
85958
  if (!response.body) {
85604
85959
  throw new WrongStackError({
@@ -85609,17 +85964,17 @@ async function downloadGitHubTarball(parsed) {
85609
85964
  });
85610
85965
  }
85611
85966
  const nodeStream = Readable.fromWeb(response.body);
85612
- const tarPath = path110.join(tempDir, ".wrongstack-download.tar");
85967
+ const tarPath = path111.join(tempDir, ".wrongstack-download.tar");
85613
85968
  await writeBoundedGzipStream(nodeStream, tarPath, SKILL_LIMITS.MAX_UNCOMPRESSED_TARBALL_SIZE);
85614
- const tarBuf = await fs52.readFile(tarPath);
85969
+ const tarBuf = await fs53.readFile(tarPath);
85615
85970
  try {
85616
85971
  await extractTar(tarBuf, tempDir);
85617
85972
  } finally {
85618
- await fs52.rm(tarPath, { force: true });
85973
+ await fs53.rm(tarPath, { force: true });
85619
85974
  }
85620
85975
  return { tempDir };
85621
85976
  } catch (err) {
85622
- await fs52.rm(tempDir, { recursive: true, force: true }).catch(() => {
85977
+ await fs53.rm(tempDir, { recursive: true, force: true }).catch(() => {
85623
85978
  });
85624
85979
  throw err;
85625
85980
  }
@@ -85674,25 +86029,25 @@ async function extractTar(buf, destDir) {
85674
86029
  const fullPath = prefix ? `${prefix}/${name}` : name;
85675
86030
  const relPath = stripTopDir(fullPath);
85676
86031
  if (relPath && relPath !== "." && relPath !== "..") {
85677
- const destPath = path110.join(destDir, relPath);
85678
- const resolvedDest = path110.resolve(destPath);
85679
- const resolvedRoot = path110.resolve(destDir);
85680
- if (resolvedDest !== resolvedRoot && !resolvedDest.startsWith(resolvedRoot + path110.sep)) {
86032
+ const destPath = path111.join(destDir, relPath);
86033
+ const resolvedDest = path111.resolve(destPath);
86034
+ const resolvedRoot = path111.resolve(destDir);
86035
+ if (resolvedDest !== resolvedRoot && !resolvedDest.startsWith(resolvedRoot + path111.sep)) {
85681
86036
  offset += 512 + Math.ceil(size / 512) * 512;
85682
86037
  continue;
85683
86038
  }
85684
86039
  if (typeflag === 53 || typeflag === 0) {
85685
86040
  if (relPath.endsWith("/") || typeflag === 53) {
85686
- await fs52.mkdir(destPath, { recursive: true });
86041
+ await fs53.mkdir(destPath, { recursive: true });
85687
86042
  }
85688
86043
  }
85689
86044
  if ((typeflag === 48 || typeflag === 0 || typeflag === 0) && size > 0) {
85690
- const dir = path110.dirname(destPath);
85691
- await fs52.mkdir(dir, { recursive: true });
86045
+ const dir = path111.dirname(destPath);
86046
+ await fs53.mkdir(dir, { recursive: true });
85692
86047
  const dataStart = offset + 512;
85693
86048
  const dataEnd = dataStart + size;
85694
86049
  if (dataEnd > buf.length) break;
85695
- await fs52.writeFile(destPath, buf.subarray(dataStart, dataEnd));
86050
+ await fs53.writeFile(destPath, buf.subarray(dataStart, dataEnd));
85696
86051
  }
85697
86052
  }
85698
86053
  offset += 512 + Math.ceil(size / 512) * 512;
@@ -85701,8 +86056,8 @@ async function extractTar(buf, destDir) {
85701
86056
 
85702
86057
  // src/skills/manifest-store.ts
85703
86058
  init_atomic_write();
85704
- import * as fs53 from "node:fs/promises";
85705
- import * as path111 from "node:path";
86059
+ import * as fs54 from "node:fs/promises";
86060
+ import * as path112 from "node:path";
85706
86061
  var SkillManifestStore = class {
85707
86062
  manifestPath;
85708
86063
  cache;
@@ -85712,7 +86067,7 @@ var SkillManifestStore = class {
85712
86067
  async read() {
85713
86068
  if (this.cache) return this.cache;
85714
86069
  try {
85715
- const raw = await fs53.readFile(this.manifestPath, "utf8");
86070
+ const raw = await fs54.readFile(this.manifestPath, "utf8");
85716
86071
  const data = JSON.parse(raw);
85717
86072
  if (!Array.isArray(data.skills)) {
85718
86073
  this.cache = { skills: [] };
@@ -85725,8 +86080,8 @@ var SkillManifestStore = class {
85725
86080
  return this.cache;
85726
86081
  }
85727
86082
  async write(data) {
85728
- const dir = path111.dirname(this.manifestPath);
85729
- await fs53.mkdir(dir, { recursive: true });
86083
+ const dir = path112.dirname(this.manifestPath);
86084
+ await fs54.mkdir(dir, { recursive: true });
85730
86085
  await atomicWrite(this.manifestPath, JSON.stringify(data, null, 2) + "\n");
85731
86086
  this.cache = data;
85732
86087
  }
@@ -85764,8 +86119,8 @@ var SkillManifestStore = class {
85764
86119
 
85765
86120
  // src/skills/skill-installer.ts
85766
86121
  function isInside3(resolved, destDir) {
85767
- const root = path112.resolve(destDir);
85768
- return resolved === root || resolved.startsWith(root + path112.sep);
86122
+ const root = path113.resolve(destDir);
86123
+ return resolved === root || resolved.startsWith(root + path113.sep);
85769
86124
  }
85770
86125
  var MAX_SKILL_FILE_SIZE = SKILL_LIMITS.MAX_SKILL_FILE_SIZE;
85771
86126
  var SkillInstaller = class {
@@ -85820,13 +86175,13 @@ var SkillInstaller = class {
85820
86175
  this.opts.log?.(`Overwriting existing skill "${skill.name}" (${scope})...`);
85821
86176
  await this.removeSkillFiles(skill.name, scope);
85822
86177
  }
85823
- const destDir = path112.join(targetDir, skill.name);
85824
- await fs54.mkdir(destDir, { recursive: true });
86178
+ const destDir = path113.join(targetDir, skill.name);
86179
+ await fs55.mkdir(destDir, { recursive: true });
85825
86180
  const copiedFiles = [];
85826
86181
  for (const file of skill.files) {
85827
- const srcPath = path112.join(skill.baseDir, file);
85828
- const destPath = path112.join(destDir, file);
85829
- const resolved2 = path112.resolve(destPath);
86182
+ const srcPath = path113.join(skill.baseDir, file);
86183
+ const destPath = path113.join(destDir, file);
86184
+ const resolved2 = path113.resolve(destPath);
85830
86185
  if (!isInside3(resolved2, destDir)) {
85831
86186
  throw new FsError({
85832
86187
  message: `Path traversal detected in skill file: ${file}`,
@@ -85835,7 +86190,7 @@ var SkillInstaller = class {
85835
86190
  context: { reason: "path_traversal", skillName: skill.name }
85836
86191
  });
85837
86192
  }
85838
- const stat40 = await fs54.stat(srcPath);
86193
+ const stat40 = await fs55.stat(srcPath);
85839
86194
  if (stat40.size > MAX_SKILL_FILE_SIZE) {
85840
86195
  throw new FsError({
85841
86196
  message: `Skill file "${file}" is too large (${(stat40.size / 1024).toFixed(1)}KB). Max: ${MAX_SKILL_FILE_SIZE / 1024}KB`,
@@ -85844,8 +86199,8 @@ var SkillInstaller = class {
85844
86199
  context: { skillName: skill.name, fileSize: stat40.size, maxSize: MAX_SKILL_FILE_SIZE }
85845
86200
  });
85846
86201
  }
85847
- await fs54.mkdir(path112.dirname(destPath), { recursive: true });
85848
- await fs54.copyFile(srcPath, destPath);
86202
+ await fs55.mkdir(path113.dirname(destPath), { recursive: true });
86203
+ await fs55.copyFile(srcPath, destPath);
85849
86204
  copiedFiles.push(file);
85850
86205
  }
85851
86206
  const entry = {
@@ -85875,7 +86230,7 @@ var SkillInstaller = class {
85875
86230
  this.invalidateLoaderCache();
85876
86231
  return results;
85877
86232
  } finally {
85878
- await fs54.rm(tempDir, { recursive: true, force: true }).catch(() => {
86233
+ await fs55.rm(tempDir, { recursive: true, force: true }).catch(() => {
85879
86234
  });
85880
86235
  }
85881
86236
  }
@@ -85890,7 +86245,7 @@ var SkillInstaller = class {
85890
86245
  const targetDir = scope === "project" ? this.opts.projectSkillsDir : this.opts.globalSkillsDir;
85891
86246
  let entries;
85892
86247
  try {
85893
- entries = await fs54.readdir(srcDir, { withFileTypes: true });
86248
+ entries = await fs55.readdir(srcDir, { withFileTypes: true });
85894
86249
  } catch {
85895
86250
  throw new WrongStackError({
85896
86251
  message: `Source directory not found or not readable: ${srcDir}`,
@@ -85902,10 +86257,10 @@ var SkillInstaller = class {
85902
86257
  const results = [];
85903
86258
  for (const e of entries) {
85904
86259
  if (!await entryIsDirectory2(srcDir, e)) continue;
85905
- const skillMdPath = path112.join(srcDir, e.name, "SKILL.md");
86260
+ const skillMdPath = path113.join(srcDir, e.name, "SKILL.md");
85906
86261
  let content;
85907
86262
  try {
85908
- content = await fs54.readFile(skillMdPath, "utf8");
86263
+ content = await fs55.readFile(skillMdPath, "utf8");
85909
86264
  } catch {
85910
86265
  continue;
85911
86266
  }
@@ -85915,15 +86270,15 @@ var SkillInstaller = class {
85915
86270
  if (existing.find((x) => x.scope === scope)) {
85916
86271
  await this.removeSkillFiles(fm.name, scope);
85917
86272
  }
85918
- const destDir = path112.join(targetDir, fm.name);
85919
- await fs54.mkdir(destDir, { recursive: true });
85920
- const srcSkillDir = path112.join(srcDir, e.name);
86273
+ const destDir = path113.join(targetDir, fm.name);
86274
+ await fs55.mkdir(destDir, { recursive: true });
86275
+ const srcSkillDir = path113.join(srcDir, e.name);
85921
86276
  const files = await collectFiles(srcSkillDir, srcSkillDir);
85922
86277
  const copiedFiles = [];
85923
86278
  for (const file of files) {
85924
- const srcPath = path112.join(srcSkillDir, file);
85925
- const destPath = path112.join(destDir, file);
85926
- const resolved = path112.resolve(destPath);
86279
+ const srcPath = path113.join(srcSkillDir, file);
86280
+ const destPath = path113.join(destDir, file);
86281
+ const resolved = path113.resolve(destPath);
85927
86282
  if (!isInside3(resolved, destDir)) {
85928
86283
  throw new FsError({
85929
86284
  message: `Path traversal detected in skill file: ${file}`,
@@ -85932,16 +86287,16 @@ var SkillInstaller = class {
85932
86287
  context: { reason: "path_traversal", skillName: fm.name }
85933
86288
  });
85934
86289
  }
85935
- await fs54.mkdir(path112.dirname(destPath), { recursive: true });
86290
+ await fs55.mkdir(path113.dirname(destPath), { recursive: true });
85936
86291
  if (opts?.link) {
85937
86292
  try {
85938
- await fs54.symlink(srcPath, destPath);
86293
+ await fs55.symlink(srcPath, destPath);
85939
86294
  } catch (err) {
85940
- await fs54.copyFile(srcPath, destPath);
86295
+ await fs55.copyFile(srcPath, destPath);
85941
86296
  this.opts.log?.(`symlink failed for ${file} (${toErrorMessage(err)}); copied instead`);
85942
86297
  }
85943
86298
  } else {
85944
- await fs54.copyFile(srcPath, destPath);
86299
+ await fs55.copyFile(srcPath, destPath);
85945
86300
  }
85946
86301
  copiedFiles.push(file);
85947
86302
  }
@@ -86095,10 +86450,10 @@ var SkillInstaller = class {
86095
86450
  */
86096
86451
  async detectSkills(baseDir2) {
86097
86452
  const results = [];
86098
- const rootSkillMd = path112.join(baseDir2, "SKILL.md");
86453
+ const rootSkillMd = path113.join(baseDir2, "SKILL.md");
86099
86454
  try {
86100
- await fs54.access(rootSkillMd);
86101
- const content = await fs54.readFile(rootSkillMd, "utf8");
86455
+ await fs55.access(rootSkillMd);
86456
+ const content = await fs55.readFile(rootSkillMd, "utf8");
86102
86457
  const fm = parseSkillFrontmatter(content);
86103
86458
  if (fm.name && fm.description && isValidSkillNameFormat(fm.name)) {
86104
86459
  results.push({
@@ -86110,17 +86465,17 @@ var SkillInstaller = class {
86110
86465
  }
86111
86466
  } catch {
86112
86467
  }
86113
- const skillsDir = path112.join(baseDir2, "skills");
86468
+ const skillsDir = path113.join(baseDir2, "skills");
86114
86469
  try {
86115
- const entries = await fs54.readdir(skillsDir, { withFileTypes: true });
86470
+ const entries = await fs55.readdir(skillsDir, { withFileTypes: true });
86116
86471
  for (const entry of entries) {
86117
86472
  if (!entry.isDirectory()) continue;
86118
- const skillFile = path112.join(skillsDir, entry.name, "SKILL.md");
86473
+ const skillFile = path113.join(skillsDir, entry.name, "SKILL.md");
86119
86474
  try {
86120
- const content = await fs54.readFile(skillFile, "utf8");
86475
+ const content = await fs55.readFile(skillFile, "utf8");
86121
86476
  const fm = parseSkillFrontmatter(content);
86122
86477
  if (fm.name && fm.description && isValidSkillNameFormat(fm.name)) {
86123
- const skillDir = path112.join(skillsDir, entry.name);
86478
+ const skillDir = path113.join(skillsDir, entry.name);
86124
86479
  const files = await collectFiles(skillDir, skillDir);
86125
86480
  results.push({
86126
86481
  name: fm.name,
@@ -86153,8 +86508,8 @@ var SkillInstaller = class {
86153
86508
  */
86154
86509
  async removeSkillFiles(name, scope) {
86155
86510
  const targetDir = scope === "project" ? this.opts.projectSkillsDir : this.opts.globalSkillsDir;
86156
- const root = path112.resolve(targetDir);
86157
- const skillDir = path112.resolve(path112.join(targetDir, name));
86511
+ const root = path113.resolve(targetDir);
86512
+ const skillDir = path113.resolve(path113.join(targetDir, name));
86158
86513
  if (skillDir === root || !isInside3(skillDir, root)) {
86159
86514
  throw new FsError({
86160
86515
  message: `Refusing to delete skill files outside the skills directory: ${name}`,
@@ -86163,7 +86518,7 @@ var SkillInstaller = class {
86163
86518
  context: { reason: "path_traversal", skillName: name, scope }
86164
86519
  });
86165
86520
  }
86166
- await fs54.rm(skillDir, { recursive: true, force: true });
86521
+ await fs55.rm(skillDir, { recursive: true, force: true });
86167
86522
  }
86168
86523
  /**
86169
86524
  * Invalidate the skill loader's cache so newly installed skills appear.
@@ -86198,7 +86553,7 @@ async function entryIsDirectory2(dir, entry) {
86198
86553
  if (entry.isDirectory()) return true;
86199
86554
  if (entry.isSymbolicLink()) {
86200
86555
  try {
86201
- return (await fs54.stat(path112.join(dir, entry.name))).isDirectory();
86556
+ return (await fs55.stat(path113.join(dir, entry.name))).isDirectory();
86202
86557
  } catch {
86203
86558
  return false;
86204
86559
  }
@@ -86207,10 +86562,10 @@ async function entryIsDirectory2(dir, entry) {
86207
86562
  }
86208
86563
  async function collectFiles(dir, baseDir2) {
86209
86564
  const results = [];
86210
- const entries = await fs54.readdir(dir, { withFileTypes: true });
86565
+ const entries = await fs55.readdir(dir, { withFileTypes: true });
86211
86566
  for (const entry of entries) {
86212
- const fullPath = path112.join(dir, entry.name);
86213
- const relPath = path112.relative(baseDir2, fullPath);
86567
+ const fullPath = path113.join(dir, entry.name);
86568
+ const relPath = path113.relative(baseDir2, fullPath);
86214
86569
  if (entry.isDirectory()) {
86215
86570
  if (entry.name.startsWith(".") || entry.name === "node_modules") continue;
86216
86571
  results.push(...await collectFiles(fullPath, baseDir2));
@@ -86289,7 +86644,7 @@ function createSkillsPlugin(opts) {
86289
86644
  function makeInstaller(skillLoader, projectRoot, registryAdapters) {
86290
86645
  const paths = resolveWstackPaths({ projectRoot });
86291
86646
  return new SkillInstaller({
86292
- manifestPath: path113.join(paths.configDir, "installed-skills.json"),
86647
+ manifestPath: path114.join(paths.configDir, "installed-skills.json"),
86293
86648
  projectSkillsDir: paths.inProjectSkills,
86294
86649
  globalSkillsDir: paths.globalSkills,
86295
86650
  projectHash: paths.projectHash,
@@ -86668,7 +87023,7 @@ function resolveImportSourceDir(tool, opts) {
86668
87023
  const entry = IMPORT_SOURCE_TOOLS.find((t2) => t2.id === tool);
86669
87024
  if (!entry) return void 0;
86670
87025
  const base = opts.global ? opts.homeDir ?? os15.homedir() : opts.projectRoot;
86671
- return path113.join(base, "." + entry.id, entry.subdir);
87026
+ return path114.join(base, "." + entry.id, entry.subdir);
86672
87027
  }
86673
87028
  function buildSkillImportCommand(skillLoader) {
86674
87029
  return {
@@ -86709,7 +87064,7 @@ function buildSkillImportCommand(skillLoader) {
86709
87064
  };
86710
87065
  }
86711
87066
  } else if (positional) {
86712
- srcDir = path113.resolve(ctx.projectRoot, positional);
87067
+ srcDir = path114.resolve(ctx.projectRoot, positional);
86713
87068
  } else {
86714
87069
  return {
86715
87070
  message: "Usage: /skill-import <src-dir> | --from <tool> | --from-claude [--global] [--link]"
@@ -86836,14 +87191,14 @@ function truncate5(s, max) {
86836
87191
  }
86837
87192
 
86838
87193
  // src/plugins/sync-plugin.ts
86839
- import * as path115 from "node:path";
87194
+ import * as path116 from "node:path";
86840
87195
  init_error();
86841
87196
 
86842
87197
  // src/storage/cloud-sync.ts
86843
87198
  init_atomic_write();
86844
87199
  init_errors();
86845
- import * as fs55 from "node:fs/promises";
86846
- import * as path114 from "node:path";
87200
+ import * as fs56 from "node:fs/promises";
87201
+ import * as path115 from "node:path";
86847
87202
  import { createHash as createHash36 } from "node:crypto";
86848
87203
  var ALL_SYNC_CATEGORIES = ["settings", "skills", "prompts", "memory", "history"];
86849
87204
  var CloudSync = class {
@@ -86851,8 +87206,8 @@ var CloudSync = class {
86851
87206
  this.paths = paths;
86852
87207
  this.getConfig = getConfig;
86853
87208
  this.setConfig = setConfig;
86854
- this.statePath = path114.join(paths.configDir, "sync-state.json");
86855
- this.getSettingsConfigPath = getSettingsConfigPath ?? (() => path114.join(this.paths.configDir, "config.json"));
87209
+ this.statePath = path115.join(paths.configDir, "sync-state.json");
87210
+ this.getSettingsConfigPath = getSettingsConfigPath ?? (() => path115.join(this.paths.configDir, "config.json"));
86856
87211
  }
86857
87212
  paths;
86858
87213
  getConfig;
@@ -87007,7 +87362,7 @@ var CloudSync = class {
87007
87362
  }
87008
87363
  async loadState() {
87009
87364
  try {
87010
- const raw = await fs55.readFile(this.statePath, "utf8");
87365
+ const raw = await fs56.readFile(this.statePath, "utf8");
87011
87366
  this.state = JSON.parse(raw);
87012
87367
  } catch {
87013
87368
  this.state = null;
@@ -87132,18 +87487,18 @@ var CloudSync = class {
87132
87487
  const localPath = this.categoryToPath(cat);
87133
87488
  if (!localPath) continue;
87134
87489
  try {
87135
- const stat40 = await fs55.lstat(localPath);
87490
+ const stat40 = await fs56.lstat(localPath);
87136
87491
  if (stat40.isSymbolicLink()) continue;
87137
87492
  if (stat40.isDirectory()) {
87138
87493
  const files = await this.walkDir(localPath, localPath);
87139
87494
  for (const file of files) {
87140
- const content = await fs55.readFile(file, "utf8");
87141
- const rel = path114.relative(localPath, file).replace(/\\/g, "/");
87495
+ const content = await fs56.readFile(file, "utf8");
87496
+ const rel = path115.relative(localPath, file).replace(/\\/g, "/");
87142
87497
  entries.push({ path: `data/${cat}/${rel}`, content, mode: "100644" });
87143
87498
  hashes.push(`${cat}/${rel}\0${content}`);
87144
87499
  }
87145
87500
  } else {
87146
- const content = await fs55.readFile(localPath, "utf8");
87501
+ const content = await fs56.readFile(localPath, "utf8");
87147
87502
  entries.push({ path: `data/${cat}`, content, mode: "100644" });
87148
87503
  hashes.push(`${cat}\0${content}`);
87149
87504
  }
@@ -87159,17 +87514,17 @@ var CloudSync = class {
87159
87514
  const localPath = this.categoryToPath(cat);
87160
87515
  if (!localPath) continue;
87161
87516
  try {
87162
- const stat40 = await fs55.lstat(localPath);
87517
+ const stat40 = await fs56.lstat(localPath);
87163
87518
  if (stat40.isSymbolicLink()) continue;
87164
87519
  if (stat40.isDirectory()) {
87165
87520
  const files = await this.walkDir(localPath, localPath);
87166
87521
  for (const file of files) {
87167
- const content = await fs55.readFile(file, "utf8");
87168
- const rel = path114.relative(localPath, file).replace(/\\/g, "/");
87522
+ const content = await fs56.readFile(file, "utf8");
87523
+ const rel = path115.relative(localPath, file).replace(/\\/g, "/");
87169
87524
  hashes.push(`${cat}/${rel}\0${content}`);
87170
87525
  }
87171
87526
  } else {
87172
- const content = await fs55.readFile(localPath, "utf8");
87527
+ const content = await fs56.readFile(localPath, "utf8");
87173
87528
  hashes.push(`${cat}\0${content}`);
87174
87529
  }
87175
87530
  } catch {
@@ -87196,10 +87551,10 @@ var CloudSync = class {
87196
87551
  }
87197
87552
  async walkDir(dir, base) {
87198
87553
  const results = [];
87199
- const entries = await fs55.readdir(dir, { withFileTypes: true });
87554
+ const entries = await fs56.readdir(dir, { withFileTypes: true });
87200
87555
  entries.sort((a, b) => a.name.localeCompare(b.name));
87201
87556
  for (const entry of entries) {
87202
- const full = path114.join(dir, entry.name);
87557
+ const full = path115.join(dir, entry.name);
87203
87558
  if (entry.isSymbolicLink()) continue;
87204
87559
  if (entry.isDirectory()) {
87205
87560
  results.push(...await this.walkDir(full, base));
@@ -87212,17 +87567,17 @@ var CloudSync = class {
87212
87567
  };
87213
87568
  async function preparePulledDestination(cat, localPath, destPath, remotePath) {
87214
87569
  const directoryBacked = cat === "skills" || cat === "prompts";
87215
- const rootPath = directoryBacked ? localPath : path114.dirname(localPath);
87570
+ const rootPath = directoryBacked ? localPath : path115.dirname(localPath);
87216
87571
  const rootStat = await lstatIfExists(rootPath);
87217
87572
  if (rootStat?.isSymbolicLink()) {
87218
87573
  throw unsafePulledSymlinkError(remotePath, rootPath);
87219
87574
  }
87220
87575
  if (directoryBacked) {
87221
- const relativeParent = path114.relative(rootPath, path114.dirname(destPath));
87576
+ const relativeParent = path115.relative(rootPath, path115.dirname(destPath));
87222
87577
  let cursor = rootPath;
87223
87578
  if (relativeParent) {
87224
- for (const segment of relativeParent.split(path114.sep)) {
87225
- cursor = path114.join(cursor, segment);
87579
+ for (const segment of relativeParent.split(path115.sep)) {
87580
+ cursor = path115.join(cursor, segment);
87226
87581
  const stat40 = await lstatIfExists(cursor);
87227
87582
  if (stat40?.isSymbolicLink()) throw unsafePulledSymlinkError(remotePath, cursor);
87228
87583
  }
@@ -87230,11 +87585,11 @@ async function preparePulledDestination(cat, localPath, destPath, remotePath) {
87230
87585
  }
87231
87586
  const destStat = await lstatIfExists(destPath);
87232
87587
  if (destStat?.isSymbolicLink()) throw unsafePulledSymlinkError(remotePath, destPath);
87233
- await fs55.mkdir(path114.dirname(destPath), { recursive: true });
87588
+ await fs56.mkdir(path115.dirname(destPath), { recursive: true });
87234
87589
  }
87235
87590
  async function lstatIfExists(filePath) {
87236
87591
  try {
87237
- return await fs55.lstat(filePath);
87592
+ return await fs56.lstat(filePath);
87238
87593
  } catch (err) {
87239
87594
  if (err.code === "ENOENT") return null;
87240
87595
  throw err;
@@ -87260,9 +87615,9 @@ function resolvePulledCategoryPath(cat, localPath, rel, remotePath) {
87260
87615
  return localPath;
87261
87616
  }
87262
87617
  if (!rel) return localPath;
87263
- const normalizedRel = path114.normalize(rel);
87264
- const traversesUp = normalizedRel === ".." || normalizedRel.startsWith(`..${path114.sep}`);
87265
- if (path114.isAbsolute(normalizedRel) || traversesUp) {
87618
+ const normalizedRel = path115.normalize(rel);
87619
+ const traversesUp = normalizedRel === ".." || normalizedRel.startsWith(`..${path115.sep}`);
87620
+ if (path115.isAbsolute(normalizedRel) || traversesUp) {
87266
87621
  throw new FsError({
87267
87622
  message: `Refusing CloudSync path traversal: ${remotePath}`,
87268
87623
  code: ERROR_CODES.FS_DELETE_FAILED,
@@ -87270,10 +87625,10 @@ function resolvePulledCategoryPath(cat, localPath, rel, remotePath) {
87270
87625
  context: { reason: "path_traversal", normalizedRel }
87271
87626
  });
87272
87627
  }
87273
- const dest = path114.resolve(localPath, normalizedRel);
87274
- const root = path114.resolve(localPath);
87275
- const relative21 = path114.relative(root, dest);
87276
- if (relative21.startsWith("..") || path114.isAbsolute(relative21)) {
87628
+ const dest = path115.resolve(localPath, normalizedRel);
87629
+ const root = path115.resolve(localPath);
87630
+ const relative21 = path115.relative(root, dest);
87631
+ if (relative21.startsWith("..") || path115.isAbsolute(relative21)) {
87277
87632
  throw new FsError({
87278
87633
  message: `Refusing CloudSync path outside category root: ${remotePath}`,
87279
87634
  code: ERROR_CODES.FS_DELETE_FAILED,
@@ -87316,7 +87671,7 @@ function createSyncPlugin(opts) {
87316
87671
  api.log.warn("[sync] paths, configStore, or configDir not available \u2014 /sync disabled");
87317
87672
  return;
87318
87673
  }
87319
- const syncConfigPath = paths.syncConfig ?? path115.join(paths.configDir, "sync.json");
87674
+ const syncConfigPath = paths.syncConfig ?? path116.join(paths.configDir, "sync.json");
87320
87675
  cloud = new CloudSync(
87321
87676
  paths,
87322
87677
  () => {
@@ -87327,7 +87682,7 @@ function createSyncPlugin(opts) {
87327
87682
  await persistSyncConfig(syncConfigPath, cfg, vault);
87328
87683
  configStore?.update({ sync: cfg });
87329
87684
  },
87330
- () => path115.join(paths.configDir, "config.json")
87685
+ () => path116.join(paths.configDir, "config.json")
87331
87686
  );
87332
87687
  void cloud.loadState();
87333
87688
  api.slashCommands.register(buildSyncCommand(cloud, configStore, vault, syncConfigPath));
@@ -87651,8 +88006,8 @@ var PromptInstaller = class {
87651
88006
 
87652
88007
  // src/prompts/prompt-manifest-store.ts
87653
88008
  init_atomic_write();
87654
- import * as fs56 from "node:fs/promises";
87655
- import * as path116 from "node:path";
88009
+ import * as fs57 from "node:fs/promises";
88010
+ import * as path117 from "node:path";
87656
88011
  var PromptManifestStore = class {
87657
88012
  constructor(manifestPath) {
87658
88013
  this.manifestPath = manifestPath;
@@ -87660,7 +88015,7 @@ var PromptManifestStore = class {
87660
88015
  manifestPath;
87661
88016
  async load() {
87662
88017
  try {
87663
- const raw = JSON.parse(await fs56.readFile(this.manifestPath, "utf8"));
88018
+ const raw = JSON.parse(await fs57.readFile(this.manifestPath, "utf8"));
87664
88019
  if (raw && typeof raw === "object" && Array.isArray(raw.entries)) {
87665
88020
  return { version: 1, entries: raw.entries };
87666
88021
  }
@@ -87669,7 +88024,7 @@ var PromptManifestStore = class {
87669
88024
  return { version: 1, entries: [] };
87670
88025
  }
87671
88026
  async save(data) {
87672
- await ensureDir(path116.dirname(this.manifestPath));
88027
+ await ensureDir(path117.dirname(this.manifestPath));
87673
88028
  await atomicWrite(this.manifestPath, JSON.stringify(data, null, 2));
87674
88029
  }
87675
88030
  /** Upsert one entry keyed by slug. */
@@ -87692,267 +88047,6 @@ var PromptManifestStore = class {
87692
88047
  }
87693
88048
  };
87694
88049
 
87695
- // src/prompts/prompt-journal.ts
87696
- import * as fs57 from "node:fs/promises";
87697
- import * as path117 from "node:path";
87698
- async function ensureGitignore(projectRoot) {
87699
- const gitignorePath = path117.join(projectRoot, ".gitignore");
87700
- try {
87701
- let content = "";
87702
- try {
87703
- content = await fs57.readFile(gitignorePath, "utf8");
87704
- } catch {
87705
- content = "";
87706
- }
87707
- if (!content.includes(".wrongstack") && !content.includes(".wrongstack/")) {
87708
- const addition = content.endsWith("\n") || content.length === 0 ? ".wrongstack/\n" : "\n.wrongstack/\n";
87709
- await fs57.writeFile(gitignorePath, content + addition, "utf8");
87710
- }
87711
- } catch {
87712
- }
87713
- }
87714
- async function recordPromptJournalEntry(opts) {
87715
- const now = /* @__PURE__ */ new Date();
87716
- const timestamp = now.toISOString();
87717
- const dateStr = timestamp.slice(0, 10);
87718
- const monthStr = dateStr.slice(0, 7);
87719
- const sessionId = opts.sessionId && opts.sessionId.trim() ? opts.sessionId.trim() : "general";
87720
- const id = `pmt_${Date.now()}_${Math.random().toString(36).slice(2, 9)}`;
87721
- const content = opts.content ?? "";
87722
- const lines = content.split("\n");
87723
- const characterCount = content.length;
87724
- const lineCount2 = lines.length;
87725
- const tokenEstimate = Math.ceil(characterCount / 4);
87726
- const entry = {
87727
- id,
87728
- timestamp,
87729
- sessionId,
87730
- projectRoot: opts.projectRoot,
87731
- role: opts.role ?? (opts.category === "system_prompt" ? "system" : "user"),
87732
- category: opts.category,
87733
- content,
87734
- rawContent: opts.rawContent,
87735
- metadata: {
87736
- model: opts.model,
87737
- provider: opts.provider,
87738
- iterationIndex: opts.iterationIndex,
87739
- tokenEstimate,
87740
- characterCount,
87741
- lineCount: lineCount2,
87742
- activeTools: opts.activeTools,
87743
- contextFiles: opts.contextFiles,
87744
- durationMs: opts.durationMs,
87745
- decisionReason: opts.decisionReason,
87746
- tags: opts.tags
87747
- }
87748
- };
87749
- const basePromptsDir = path117.join(opts.projectRoot, ".wrongstack", "prompts");
87750
- const dayDir = path117.join(basePromptsDir, monthStr, dateStr);
87751
- try {
87752
- await fs57.mkdir(dayDir, { recursive: true });
87753
- await ensureGitignore(opts.projectRoot);
87754
- const sessionJsonlFile = path117.join(dayDir, `session-${sessionId}.jsonl`);
87755
- await fs57.appendFile(sessionJsonlFile, JSON.stringify(entry) + "\n", "utf8");
87756
- const sessionMdFile = path117.join(dayDir, `session-${sessionId}.md`);
87757
- const mdSection = formatEntryMarkdown(entry);
87758
- await fs57.appendFile(sessionMdFile, mdSection, "utf8");
87759
- const dailySummaryFile = path117.join(dayDir, "daily-summary.md");
87760
- await updateDailySummary(dailySummaryFile, dateStr, entry);
87761
- await updateRootCatalog(basePromptsDir, monthStr, dateStr, sessionId, entry);
87762
- } catch (err) {
87763
- console.error?.(`Failed to write hierarchical prompt journal: ${err}`);
87764
- }
87765
- return entry;
87766
- }
87767
- function formatEntryMarkdown(entry) {
87768
- const tagList = [
87769
- `**Category:** \`${entry.category}\``,
87770
- `**Role:** \`${entry.role}\``,
87771
- entry.metadata.model ? `**Model:** \`${entry.metadata.model}\`` : null,
87772
- `**Tokens (est):** ~${entry.metadata.tokenEstimate}`,
87773
- entry.metadata.iterationIndex !== void 0 ? `**Iteration:** #${entry.metadata.iterationIndex}` : null,
87774
- `**Session:** \`${entry.sessionId}\``
87775
- ].filter(Boolean).join(" | ");
87776
- let md = `
87777
- ### \u{1F4DD} [${entry.timestamp}] \`${entry.id}\`
87778
- ${tagList}
87779
-
87780
- `;
87781
- if (entry.metadata.decisionReason) {
87782
- md += `> **Rationale:** ${entry.metadata.decisionReason}
87783
-
87784
- `;
87785
- }
87786
- if (entry.metadata.activeTools && entry.metadata.activeTools.length > 0) {
87787
- md += `*Active Tools:* \`${entry.metadata.activeTools.join("`, `")}\`
87788
-
87789
- `;
87790
- }
87791
- if (entry.rawContent && entry.rawContent !== entry.content) {
87792
- md += `**Raw Input:**
87793
- \`\`\`text
87794
- ${entry.rawContent.trim()}
87795
- \`\`\`
87796
-
87797
- `;
87798
- md += `**Refined / Injected Prompt:**
87799
- \`\`\`text
87800
- ${entry.content.trim()}
87801
- \`\`\`
87802
-
87803
- `;
87804
- } else {
87805
- md += `**Prompt Content:**
87806
- \`\`\`text
87807
- ${entry.content.trim()}
87808
- \`\`\`
87809
-
87810
- `;
87811
- }
87812
- md += `---
87813
- `;
87814
- return md;
87815
- }
87816
- async function updateDailySummary(summaryFile, dateStr, entry) {
87817
- try {
87818
- let content = "";
87819
- try {
87820
- content = await fs57.readFile(summaryFile, "utf8");
87821
- } catch {
87822
- content = `# \u{1F4C5} Daily Prompt Summary \u2014 ${dateStr}
87823
-
87824
- | Time | ID | Session | Category | Model | Tokens | Rationale |
87825
- | :--- | :--- | :--- | :--- | :--- | :--- | :--- |
87826
- `;
87827
- }
87828
- const time = entry.timestamp.slice(11, 19);
87829
- const model = entry.metadata.model ?? "-";
87830
- const reason = entry.metadata.decisionReason ? entry.metadata.decisionReason.slice(0, 40) : "-";
87831
- const row = `| ${time} | [\`${entry.id}\`](session-${entry.sessionId}.md) | \`${entry.sessionId}\` | \`${entry.category}\` | ${model} | ~${entry.metadata.tokenEstimate} | ${reason} |
87832
- `;
87833
- await fs57.writeFile(summaryFile, content + row, "utf8");
87834
- } catch {
87835
- }
87836
- }
87837
- async function updateRootCatalog(baseDir2, monthStr, dateStr, sessionId, entry) {
87838
- const indexJsonFile = path117.join(baseDir2, "index.json");
87839
- const indexMdFile = path117.join(baseDir2, "index.md");
87840
- let catalog;
87841
- try {
87842
- const raw = await fs57.readFile(indexJsonFile, "utf8");
87843
- catalog = JSON.parse(raw);
87844
- } catch {
87845
- catalog = {
87846
- updatedAt: entry.timestamp,
87847
- totalPrompts: 0,
87848
- totalTokensEstimated: 0,
87849
- months: {}
87850
- };
87851
- }
87852
- catalog.updatedAt = entry.timestamp;
87853
- catalog.totalPrompts += 1;
87854
- catalog.totalTokensEstimated += entry.metadata.tokenEstimate;
87855
- if (!catalog.months[monthStr]) {
87856
- catalog.months[monthStr] = { days: {} };
87857
- }
87858
- const monthData = catalog.months[monthStr];
87859
- if (!monthData.days[dateStr]) {
87860
- monthData.days[dateStr] = { sessions: {} };
87861
- }
87862
- const dayData = monthData.days[dateStr];
87863
- if (!dayData.sessions[sessionId]) {
87864
- dayData.sessions[sessionId] = {
87865
- promptCount: 0,
87866
- tokenEstimate: 0,
87867
- lastTimestamp: entry.timestamp,
87868
- categories: {}
87869
- };
87870
- }
87871
- const sessionData = dayData.sessions[sessionId];
87872
- sessionData.promptCount += 1;
87873
- sessionData.tokenEstimate += entry.metadata.tokenEstimate;
87874
- sessionData.lastTimestamp = entry.timestamp;
87875
- sessionData.categories[entry.category] = (sessionData.categories[entry.category] ?? 0) + 1;
87876
- try {
87877
- await fs57.writeFile(indexJsonFile, JSON.stringify(catalog, null, 2), "utf8");
87878
- let md = `# \u{1F5C2}\uFE0F Prompt Journal Navigation Index
87879
-
87880
- `;
87881
- md += `* **Total Prompts Logged:** ${catalog.totalPrompts}
87882
- `;
87883
- md += `* **Total Tokens (est):** ~${catalog.totalTokensEstimated.toLocaleString()}
87884
- `;
87885
- md += `* **Last Recorded Activity:** ${catalog.updatedAt}
87886
-
87887
- `;
87888
- md += `## \u{1F4C5} Recorded Dates & Sessions
87889
-
87890
- `;
87891
- md += `| Date | Session | Prompts | Tokens (est) | Daily Log | Session Log |
87892
- `;
87893
- md += `| :--- | :--- | :--- | :--- | :--- | :--- |
87894
- `;
87895
- for (const [m, mObj] of Object.entries(catalog.months).sort().reverse()) {
87896
- for (const [d, dObj] of Object.entries(mObj.days).sort().reverse()) {
87897
- for (const [sId, sData] of Object.entries(dObj.sessions)) {
87898
- const dailyLink = `[daily-summary.md](./${m}/${d}/daily-summary.md)`;
87899
- const sessionLink = `[session-${sId}.md](./${m}/${d}/session-${sId}.md)`;
87900
- md += `| **${d}** | \`${sId}\` | ${sData.promptCount} | ~${sData.tokenEstimate.toLocaleString()} | ${dailyLink} | ${sessionLink} |
87901
- `;
87902
- }
87903
- }
87904
- }
87905
- await fs57.writeFile(indexMdFile, md, "utf8");
87906
- } catch {
87907
- }
87908
- }
87909
- async function getPromptJournalEntries(projectRoot, filter = {}) {
87910
- const basePromptsDir = path117.join(projectRoot, ".wrongstack", "prompts");
87911
- const results = [];
87912
- try {
87913
- const months = await fs57.readdir(basePromptsDir);
87914
- for (const month of months) {
87915
- if (!/^\d{4}-\d{2}$/.test(month)) continue;
87916
- if (filter.month && filter.month !== month) continue;
87917
- const monthDir = path117.join(basePromptsDir, month);
87918
- const days = await fs57.readdir(monthDir);
87919
- for (const day of days) {
87920
- if (!/^\d{4}-\d{2}-\d{2}$/.test(day)) continue;
87921
- if (filter.date && filter.date !== day) continue;
87922
- const dayDir = path117.join(monthDir, day);
87923
- const files = await fs57.readdir(dayDir);
87924
- const jsonlFiles = files.filter((f) => f.startsWith("session-") && f.endsWith(".jsonl"));
87925
- for (const jsonlFile of jsonlFiles) {
87926
- const sessionMatch = jsonlFile.match(/^session-(.+)\.jsonl$/);
87927
- const sId = sessionMatch ? sessionMatch[1] : void 0;
87928
- if (filter.sessionId && sId !== filter.sessionId) continue;
87929
- const filePath = path117.join(dayDir, jsonlFile);
87930
- const content = await fs57.readFile(filePath, "utf8");
87931
- const lines = content.split("\n");
87932
- for (const line of lines) {
87933
- if (!line.trim()) continue;
87934
- try {
87935
- const entry = JSON.parse(line);
87936
- if (filter.sessionId && entry.sessionId !== filter.sessionId) continue;
87937
- if (filter.category && entry.category !== filter.category) continue;
87938
- if (filter.since && entry.timestamp < filter.since) continue;
87939
- results.push(entry);
87940
- } catch {
87941
- }
87942
- }
87943
- }
87944
- }
87945
- }
87946
- } catch {
87947
- return [];
87948
- }
87949
- results.sort((a, b) => a.timestamp.localeCompare(b.timestamp));
87950
- if (filter.limit && results.length > filter.limit) {
87951
- return results.slice(-filter.limit);
87952
- }
87953
- return results;
87954
- }
87955
-
87956
88050
  // src/registry/provider-registry.ts
87957
88051
  var ProviderRegistry = class {
87958
88052
  factories = /* @__PURE__ */ new Map();
@@ -97238,6 +97332,7 @@ export {
97238
97332
  PROJECT_ID_PREFIX,
97239
97333
  PROMETHEUS_CONTENT_TYPE,
97240
97334
  PROMPT_CATEGORY_LABELS,
97335
+ PROMPT_JOURNAL_RAW_MARKER,
97241
97336
  PROVIDER_KEY_SET_TOOL_NAME,
97242
97337
  PROVIDER_MANAGE_TOOL_NAME,
97243
97338
  ParallelEternalEngine,