noumen 0.1.0 → 0.3.0

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 (127) hide show
  1. package/README.md +846 -51
  2. package/dist/a2a/index.d.ts +148 -0
  3. package/dist/a2a/index.js +579 -0
  4. package/dist/a2a/index.js.map +1 -0
  5. package/dist/acp/index.d.ts +129 -0
  6. package/dist/acp/index.js +498 -0
  7. package/dist/acp/index.js.map +1 -0
  8. package/dist/agent-1nFVUP9E.d.ts +1332 -0
  9. package/dist/cache-DsRqxx6v.d.ts +38 -0
  10. package/dist/chunk-3HEYCV26.js +10 -0
  11. package/dist/chunk-3HEYCV26.js.map +1 -0
  12. package/dist/chunk-3SK5GCI6.js +75 -0
  13. package/dist/chunk-3SK5GCI6.js.map +1 -0
  14. package/dist/chunk-42PHHZUA.js +132 -0
  15. package/dist/chunk-42PHHZUA.js.map +1 -0
  16. package/dist/chunk-4HW6LN6D.js +10365 -0
  17. package/dist/chunk-4HW6LN6D.js.map +1 -0
  18. package/dist/chunk-4SQA2UCV.js +26 -0
  19. package/dist/chunk-4SQA2UCV.js.map +1 -0
  20. package/dist/chunk-5GEX6ZSB.js +179 -0
  21. package/dist/chunk-5GEX6ZSB.js.map +1 -0
  22. package/dist/chunk-5JN4SPI7.js +94 -0
  23. package/dist/chunk-5JN4SPI7.js.map +1 -0
  24. package/dist/chunk-AMYIJSAZ.js +57 -0
  25. package/dist/chunk-AMYIJSAZ.js.map +1 -0
  26. package/dist/chunk-BZSFUEWM.js +43 -0
  27. package/dist/chunk-BZSFUEWM.js.map +1 -0
  28. package/dist/chunk-CS6WNDCF.js +171 -0
  29. package/dist/chunk-CS6WNDCF.js.map +1 -0
  30. package/dist/chunk-D43BWEZA.js +346 -0
  31. package/dist/chunk-D43BWEZA.js.map +1 -0
  32. package/dist/chunk-DGUM43GV.js +11 -0
  33. package/dist/chunk-DGUM43GV.js.map +1 -0
  34. package/dist/chunk-EKOGVTBT.js +472 -0
  35. package/dist/chunk-EKOGVTBT.js.map +1 -0
  36. package/dist/chunk-HEQQQGK5.js +131 -0
  37. package/dist/chunk-HEQQQGK5.js.map +1 -0
  38. package/dist/chunk-HL6JCRZJ.js +3112 -0
  39. package/dist/chunk-HL6JCRZJ.js.map +1 -0
  40. package/dist/chunk-JACGEMTF.js +43 -0
  41. package/dist/chunk-JACGEMTF.js.map +1 -0
  42. package/dist/chunk-JX7CLUCV.js +21 -0
  43. package/dist/chunk-JX7CLUCV.js.map +1 -0
  44. package/dist/chunk-KXDB56YW.js +39 -0
  45. package/dist/chunk-KXDB56YW.js.map +1 -0
  46. package/dist/chunk-L3L3FG5T.js +16 -0
  47. package/dist/chunk-L3L3FG5T.js.map +1 -0
  48. package/dist/chunk-OGXNFXFA.js +196 -0
  49. package/dist/chunk-OGXNFXFA.js.map +1 -0
  50. package/dist/chunk-UVSSQBDY.js +192 -0
  51. package/dist/chunk-UVSSQBDY.js.map +1 -0
  52. package/dist/chunk-Y45R3PQL.js +684 -0
  53. package/dist/chunk-Y45R3PQL.js.map +1 -0
  54. package/dist/cli/index.d.ts +1 -0
  55. package/dist/cli/index.js +874 -0
  56. package/dist/cli/index.js.map +1 -0
  57. package/dist/client/index.d.ts +64 -0
  58. package/dist/client/index.js +409 -0
  59. package/dist/client/index.js.map +1 -0
  60. package/dist/client-CRRO2376.js +10 -0
  61. package/dist/client-CRRO2376.js.map +1 -0
  62. package/dist/headless-FFU2DESQ.js +142 -0
  63. package/dist/headless-FFU2DESQ.js.map +1 -0
  64. package/dist/history-snip-64GYP4ZL.js +12 -0
  65. package/dist/history-snip-64GYP4ZL.js.map +1 -0
  66. package/dist/index.d.ts +1459 -422
  67. package/dist/index.js +398 -1757
  68. package/dist/index.js.map +1 -1
  69. package/dist/jsonrpc/index.d.ts +54 -0
  70. package/dist/jsonrpc/index.js +34 -0
  71. package/dist/jsonrpc/index.js.map +1 -0
  72. package/dist/lsp/index.d.ts +36 -0
  73. package/dist/lsp/index.js +16 -0
  74. package/dist/lsp/index.js.map +1 -0
  75. package/dist/lsp-PS3BWIHC.js +8 -0
  76. package/dist/lsp-PS3BWIHC.js.map +1 -0
  77. package/dist/manager-DLXK63XC.js +8 -0
  78. package/dist/manager-DLXK63XC.js.map +1 -0
  79. package/dist/mcp/index.d.ts +111 -0
  80. package/dist/mcp/index.js +105 -0
  81. package/dist/mcp/index.js.map +1 -0
  82. package/dist/mcp-auth-AEI2R4ZC.js +9 -0
  83. package/dist/mcp-auth-AEI2R4ZC.js.map +1 -0
  84. package/dist/provider-factory-KCLIF34X.js +20 -0
  85. package/dist/provider-factory-KCLIF34X.js.map +1 -0
  86. package/dist/providers/anthropic.d.ts +19 -0
  87. package/dist/providers/anthropic.js +35 -0
  88. package/dist/providers/anthropic.js.map +1 -0
  89. package/dist/providers/bedrock.d.ts +39 -0
  90. package/dist/providers/bedrock.js +56 -0
  91. package/dist/providers/bedrock.js.map +1 -0
  92. package/dist/providers/gemini.d.ts +17 -0
  93. package/dist/providers/gemini.js +262 -0
  94. package/dist/providers/gemini.js.map +1 -0
  95. package/dist/providers/ollama.d.ts +13 -0
  96. package/dist/providers/ollama.js +20 -0
  97. package/dist/providers/ollama.js.map +1 -0
  98. package/dist/providers/openai.d.ts +21 -0
  99. package/dist/providers/openai.js +9 -0
  100. package/dist/providers/openai.js.map +1 -0
  101. package/dist/providers/openrouter.d.ts +16 -0
  102. package/dist/providers/openrouter.js +24 -0
  103. package/dist/providers/openrouter.js.map +1 -0
  104. package/dist/providers/vertex.d.ts +42 -0
  105. package/dist/providers/vertex.js +67 -0
  106. package/dist/providers/vertex.js.map +1 -0
  107. package/dist/render-GRN4ZSSW.js +14 -0
  108. package/dist/render-GRN4ZSSW.js.map +1 -0
  109. package/dist/resolve-4JA2BBDA.js +14 -0
  110. package/dist/resolve-4JA2BBDA.js.map +1 -0
  111. package/dist/server/index.d.ts +143 -0
  112. package/dist/server/index.js +695 -0
  113. package/dist/server/index.js.map +1 -0
  114. package/dist/server-CHMxuWKq.d.ts +96 -0
  115. package/dist/spinner-OJNR6NFO.js +8 -0
  116. package/dist/spinner-OJNR6NFO.js.map +1 -0
  117. package/dist/types-2kTLUCnD.d.ts +107 -0
  118. package/dist/types-CD0rUKKT.d.ts +109 -0
  119. package/dist/types-LrU4LRmX.d.ts +575 -0
  120. package/dist/types-NIyVwQ4h.d.ts +109 -0
  121. package/dist/types-QwfylltH.d.ts +71 -0
  122. package/dist/types-RPKUTu1k.d.ts +645 -0
  123. package/dist/uuid-RVN2T26F.js +8 -0
  124. package/dist/uuid-RVN2T26F.js.map +1 -0
  125. package/dist/zod-7YXKWYMC.js +12 -0
  126. package/dist/zod-7YXKWYMC.js.map +1 -0
  127. package/package.json +141 -7
@@ -0,0 +1,38 @@
1
+ import { b as ChatMessage, T as ToolDefinition } from './types-LrU4LRmX.js';
2
+
3
+ /**
4
+ * Provider-agnostic prompt caching utilities.
5
+ *
6
+ * Stable tool ordering prevents cache invalidation when the tool set is
7
+ * unchanged. The breakpoint index helper determines which message gets a
8
+ * single cache_control marker per request (matching claude-code's strategy).
9
+ */
10
+
11
+ type CacheScope = "global" | "org";
12
+ interface CacheControlConfig {
13
+ enabled: boolean;
14
+ /** TTL for cached content. When set, produces `ttl: '1h'` in cache_control. */
15
+ ttl?: "1h";
16
+ /** Scope for shared cache across sessions/orgs. */
17
+ scope?: CacheScope;
18
+ }
19
+ /**
20
+ * Sort tool definitions deterministically for prompt cache stability.
21
+ *
22
+ * Strategy (matching claude-code's assembleToolPool): built-in tools form a
23
+ * contiguous prefix sorted by name, followed by MCP/external tools sorted by
24
+ * name. Tools with `mcpInfo` on the original Tool object are treated as MCP;
25
+ * everything else is built-in. Since ToolDefinition doesn't carry mcpInfo,
26
+ * callers can pass an optional set of MCP tool names to partition correctly.
27
+ */
28
+ declare function sortToolDefinitionsForCache(tools: ToolDefinition[], mcpToolNames?: ReadonlySet<string>): ToolDefinition[];
29
+ /**
30
+ * Determine which message index should receive the cache_control breakpoint.
31
+ *
32
+ * Exactly one message per request is marked. Normally the last message;
33
+ * for forked agents with skipCacheWrite the second-to-last so the fork
34
+ * doesn't write its own tail into the cache.
35
+ */
36
+ declare function getMessageCacheBreakpointIndex(messages: ChatMessage[], skipCacheWrite?: boolean): number;
37
+
38
+ export { type CacheControlConfig as C, type CacheScope as a, getMessageCacheBreakpointIndex as g, sortToolDefinitionsForCache as s };
@@ -0,0 +1,10 @@
1
+ // src/utils/uuid.ts
2
+ import { v4 } from "uuid";
3
+ function generateUUID() {
4
+ return v4();
5
+ }
6
+
7
+ export {
8
+ generateUUID
9
+ };
10
+ //# sourceMappingURL=chunk-3HEYCV26.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/uuid.ts"],"sourcesContent":["import { v4 } from \"uuid\";\n\nexport type UUID = string & { readonly __brand: unique symbol };\n\nexport function generateUUID(): UUID {\n return v4() as UUID;\n}\n"],"mappings":";AAAA,SAAS,UAAU;AAIZ,SAAS,eAAqB;AACnC,SAAO,GAAG;AACZ;","names":[]}
@@ -0,0 +1,75 @@
1
+ // src/utils/zod.ts
2
+ var cache = /* @__PURE__ */ new WeakMap();
3
+ function zodToJsonSchema(schema) {
4
+ const hit = cache.get(schema);
5
+ if (hit) return hit;
6
+ const zod = schema._zod ? schema : void 0;
7
+ if (!zod) {
8
+ throw new Error(
9
+ "zodToJsonSchema requires a Zod v4 schema. Install zod and pass a z.object(\u2026) schema."
10
+ );
11
+ }
12
+ let toJSONSchema;
13
+ try {
14
+ const sAny = schema;
15
+ if (typeof sAny._toJSONSchema === "function") {
16
+ const result = sAny._toJSONSchema();
17
+ cache.set(schema, result);
18
+ return result;
19
+ }
20
+ toJSONSchema = globalThis.__noumen_toJSONSchema;
21
+ } catch {
22
+ }
23
+ if (toJSONSchema) {
24
+ const result = toJSONSchema(schema);
25
+ cache.set(schema, result);
26
+ return result;
27
+ }
28
+ throw new Error(
29
+ "Could not convert Zod schema to JSON Schema. Call `registerZodToJsonSchema(toJSONSchema)` from zod/v4 or upgrade to Zod v4."
30
+ );
31
+ }
32
+ function registerZodToJsonSchema(fn) {
33
+ globalThis.__noumen_toJSONSchema = fn;
34
+ }
35
+ function formatZodValidationError(toolName, issues) {
36
+ if (!issues || !issues.issues.length) {
37
+ return `${toolName}: validation failed with unknown error`;
38
+ }
39
+ const parts = [];
40
+ const missing = issues.issues.filter(
41
+ (i) => i.code === "invalid_type" && i.message.includes("required")
42
+ );
43
+ const unrecognized = issues.issues.filter(
44
+ (i) => i.code === "unrecognized_keys"
45
+ );
46
+ const other = issues.issues.filter(
47
+ (i) => !missing.includes(i) && !unrecognized.includes(i)
48
+ );
49
+ if (missing.length) {
50
+ parts.push(
51
+ `Missing required parameter${missing.length > 1 ? "s" : ""}: ${missing.map((m) => formatPath(m.path)).join(", ")}`
52
+ );
53
+ }
54
+ if (unrecognized.length) {
55
+ parts.push(
56
+ `Unrecognized parameter${unrecognized.length > 1 ? "s" : ""}: ${unrecognized.map((u) => u.message).join(", ")}`
57
+ );
58
+ }
59
+ for (const issue of other) {
60
+ const path = formatPath(issue.path);
61
+ parts.push(`${path ? path + ": " : ""}${issue.message}`);
62
+ }
63
+ return `${toolName} failed due to the following ${parts.length > 1 ? "issues" : "issue"}:
64
+ ${parts.join("\n")}`;
65
+ }
66
+ function formatPath(path) {
67
+ return path.map((p, i) => typeof p === "number" ? `[${p}]` : i > 0 ? `.${p}` : p).join("");
68
+ }
69
+
70
+ export {
71
+ zodToJsonSchema,
72
+ registerZodToJsonSchema,
73
+ formatZodValidationError
74
+ };
75
+ //# sourceMappingURL=chunk-3SK5GCI6.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/utils/zod.ts"],"sourcesContent":["/**\n * Zod integration utilities. Users bring their own `zod` dependency — these\n * helpers accept duck-typed schemas so we don't force a hard dependency.\n */\n\nexport type JsonSchemaType = Record<string, unknown>;\n\n/**\n * Minimal interface matching Zod v4's safeParse return. Allows noumen to\n * validate tool input without depending on zod directly.\n */\nexport interface SafeParseResult {\n success: boolean;\n data?: unknown;\n error?: {\n issues: Array<{\n code: string;\n path: (string | number)[];\n message: string;\n }>;\n };\n}\n\nexport interface ZodLikeSchema {\n safeParse(data: unknown): SafeParseResult;\n}\n\nconst cache = new WeakMap<object, JsonSchemaType>();\n\n/**\n * Convert a Zod v4 schema to JSON Schema. Caches by schema identity.\n * Requires `zod/v4` to be installed — calls its native `toJSONSchema`.\n */\nexport function zodToJsonSchema(schema: ZodLikeSchema): JsonSchemaType {\n const hit = cache.get(schema);\n if (hit) return hit;\n\n const zod = (schema as unknown as { _zod?: unknown })._zod\n ? schema\n : undefined;\n\n if (!zod) {\n throw new Error(\n \"zodToJsonSchema requires a Zod v4 schema. Install zod and pass a z.object(…) schema.\",\n );\n }\n\n let toJSONSchema: ((s: unknown) => JsonSchemaType) | undefined;\n try {\n // Dynamic import isn't possible synchronously, so we look for the\n // schema's own conversion method first (Zod v4 attaches _toJSONSchema).\n const sAny = schema as unknown as Record<string, unknown>;\n if (typeof sAny._toJSONSchema === \"function\") {\n const result = sAny._toJSONSchema() as JsonSchemaType;\n cache.set(schema, result);\n return result;\n }\n // Fallback: try the module-level toJSONSchema from zod/v4\n // eslint-disable-next-line @typescript-eslint/no-require-imports\n toJSONSchema = (globalThis as unknown as Record<string, unknown>)\n .__noumen_toJSONSchema as typeof toJSONSchema;\n } catch {\n // not available\n }\n\n if (toJSONSchema) {\n const result = toJSONSchema(schema) as JsonSchemaType;\n cache.set(schema, result);\n return result;\n }\n\n throw new Error(\n \"Could not convert Zod schema to JSON Schema. \" +\n \"Call `registerZodToJsonSchema(toJSONSchema)` from zod/v4 or upgrade to Zod v4.\",\n );\n}\n\n/**\n * Register the `toJSONSchema` function from `zod/v4` so `zodToJsonSchema` can use it.\n *\n * ```ts\n * import { toJSONSchema } from \"zod/v4\";\n * import { registerZodToJsonSchema } from \"noumen\";\n * registerZodToJsonSchema(toJSONSchema);\n * ```\n */\nexport function registerZodToJsonSchema(\n fn: (schema: unknown) => JsonSchemaType,\n): void {\n (globalThis as unknown as Record<string, unknown>).__noumen_toJSONSchema = fn;\n}\n\n/**\n * Format a Zod validation error into a human-readable string suitable\n * for feeding back to the model as a tool_result error.\n */\nexport function formatZodValidationError(\n toolName: string,\n issues: SafeParseResult[\"error\"],\n): string {\n if (!issues || !issues.issues.length) {\n return `${toolName}: validation failed with unknown error`;\n }\n\n const parts: string[] = [];\n\n const missing = issues.issues.filter(\n (i) => i.code === \"invalid_type\" && i.message.includes(\"required\"),\n );\n const unrecognized = issues.issues.filter(\n (i) => i.code === \"unrecognized_keys\",\n );\n const other = issues.issues.filter(\n (i) =>\n !missing.includes(i) && !unrecognized.includes(i),\n );\n\n if (missing.length) {\n parts.push(\n `Missing required parameter${missing.length > 1 ? \"s\" : \"\"}: ${missing.map((m) => formatPath(m.path)).join(\", \")}`,\n );\n }\n if (unrecognized.length) {\n parts.push(\n `Unrecognized parameter${unrecognized.length > 1 ? \"s\" : \"\"}: ${unrecognized.map((u) => u.message).join(\", \")}`,\n );\n }\n for (const issue of other) {\n const path = formatPath(issue.path);\n parts.push(`${path ? path + \": \" : \"\"}${issue.message}`);\n }\n\n return `${toolName} failed due to the following ${parts.length > 1 ? \"issues\" : \"issue\"}:\\n${parts.join(\"\\n\")}`;\n}\n\nfunction formatPath(path: (string | number)[]): string {\n return path\n .map((p, i) => (typeof p === \"number\" ? `[${p}]` : i > 0 ? `.${p}` : p))\n .join(\"\");\n}\n"],"mappings":";AA2BA,IAAM,QAAQ,oBAAI,QAAgC;AAM3C,SAAS,gBAAgB,QAAuC;AACrE,QAAM,MAAM,MAAM,IAAI,MAAM;AAC5B,MAAI,IAAK,QAAO;AAEhB,QAAM,MAAO,OAAyC,OAClD,SACA;AAEJ,MAAI,CAAC,KAAK;AACR,UAAM,IAAI;AAAA,MACR;AAAA,IACF;AAAA,EACF;AAEA,MAAI;AACJ,MAAI;AAGF,UAAM,OAAO;AACb,QAAI,OAAO,KAAK,kBAAkB,YAAY;AAC5C,YAAM,SAAS,KAAK,cAAc;AAClC,YAAM,IAAI,QAAQ,MAAM;AACxB,aAAO;AAAA,IACT;AAGA,mBAAgB,WACb;AAAA,EACL,QAAQ;AAAA,EAER;AAEA,MAAI,cAAc;AAChB,UAAM,SAAS,aAAa,MAAM;AAClC,UAAM,IAAI,QAAQ,MAAM;AACxB,WAAO;AAAA,EACT;AAEA,QAAM,IAAI;AAAA,IACR;AAAA,EAEF;AACF;AAWO,SAAS,wBACd,IACM;AACN,EAAC,WAAkD,wBAAwB;AAC7E;AAMO,SAAS,yBACd,UACA,QACQ;AACR,MAAI,CAAC,UAAU,CAAC,OAAO,OAAO,QAAQ;AACpC,WAAO,GAAG,QAAQ;AAAA,EACpB;AAEA,QAAM,QAAkB,CAAC;AAEzB,QAAM,UAAU,OAAO,OAAO;AAAA,IAC5B,CAAC,MAAM,EAAE,SAAS,kBAAkB,EAAE,QAAQ,SAAS,UAAU;AAAA,EACnE;AACA,QAAM,eAAe,OAAO,OAAO;AAAA,IACjC,CAAC,MAAM,EAAE,SAAS;AAAA,EACpB;AACA,QAAM,QAAQ,OAAO,OAAO;AAAA,IAC1B,CAAC,MACC,CAAC,QAAQ,SAAS,CAAC,KAAK,CAAC,aAAa,SAAS,CAAC;AAAA,EACpD;AAEA,MAAI,QAAQ,QAAQ;AAClB,UAAM;AAAA,MACJ,6BAA6B,QAAQ,SAAS,IAAI,MAAM,EAAE,KAAK,QAAQ,IAAI,CAAC,MAAM,WAAW,EAAE,IAAI,CAAC,EAAE,KAAK,IAAI,CAAC;AAAA,IAClH;AAAA,EACF;AACA,MAAI,aAAa,QAAQ;AACvB,UAAM;AAAA,MACJ,yBAAyB,aAAa,SAAS,IAAI,MAAM,EAAE,KAAK,aAAa,IAAI,CAAC,MAAM,EAAE,OAAO,EAAE,KAAK,IAAI,CAAC;AAAA,IAC/G;AAAA,EACF;AACA,aAAW,SAAS,OAAO;AACzB,UAAM,OAAO,WAAW,MAAM,IAAI;AAClC,UAAM,KAAK,GAAG,OAAO,OAAO,OAAO,EAAE,GAAG,MAAM,OAAO,EAAE;AAAA,EACzD;AAEA,SAAO,GAAG,QAAQ,gCAAgC,MAAM,SAAS,IAAI,WAAW,OAAO;AAAA,EAAM,MAAM,KAAK,IAAI,CAAC;AAC/G;AAEA,SAAS,WAAW,MAAmC;AACrD,SAAO,KACJ,IAAI,CAAC,GAAG,MAAO,OAAO,MAAM,WAAW,IAAI,CAAC,MAAM,IAAI,IAAI,IAAI,CAAC,KAAK,CAAE,EACtE,KAAK,EAAE;AACZ;","names":[]}
@@ -0,0 +1,132 @@
1
+ // src/compact/history-snip.ts
2
+ function applySnipRemovals(entries) {
3
+ const toDelete = /* @__PURE__ */ new Set();
4
+ for (const entry of entries) {
5
+ if (entry.type === "snip-boundary" && entry.snipMetadata?.removedUuids) {
6
+ for (const uuid of entry.snipMetadata.removedUuids) {
7
+ toDelete.add(uuid);
8
+ }
9
+ }
10
+ }
11
+ if (toDelete.size === 0) {
12
+ const messages = [];
13
+ for (const entry of entries) {
14
+ if (entry.type === "message" || entry.type === "summary") {
15
+ messages.push(entry.message);
16
+ }
17
+ }
18
+ return { messages, removedCount: 0, relinkedCount: 0 };
19
+ }
20
+ const messagesMap = /* @__PURE__ */ new Map();
21
+ const ordered = [];
22
+ for (const entry of entries) {
23
+ if (entry.type === "message" || entry.type === "summary") {
24
+ const e = entry;
25
+ messagesMap.set(e.uuid, {
26
+ uuid: e.uuid,
27
+ parentUuid: e.parentUuid,
28
+ message: e.message
29
+ });
30
+ ordered.push(e.uuid);
31
+ }
32
+ }
33
+ const deletedParent = /* @__PURE__ */ new Map();
34
+ let removedCount = 0;
35
+ for (const uuid of toDelete) {
36
+ const entry = messagesMap.get(uuid);
37
+ if (!entry) continue;
38
+ deletedParent.set(uuid, entry.parentUuid);
39
+ messagesMap.delete(uuid);
40
+ removedCount++;
41
+ }
42
+ const resolve = (start) => {
43
+ const path = [];
44
+ let cur = start;
45
+ while (cur && toDelete.has(cur)) {
46
+ path.push(cur);
47
+ cur = deletedParent.get(cur);
48
+ if (cur === void 0) {
49
+ cur = null;
50
+ break;
51
+ }
52
+ }
53
+ for (const p of path) {
54
+ deletedParent.set(p, cur);
55
+ }
56
+ return cur;
57
+ };
58
+ let relinkedCount = 0;
59
+ for (const [uuid, msg] of messagesMap) {
60
+ if (!msg.parentUuid || !toDelete.has(msg.parentUuid)) continue;
61
+ const newParent = resolve(msg.parentUuid);
62
+ messagesMap.set(uuid, { ...msg, parentUuid: newParent });
63
+ relinkedCount++;
64
+ }
65
+ const result = [];
66
+ for (const uuid of ordered) {
67
+ const msg = messagesMap.get(uuid);
68
+ if (msg) {
69
+ result.push(msg.message);
70
+ }
71
+ }
72
+ return { messages: result, removedCount, relinkedCount };
73
+ }
74
+ function snipMessagesByUuids(entries, removedUuids) {
75
+ if (removedUuids.size === 0) {
76
+ return {
77
+ messages: entries.map((e) => e.message),
78
+ removedCount: 0,
79
+ relinkedCount: 0
80
+ };
81
+ }
82
+ const deletedParent = /* @__PURE__ */ new Map();
83
+ const surviving = [];
84
+ for (const entry of entries) {
85
+ if (removedUuids.has(entry.uuid)) {
86
+ deletedParent.set(entry.uuid, entry.parentUuid);
87
+ } else {
88
+ surviving.push({ ...entry });
89
+ }
90
+ }
91
+ const resolve = (start) => {
92
+ const path = [];
93
+ let cur = start;
94
+ while (cur && removedUuids.has(cur)) {
95
+ path.push(cur);
96
+ cur = deletedParent.get(cur);
97
+ if (cur === void 0) {
98
+ cur = null;
99
+ break;
100
+ }
101
+ }
102
+ for (const p of path) {
103
+ deletedParent.set(p, cur);
104
+ }
105
+ return cur;
106
+ };
107
+ let relinkedCount = 0;
108
+ for (const entry of surviving) {
109
+ if (entry.parentUuid && removedUuids.has(entry.parentUuid)) {
110
+ entry.parentUuid = resolve(entry.parentUuid);
111
+ relinkedCount++;
112
+ }
113
+ }
114
+ return {
115
+ messages: surviving.map((e) => e.message),
116
+ removedCount: removedUuids.size,
117
+ relinkedCount
118
+ };
119
+ }
120
+ function projectSnippedView(messages, snippedIndices, opts) {
121
+ if (opts?.includeSnipped || snippedIndices.size === 0) {
122
+ return messages;
123
+ }
124
+ return messages.filter((_, i) => !snippedIndices.has(i));
125
+ }
126
+
127
+ export {
128
+ applySnipRemovals,
129
+ snipMessagesByUuids,
130
+ projectSnippedView
131
+ };
132
+ //# sourceMappingURL=chunk-42PHHZUA.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/compact/history-snip.ts"],"sourcesContent":["/**\n * History snip: remove middle ranges of conversation history.\n *\n * Unlike prefix compaction (which summarizes and removes the oldest\n * messages), history snip removes specific message ranges from the middle\n * of the conversation. The JSONL transcript stays append-only — snipped\n * messages remain on disk but their UUIDs are recorded on a snip-boundary\n * entry so they're filtered out on resume.\n *\n * Parent pointers are relinked across gaps using path compression so the\n * conversation chain stays intact.\n */\n\nimport type { ChatMessage, Entry, MessageEntry, SummaryEntry } from \"../session/types.js\";\nimport type { UUID } from \"../utils/uuid.js\";\n\nexport interface SnipConfig {\n enabled: boolean;\n}\n\nexport interface SnipResult {\n messages: ChatMessage[];\n removedCount: number;\n relinkedCount: number;\n}\n\n/**\n * UUID-keyed transcript message used during snip processing.\n * Mirrors the shape we need from JSONL entries for relinking.\n */\ninterface TranscriptMessage {\n uuid: UUID;\n parentUuid: UUID | null;\n message: ChatMessage;\n}\n\n/**\n * Apply snip removals to a UUID-keyed message map.\n *\n * Ported from claude-code's `applySnipRemovals`. Walks entries looking\n * for snip-boundary entries with `snipMetadata.removedUuids`, deletes\n * those messages, and relinks parentUuid across gaps with path compression.\n */\nexport function applySnipRemovals(\n entries: Entry[],\n): { messages: ChatMessage[]; removedCount: number; relinkedCount: number } {\n // Collect all UUIDs to remove from snip-boundary entries\n const toDelete = new Set<UUID>();\n for (const entry of entries) {\n if (entry.type === \"snip-boundary\" && entry.snipMetadata?.removedUuids) {\n for (const uuid of entry.snipMetadata.removedUuids) {\n toDelete.add(uuid as UUID);\n }\n }\n }\n\n if (toDelete.size === 0) {\n // No snips — just extract messages in order\n const messages: ChatMessage[] = [];\n for (const entry of entries) {\n if (entry.type === \"message\" || entry.type === \"summary\") {\n messages.push(entry.message);\n }\n }\n return { messages, removedCount: 0, relinkedCount: 0 };\n }\n\n // Build a Map of UUID -> TranscriptMessage for relinking\n const messagesMap = new Map<UUID, TranscriptMessage>();\n const ordered: UUID[] = [];\n\n for (const entry of entries) {\n if (entry.type === \"message\" || entry.type === \"summary\") {\n const e = entry as MessageEntry | SummaryEntry;\n messagesMap.set(e.uuid, {\n uuid: e.uuid,\n parentUuid: e.parentUuid,\n message: e.message,\n });\n ordered.push(e.uuid);\n }\n }\n\n // Record parent pointers of deleted entries before removing them\n const deletedParent = new Map<UUID, UUID | null>();\n let removedCount = 0;\n for (const uuid of toDelete) {\n const entry = messagesMap.get(uuid);\n if (!entry) continue;\n deletedParent.set(uuid, entry.parentUuid);\n messagesMap.delete(uuid);\n removedCount++;\n }\n\n // Path-compression resolver: walk deleted parent chain to find a surviving ancestor\n const resolve = (start: UUID): UUID | null => {\n const path: UUID[] = [];\n let cur: UUID | null | undefined = start;\n while (cur && toDelete.has(cur)) {\n path.push(cur);\n cur = deletedParent.get(cur);\n if (cur === undefined) {\n cur = null;\n break;\n }\n }\n // Path compression: cache resolved parent for all nodes on the path\n for (const p of path) {\n deletedParent.set(p, cur);\n }\n return cur;\n };\n\n // Relink surviving messages whose parent was deleted\n let relinkedCount = 0;\n for (const [uuid, msg] of messagesMap) {\n if (!msg.parentUuid || !toDelete.has(msg.parentUuid)) continue;\n const newParent = resolve(msg.parentUuid);\n messagesMap.set(uuid, { ...msg, parentUuid: newParent });\n relinkedCount++;\n }\n\n // Rebuild ordered message array (preserving original insertion order)\n const result: ChatMessage[] = [];\n for (const uuid of ordered) {\n const msg = messagesMap.get(uuid);\n if (msg) {\n result.push(msg.message);\n }\n }\n\n return { messages: result, removedCount, relinkedCount };\n}\n\n/**\n * Snip specific messages from an in-memory message array by UUID.\n *\n * This is the in-memory operation — call this during a live thread to\n * remove messages before the next model call. The caller is responsible\n * for persisting a snip-boundary entry to the JSONL transcript.\n */\nexport function snipMessagesByUuids(\n entries: Array<{ uuid: UUID; parentUuid: UUID | null; message: ChatMessage }>,\n removedUuids: Set<UUID>,\n): SnipResult {\n if (removedUuids.size === 0) {\n return {\n messages: entries.map((e) => e.message),\n removedCount: 0,\n relinkedCount: 0,\n };\n }\n\n const deletedParent = new Map<UUID, UUID | null>();\n const surviving: Array<{ uuid: UUID; parentUuid: UUID | null; message: ChatMessage }> = [];\n\n for (const entry of entries) {\n if (removedUuids.has(entry.uuid)) {\n deletedParent.set(entry.uuid, entry.parentUuid);\n } else {\n surviving.push({ ...entry });\n }\n }\n\n const resolve = (start: UUID): UUID | null => {\n const path: UUID[] = [];\n let cur: UUID | null | undefined = start;\n while (cur && removedUuids.has(cur)) {\n path.push(cur);\n cur = deletedParent.get(cur);\n if (cur === undefined) {\n cur = null;\n break;\n }\n }\n for (const p of path) {\n deletedParent.set(p, cur);\n }\n return cur;\n };\n\n let relinkedCount = 0;\n for (const entry of surviving) {\n if (entry.parentUuid && removedUuids.has(entry.parentUuid)) {\n entry.parentUuid = resolve(entry.parentUuid);\n relinkedCount++;\n }\n }\n\n return {\n messages: surviving.map((e) => e.message),\n removedCount: removedUuids.size,\n relinkedCount,\n };\n}\n\n/**\n * Project a \"snipped view\" of messages for the model.\n *\n * Filters out messages marked as snipped. Use the `includeSnipped` option\n * to get the full scrollback for UI display.\n */\nexport function projectSnippedView(\n messages: ChatMessage[],\n snippedIndices: Set<number>,\n opts?: { includeSnipped?: boolean },\n): ChatMessage[] {\n if (opts?.includeSnipped || snippedIndices.size === 0) {\n return messages;\n }\n return messages.filter((_, i) => !snippedIndices.has(i));\n}\n"],"mappings":"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","names":[]}