@wrongstack/core 0.107.2 → 0.119.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 (63) hide show
  1. package/dist/{agent-bridge-mOxbpFcg.d.ts → agent-bridge-PRAbEX-9.d.ts} +1 -1
  2. package/dist/{agent-subagent-runner-DukQLUcS.d.ts → agent-subagent-runner-DXWImnNV.d.ts} +7 -8
  3. package/dist/{brain-Dfv4Y82E.d.ts → brain-NZZqL8sn.d.ts} +1 -1
  4. package/dist/{compactor-DXLxLcmU.d.ts → compactor-C3stu664.d.ts} +1 -1
  5. package/dist/{config-BSU-6vah.d.ts → config-DZV9VK9n.d.ts} +104 -3
  6. package/dist/{context-CNRYfhUv.d.ts → context-hvXINa6a.d.ts} +31 -1
  7. package/dist/coordination/index.d.ts +12 -13
  8. package/dist/coordination/index.js +198 -0
  9. package/dist/coordination/index.js.map +1 -1
  10. package/dist/defaults/index.d.ts +27 -28
  11. package/dist/defaults/index.js +346 -86
  12. package/dist/defaults/index.js.map +1 -1
  13. package/dist/execution/index.d.ts +16 -17
  14. package/dist/execution/index.js +266 -12
  15. package/dist/execution/index.js.map +1 -1
  16. package/dist/extension/index.d.ts +6 -7
  17. package/dist/{goal-preamble-CI8lxeY1.d.ts → goal-preamble-COpt55W8.d.ts} +10 -10
  18. package/dist/{goal-store-ht0VmR1A.d.ts → goal-store-CV9Yz2X_.d.ts} +11 -0
  19. package/dist/{index-DIKEcfgC.d.ts → index-4VVHuTZF.d.ts} +7 -6
  20. package/dist/{index-BWRN6wOb.d.ts → index-Cj3le7TI.d.ts} +9 -10
  21. package/dist/index.d.ts +41 -42
  22. package/dist/index.js +372 -118
  23. package/dist/index.js.map +1 -1
  24. package/dist/infrastructure/index.d.ts +6 -7
  25. package/dist/kernel/index.d.ts +10 -11
  26. package/dist/llm-selector-Bmx4PsVM.d.ts +58 -0
  27. package/dist/{mcp-servers-CXCsANdY.d.ts → mcp-servers-CofNHOqn.d.ts} +3 -3
  28. package/dist/{mode-ARA3HrkY.d.ts → mode-CZlO9iU1.d.ts} +1 -1
  29. package/dist/models/index.d.ts +157 -53
  30. package/dist/models/index.js +423 -1
  31. package/dist/models/index.js.map +1 -1
  32. package/dist/{models-registry-DU64QxQa.d.ts → models-registry-BzlsjKcy.d.ts} +1 -1
  33. package/dist/{multi-agent-coordinator-51LvnXkD.d.ts → multi-agent-coordinator-CmDmUgq2.d.ts} +1 -1
  34. package/dist/{null-fleet-bus-D09hMzFQ.d.ts → null-fleet-bus-CyH2YqP4.d.ts} +6 -6
  35. package/dist/observability/index.d.ts +2 -2
  36. package/dist/{parallel-eternal-engine-CUtmM_0V.d.ts → parallel-eternal-engine-uxVm4y4V.d.ts} +11 -10
  37. package/dist/{path-resolver-DDJiMAtX.d.ts → path-resolver-gfoGxpdd.d.ts} +3 -3
  38. package/dist/{permission-BDv7z0mk.d.ts → permission-DhLrgA30.d.ts} +1 -1
  39. package/dist/{permission-policy-dF74EpDp.d.ts → permission-policy-DGOvne7i.d.ts} +2 -2
  40. package/dist/{pipeline-BqiA_UMr.d.ts → pipeline-CqF7uju2.d.ts} +2 -2
  41. package/dist/{plan-templates-BdDxl9cI.d.ts → plan-templates-DoKhzenv.d.ts} +6 -6
  42. package/dist/{provider-runner-BUunikwY.d.ts → provider-runner-BPlI5sPZ.d.ts} +3 -3
  43. package/dist/{retry-policy-BcmuT_V0.d.ts → retry-policy-B4Q-FZgE.d.ts} +1 -1
  44. package/dist/sdd/index.d.ts +8 -9
  45. package/dist/sdd/index.js +198 -0
  46. package/dist/sdd/index.js.map +1 -1
  47. package/dist/{secret-vault-DrOhc2i5.d.ts → secret-vault-B7GnL6o9.d.ts} +1 -1
  48. package/dist/security/index.d.ts +4 -4
  49. package/dist/{selector-C7wcdqMA.d.ts → selector-BakeMnWR.d.ts} +1 -1
  50. package/dist/{session-event-bridge-BpJ5trO9.d.ts → session-event-bridge-DE5Oekwx.d.ts} +1 -1
  51. package/dist/{session-reader-DDz1Ek4V.d.ts → session-reader-DFC81-4p.d.ts} +1 -1
  52. package/dist/storage/index.d.ts +12 -13
  53. package/dist/storage/index.js +147 -88
  54. package/dist/storage/index.js.map +1 -1
  55. package/dist/types/index.d.ts +20 -21
  56. package/dist/types/index.js +35 -1
  57. package/dist/types/index.js.map +1 -1
  58. package/dist/utils/index.d.ts +3 -4
  59. package/dist/utils/index.js +2 -1
  60. package/dist/utils/index.js.map +1 -1
  61. package/dist/{wstack-paths-_lqjzErq.d.ts → wstack-paths-DD50Omgn.d.ts} +3 -0
  62. package/package.json +1 -1
  63. package/dist/models-registry-B6_KfS65.d.ts +0 -95
@@ -1,4 +1,4 @@
1
- import { S as SecretScrubber } from './permission-BDv7z0mk.js';
1
+ import { S as SecretScrubber } from './permission-DhLrgA30.js';
2
2
  import { S as SecretVault } from './secret-vault-DoISxaKO.js';
3
3
 
4
4
  declare class DefaultSecretScrubber implements SecretScrubber {
@@ -1,7 +1,7 @@
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-vault-DrOhc2i5.js';
2
- export { A as AutoApprovePermissionPolicy, D as DefaultPermissionPolicy, P as PermissionPolicyOptions } from '../permission-policy-dF74EpDp.js';
3
- import '../permission-BDv7z0mk.js';
4
- import '../context-CNRYfhUv.js';
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-vault-B7GnL6o9.js';
2
+ export { A as AutoApprovePermissionPolicy, D as DefaultPermissionPolicy, P as PermissionPolicyOptions } from '../permission-policy-DGOvne7i.js';
3
+ import '../permission-DhLrgA30.js';
4
+ import '../context-hvXINa6a.js';
5
5
  import '../secret-vault-DoISxaKO.js';
6
6
  import '../input-reader-E-ffP2ee.js';
7
7
 
@@ -1,4 +1,4 @@
1
- import { M as Message } from './context-CNRYfhUv.js';
1
+ import { M as Message } from './context-hvXINa6a.js';
2
2
 
3
3
  /**
4
4
  * Result of LLM-driven message importance analysis.
@@ -1,4 +1,4 @@
1
- import { S as SessionEvent, a as SessionWriter } from './context-CNRYfhUv.js';
1
+ import { S as SessionEvent, a as SessionWriter } from './context-hvXINa6a.js';
2
2
 
3
3
  type AuditLevel = 'minimal' | 'standard' | 'full';
4
4
  /**
@@ -1,4 +1,4 @@
1
- import { g as ContentBlock, S as SessionEvent, h as SessionMetadata, i as SessionStore } from './context-CNRYfhUv.js';
1
+ import { g as ContentBlock, S as SessionEvent, h as SessionMetadata, i as SessionStore } from './context-hvXINa6a.js';
2
2
 
3
3
  type AttachmentKind = 'text' | 'image' | 'file';
4
4
  interface AttachmentMeta {
@@ -1,22 +1,21 @@
1
- import { M as MemoryBackend, j as FileMemoryBackendOptions } from '../plan-templates-BdDxl9cI.js';
2
- 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, F as FileMemoryBackend, k as MemoryStoreOptions, l as MigrationContext, m as MigrationResult, P as PersistedQueueItem, n as PlanFile, o as PlanItem, p as PlanTemplate, Q as QueueStore, R as RecoveryLock, q as RecoveryLockOptions, S as SessionAnalyzer, r as SessionStoreOptions, T as TodosCheckpointFile, s as addPlanItem, t as attachPlanCheckpoint, u as attachTodosCheckpoint, v as clearPlan, w as deriveTodosFromPlanItem, x as emptyPlan, y as formatPlan, z as formatPlanTemplates, B as getPlanTemplate, E as listPlanTemplates, G as loadPlan, H as loadTodosCheckpoint, I as parseEntries, J as removePlanItem, K as runConfigMigrations, L as savePlan, N as saveTodosCheckpoint, O as setPlanItemStatus } from '../plan-templates-BdDxl9cI.js';
3
- import { M as MemoryScope, k as MemoryEntry, l as MemoryStore } from '../brain-Dfv4Y82E.js';
4
- import { l as AgentExtension, j as AfterRunHook } from '../index-DIKEcfgC.js';
5
- import { P as Provider, R as Request, b as Response, S as SessionEvent } from '../context-CNRYfhUv.js';
6
- export { D as DefaultSessionReader, f as DefaultSessionReaderOptions, S as SessionReader } from '../session-reader-DDz1Ek4V.js';
1
+ import { M as MemoryBackend, j as FileMemoryBackendOptions } from '../plan-templates-DoKhzenv.js';
2
+ 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, F as FileMemoryBackend, k as MemoryStoreOptions, l as MigrationContext, m as MigrationResult, P as PersistedQueueItem, n as PlanFile, o as PlanItem, p as PlanTemplate, Q as QueueStore, R as RecoveryLock, q as RecoveryLockOptions, S as SessionAnalyzer, r as SessionStoreOptions, T as TodosCheckpointFile, s as addPlanItem, t as attachPlanCheckpoint, u as attachTodosCheckpoint, v as clearPlan, w as deriveTodosFromPlanItem, x as emptyPlan, y as formatPlan, z as formatPlanTemplates, B as getPlanTemplate, E as listPlanTemplates, G as loadPlan, H as loadTodosCheckpoint, I as parseEntries, J as removePlanItem, K as runConfigMigrations, L as savePlan, N as saveTodosCheckpoint, O as setPlanItemStatus } from '../plan-templates-DoKhzenv.js';
3
+ import { M as MemoryScope, k as MemoryEntry, l as MemoryStore } from '../brain-NZZqL8sn.js';
4
+ import { l as AgentExtension, j as AfterRunHook } from '../index-4VVHuTZF.js';
5
+ import { P as Provider, R as Request, b as Response, S as SessionEvent } from '../context-hvXINa6a.js';
6
+ export { D as DefaultSessionReader, f as DefaultSessionReaderOptions, S as SessionReader } from '../session-reader-DFC81-4p.js';
7
7
  import { S as SessionRewinder, C as CheckpointInfo, a as RewindResultExtended } from '../session-rewinder-C9HnMkhP.js';
8
8
  import { T as TaskItem } from '../task-format-vGOIftmK.js';
9
9
  export { a as DirectorStateCheckpoint, D as DirectorStateSnapshot, b as DirectorSubagentState, c as DirectorTaskState, l as loadDirectorState } from '../director-state-BfeCUbmk.js';
10
- export { G as GoalFile, J as JournalEntry, M as MAX_JOURNAL_ENTRIES, a as MAX_PROGRESS_HISTORY, P as ProgressSnapshot, b as appendJournal, e as emptyGoal, f as formatGoal, g as goalFilePath, l as loadGoal, p as parseProgressFromText, r as recordProgress, s as saveGoal, c as setProgress, d as summarizeUsage } from '../goal-store-ht0VmR1A.js';
11
- import { W as WstackPaths } from '../wstack-paths-_lqjzErq.js';
12
- import { w as SyncCategory, g as SyncConfig } from '../config-BSU-6vah.js';
13
- export { A as AuditLevel, C as CORE_RECONSTRUCT_EVENTS, a as STANDARD_AUDIT_EVENTS, S as SessionEventBridge, b as SessionEventBridgeOptions, c as SessionSamplingOptions, T as ToolProgressSamplingOptions, d as createSessionEventBridge, r as resolveAuditLevel, e as resolveSessionLoggingConfig } from '../session-event-bridge-BpJ5trO9.js';
14
- import '../permission-BDv7z0mk.js';
10
+ export { G as GoalFile, J as JournalEntry, M as MAX_JOURNAL_ENTRIES, a as MAX_PROGRESS_HISTORY, P as ProgressSnapshot, b as appendJournal, e as emptyGoal, f as formatGoal, g as goalFilePath, l as loadGoal, p as parseProgressFromText, r as recordProgress, s as saveGoal, c as setProgress, d as summarizeUsage } from '../goal-store-CV9Yz2X_.js';
11
+ import { W as WstackPaths } from '../wstack-paths-DD50Omgn.js';
12
+ import { B as SyncCategory, k as SyncConfig } from '../config-DZV9VK9n.js';
13
+ export { A as AuditLevel, C as CORE_RECONSTRUCT_EVENTS, a as STANDARD_AUDIT_EVENTS, S as SessionEventBridge, b as SessionEventBridgeOptions, c as SessionSamplingOptions, T as ToolProgressSamplingOptions, d as createSessionEventBridge, r as resolveAuditLevel, e as resolveSessionLoggingConfig } from '../session-event-bridge-DE5Oekwx.js';
14
+ import '../permission-DhLrgA30.js';
15
15
  import '../secret-vault-DoISxaKO.js';
16
16
  import '../logger-B63L5bTg.js';
17
- import '../pipeline-BqiA_UMr.js';
17
+ import '../pipeline-CqF7uju2.js';
18
18
  import '../observability-D-HZN_mF.js';
19
- import '../models-registry-B6_KfS65.js';
20
19
  import '../task-graph-u1q9Jkyk.js';
21
20
 
22
21
  interface GraphNode {
@@ -1,6 +1,6 @@
1
1
  import { randomBytes, randomUUID, createHash } from 'crypto';
2
2
  import * as fsp from 'fs/promises';
3
- import * as path2 from 'path';
3
+ import * as path12 from 'path';
4
4
  import * as os from 'os';
5
5
  import { hostname } from 'os';
6
6
 
@@ -12,9 +12,9 @@ function expectDefined(value, label) {
12
12
  return value;
13
13
  }
14
14
  async function atomicWrite(targetPath, content, opts = {}) {
15
- const dir = path2.dirname(targetPath);
15
+ const dir = path12.dirname(targetPath);
16
16
  await fsp.mkdir(dir, { recursive: true });
17
- const tmp = path2.join(dir, `.${path2.basename(targetPath)}.${randomBytes(6).toString("hex")}.tmp`);
17
+ const tmp = path12.join(dir, `.${path12.basename(targetPath)}.${randomBytes(6).toString("hex")}.tmp`);
18
18
  try {
19
19
  if (typeof content === "string") {
20
20
  await fsp.writeFile(tmp, content, { flag: "wx", encoding: opts.encoding ?? "utf8" });
@@ -53,9 +53,9 @@ async function ensureDir(dir) {
53
53
  await fsp.mkdir(dir, { recursive: true });
54
54
  }
55
55
  async function withFileLock(targetPath, fn, opts = {}) {
56
- const dir = path2.dirname(targetPath);
56
+ const dir = path12.dirname(targetPath);
57
57
  await fsp.mkdir(dir, { recursive: true });
58
- const lockPath = path2.join(dir, `.${path2.basename(targetPath)}.lock`);
58
+ const lockPath = path12.join(dir, `.${path12.basename(targetPath)}.lock`);
59
59
  const timeoutMs = opts.timeoutMs ?? 5e3;
60
60
  const staleMs = opts.staleMs ?? 3e4;
61
61
  const started = Date.now();
@@ -233,11 +233,11 @@ var DefaultSessionStore = class _DefaultSessionStore {
233
233
  }
234
234
  /** Absolute path to the session index file. */
235
235
  get indexFile() {
236
- return path2.join(this.dir, "_index.jsonl");
236
+ return path12.join(this.dir, "_index.jsonl");
237
237
  }
238
238
  /** Join session ID to its absolute path within the store directory. */
239
239
  sessionPath(id, ext) {
240
- return path2.join(this.dir, `${id}${ext}`);
240
+ return path12.join(this.dir, `${id}${ext}`);
241
241
  }
242
242
  /**
243
243
  * Ensure the directory implied by the session ID exists. When the ID
@@ -245,7 +245,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
245
245
  * subdirectory so sessions group naturally by day.
246
246
  */
247
247
  async ensureShardDir(id) {
248
- const dirPath = path2.dirname(path2.join(this.dir, id));
248
+ const dirPath = path12.dirname(path12.join(this.dir, id));
249
249
  await ensureDir(dirPath);
250
250
  return dirPath;
251
251
  }
@@ -253,7 +253,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
253
253
  const startedAt = (/* @__PURE__ */ new Date()).toISOString();
254
254
  const id = meta.id && meta.id.length > 0 ? meta.id : generateSessionId(startedAt, meta.model ?? meta.provider);
255
255
  const shardDir = await this.ensureShardDir(id);
256
- const file = path2.join(shardDir, `${path2.basename(id)}.jsonl`);
256
+ const file = path12.join(shardDir, `${path12.basename(id)}.jsonl`);
257
257
  let handle;
258
258
  try {
259
259
  handle = await fsp.open(file, "a", 384);
@@ -461,7 +461,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
461
461
  continue;
462
462
  if (entry.isDirectory()) {
463
463
  const childPrefix = depth === 0 ? entry.name : `${prefix}/${entry.name}`;
464
- ids.push(...await this.collectSessionIds(path2.join(dir, entry.name), childPrefix, depth + 1));
464
+ ids.push(...await this.collectSessionIds(path12.join(dir, entry.name), childPrefix, depth + 1));
465
465
  } else if (entry.isFile() && entry.name.endsWith(".jsonl")) {
466
466
  if (entry.name === "_index.jsonl") continue;
467
467
  const base = entry.name.replace(/\.jsonl$/, "");
@@ -495,12 +495,12 @@ var DefaultSessionStore = class _DefaultSessionStore {
495
495
  async deleteSession(id) {
496
496
  await fsp.unlink(this.sessionPath(id, ".jsonl")).catch(() => void 0);
497
497
  await fsp.unlink(this.sessionPath(id, ".summary.json")).catch(() => void 0);
498
- const shardDir = path2.dirname(path2.join(this.dir, id));
499
- const base = path2.basename(id);
498
+ const shardDir = path12.dirname(path12.join(this.dir, id));
499
+ const base = path12.basename(id);
500
500
  for (const ext of [".plan.json", ".todos.json"]) {
501
- await fsp.unlink(path2.join(shardDir, `${base}${ext}`)).catch(() => void 0);
501
+ await fsp.unlink(path12.join(shardDir, `${base}${ext}`)).catch(() => void 0);
502
502
  }
503
- const sessDir = path2.join(shardDir, base);
503
+ const sessDir = path12.join(shardDir, base);
504
504
  await fsp.rm(sessDir, { recursive: true, force: true }).catch(() => void 0);
505
505
  await this.writeTombstone(id);
506
506
  }
@@ -512,7 +512,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
512
512
  let deleted = 0;
513
513
  let activeSessionId = null;
514
514
  try {
515
- const raw = await fsp.readFile(path2.join(this.dir, "active.json"), "utf8");
515
+ const raw = await fsp.readFile(path12.join(this.dir, "active.json"), "utf8");
516
516
  const active = JSON.parse(raw);
517
517
  activeSessionId = active.sessionId ?? null;
518
518
  } catch {
@@ -520,11 +520,11 @@ var DefaultSessionStore = class _DefaultSessionStore {
520
520
  const entries = await fsp.readdir(this.dir, { withFileTypes: true }).catch(() => []);
521
521
  for (const entry of entries) {
522
522
  if (!entry.isDirectory()) continue;
523
- const dateDir = path2.join(this.dir, entry.name);
523
+ const dateDir = path12.join(this.dir, entry.name);
524
524
  const files = await fsp.readdir(dateDir, { withFileTypes: true }).catch(() => []);
525
525
  for (const file of files) {
526
526
  if (!file.isFile() || !file.name.endsWith(".jsonl")) continue;
527
- const jsonlPath = path2.join(dateDir, file.name);
527
+ const jsonlPath = path12.join(dateDir, file.name);
528
528
  try {
529
529
  const stat5 = await fsp.stat(jsonlPath);
530
530
  if (stat5.mtimeMs >= cutoff) continue;
@@ -542,7 +542,7 @@ var DefaultSessionStore = class _DefaultSessionStore {
542
542
  }
543
543
  for (const entry of entries) {
544
544
  if (!entry.isDirectory()) continue;
545
- const dateDir = path2.join(this.dir, entry.name);
545
+ const dateDir = path12.join(this.dir, entry.name);
546
546
  try {
547
547
  const remaining = await fsp.readdir(dateDir);
548
548
  if (remaining.length === 0) {
@@ -707,7 +707,7 @@ var FileSessionWriter = class {
707
707
  this.meta = meta;
708
708
  this.events = events;
709
709
  this.resumed = opts.resumed ?? false;
710
- this.manifestFile = opts.dir ? path2.join(opts.dir, `${path2.basename(id)}.summary.json`) : "";
710
+ this.manifestFile = opts.dir ? path12.join(opts.dir, `${path12.basename(id)}.summary.json`) : "";
711
711
  this.filePath = opts.filePath ?? "";
712
712
  this.secretScrubber = opts.secretScrubber;
713
713
  this.onCloseCb = opts.onClose;
@@ -1027,7 +1027,7 @@ function userInputTitle(content) {
1027
1027
  var QueueStore = class {
1028
1028
  file;
1029
1029
  constructor(opts) {
1030
- this.file = path2.join(opts.dir, "queue.json");
1030
+ this.file = path12.join(opts.dir, "queue.json");
1031
1031
  }
1032
1032
  async write(items) {
1033
1033
  if (items.length === 0) {
@@ -1094,7 +1094,7 @@ var DefaultAttachmentStore = class {
1094
1094
  let data = input.data;
1095
1095
  if (this.spoolDir && bytes >= this.spoolThreshold) {
1096
1096
  await fsp.mkdir(this.spoolDir, { recursive: true });
1097
- spooledPath = path2.join(this.spoolDir, `${id}.bin`);
1097
+ spooledPath = path12.join(this.spoolDir, `${id}.bin`);
1098
1098
  await atomicWrite(spooledPath, input.data, {
1099
1099
  encoding: input.kind === "image" ? "base64" : "utf8"
1100
1100
  });
@@ -1305,7 +1305,7 @@ var FileMemoryBackend = class {
1305
1305
  }
1306
1306
  async remember(scope, entry, filePath) {
1307
1307
  const file = this.resolveFile(filePath, scope);
1308
- await ensureDir(path2.dirname(file));
1308
+ await ensureDir(path12.dirname(file));
1309
1309
  let existing = "";
1310
1310
  try {
1311
1311
  existing = await fsp.readFile(file, "utf8");
@@ -1322,39 +1322,41 @@ ${line}`;
1322
1322
  }
1323
1323
  async forget(scope, query, filePath) {
1324
1324
  const file = this.resolveFile(filePath, scope);
1325
- let existing;
1326
- try {
1327
- existing = await fsp.readFile(file, "utf8");
1328
- } catch {
1329
- return 0;
1330
- }
1331
- const needle = query.toLowerCase();
1332
- const idMatcher = /mem_\d+_\w+/;
1333
- let removed = 0;
1334
- const lines = existing.split("\n").filter((line) => {
1335
- const trimmed = line.trim();
1336
- if (!trimmed.startsWith("- ")) return true;
1337
- if (idMatcher.test(query)) {
1338
- const entryIdMatch = /mem_\d+_\w+/.exec(trimmed);
1339
- if (entryIdMatch && entryIdMatch[0] === query) {
1325
+ return withFileLock(file, async () => {
1326
+ let existing;
1327
+ try {
1328
+ existing = await fsp.readFile(file, "utf8");
1329
+ } catch {
1330
+ return 0;
1331
+ }
1332
+ const needle = query.toLowerCase();
1333
+ const idMatcher = /mem_\d+_\w+/;
1334
+ let removed = 0;
1335
+ const lines = existing.split("\n").filter((line) => {
1336
+ const trimmed = line.trim();
1337
+ if (!trimmed.startsWith("- ")) return true;
1338
+ if (idMatcher.test(query)) {
1339
+ const entryIdMatch = /mem_\d+_\w+/.exec(trimmed);
1340
+ if (entryIdMatch && entryIdMatch[0] === query) {
1341
+ removed++;
1342
+ return false;
1343
+ }
1344
+ }
1345
+ if (trimmed.toLowerCase().includes(needle)) {
1340
1346
  removed++;
1341
1347
  return false;
1342
1348
  }
1349
+ return true;
1350
+ });
1351
+ if (removed > 0) {
1352
+ if (lines.length === 0 || lines.length === 1 && !lines[0]?.trim()) {
1353
+ await atomicWrite(file, "");
1354
+ } else {
1355
+ await atomicWrite(file, lines.join("\n"));
1356
+ }
1343
1357
  }
1344
- if (trimmed.toLowerCase().includes(needle)) {
1345
- removed++;
1346
- return false;
1347
- }
1348
- return true;
1358
+ return removed;
1349
1359
  });
1350
- if (removed > 0) {
1351
- if (lines.length === 0 || lines.length === 1 && !lines[0]?.trim()) {
1352
- await atomicWrite(file, "");
1353
- } else {
1354
- await atomicWrite(file, lines.join("\n"));
1355
- }
1356
- }
1357
- return removed;
1358
1360
  }
1359
1361
  async readAll(scope, filePath) {
1360
1362
  const file = this.resolveFile(filePath, scope);
@@ -2067,7 +2069,7 @@ var SessionMemoryConsolidator = class {
2067
2069
  for (const op of parsed.operations) {
2068
2070
  switch (op.action) {
2069
2071
  case "add": {
2070
- if (op.text && op.text.trim()) {
2072
+ if (op.text?.trim()) {
2071
2073
  await this.memoryStore.remember(op.text.trim(), void 0, {
2072
2074
  type: op.type,
2073
2075
  tags: op.tags,
@@ -2439,12 +2441,14 @@ var DefaultConfigLoader = class {
2439
2441
  }
2440
2442
  async load(opts = {}) {
2441
2443
  let cfg = { ...BEHAVIOR_DEFAULTS };
2442
- const [global, local] = await Promise.all([
2444
+ const [global, local, inProject] = await Promise.all([
2443
2445
  this.readJson(this.paths.globalConfig),
2444
- this.readJson(this.paths.projectLocalConfig)
2446
+ this.readJson(this.paths.projectLocalConfig),
2447
+ this.readJson(this.paths.inProjectConfig)
2445
2448
  ]);
2446
2449
  cfg = deepMerge(cfg, global);
2447
2450
  cfg = deepMerge(cfg, local);
2451
+ cfg = deepMerge(cfg, inProject);
2448
2452
  for (const [key, fn] of Object.entries(ENV_MAP)) {
2449
2453
  const v = process.env[key];
2450
2454
  if (v) fn(cfg, v);
@@ -2643,7 +2647,7 @@ var RecoveryLock = class {
2643
2647
  sessionStore;
2644
2648
  probe;
2645
2649
  constructor(opts) {
2646
- this.file = path2.join(opts.dir, LOCK_FILE);
2650
+ this.file = path12.join(opts.dir, LOCK_FILE);
2647
2651
  this.pid = opts.pid ?? process.pid;
2648
2652
  this.hostname = opts.hostname ?? os.hostname();
2649
2653
  this.maxAgeMs = opts.maxAgeMs ?? DEFAULT_MAX_AGE_MS;
@@ -2701,7 +2705,7 @@ var RecoveryLock = class {
2701
2705
  * null return before calling this.
2702
2706
  */
2703
2707
  async write(sessionId) {
2704
- await ensureDir(path2.dirname(this.file));
2708
+ await ensureDir(path12.dirname(this.file));
2705
2709
  const lock = {
2706
2710
  v: 1,
2707
2711
  sessionId,
@@ -3188,7 +3192,7 @@ var AnnotationsStore = class {
3188
3192
  if (!sessionId || sessionId.includes("/") || sessionId.includes("\\") || sessionId.includes("..")) {
3189
3193
  throw new Error(`Invalid sessionId: ${sessionId}`);
3190
3194
  }
3191
- return path2.join(this.dir, `${sessionId}.annotations.json`);
3195
+ return path12.join(this.dir, `${sessionId}.annotations.json`);
3192
3196
  }
3193
3197
  async readFile(sessionId) {
3194
3198
  const fp = this.filePath(sessionId);
@@ -3345,7 +3349,7 @@ var ReplayLogStore = class {
3345
3349
  out.push({
3346
3350
  sessionId,
3347
3351
  entryCount: all.length,
3348
- path: path2.join(this.dir, name)
3352
+ path: path12.join(this.dir, name)
3349
3353
  });
3350
3354
  }
3351
3355
  return out.sort((a, b) => a.sessionId.localeCompare(b.sessionId));
@@ -3355,7 +3359,7 @@ var ReplayLogStore = class {
3355
3359
  if (!sessionId || sessionId.includes("/") || sessionId.includes("\\") || sessionId.includes("..")) {
3356
3360
  throw new Error(`Invalid sessionId: ${sessionId}`);
3357
3361
  }
3358
- return path2.join(this.dir, `${sessionId}.replay.jsonl`);
3362
+ return path12.join(this.dir, `${sessionId}.replay.jsonl`);
3359
3363
  }
3360
3364
  async readAll(sessionId) {
3361
3365
  const fp = this.filePath(sessionId);
@@ -3544,7 +3548,7 @@ var SessionRecovery = class {
3544
3548
  if (!sessionId || sessionId.includes("/") || sessionId.includes("\\") || sessionId.includes("..")) {
3545
3549
  throw new Error(`Invalid sessionId: ${sessionId}`);
3546
3550
  }
3547
- return path2.join(this.dir, `${sessionId}.jsonl`);
3551
+ return path12.join(this.dir, `${sessionId}.jsonl`);
3548
3552
  }
3549
3553
  };
3550
3554
  var GENESIS_PREV = "0".repeat(64);
@@ -3667,7 +3671,7 @@ var ToolAuditLog = class {
3667
3671
  if (!sessionId || sessionId.includes("/") || sessionId.includes("\\") || sessionId.includes("..")) {
3668
3672
  throw new Error(`Invalid sessionId: ${sessionId}`);
3669
3673
  }
3670
- return path2.join(this.dir, `${sessionId}.audit.jsonl`);
3674
+ return path12.join(this.dir, `${sessionId}.audit.jsonl`);
3671
3675
  }
3672
3676
  async readAll(sessionId) {
3673
3677
  const fp = this.filePath(sessionId);
@@ -3852,7 +3856,7 @@ var DefaultSessionRewinder = class {
3852
3856
  sessionsDir;
3853
3857
  projectRoot;
3854
3858
  async listCheckpoints(sessionId) {
3855
- const file = path2.join(this.sessionsDir, `${sessionId}.jsonl`);
3859
+ const file = path12.join(this.sessionsDir, `${sessionId}.jsonl`);
3856
3860
  const raw = await fsp.readFile(file, "utf8");
3857
3861
  const events = parseEvents(raw);
3858
3862
  const fileCountMap = /* @__PURE__ */ new Map();
@@ -3877,7 +3881,7 @@ var DefaultSessionRewinder = class {
3877
3881
  return checkpoints;
3878
3882
  }
3879
3883
  async rewindToCheckpoint(sessionId, checkpointIndex) {
3880
- const file = path2.join(this.sessionsDir, `${sessionId}.jsonl`);
3884
+ const file = path12.join(this.sessionsDir, `${sessionId}.jsonl`);
3881
3885
  const raw = await fsp.readFile(file, "utf8");
3882
3886
  const events = parseEvents(raw);
3883
3887
  let targetIdx = -1;
@@ -3912,7 +3916,7 @@ var DefaultSessionRewinder = class {
3912
3916
  return { ...result, toPromptIndex: checkpointIndex, removedEvents };
3913
3917
  }
3914
3918
  async rewindLastN(sessionId, n) {
3915
- const file = path2.join(this.sessionsDir, `${sessionId}.jsonl`);
3919
+ const file = path12.join(this.sessionsDir, `${sessionId}.jsonl`);
3916
3920
  const raw = await fsp.readFile(file, "utf8");
3917
3921
  const events = parseEvents(raw);
3918
3922
  const checkpoints = [];
@@ -3941,7 +3945,7 @@ var DefaultSessionRewinder = class {
3941
3945
  return { ...result, toPromptIndex: targetIndex, removedEvents: snapshotsToRevert.length };
3942
3946
  }
3943
3947
  async rewindToStart(sessionId) {
3944
- const file = path2.join(this.sessionsDir, `${sessionId}.jsonl`);
3948
+ const file = path12.join(this.sessionsDir, `${sessionId}.jsonl`);
3945
3949
  const raw = await fsp.readFile(file, "utf8");
3946
3950
  const events = parseEvents(raw);
3947
3951
  const allSnapshots = [];
@@ -3977,10 +3981,10 @@ async function revertSnapshots(snapshots, projectRoot) {
3977
3981
  for (const snapshot of snapshots) {
3978
3982
  for (const file of snapshot.files) {
3979
3983
  try {
3980
- const absPath = path2.resolve(file.path);
3981
- const root = path2.resolve(projectRoot);
3982
- const rel = path2.relative(root, absPath);
3983
- if (rel.startsWith("..") || path2.isAbsolute(rel)) {
3984
+ const absPath = path12.resolve(file.path);
3985
+ const root = path12.resolve(projectRoot);
3986
+ const rel = path12.relative(root, absPath);
3987
+ if (rel.startsWith("..") || path12.isAbsolute(rel)) {
3984
3988
  errors.push(`${file.path}: path resolves outside project root \u2014 skipping`);
3985
3989
  continue;
3986
3990
  }
@@ -4560,6 +4564,58 @@ var color = {
4560
4564
  bgRed: wrap("41", "49"),
4561
4565
  bgGreen: wrap("42", "49")
4562
4566
  };
4567
+ function projectHash(absRoot) {
4568
+ return createHash("sha256").update(path12.resolve(absRoot)).digest("hex").slice(0, 12);
4569
+ }
4570
+ function projectSlug(absRoot) {
4571
+ const base = slugify(path12.basename(absRoot));
4572
+ const hash = createHash("sha256").update(path12.resolve(absRoot)).digest("hex").slice(0, 6);
4573
+ return `${base}-${hash}`;
4574
+ }
4575
+ function slugify(name) {
4576
+ return name.toLowerCase().replace(/[^a-z0-9]+/g, "-").replace(/^-+|-+$/g, "").slice(0, 40) || "project";
4577
+ }
4578
+ function resolveWstackPaths(opts) {
4579
+ const home = opts.userHome ?? os.homedir();
4580
+ const globalRoot = opts.globalRoot ?? path12.join(home, ".wrongstack");
4581
+ const hash = projectHash(opts.projectRoot);
4582
+ const slug = projectSlug(opts.projectRoot);
4583
+ const projectDir = path12.join(globalRoot, "projects", slug);
4584
+ return {
4585
+ globalRoot,
4586
+ configDir: globalRoot,
4587
+ globalConfig: path12.join(globalRoot, "config.json"),
4588
+ secretsKey: path12.join(globalRoot, ".key"),
4589
+ globalMemory: path12.join(globalRoot, "memory.md"),
4590
+ globalSkills: path12.join(globalRoot, "skills"),
4591
+ globalPrompts: path12.join(globalRoot, "prompts"),
4592
+ cacheDir: path12.join(globalRoot, "cache"),
4593
+ modelsCache: path12.join(globalRoot, "cache", "models.dev.json"),
4594
+ modelsOverlayCache: path12.join(globalRoot, "cache", "models-overlay.json"),
4595
+ historyFile: path12.join(globalRoot, "history"),
4596
+ logFile: path12.join(globalRoot, "logs", "wrongstack.log"),
4597
+ projectDir,
4598
+ projectCodebaseIndex: path12.join(projectDir, "codebase-index"),
4599
+ projectMemory: path12.join(projectDir, "memory.md"),
4600
+ projectSessions: path12.join(projectDir, "sessions"),
4601
+ projectTrust: path12.join(projectDir, "trust.json"),
4602
+ projectMeta: path12.join(projectDir, "meta.json"),
4603
+ projectLocalConfig: path12.join(projectDir, "config.local.json"),
4604
+ inProjectConfig: path12.join(opts.projectRoot, ".wrongstack", "config.json"),
4605
+ inProjectAgentsFile: path12.join(opts.projectRoot, ".wrongstack", "AGENTS.md"),
4606
+ inProjectSkills: path12.join(opts.projectRoot, ".wrongstack", "skills"),
4607
+ inProjectWorktrees: path12.join(opts.projectRoot, ".wrongstack", "worktrees"),
4608
+ projectHash: hash,
4609
+ projectSlug: slug,
4610
+ projectGoal: path12.join(projectDir, "goal.json"),
4611
+ projectSpecs: path12.join(projectDir, "specs"),
4612
+ projectTaskGraphs: path12.join(projectDir, "task-graphs"),
4613
+ projectSddSession: path12.join(projectDir, "sdd-session.json"),
4614
+ projectPlan: path12.join(projectDir, "plan.json"),
4615
+ projectAutophase: path12.join(projectDir, "autophase"),
4616
+ syncConfig: path12.join(globalRoot, "sync.json")
4617
+ };
4618
+ }
4563
4619
 
4564
4620
  // src/types/errors.ts
4565
4621
  var ERROR_CODES = {
@@ -4614,23 +4670,26 @@ var FsError = class extends WrongStackError {
4614
4670
  // src/storage/goal-store.ts
4615
4671
  var MAX_JOURNAL_ENTRIES = 500;
4616
4672
  function goalFilePath(projectRoot) {
4617
- const hash = createHash("sha256").update(path2.resolve(projectRoot)).digest("hex").slice(0, 12);
4618
- return path2.join(os.homedir(), ".wrongstack", "projects", hash, "goal.json");
4673
+ return resolveWstackPaths({ projectRoot }).projectGoal;
4619
4674
  }
4620
4675
  async function loadGoal(filePath) {
4621
4676
  let raw;
4622
4677
  try {
4623
4678
  raw = await fsp.readFile(filePath, "utf8");
4624
- } catch {
4625
- return null;
4679
+ } catch (err) {
4680
+ const code = err.code;
4681
+ if (code === "ENOENT") return null;
4682
+ throw err;
4626
4683
  }
4627
4684
  try {
4628
4685
  const parsed = JSON.parse(raw);
4629
4686
  if (parsed?.version !== 1 || typeof parsed.goal !== "string" || !Array.isArray(parsed.journal)) {
4687
+ console.warn(`[goal-store] Corrupt goal.json at ${filePath} \u2014 invalid schema. Consider deleting it and re-creating.`);
4630
4688
  return null;
4631
4689
  }
4632
4690
  return parsed;
4633
4691
  } catch {
4692
+ console.warn(`[goal-store] Corrupt goal.json at ${filePath} \u2014 JSON parse failed. Consider deleting it and re-creating.`);
4634
4693
  return null;
4635
4694
  }
4636
4695
  }
@@ -4779,7 +4838,7 @@ function computeTrend(history) {
4779
4838
  const recent = history.slice(-5);
4780
4839
  const deltas = [];
4781
4840
  for (let i = 1; i < recent.length; i++) {
4782
- deltas.push(recent[i].progress - recent[i - 1].progress);
4841
+ deltas.push((recent[i]?.progress ?? 0) - (recent[i - 1]?.progress ?? 0));
4783
4842
  }
4784
4843
  if (deltas.length < 2) return void 0;
4785
4844
  const avgDelta = deltas.reduce((a, b) => a + b, 0) / deltas.length;
@@ -4801,7 +4860,7 @@ var DefaultPromptStore = class {
4801
4860
  if (!file.endsWith(".json")) continue;
4802
4861
  try {
4803
4862
  const raw = JSON.parse(
4804
- await fsp.readFile(path2.join(this.dir, file), "utf8")
4863
+ await fsp.readFile(path12.join(this.dir, file), "utf8")
4805
4864
  );
4806
4865
  entries.push(raw.entry);
4807
4866
  } catch {
@@ -4814,7 +4873,7 @@ var DefaultPromptStore = class {
4814
4873
  );
4815
4874
  }
4816
4875
  async get(id) {
4817
- const file = path2.join(this.dir, `${id}.json`);
4876
+ const file = path12.join(this.dir, `${id}.json`);
4818
4877
  try {
4819
4878
  const raw = JSON.parse(await fsp.readFile(file, "utf8"));
4820
4879
  return raw.entry;
@@ -4824,12 +4883,12 @@ var DefaultPromptStore = class {
4824
4883
  }
4825
4884
  async save(entry) {
4826
4885
  await ensureDir(this.dir);
4827
- const file = path2.join(this.dir, `${entry.id}.json`);
4886
+ const file = path12.join(this.dir, `${entry.id}.json`);
4828
4887
  const raw = { version: 1, entry };
4829
4888
  await atomicWrite(file, JSON.stringify(raw, null, 2));
4830
4889
  }
4831
4890
  async delete(id) {
4832
- const file = path2.join(this.dir, `${id}.json`);
4891
+ const file = path12.join(this.dir, `${id}.json`);
4833
4892
  try {
4834
4893
  await fsp.unlink(file);
4835
4894
  return true;
@@ -4863,7 +4922,7 @@ var CloudSync = class {
4863
4922
  this.paths = paths;
4864
4923
  this.getConfig = getConfig;
4865
4924
  this.setConfig = setConfig;
4866
- this.statePath = path2.join(paths.globalRoot, "sync-state.json");
4925
+ this.statePath = path12.join(paths.globalRoot, "sync-state.json");
4867
4926
  }
4868
4927
  paths;
4869
4928
  getConfig;
@@ -4970,7 +5029,7 @@ var CloudSync = class {
4970
5029
  const rel = segments.slice(2).join("/");
4971
5030
  const destPath = resolvePulledCategoryPath(cat, localPath, rel, entry.path);
4972
5031
  const blobData = await this.getBlob(token, owner, repoName, entry.sha);
4973
- await fsp.mkdir(path2.dirname(destPath), { recursive: true });
5032
+ await fsp.mkdir(path12.dirname(destPath), { recursive: true });
4974
5033
  await fsp.writeFile(destPath, Buffer.from(blobData, "base64"));
4975
5034
  }
4976
5035
  const localRev = await this.hashLocalCategories(cfg.categories);
@@ -5077,7 +5136,7 @@ var CloudSync = class {
5077
5136
  const files = await this.walkDir(localPath, localPath);
5078
5137
  for (const file of files) {
5079
5138
  const content = await fsp.readFile(file, "utf8");
5080
- const rel = path2.relative(localPath, file).replace(/\\/g, "/");
5139
+ const rel = path12.relative(localPath, file).replace(/\\/g, "/");
5081
5140
  entries.push({ path: `data/${cat}/${rel}`, content, mode: "100644" });
5082
5141
  hashes.push(content);
5083
5142
  }
@@ -5134,7 +5193,7 @@ var CloudSync = class {
5134
5193
  const results = [];
5135
5194
  const entries = await fsp.readdir(dir, { withFileTypes: true });
5136
5195
  for (const entry of entries) {
5137
- const full = path2.join(dir, entry.name);
5196
+ const full = path12.join(dir, entry.name);
5138
5197
  if (entry.isDirectory()) {
5139
5198
  results.push(...await this.walkDir(full, base));
5140
5199
  } else {
@@ -5151,15 +5210,15 @@ function resolvePulledCategoryPath(cat, localPath, rel, remotePath) {
5151
5210
  return localPath;
5152
5211
  }
5153
5212
  if (!rel) return localPath;
5154
- const normalizedRel = path2.normalize(rel);
5155
- const traversesUp = normalizedRel === ".." || normalizedRel.startsWith(`..${path2.sep}`);
5156
- if (path2.isAbsolute(normalizedRel) || traversesUp) {
5213
+ const normalizedRel = path12.normalize(rel);
5214
+ const traversesUp = normalizedRel === ".." || normalizedRel.startsWith(`..${path12.sep}`);
5215
+ if (path12.isAbsolute(normalizedRel) || traversesUp) {
5157
5216
  throw new Error(`Refusing CloudSync path traversal: ${remotePath}`);
5158
5217
  }
5159
- const dest = path2.resolve(localPath, normalizedRel);
5160
- const root = path2.resolve(localPath);
5161
- const relative3 = path2.relative(root, dest);
5162
- if (relative3.startsWith("..") || path2.isAbsolute(relative3)) {
5218
+ const dest = path12.resolve(localPath, normalizedRel);
5219
+ const root = path12.resolve(localPath);
5220
+ const relative3 = path12.relative(root, dest);
5221
+ if (relative3.startsWith("..") || path12.isAbsolute(relative3)) {
5163
5222
  throw new Error(`Refusing CloudSync path outside category root: ${remotePath}`);
5164
5223
  }
5165
5224
  return dest;