@wrongstack/core 0.41.0 → 0.54.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.
Files changed (58) hide show
  1. package/dist/{agent-bridge-D_XcS2HL.d.ts → agent-bridge-Dnhw4tnM.d.ts} +1 -1
  2. package/dist/{agent-subagent-runner-C66vi4Gq.d.ts → agent-subagent-runner-By7jruZ_.d.ts} +3 -3
  3. package/dist/{compactor-D1RHFRmF.d.ts → compactor-Duhsf0ge.d.ts} +1 -1
  4. package/dist/{config-ZRCf7sTu.d.ts → config-bht0txXS.d.ts} +33 -2
  5. package/dist/{context-7u93AcGD.d.ts → context-DtPKqKYV.d.ts} +1 -0
  6. package/dist/coordination/index.d.ts +12 -12
  7. package/dist/coordination/index.js +234 -32
  8. package/dist/coordination/index.js.map +1 -1
  9. package/dist/defaults/index.d.ts +23 -23
  10. package/dist/defaults/index.js +182 -75
  11. package/dist/defaults/index.js.map +1 -1
  12. package/dist/{events-BrQiweXN.d.ts → events-CbHTS4ZZ.d.ts} +136 -2
  13. package/dist/execution/index.d.ts +42 -16
  14. package/dist/execution/index.js +61 -28
  15. package/dist/execution/index.js.map +1 -1
  16. package/dist/extension/index.d.ts +6 -6
  17. package/dist/{goal-store-BeRsj7YX.d.ts → goal-store-DwcTDDiX.d.ts} +1 -1
  18. package/dist/{index-6_csX32J.d.ts → index-CI271MjL.d.ts} +5 -5
  19. package/dist/{index-DkVgH3wC.d.ts → index-ge5F2dnc.d.ts} +10 -8
  20. package/dist/index.d.ts +113 -37
  21. package/dist/index.js +601 -149
  22. package/dist/index.js.map +1 -1
  23. package/dist/infrastructure/index.d.ts +6 -6
  24. package/dist/kernel/index.d.ts +9 -9
  25. package/dist/kernel/index.js +3 -1
  26. package/dist/kernel/index.js.map +1 -1
  27. package/dist/{mcp-servers-DONdo-XM.d.ts → mcp-servers-DE6gzBry.d.ts} +3 -3
  28. package/dist/models/index.d.ts +3 -3
  29. package/dist/models/index.js +36 -18
  30. package/dist/models/index.js.map +1 -1
  31. package/dist/{models-registry-gwMAo6E3.d.ts → models-registry-Cuq1C8V9.d.ts} +7 -0
  32. package/dist/{multi-agent-C8Z1i__e.d.ts → multi-agent-BmC_xiog.d.ts} +2 -2
  33. package/dist/{multi-agent-coordinator-BUsjiRWl.d.ts → multi-agent-coordinator-CjNX4uBD.d.ts} +2 -2
  34. package/dist/{null-fleet-bus-FvgHnZah.d.ts → null-fleet-bus-BNiSlTna.d.ts} +23 -11
  35. package/dist/observability/index.d.ts +2 -2
  36. package/dist/{path-resolver-DumKAi0n.d.ts → path-resolver-Bax85amb.d.ts} +2 -2
  37. package/dist/{permission-B6sldrSp.d.ts → permission-Drm7LpPo.d.ts} +1 -1
  38. package/dist/{permission-policy-CtNscWOA.d.ts → permission-policy-CU6sqWxF.d.ts} +2 -2
  39. package/dist/{plan-templates-DYCeRCDN.d.ts → plan-templates-CLRcurWN.d.ts} +4 -4
  40. package/dist/{provider-runner-Dlv8Fvw9.d.ts → provider-runner-BikCxGCx.d.ts} +3 -3
  41. package/dist/{retry-policy-KF18W4dg.d.ts → retry-policy-Chtlvr5b.d.ts} +1 -1
  42. package/dist/sdd/index.d.ts +8 -8
  43. package/dist/sdd/index.js.map +1 -1
  44. package/dist/security/index.d.ts +3 -3
  45. package/dist/{selector-DmXxpFyM.d.ts → selector-BvSPdJj6.d.ts} +1 -1
  46. package/dist/{session-reader-bfgsy2a0.d.ts → session-reader-BGhzMir4.d.ts} +1 -1
  47. package/dist/storage/index.d.ts +6 -6
  48. package/dist/storage/index.js +57 -37
  49. package/dist/storage/index.js.map +1 -1
  50. package/dist/{system-prompt-CM6zOhd2.d.ts → system-prompt-dtzV_mLm.d.ts} +1 -1
  51. package/dist/{tool-executor-BpK-SWtJ.d.ts → tool-executor-CgU0yWpB.d.ts} +4 -4
  52. package/dist/types/index.d.ts +15 -15
  53. package/dist/types/index.js +36 -18
  54. package/dist/types/index.js.map +1 -1
  55. package/dist/utils/index.d.ts +14 -2
  56. package/dist/utils/index.js +18 -1
  57. package/dist/utils/index.js.map +1 -1
  58. package/package.json +1 -1
@@ -1,10 +1,10 @@
1
1
  export { D as DefaultSecretScrubber, a as DefaultSecretVault, S as SecretVaultOptions, d as decryptConfigSecrets, e as encryptConfigSecrets, m as migratePlaintextSecrets, r as rewriteConfigEncrypted } from '../secret-scrubber-7rSC_emZ.js';
2
- export { A as AutoApprovePermissionPolicy, D as DefaultPermissionPolicy, P as PermissionPolicyOptions } from '../permission-policy-CtNscWOA.js';
2
+ export { A as AutoApprovePermissionPolicy, D as DefaultPermissionPolicy, P as PermissionPolicyOptions } from '../permission-policy-CU6sqWxF.js';
3
3
  import '../secret-vault-DoISxaKO.js';
4
4
  import '../secret-scrubber-3MHDDAtm.js';
5
- import '../context-7u93AcGD.js';
5
+ import '../context-DtPKqKYV.js';
6
6
  import '../input-reader-E-ffP2ee.js';
7
- import '../permission-B6sldrSp.js';
7
+ import '../permission-Drm7LpPo.js';
8
8
 
9
9
  declare function isSecretField(name: string): boolean;
10
10
 
@@ -1,4 +1,4 @@
1
- import { M as Message } from './context-7u93AcGD.js';
1
+ import { M as Message } from './context-DtPKqKYV.js';
2
2
 
3
3
  /**
4
4
  * Result of LLM-driven message importance analysis.
@@ -1,4 +1,4 @@
1
- import { c as ContentBlock, w as SessionEvent, x as SessionMetadata, y as SessionStore } from './context-7u93AcGD.js';
1
+ import { c as ContentBlock, w as SessionEvent, x as SessionMetadata, y as SessionStore } from './context-DtPKqKYV.js';
2
2
 
3
3
  type AttachmentKind = 'text' | 'image' | 'file';
4
4
  interface AttachmentMeta {
@@ -1,12 +1,12 @@
1
- export { A as AbandonedSession, a as AttachmentStoreOptions, C as ConfigLoaderOptions, b as ConfigMigration, c as ConfigMigrationError, d as ConfigSource, D as DEFAULT_CONFIG_MIGRATIONS, e as DefaultAttachmentStore, f as DefaultConfigLoader, g as DefaultConfigStore, h as DefaultMemoryStore, i as DefaultSessionStore, M as MemoryStoreOptions, j as MigrationContext, k as MigrationResult, P as PersistedQueueItem, l as PlanFile, m as PlanItem, n as PlanTemplate, Q as QueueStore, R as RecoveryLock, o as RecoveryLockOptions, S as SessionAnalyzer, p as SessionStoreOptions, T as TodosCheckpointFile, q as addPlanItem, r as attachPlanCheckpoint, s as attachTodosCheckpoint, t as clearPlan, u as deriveTodosFromPlanItem, v as emptyPlan, w as formatPlan, x as formatPlanTemplates, y as getPlanTemplate, z as listPlanTemplates, B as loadPlan, E as loadTodosCheckpoint, F as removePlanItem, G as runConfigMigrations, H as savePlan, I as saveTodosCheckpoint, J as setPlanItemStatus } from '../plan-templates-DYCeRCDN.js';
2
- export { D as DefaultSessionReader, f as DefaultSessionReaderOptions, S as SessionReader } from '../session-reader-bfgsy2a0.js';
3
- import { p as Request, q as Response, w as SessionEvent } from '../context-7u93AcGD.js';
1
+ export { A as AbandonedSession, a as AttachmentStoreOptions, C as ConfigLoaderOptions, b as ConfigMigration, c as ConfigMigrationError, d as ConfigSource, D as DEFAULT_CONFIG_MIGRATIONS, e as DefaultAttachmentStore, f as DefaultConfigLoader, g as DefaultConfigStore, h as DefaultMemoryStore, i as DefaultSessionStore, M as MemoryStoreOptions, j as MigrationContext, k as MigrationResult, P as PersistedQueueItem, l as PlanFile, m as PlanItem, n as PlanTemplate, Q as QueueStore, R as RecoveryLock, o as RecoveryLockOptions, S as SessionAnalyzer, p as SessionStoreOptions, T as TodosCheckpointFile, q as addPlanItem, r as attachPlanCheckpoint, s as attachTodosCheckpoint, t as clearPlan, u as deriveTodosFromPlanItem, v as emptyPlan, w as formatPlan, x as formatPlanTemplates, y as getPlanTemplate, z as listPlanTemplates, B as loadPlan, E as loadTodosCheckpoint, F as removePlanItem, G as runConfigMigrations, H as savePlan, I as saveTodosCheckpoint, J as setPlanItemStatus } from '../plan-templates-CLRcurWN.js';
2
+ export { D as DefaultSessionReader, f as DefaultSessionReaderOptions, S as SessionReader } from '../session-reader-BGhzMir4.js';
3
+ import { p as Request, q as Response, w as SessionEvent } from '../context-DtPKqKYV.js';
4
4
  import { S as SessionRewinder, C as CheckpointInfo, a as RewindResultExtended } from '../session-rewinder-C9HnMkhP.js';
5
5
  export { D as DirectorStateCheckpoint, a as DirectorStateSnapshot, b as DirectorSubagentState, c as DirectorTaskState, l as loadDirectorState } from '../director-state-BmYi3DGA.js';
6
- export { A as AuditLevel, C as CORE_RECONSTRUCT_EVENTS, G as GoalFile, J as JournalEntry, M as MAX_JOURNAL_ENTRIES, S as STANDARD_AUDIT_EVENTS, a as SessionEventBridge, b as SessionEventBridgeOptions, c as SessionSamplingOptions, T as ToolProgressSamplingOptions, d as appendJournal, e as createSessionEventBridge, f as emptyGoal, g as formatGoal, h as goalFilePath, l as loadGoal, r as resolveAuditLevel, i as resolveSessionLoggingConfig, s as saveGoal, j as summarizeUsage } from '../goal-store-BeRsj7YX.js';
6
+ export { A as AuditLevel, C as CORE_RECONSTRUCT_EVENTS, G as GoalFile, J as JournalEntry, M as MAX_JOURNAL_ENTRIES, S as STANDARD_AUDIT_EVENTS, a as SessionEventBridge, b as SessionEventBridgeOptions, c as SessionSamplingOptions, T as ToolProgressSamplingOptions, d as appendJournal, e as createSessionEventBridge, f as emptyGoal, g as formatGoal, h as goalFilePath, l as loadGoal, r as resolveAuditLevel, i as resolveSessionLoggingConfig, s as saveGoal, j as summarizeUsage } from '../goal-store-DwcTDDiX.js';
7
7
  import { a as WstackPaths } from '../wstack-paths-eMXnY1_X.js';
8
- import { n as SyncCategory, o as SyncConfig } from '../config-ZRCf7sTu.js';
9
- import '../events-BrQiweXN.js';
8
+ import { o as SyncCategory, p as SyncConfig } from '../config-bht0txXS.js';
9
+ import '../events-CbHTS4ZZ.js';
10
10
  import '../secret-scrubber-3MHDDAtm.js';
11
11
  import '../memory-CEXuo7sz.js';
12
12
  import '../secret-vault-DoISxaKO.js';
@@ -1,6 +1,6 @@
1
1
  import { randomBytes, randomUUID, createHash } from 'crypto';
2
2
  import * as fsp from 'fs/promises';
3
- import * as path11 from 'path';
3
+ import * as path14 from 'path';
4
4
  import * as os from 'os';
5
5
 
6
6
  var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
@@ -10,9 +10,9 @@ var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require
10
10
  throw Error('Dynamic require of "' + x + '" is not supported');
11
11
  });
12
12
  async function atomicWrite(targetPath, content, opts = {}) {
13
- const dir = path11.dirname(targetPath);
13
+ const dir = path14.dirname(targetPath);
14
14
  await fsp.mkdir(dir, { recursive: true });
15
- const tmp = path11.join(dir, `.${path11.basename(targetPath)}.${randomBytes(6).toString("hex")}.tmp`);
15
+ const tmp = path14.join(dir, `.${path14.basename(targetPath)}.${randomBytes(6).toString("hex")}.tmp`);
16
16
  try {
17
17
  if (typeof content === "string") {
18
18
  await fsp.writeFile(tmp, content, { flag: "wx", encoding: opts.encoding ?? "utf8" });
@@ -68,7 +68,7 @@ async function renameWithRetry(from, to) {
68
68
  if (!code || !TRANSIENT_RENAME_CODES.has(code) || i === delays.length) {
69
69
  throw err;
70
70
  }
71
- await new Promise((resolve3) => setTimeout(resolve3, delays[i]));
71
+ await new Promise((resolve4) => setTimeout(resolve4, delays[i]));
72
72
  }
73
73
  }
74
74
  throw lastErr;
@@ -178,7 +178,7 @@ var DefaultSessionStore = class {
178
178
  }
179
179
  /** Join session ID to its absolute path within the store directory. */
180
180
  sessionPath(id, ext) {
181
- return path11.join(this.dir, `${id}${ext}`);
181
+ return path14.join(this.dir, `${id}${ext}`);
182
182
  }
183
183
  async ensureShardDir(_id) {
184
184
  await ensureDir(this.dir);
@@ -188,7 +188,7 @@ var DefaultSessionStore = class {
188
188
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
189
189
  const id = meta.id ?? `${startedAt.replace(/[:.]/g, "-")}-${randomBytes(2).toString("hex")}`;
190
190
  const shardDir = await this.ensureShardDir(id);
191
- const file = path11.join(shardDir, `${id}.jsonl`);
191
+ const file = path14.join(shardDir, `${id}.jsonl`);
192
192
  let handle;
193
193
  try {
194
194
  handle = await fsp.open(file, "a", 384);
@@ -281,7 +281,7 @@ var DefaultSessionStore = class {
281
281
  const ids = [];
282
282
  const entries = await fsp.readdir(dir, { withFileTypes: true });
283
283
  for (const entry of entries) {
284
- const full = path11.join(dir, entry.name);
284
+ const full = path14.join(dir, entry.name);
285
285
  if (entry.isDirectory()) {
286
286
  ids.push(...await this.collectSessionIds(full));
287
287
  } else if (entry.isFile() && entry.name.endsWith(".jsonl")) {
@@ -437,7 +437,7 @@ var FileSessionWriter = class {
437
437
  this.meta = meta;
438
438
  this.events = events;
439
439
  this.resumed = opts.resumed ?? false;
440
- this.manifestFile = opts.dir ? path11.join(opts.dir, `${id}.summary.json`) : "";
440
+ this.manifestFile = opts.dir ? path14.join(opts.dir, `${id}.summary.json`) : "";
441
441
  this.filePath = opts.filePath ?? "";
442
442
  this.secretScrubber = opts.secretScrubber;
443
443
  this.summary = {
@@ -716,7 +716,7 @@ function userInputTitle(content) {
716
716
  var QueueStore = class {
717
717
  file;
718
718
  constructor(opts) {
719
- this.file = path11.join(opts.dir, "queue.json");
719
+ this.file = path14.join(opts.dir, "queue.json");
720
720
  }
721
721
  async write(items) {
722
722
  if (items.length === 0) {
@@ -783,7 +783,7 @@ var DefaultAttachmentStore = class {
783
783
  let data = input.data;
784
784
  if (this.spoolDir && bytes >= this.spoolThreshold) {
785
785
  await fsp.mkdir(this.spoolDir, { recursive: true });
786
- spooledPath = path11.join(this.spoolDir, `${id}.bin`);
786
+ spooledPath = path14.join(this.spoolDir, `${id}.bin`);
787
787
  await atomicWrite(spooledPath, input.data, {
788
788
  encoding: input.kind === "image" ? "base64" : "utf8"
789
789
  });
@@ -968,7 +968,7 @@ ${body.trim()}`);
968
968
  async remember(text, scope = "project-memory") {
969
969
  return this.runSerialized(scope, async () => {
970
970
  const file = this.files[scope];
971
- await ensureDir(path11.dirname(file));
971
+ await ensureDir(path14.dirname(file));
972
972
  let existing = "";
973
973
  try {
974
974
  existing = await fsp.readFile(file, "utf8");
@@ -1583,7 +1583,7 @@ var RecoveryLock = class {
1583
1583
  sessionStore;
1584
1584
  probe;
1585
1585
  constructor(opts) {
1586
- this.file = path11.join(opts.dir, LOCK_FILE);
1586
+ this.file = path14.join(opts.dir, LOCK_FILE);
1587
1587
  this.pid = opts.pid ?? process.pid;
1588
1588
  this.hostname = opts.hostname ?? os.hostname();
1589
1589
  this.maxAgeMs = opts.maxAgeMs ?? DEFAULT_MAX_AGE_MS;
@@ -1641,7 +1641,7 @@ var RecoveryLock = class {
1641
1641
  * null return before calling this.
1642
1642
  */
1643
1643
  async write(sessionId) {
1644
- await ensureDir(path11.dirname(this.file));
1644
+ await ensureDir(path14.dirname(this.file));
1645
1645
  const lock = {
1646
1646
  v: 1,
1647
1647
  sessionId,
@@ -2126,7 +2126,7 @@ var AnnotationsStore = class {
2126
2126
  if (!sessionId || sessionId.includes("/") || sessionId.includes("\\") || sessionId.includes("..")) {
2127
2127
  throw new Error(`Invalid sessionId: ${sessionId}`);
2128
2128
  }
2129
- return path11.join(this.dir, `${sessionId}.annotations.json`);
2129
+ return path14.join(this.dir, `${sessionId}.annotations.json`);
2130
2130
  }
2131
2131
  async readFile(sessionId) {
2132
2132
  const fp = this.filePath(sessionId);
@@ -2283,7 +2283,7 @@ var ReplayLogStore = class {
2283
2283
  out.push({
2284
2284
  sessionId,
2285
2285
  entryCount: all.length,
2286
- path: path11.join(this.dir, name)
2286
+ path: path14.join(this.dir, name)
2287
2287
  });
2288
2288
  }
2289
2289
  return out.sort((a, b) => a.sessionId.localeCompare(b.sessionId));
@@ -2293,7 +2293,7 @@ var ReplayLogStore = class {
2293
2293
  if (!sessionId || sessionId.includes("/") || sessionId.includes("\\") || sessionId.includes("..")) {
2294
2294
  throw new Error(`Invalid sessionId: ${sessionId}`);
2295
2295
  }
2296
- return path11.join(this.dir, `${sessionId}.replay.jsonl`);
2296
+ return path14.join(this.dir, `${sessionId}.replay.jsonl`);
2297
2297
  }
2298
2298
  async readAll(sessionId) {
2299
2299
  const fp = this.filePath(sessionId);
@@ -2482,7 +2482,7 @@ var SessionRecovery = class {
2482
2482
  if (!sessionId || sessionId.includes("/") || sessionId.includes("\\") || sessionId.includes("..")) {
2483
2483
  throw new Error(`Invalid sessionId: ${sessionId}`);
2484
2484
  }
2485
- return path11.join(this.dir, `${sessionId}.jsonl`);
2485
+ return path14.join(this.dir, `${sessionId}.jsonl`);
2486
2486
  }
2487
2487
  };
2488
2488
  var GENESIS_PREV = "0".repeat(64);
@@ -2600,7 +2600,7 @@ var ToolAuditLog = class {
2600
2600
  if (!sessionId || sessionId.includes("/") || sessionId.includes("\\") || sessionId.includes("..")) {
2601
2601
  throw new Error(`Invalid sessionId: ${sessionId}`);
2602
2602
  }
2603
- return path11.join(this.dir, `${sessionId}.audit.jsonl`);
2603
+ return path14.join(this.dir, `${sessionId}.audit.jsonl`);
2604
2604
  }
2605
2605
  async readAll(sessionId) {
2606
2606
  const fp = this.filePath(sessionId);
@@ -2781,7 +2781,7 @@ var DefaultSessionRewinder = class {
2781
2781
  sessionsDir;
2782
2782
  projectRoot;
2783
2783
  async listCheckpoints(sessionId) {
2784
- const file = path11.join(this.sessionsDir, `${sessionId}.jsonl`);
2784
+ const file = path14.join(this.sessionsDir, `${sessionId}.jsonl`);
2785
2785
  const raw = await fsp.readFile(file, "utf8");
2786
2786
  const events = parseEvents(raw);
2787
2787
  const fileCountMap = /* @__PURE__ */ new Map();
@@ -2806,7 +2806,7 @@ var DefaultSessionRewinder = class {
2806
2806
  return checkpoints;
2807
2807
  }
2808
2808
  async rewindToCheckpoint(sessionId, checkpointIndex) {
2809
- const file = path11.join(this.sessionsDir, `${sessionId}.jsonl`);
2809
+ const file = path14.join(this.sessionsDir, `${sessionId}.jsonl`);
2810
2810
  const raw = await fsp.readFile(file, "utf8");
2811
2811
  const events = parseEvents(raw);
2812
2812
  let targetIdx = -1;
@@ -2841,7 +2841,7 @@ var DefaultSessionRewinder = class {
2841
2841
  return { ...result, toPromptIndex: checkpointIndex, removedEvents };
2842
2842
  }
2843
2843
  async rewindLastN(sessionId, n) {
2844
- const file = path11.join(this.sessionsDir, `${sessionId}.jsonl`);
2844
+ const file = path14.join(this.sessionsDir, `${sessionId}.jsonl`);
2845
2845
  const raw = await fsp.readFile(file, "utf8");
2846
2846
  const events = parseEvents(raw);
2847
2847
  const checkpoints = [];
@@ -2870,7 +2870,7 @@ var DefaultSessionRewinder = class {
2870
2870
  return { ...result, toPromptIndex: targetIndex, removedEvents: snapshotsToRevert.length };
2871
2871
  }
2872
2872
  async rewindToStart(sessionId) {
2873
- const file = path11.join(this.sessionsDir, `${sessionId}.jsonl`);
2873
+ const file = path14.join(this.sessionsDir, `${sessionId}.jsonl`);
2874
2874
  const raw = await fsp.readFile(file, "utf8");
2875
2875
  const events = parseEvents(raw);
2876
2876
  const allSnapshots = [];
@@ -2906,10 +2906,10 @@ async function revertSnapshots(snapshots, projectRoot) {
2906
2906
  for (const snapshot of snapshots) {
2907
2907
  for (const file of snapshot.files) {
2908
2908
  try {
2909
- const absPath = path11.resolve(file.path);
2910
- const root = path11.resolve(projectRoot);
2911
- const rel = path11.relative(root, absPath);
2912
- if (rel.startsWith("..") || path11.isAbsolute(rel)) {
2909
+ const absPath = path14.resolve(file.path);
2910
+ const root = path14.resolve(projectRoot);
2911
+ const rel = path14.relative(root, absPath);
2912
+ if (rel.startsWith("..") || path14.isAbsolute(rel)) {
2913
2913
  errors.push(`${file.path}: path resolves outside project root \u2014 skipping`);
2914
2914
  continue;
2915
2915
  }
@@ -3468,8 +3468,8 @@ var FsError = class extends WrongStackError {
3468
3468
  // src/storage/goal-store.ts
3469
3469
  var MAX_JOURNAL_ENTRIES = 500;
3470
3470
  function goalFilePath(projectRoot) {
3471
- const hash = createHash("sha256").update(path11.resolve(projectRoot)).digest("hex").slice(0, 12);
3472
- return path11.join(os.homedir(), ".wrongstack", "projects", hash, "goal.json");
3471
+ const hash = createHash("sha256").update(path14.resolve(projectRoot)).digest("hex").slice(0, 12);
3472
+ return path14.join(os.homedir(), ".wrongstack", "projects", hash, "goal.json");
3473
3473
  }
3474
3474
  async function loadGoal(filePath) {
3475
3475
  let raw;
@@ -3584,7 +3584,7 @@ var DefaultPromptStore = class {
3584
3584
  if (!file.endsWith(".json")) continue;
3585
3585
  try {
3586
3586
  const raw = JSON.parse(
3587
- await fsp.readFile(path11.join(this.dir, file), "utf8")
3587
+ await fsp.readFile(path14.join(this.dir, file), "utf8")
3588
3588
  );
3589
3589
  entries.push(raw.entry);
3590
3590
  } catch {
@@ -3597,7 +3597,7 @@ var DefaultPromptStore = class {
3597
3597
  );
3598
3598
  }
3599
3599
  async get(id) {
3600
- const file = path11.join(this.dir, `${id}.json`);
3600
+ const file = path14.join(this.dir, `${id}.json`);
3601
3601
  try {
3602
3602
  const raw = JSON.parse(await fsp.readFile(file, "utf8"));
3603
3603
  return raw.entry;
@@ -3607,12 +3607,12 @@ var DefaultPromptStore = class {
3607
3607
  }
3608
3608
  async save(entry) {
3609
3609
  await ensureDir(this.dir);
3610
- const file = path11.join(this.dir, `${entry.id}.json`);
3610
+ const file = path14.join(this.dir, `${entry.id}.json`);
3611
3611
  const raw = { version: 1, entry };
3612
3612
  await atomicWrite(file, JSON.stringify(raw, null, 2));
3613
3613
  }
3614
3614
  async delete(id) {
3615
- const file = path11.join(this.dir, `${id}.json`);
3615
+ const file = path14.join(this.dir, `${id}.json`);
3616
3616
  try {
3617
3617
  await fsp.unlink(file);
3618
3618
  return true;
@@ -3646,7 +3646,7 @@ var CloudSync = class {
3646
3646
  this.paths = paths;
3647
3647
  this.getConfig = getConfig;
3648
3648
  this.setConfig = setConfig;
3649
- this.statePath = path11.join(paths.globalRoot, "sync-state.json");
3649
+ this.statePath = path14.join(paths.globalRoot, "sync-state.json");
3650
3650
  }
3651
3651
  paths;
3652
3652
  getConfig;
@@ -3751,9 +3751,9 @@ var CloudSync = class {
3751
3751
  const localPath = this.categoryToPath(cat);
3752
3752
  if (!localPath) continue;
3753
3753
  const rel = segments.slice(2).join("/");
3754
- const destPath = rel ? path11.join(localPath, rel) : localPath;
3754
+ const destPath = resolvePulledCategoryPath(cat, localPath, rel, entry.path);
3755
3755
  const blobData = await this.getBlob(token, owner, repoName, entry.sha);
3756
- await fsp.mkdir(path11.dirname(destPath), { recursive: true });
3756
+ await fsp.mkdir(path14.dirname(destPath), { recursive: true });
3757
3757
  await fsp.writeFile(destPath, Buffer.from(blobData, "base64"));
3758
3758
  }
3759
3759
  const localRev = await this.hashLocalCategories(cfg.categories);
@@ -3858,7 +3858,7 @@ var CloudSync = class {
3858
3858
  const files = await this.walkDir(localPath, localPath);
3859
3859
  for (const file of files) {
3860
3860
  const content = await fsp.readFile(file, "utf8");
3861
- const rel = path11.relative(localPath, file).replace(/\\/g, "/");
3861
+ const rel = path14.relative(localPath, file).replace(/\\/g, "/");
3862
3862
  entries.push({ path: `data/${cat}/${rel}`, content, mode: "100644" });
3863
3863
  hashes.push(content);
3864
3864
  }
@@ -3915,7 +3915,7 @@ var CloudSync = class {
3915
3915
  const results = [];
3916
3916
  const entries = await fsp.readdir(dir, { withFileTypes: true });
3917
3917
  for (const entry of entries) {
3918
- const full = path11.join(dir, entry.name);
3918
+ const full = path14.join(dir, entry.name);
3919
3919
  if (entry.isDirectory()) {
3920
3920
  results.push(...await this.walkDir(full, base));
3921
3921
  } else {
@@ -3925,6 +3925,26 @@ var CloudSync = class {
3925
3925
  return results;
3926
3926
  }
3927
3927
  };
3928
+ function resolvePulledCategoryPath(cat, localPath, rel, remotePath) {
3929
+ const directoryBacked = cat === "skills" || cat === "prompts";
3930
+ if (!directoryBacked) {
3931
+ if (rel) throw new Error(`Refusing nested CloudSync path for file category: ${remotePath}`);
3932
+ return localPath;
3933
+ }
3934
+ if (!rel) return localPath;
3935
+ const normalizedRel = path14.normalize(rel);
3936
+ const traversesUp = normalizedRel === ".." || normalizedRel.startsWith(`..${path14.sep}`);
3937
+ if (path14.isAbsolute(normalizedRel) || traversesUp) {
3938
+ throw new Error(`Refusing CloudSync path traversal: ${remotePath}`);
3939
+ }
3940
+ const dest = path14.resolve(localPath, normalizedRel);
3941
+ const root = path14.resolve(localPath);
3942
+ const relative3 = path14.relative(root, dest);
3943
+ if (relative3.startsWith("..") || path14.isAbsolute(relative3)) {
3944
+ throw new Error(`Refusing CloudSync path outside category root: ${remotePath}`);
3945
+ }
3946
+ return dest;
3947
+ }
3928
3948
  function timeAgo(iso) {
3929
3949
  const diff = Date.now() - new Date(iso).getTime();
3930
3950
  const mins = Math.floor(diff / 6e4);