@theokit/sdk 4.30.0 → 4.31.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 (77) hide show
  1. package/CHANGELOG.md +43 -0
  2. package/dist/{agent-LD76RI74.cjs → agent-6GQBOHHA.cjs} +8 -8
  3. package/dist/{agent-LD76RI74.cjs.map → agent-6GQBOHHA.cjs.map} +1 -1
  4. package/dist/{agent-7YUGJJTU.js → agent-DY5LGZ5E.js} +7 -7
  5. package/dist/{agent-7YUGJJTU.js.map → agent-DY5LGZ5E.js.map} +1 -1
  6. package/dist/agent.d.ts +15 -2
  7. package/dist/{chunk-5YCAR23S.js → chunk-4JWZRASX.js} +3 -3
  8. package/dist/{chunk-5YCAR23S.js.map → chunk-4JWZRASX.js.map} +1 -1
  9. package/dist/{chunk-GWMQ5CS3.cjs → chunk-CYTAM3E6.cjs} +70 -40
  10. package/dist/chunk-CYTAM3E6.cjs.map +1 -0
  11. package/dist/{chunk-NG6B2PMA.cjs → chunk-FDGRQQWX.cjs} +5 -5
  12. package/dist/{chunk-NG6B2PMA.cjs.map → chunk-FDGRQQWX.cjs.map} +1 -1
  13. package/dist/{chunk-ISZ3MBUD.js → chunk-FZ75EZR5.js} +41 -11
  14. package/dist/chunk-FZ75EZR5.js.map +1 -0
  15. package/dist/chunk-ICSCKB3N.js +140 -0
  16. package/dist/chunk-ICSCKB3N.js.map +1 -0
  17. package/dist/{chunk-U6QGZHPN.js → chunk-PORDVVJS.js} +5 -6
  18. package/dist/chunk-PORDVVJS.js.map +1 -0
  19. package/dist/{chunk-NRSH7RJY.js → chunk-TLG444A6.js} +61 -13
  20. package/dist/chunk-TLG444A6.js.map +1 -0
  21. package/dist/{chunk-2HRYBRD7.cjs → chunk-U447MTG4.cjs} +5 -6
  22. package/dist/chunk-U447MTG4.cjs.map +1 -0
  23. package/dist/{chunk-2MF3IE2D.cjs → chunk-UKNMWCPZ.cjs} +63 -15
  24. package/dist/chunk-UKNMWCPZ.cjs.map +1 -0
  25. package/dist/{chunk-SQLZ7ONU.js → chunk-VUXLNVX7.js} +3 -3
  26. package/dist/{chunk-SQLZ7ONU.js.map → chunk-VUXLNVX7.js.map} +1 -1
  27. package/dist/{chunk-HK7ZHSAX.cjs → chunk-WQEQCJTZ.cjs} +64 -3
  28. package/dist/chunk-WQEQCJTZ.cjs.map +1 -0
  29. package/dist/{chunk-YU6KON2I.cjs → chunk-XJT5VACT.cjs} +3 -3
  30. package/dist/{chunk-YU6KON2I.cjs.map → chunk-XJT5VACT.cjs.map} +1 -1
  31. package/dist/{compact-session-OO7NVWPB.cjs → compact-session-2BFNMENR.cjs} +11 -11
  32. package/dist/{compact-session-OO7NVWPB.cjs.map → compact-session-2BFNMENR.cjs.map} +1 -1
  33. package/dist/{compact-session-OO2GD76G.js → compact-session-2JONXHLR.js} +3 -3
  34. package/dist/{compact-session-OO2GD76G.js.map → compact-session-2JONXHLR.js.map} +1 -1
  35. package/dist/cron.cjs +7 -7
  36. package/dist/cron.js +6 -6
  37. package/dist/eval.cjs +10 -11
  38. package/dist/eval.cjs.map +1 -1
  39. package/dist/eval.js +6 -7
  40. package/dist/eval.js.map +1 -1
  41. package/dist/fs-session-store-26WVVMC4.cjs +17 -0
  42. package/dist/{fs-session-store-KAUQYSGI.cjs.map → fs-session-store-26WVVMC4.cjs.map} +1 -1
  43. package/dist/fs-session-store-7AEI4STY.js +8 -0
  44. package/dist/{fs-session-store-ZKB5NN37.js.map → fs-session-store-7AEI4STY.js.map} +1 -1
  45. package/dist/index.cjs +28 -28
  46. package/dist/index.d.cts +15 -2
  47. package/dist/index.d.ts +15 -2
  48. package/dist/index.js +8 -8
  49. package/dist/{inject-session-6MJUSGZP.cjs → inject-session-MIFEKATN.cjs} +4 -4
  50. package/dist/{inject-session-6MJUSGZP.cjs.map → inject-session-MIFEKATN.cjs.map} +1 -1
  51. package/dist/{inject-session-KOFHS5K3.js → inject-session-NNSCCIVP.js} +3 -3
  52. package/dist/{inject-session-KOFHS5K3.js.map → inject-session-NNSCCIVP.js.map} +1 -1
  53. package/dist/internal/llm/retrying-client.d.ts +29 -0
  54. package/dist/internal/persistence/index.cjs +18 -19
  55. package/dist/internal/persistence/index.cjs.map +1 -1
  56. package/dist/internal/persistence/index.js +1 -2
  57. package/dist/internal/persistence/index.js.map +1 -1
  58. package/dist/persistence.cjs +10 -11
  59. package/dist/persistence.cjs.map +1 -1
  60. package/dist/persistence.js +1 -2
  61. package/dist/persistence.js.map +1 -1
  62. package/package.json +1 -1
  63. package/dist/chunk-2HRYBRD7.cjs.map +0 -1
  64. package/dist/chunk-2MF3IE2D.cjs.map +0 -1
  65. package/dist/chunk-C7PICHRF.cjs +0 -68
  66. package/dist/chunk-C7PICHRF.cjs.map +0 -1
  67. package/dist/chunk-GWMQ5CS3.cjs.map +0 -1
  68. package/dist/chunk-HK7ZHSAX.cjs.map +0 -1
  69. package/dist/chunk-HZQEDNF6.js +0 -66
  70. package/dist/chunk-HZQEDNF6.js.map +0 -1
  71. package/dist/chunk-ISZ3MBUD.js.map +0 -1
  72. package/dist/chunk-NRSH7RJY.js.map +0 -1
  73. package/dist/chunk-R6ZP6KNB.js +0 -80
  74. package/dist/chunk-R6ZP6KNB.js.map +0 -1
  75. package/dist/chunk-U6QGZHPN.js.map +0 -1
  76. package/dist/fs-session-store-KAUQYSGI.cjs +0 -17
  77. package/dist/fs-session-store-ZKB5NN37.js +0 -8
package/dist/index.cjs CHANGED
@@ -8,14 +8,14 @@ require('./chunk-EPYZOCOL.cjs');
8
8
  var chunkZ2OC3UIW_cjs = require('./chunk-Z2OC3UIW.cjs');
9
9
  require('./chunk-BWT67BI4.cjs');
10
10
  require('./chunk-PNVDQL5Y.cjs');
11
- var chunkNG6B2PMA_cjs = require('./chunk-NG6B2PMA.cjs');
12
- var chunkGWMQ5CS3_cjs = require('./chunk-GWMQ5CS3.cjs');
11
+ var chunkFDGRQQWX_cjs = require('./chunk-FDGRQQWX.cjs');
12
+ var chunkCYTAM3E6_cjs = require('./chunk-CYTAM3E6.cjs');
13
13
  require('./chunk-BV2MWEMV.cjs');
14
14
  var chunkMZ5ZRORA_cjs = require('./chunk-MZ5ZRORA.cjs');
15
- require('./chunk-YU6KON2I.cjs');
15
+ require('./chunk-XJT5VACT.cjs');
16
16
  require('./chunk-BUUUWQMB.cjs');
17
- require('./chunk-2HRYBRD7.cjs');
18
- var chunk2MF3IE2D_cjs = require('./chunk-2MF3IE2D.cjs');
17
+ require('./chunk-U447MTG4.cjs');
18
+ var chunkUKNMWCPZ_cjs = require('./chunk-UKNMWCPZ.cjs');
19
19
  require('./chunk-LUSXDZPV.cjs');
20
20
  require('./chunk-IT3PWBW4.cjs');
21
21
  var chunkJLMXKTBX_cjs = require('./chunk-JLMXKTBX.cjs');
@@ -30,7 +30,7 @@ require('./chunk-YPEPCZHF.cjs');
30
30
  require('./chunk-VJ26EKGJ.cjs');
31
31
  require('./chunk-GIW4L6HY.cjs');
32
32
  require('./chunk-7S7KKUO6.cjs');
33
- require('./chunk-C7PICHRF.cjs');
33
+ require('./chunk-WQEQCJTZ.cjs');
34
34
  require('./chunk-JD74LN7R.cjs');
35
35
  var chunkYLQQX5W2_cjs = require('./chunk-YLQQX5W2.cjs');
36
36
  require('./chunk-4SXHEZIV.cjs');
@@ -57,8 +57,8 @@ var fs = require('fs');
57
57
  // src/agent-factory.ts
58
58
  function createAgentFactory(common) {
59
59
  return {
60
- forSession: (agentId, overrides) => chunkGWMQ5CS3_cjs.Agent.create(mergeAgentOptions(common, overrides, agentId)),
61
- getOrCreate: (agentId, overrides) => chunkGWMQ5CS3_cjs.Agent.getOrCreate(agentId, mergeAgentOptions(common, overrides, agentId))
60
+ forSession: (agentId, overrides) => chunkCYTAM3E6_cjs.Agent.create(mergeAgentOptions(common, overrides, agentId)),
61
+ getOrCreate: (agentId, overrides) => chunkCYTAM3E6_cjs.Agent.getOrCreate(agentId, mergeAgentOptions(common, overrides, agentId))
62
62
  };
63
63
  }
64
64
  function mergeAgentOptions(common, overrides, agentId) {
@@ -1145,7 +1145,7 @@ var Memory = {
1145
1145
  return await peer.IndexManager.open(openArgs);
1146
1146
  }
1147
1147
  const { IndexManager } = await import('./index-manager-H7HUMW52.cjs');
1148
- openArgs.embedding = await resolveEmbedding(opts.embedding, chunkGWMQ5CS3_cjs.MEMORY_EMBEDDING_ADAPTERS);
1148
+ openArgs.embedding = await resolveEmbedding(opts.embedding, chunkCYTAM3E6_cjs.MEMORY_EMBEDDING_ADAPTERS);
1149
1149
  return await IndexManager.open(openArgs);
1150
1150
  },
1151
1151
  /**
@@ -1156,7 +1156,7 @@ var Memory = {
1156
1156
  */
1157
1157
  async runDreamingSweep(opts) {
1158
1158
  const peer = await tryLoadSdkMemoryPeer();
1159
- const catalog = peer !== null ? peer.MEMORY_EMBEDDING_ADAPTERS : chunkGWMQ5CS3_cjs.MEMORY_EMBEDDING_ADAPTERS;
1159
+ const catalog = peer !== null ? peer.MEMORY_EMBEDDING_ADAPTERS : chunkCYTAM3E6_cjs.MEMORY_EMBEDDING_ADAPTERS;
1160
1160
  const sweepArgs = await buildDreamingSweepArgs(opts, catalog);
1161
1161
  const result = peer !== null ? (
1162
1162
  // biome-ignore lint/suspicious/noExplicitAny: peer is dynamically loaded — structural compat ensured by sdk-memory
@@ -1578,7 +1578,7 @@ function ehAgenteConstruido(m) {
1578
1578
  return typeof m.send === "function";
1579
1579
  }
1580
1580
  async function materializar(def, indice) {
1581
- const { Agent: Agent2 } = await import('./agent-LD76RI74.cjs');
1581
+ const { Agent: Agent2 } = await import('./agent-6GQBOHHA.cjs');
1582
1582
  return Agent2.create({
1583
1583
  // `AgentDefinition.model` admite o sentinel `'inherit'`, que não é um id de modelo. Herdar
1584
1584
  // aqui significa "não declare nada e deixe o default valer" — passar o literal adiante criaria
@@ -1720,7 +1720,7 @@ var FIXTURE_USER = {
1720
1720
  };
1721
1721
  var FIXTURE_MODELS = [
1722
1722
  {
1723
- id: chunkGWMQ5CS3_cjs.DEFAULT_AGENTIC_MODEL_ID,
1723
+ id: chunkCYTAM3E6_cjs.DEFAULT_AGENTIC_MODEL_ID,
1724
1724
  name: "Gemini 2.0 Flash",
1725
1725
  displayName: "Gemini 2.0 Flash",
1726
1726
  parameters: [
@@ -1796,7 +1796,7 @@ async function listLocalModelsViaOpenAiCompat(baseUrl) {
1796
1796
  try {
1797
1797
  response = await fetch(url, { method: "GET" });
1798
1798
  } catch (fetchErr) {
1799
- const mapped = chunk2MF3IE2D_cjs.mapOllamaTransportError({
1799
+ const mapped = chunkUKNMWCPZ_cjs.mapOllamaTransportError({
1800
1800
  providerId: "ollama",
1801
1801
  cause: fetchErr,
1802
1802
  endpoint: "/v1/models"
@@ -1814,7 +1814,7 @@ async function listLocalModelsViaOpenAiCompat(baseUrl) {
1814
1814
  body = JSON.parse(text);
1815
1815
  } catch {
1816
1816
  }
1817
- const mapped = chunk2MF3IE2D_cjs.mapOllamaHttpError({
1817
+ const mapped = chunkUKNMWCPZ_cjs.mapOllamaHttpError({
1818
1818
  providerId: "ollama",
1819
1819
  status: response.status,
1820
1820
  body,
@@ -1928,7 +1928,7 @@ var Theokit = class {
1928
1928
  envVars: p.envVars
1929
1929
  }));
1930
1930
  },
1931
- embeddingAdapters: () => Object.entries(chunkGWMQ5CS3_cjs.MEMORY_EMBEDDING_ADAPTERS).map(([id, adapter]) => ({
1931
+ embeddingAdapters: () => Object.entries(chunkCYTAM3E6_cjs.MEMORY_EMBEDDING_ADAPTERS).map(([id, adapter]) => ({
1932
1932
  id,
1933
1933
  transport: adapter.transport,
1934
1934
  defaultModel: adapter.defaultModel
@@ -1946,7 +1946,7 @@ var Theokit = class {
1946
1946
  };
1947
1947
  async function maybeListLocalModels(providerName) {
1948
1948
  chunkD42XHI4O_cjs.registerBuiltins();
1949
- await chunk2MF3IE2D_cjs.discoverProviderPlugins();
1949
+ await chunkUKNMWCPZ_cjs.discoverProviderPlugins();
1950
1950
  const profile = chunkD42XHI4O_cjs.getProviderProfile(providerName);
1951
1951
  if (profile === void 0) return void 0;
1952
1952
  if (profile.authType !== "none") return void 0;
@@ -1960,17 +1960,17 @@ function resolveLocalProviderBaseUrl(providerName, fallback) {
1960
1960
  return fallback;
1961
1961
  }
1962
1962
  async function executeCatalogRequest(request) {
1963
- const apiKey = chunkGWMQ5CS3_cjs.resolveApiKey(request.apiKey);
1963
+ const apiKey = chunkCYTAM3E6_cjs.resolveApiKey(request.apiKey);
1964
1964
  if (apiKey === void 0) {
1965
1965
  throw new chunkA44COQJJ_cjs.AuthenticationError("Missing API key", { code: "missing_api_key" });
1966
1966
  }
1967
- if (chunkGWMQ5CS3_cjs.shouldUseFixtureMode(apiKey)) {
1967
+ if (chunkCYTAM3E6_cjs.shouldUseFixtureMode(apiKey)) {
1968
1968
  return request.fixture;
1969
1969
  }
1970
- if (!chunkGWMQ5CS3_cjs.isFixtureApiKey(apiKey) && process.env.THEOKIT_API_BASE_URL === void 0) {
1970
+ if (!chunkCYTAM3E6_cjs.isFixtureApiKey(apiKey) && process.env.THEOKIT_API_BASE_URL === void 0) {
1971
1971
  throw new chunkA44COQJJ_cjs.AuthenticationError("Invalid API key", { code: "authentication_error" });
1972
1972
  }
1973
- return chunkGWMQ5CS3_cjs.httpRequest(request.path, { apiKey });
1973
+ return chunkCYTAM3E6_cjs.httpRequest(request.path, { apiKey });
1974
1974
  }
1975
1975
 
1976
1976
  // src/trajectory-helpers.ts
@@ -2086,35 +2086,35 @@ Object.defineProperty(exports, "GenerateObjectError", {
2086
2086
  });
2087
2087
  Object.defineProperty(exports, "Cron", {
2088
2088
  enumerable: true,
2089
- get: function () { return chunkNG6B2PMA_cjs.Cron; }
2089
+ get: function () { return chunkFDGRQQWX_cjs.Cron; }
2090
2090
  });
2091
2091
  Object.defineProperty(exports, "Agent", {
2092
2092
  enumerable: true,
2093
- get: function () { return chunkGWMQ5CS3_cjs.Agent; }
2093
+ get: function () { return chunkCYTAM3E6_cjs.Agent; }
2094
2094
  });
2095
2095
  Object.defineProperty(exports, "AgentBuilder", {
2096
2096
  enumerable: true,
2097
- get: function () { return chunkGWMQ5CS3_cjs.AgentBuilder; }
2097
+ get: function () { return chunkCYTAM3E6_cjs.AgentBuilder; }
2098
2098
  });
2099
2099
  Object.defineProperty(exports, "Tool", {
2100
2100
  enumerable: true,
2101
- get: function () { return chunkGWMQ5CS3_cjs.Tool; }
2101
+ get: function () { return chunkCYTAM3E6_cjs.Tool; }
2102
2102
  });
2103
2103
  Object.defineProperty(exports, "ToolError", {
2104
2104
  enumerable: true,
2105
- get: function () { return chunkGWMQ5CS3_cjs.ToolError; }
2105
+ get: function () { return chunkCYTAM3E6_cjs.ToolError; }
2106
2106
  });
2107
2107
  Object.defineProperty(exports, "UsageAccumulator", {
2108
2108
  enumerable: true,
2109
- get: function () { return chunkGWMQ5CS3_cjs.UsageAccumulator; }
2109
+ get: function () { return chunkCYTAM3E6_cjs.UsageAccumulator; }
2110
2110
  });
2111
2111
  Object.defineProperty(exports, "computeCost", {
2112
2112
  enumerable: true,
2113
- get: function () { return chunkGWMQ5CS3_cjs.computeCost; }
2113
+ get: function () { return chunkCYTAM3E6_cjs.computeCost; }
2114
2114
  });
2115
2115
  Object.defineProperty(exports, "getPricingEntry", {
2116
2116
  enumerable: true,
2117
- get: function () { return chunkGWMQ5CS3_cjs.getPricingEntry; }
2117
+ get: function () { return chunkCYTAM3E6_cjs.getPricingEntry; }
2118
2118
  });
2119
2119
  Object.defineProperty(exports, "emitRunEvent", {
2120
2120
  enumerable: true,
package/dist/index.d.cts CHANGED
@@ -590,8 +590,21 @@ declare class Agent {
590
590
  * Caveats:
591
591
  * - The function-level `agentId` always wins over `options.agentId`.
592
592
  * - Options differ between calls? Last-call-wins for this handle (matches `Agent.resume`).
593
- * - Disposed agents are NOT auto-deleted from the registry. To force a fresh
594
- * agent, call `Agent.delete(agentId)` first.
593
+ * - A DISPOSED agent is replaced automatically. `dispose()` evicts the id from the
594
+ * live cache (`liveAgentRegistry.forget`), so the next `getOrCreate(id)` builds a
595
+ * fresh handle — no `Agent.delete(agentId)` needed.
596
+ *
597
+ * This bullet used to say the opposite ("Disposed agents are NOT auto-deleted...
598
+ * call `Agent.delete(agentId)` first"). It was measured false in M91:
599
+ * `tests/m91-getorcreate-apos-dispose.test.ts` builds an agent, disposes it, and
600
+ * gets a different instance back. The claim was about the PERSISTENT registry and
601
+ * read as being about the live cache — and consumers built around the wrong half.
602
+ * The agent-builder's M85 interrupt rotates the session id to work around a
603
+ * constraint that does not exist.
604
+ *
605
+ * - `close()` marks the handle disposed WITHOUT evicting the cache entry. It is
606
+ * internal and unused today; if it becomes reachable, this bullet stops being true
607
+ * for that path.
595
608
  *
596
609
  * @public
597
610
  */
package/dist/index.d.ts CHANGED
@@ -590,8 +590,21 @@ declare class Agent {
590
590
  * Caveats:
591
591
  * - The function-level `agentId` always wins over `options.agentId`.
592
592
  * - Options differ between calls? Last-call-wins for this handle (matches `Agent.resume`).
593
- * - Disposed agents are NOT auto-deleted from the registry. To force a fresh
594
- * agent, call `Agent.delete(agentId)` first.
593
+ * - A DISPOSED agent is replaced automatically. `dispose()` evicts the id from the
594
+ * live cache (`liveAgentRegistry.forget`), so the next `getOrCreate(id)` builds a
595
+ * fresh handle — no `Agent.delete(agentId)` needed.
596
+ *
597
+ * This bullet used to say the opposite ("Disposed agents are NOT auto-deleted...
598
+ * call `Agent.delete(agentId)` first"). It was measured false in M91:
599
+ * `tests/m91-getorcreate-apos-dispose.test.ts` builds an agent, disposes it, and
600
+ * gets a different instance back. The claim was about the PERSISTENT registry and
601
+ * read as being about the live cache — and consumers built around the wrong half.
602
+ * The agent-builder's M85 interrupt rotates the session id to work around a
603
+ * constraint that does not exist.
604
+ *
605
+ * - `close()` marks the handle disposed WITHOUT evicting the cache entry. It is
606
+ * internal and unused today; if it becomes reachable, this bullet stops being true
607
+ * for that path.
595
608
  *
596
609
  * @public
597
610
  */
package/dist/index.js CHANGED
@@ -6,16 +6,16 @@ import './chunk-GJAGKFTR.js';
6
6
  import { Workflow, agentStep } from './chunk-BFWPZMG7.js';
7
7
  import './chunk-UVNG67DG.js';
8
8
  import './chunk-CAH3G4IS.js';
9
- export { Cron } from './chunk-5YCAR23S.js';
10
- import { MEMORY_EMBEDDING_ADAPTERS, resolveApiKey, shouldUseFixtureMode, isFixtureApiKey, httpRequest, DEFAULT_AGENTIC_MODEL_ID, Agent } from './chunk-ISZ3MBUD.js';
11
- export { Agent, AgentBuilder, Tool, ToolError, UsageAccumulator, computeCost, getPricingEntry } from './chunk-ISZ3MBUD.js';
9
+ export { Cron } from './chunk-4JWZRASX.js';
10
+ import { MEMORY_EMBEDDING_ADAPTERS, resolveApiKey, shouldUseFixtureMode, isFixtureApiKey, httpRequest, DEFAULT_AGENTIC_MODEL_ID, Agent } from './chunk-FZ75EZR5.js';
11
+ export { Agent, AgentBuilder, Tool, ToolError, UsageAccumulator, computeCost, getPricingEntry } from './chunk-FZ75EZR5.js';
12
12
  import './chunk-2SFBB54R.js';
13
13
  import { configure, submit, list, get, cancel, subscribe } from './chunk-HRA3CPGG.js';
14
14
  export { emitRunEvent } from './chunk-HRA3CPGG.js';
15
- import './chunk-SQLZ7ONU.js';
15
+ import './chunk-VUXLNVX7.js';
16
16
  import './chunk-K2BQQ445.js';
17
- import './chunk-U6QGZHPN.js';
18
- import { discoverProviderPlugins, mapOllamaTransportError, mapOllamaHttpError } from './chunk-NRSH7RJY.js';
17
+ import './chunk-PORDVVJS.js';
18
+ import { discoverProviderPlugins, mapOllamaTransportError, mapOllamaHttpError } from './chunk-TLG444A6.js';
19
19
  import './chunk-6CLRANZA.js';
20
20
  import './chunk-EEZ7CFMM.js';
21
21
  import { lanceStoragePath, LanceIndex, readFactsFromMarkdown, defaultIndexPath, openMemoryDb, memoryDir } from './chunk-XAUBQMQU.js';
@@ -30,7 +30,7 @@ import './chunk-UJ7IQJAG.js';
30
30
  import './chunk-7AD3ZTZL.js';
31
31
  import './chunk-V4XRLPEF.js';
32
32
  import './chunk-5PZMMF4H.js';
33
- import './chunk-HZQEDNF6.js';
33
+ import './chunk-ICSCKB3N.js';
34
34
  import './chunk-77FOZCOT.js';
35
35
  import { withCwdMutex } from './chunk-2XLKLVVR.js';
36
36
  export { withCwdMutex } from './chunk-2XLKLVVR.js';
@@ -1580,7 +1580,7 @@ function ehAgenteConstruido(m) {
1580
1580
  return typeof m.send === "function";
1581
1581
  }
1582
1582
  async function materializar(def, indice) {
1583
- const { Agent: Agent2 } = await import('./agent-7YUGJJTU.js');
1583
+ const { Agent: Agent2 } = await import('./agent-DY5LGZ5E.js');
1584
1584
  return Agent2.create({
1585
1585
  // `AgentDefinition.model` admite o sentinel `'inherit'`, que não é um id de modelo. Herdar
1586
1586
  // aqui significa "não declare nada e deixe o default valer" — passar o literal adiante criaria
@@ -1,6 +1,6 @@
1
1
  'use strict';
2
2
 
3
- var chunkYU6KON2I_cjs = require('./chunk-YU6KON2I.cjs');
3
+ var chunkXJT5VACT_cjs = require('./chunk-XJT5VACT.cjs');
4
4
  var chunkIT3PWBW4_cjs = require('./chunk-IT3PWBW4.cjs');
5
5
  var chunk4SXHEZIV_cjs = require('./chunk-4SXHEZIV.cjs');
6
6
  require('./chunk-TIZ4TS5V.cjs');
@@ -8,7 +8,7 @@ require('./chunk-BEURCLDV.cjs');
8
8
 
9
9
  // src/internal/session/inject-session.ts
10
10
  async function injectSessionTurn(opts) {
11
- await chunkYU6KON2I_cjs.enqueueSessionWrite(opts.loc.cwd, opts.loc.agentId, async () => {
11
+ await chunkXJT5VACT_cjs.enqueueSessionWrite(opts.loc.cwd, opts.loc.agentId, async () => {
12
12
  const prior = await opts.store.readRecords(opts.loc.agentId);
13
13
  const transcript = chunk4SXHEZIV_cjs.SessionTranscript.fromRecords(prior, {
14
14
  cwd: opts.loc.cwd,
@@ -23,5 +23,5 @@ async function injectSessionTurn(opts) {
23
23
  }
24
24
 
25
25
  exports.injectSessionTurn = injectSessionTurn;
26
- //# sourceMappingURL=inject-session-6MJUSGZP.cjs.map
27
- //# sourceMappingURL=inject-session-6MJUSGZP.cjs.map
26
+ //# sourceMappingURL=inject-session-MIFEKATN.cjs.map
27
+ //# sourceMappingURL=inject-session-MIFEKATN.cjs.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/internal/session/inject-session.ts"],"names":["enqueueSessionWrite","SessionTranscript","invalidateSessionCache"],"mappings":";;;;;;;;;AAWA,eAAsB,kBAAkB,IAAA,EAMtB;AAChB,EAAA,MAAMA,sCAAoB,IAAA,CAAK,GAAA,CAAI,KAAK,IAAA,CAAK,GAAA,CAAI,SAAS,YAAY;AACpE,IAAA,MAAM,QAAQ,MAAM,IAAA,CAAK,MAAM,WAAA,CAAY,IAAA,CAAK,IAAI,OAAO,CAAA;AAC3D,IAAA,MAAM,UAAA,GAAaC,mCAAA,CAAkB,WAAA,CAAY,KAAA,EAAO;AAAA,MACtD,GAAA,EAAK,KAAK,GAAA,CAAI,GAAA;AAAA,MACd,WAAW,IAAA,CAAK,SAAA;AAAA,MAChB,KAAA,EAAO,IAAA,CAAK,GAAA,CAAI,KAAA,IAAS;AAAA,KAC1B,CAAA;AACD,IAAA,UAAA,CAAW,cAAA,CAAe,KAAK,QAAQ,CAAA;AACvC,IAAA,UAAA,CAAW,mBAAA,CAAoB,EAAE,IAAA,EAAM,IAAA,CAAK,eAAe,CAAA;AAC3D,IAAA,MAAM,IAAA,CAAK,KAAA,CAAM,aAAA,CAAc,IAAA,CAAK,GAAA,CAAI,OAAA,EAAS,UAAA,CAAW,OAAA,EAAQ,CAAE,KAAA,CAAM,KAAA,CAAM,MAAM,CAAC,CAAA;AACzF,IAAAC,wCAAA,CAAuB,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,IAAA,CAAK,IAAI,OAAO,CAAA;AAAA,EACvD,CAAC,CAAA;AACH","file":"inject-session-6MJUSGZP.cjs","sourcesContent":["/**\n * M51 (agent-builder) — inject a SYNTHETIC user+assistant pair into a session's persisted transcript\n * WITHOUT running an LLM turn. This is the Codex review-exit mechanism (`exit_success.xml` appended to\n * the parent thread history so follow-ups like \"fix finding 2\" work): the pair chains onto the DAG\n * leaf (M50 pattern) and the in-memory cache is invalidated so the NEXT send re-hydrates with it.\n */\nimport type { SessionStore } from \"../../types/session-store.js\";\nimport { SessionTranscript } from \"../persistence/session-transcript.js\";\nimport { enqueueSessionWrite, invalidateSessionCache } from \"./agent-session.js\";\nimport type { CompactLocation } from \"./compact-session.js\";\n\nexport async function injectSessionTurn(opts: {\n store: SessionStore;\n loc: CompactLocation;\n sessionId: string;\n userText: string;\n assistantText: string;\n}): Promise<void> {\n await enqueueSessionWrite(opts.loc.cwd, opts.loc.agentId, async () => {\n const prior = await opts.store.readRecords(opts.loc.agentId);\n const transcript = SessionTranscript.fromRecords(prior, {\n cwd: opts.loc.cwd,\n sessionId: opts.sessionId,\n model: opts.loc.model ?? \"unknown\",\n });\n transcript.appendUserTurn(opts.userText);\n transcript.appendAssistantTurn({ text: opts.assistantText });\n await opts.store.appendRecords(opts.loc.agentId, transcript.records().slice(prior.length));\n invalidateSessionCache(opts.loc.cwd, opts.loc.agentId);\n });\n}\n"]}
1
+ {"version":3,"sources":["../src/internal/session/inject-session.ts"],"names":["enqueueSessionWrite","SessionTranscript","invalidateSessionCache"],"mappings":";;;;;;;;;AAWA,eAAsB,kBAAkB,IAAA,EAMtB;AAChB,EAAA,MAAMA,sCAAoB,IAAA,CAAK,GAAA,CAAI,KAAK,IAAA,CAAK,GAAA,CAAI,SAAS,YAAY;AACpE,IAAA,MAAM,QAAQ,MAAM,IAAA,CAAK,MAAM,WAAA,CAAY,IAAA,CAAK,IAAI,OAAO,CAAA;AAC3D,IAAA,MAAM,UAAA,GAAaC,mCAAA,CAAkB,WAAA,CAAY,KAAA,EAAO;AAAA,MACtD,GAAA,EAAK,KAAK,GAAA,CAAI,GAAA;AAAA,MACd,WAAW,IAAA,CAAK,SAAA;AAAA,MAChB,KAAA,EAAO,IAAA,CAAK,GAAA,CAAI,KAAA,IAAS;AAAA,KAC1B,CAAA;AACD,IAAA,UAAA,CAAW,cAAA,CAAe,KAAK,QAAQ,CAAA;AACvC,IAAA,UAAA,CAAW,mBAAA,CAAoB,EAAE,IAAA,EAAM,IAAA,CAAK,eAAe,CAAA;AAC3D,IAAA,MAAM,IAAA,CAAK,KAAA,CAAM,aAAA,CAAc,IAAA,CAAK,GAAA,CAAI,OAAA,EAAS,UAAA,CAAW,OAAA,EAAQ,CAAE,KAAA,CAAM,KAAA,CAAM,MAAM,CAAC,CAAA;AACzF,IAAAC,wCAAA,CAAuB,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,IAAA,CAAK,IAAI,OAAO,CAAA;AAAA,EACvD,CAAC,CAAA;AACH","file":"inject-session-MIFEKATN.cjs","sourcesContent":["/**\n * M51 (agent-builder) — inject a SYNTHETIC user+assistant pair into a session's persisted transcript\n * WITHOUT running an LLM turn. This is the Codex review-exit mechanism (`exit_success.xml` appended to\n * the parent thread history so follow-ups like \"fix finding 2\" work): the pair chains onto the DAG\n * leaf (M50 pattern) and the in-memory cache is invalidated so the NEXT send re-hydrates with it.\n */\nimport type { SessionStore } from \"../../types/session-store.js\";\nimport { SessionTranscript } from \"../persistence/session-transcript.js\";\nimport { enqueueSessionWrite, invalidateSessionCache } from \"./agent-session.js\";\nimport type { CompactLocation } from \"./compact-session.js\";\n\nexport async function injectSessionTurn(opts: {\n store: SessionStore;\n loc: CompactLocation;\n sessionId: string;\n userText: string;\n assistantText: string;\n}): Promise<void> {\n await enqueueSessionWrite(opts.loc.cwd, opts.loc.agentId, async () => {\n const prior = await opts.store.readRecords(opts.loc.agentId);\n const transcript = SessionTranscript.fromRecords(prior, {\n cwd: opts.loc.cwd,\n sessionId: opts.sessionId,\n model: opts.loc.model ?? \"unknown\",\n });\n transcript.appendUserTurn(opts.userText);\n transcript.appendAssistantTurn({ text: opts.assistantText });\n await opts.store.appendRecords(opts.loc.agentId, transcript.records().slice(prior.length));\n invalidateSessionCache(opts.loc.cwd, opts.loc.agentId);\n });\n}\n"]}
@@ -1,4 +1,4 @@
1
- import { enqueueSessionWrite } from './chunk-SQLZ7ONU.js';
1
+ import { enqueueSessionWrite } from './chunk-VUXLNVX7.js';
2
2
  import { invalidateSessionCache } from './chunk-EEZ7CFMM.js';
3
3
  import { SessionTranscript } from './chunk-ZZWTY3RX.js';
4
4
  import './chunk-S2BBRVQX.js';
@@ -21,5 +21,5 @@ async function injectSessionTurn(opts) {
21
21
  }
22
22
 
23
23
  export { injectSessionTurn };
24
- //# sourceMappingURL=inject-session-KOFHS5K3.js.map
25
- //# sourceMappingURL=inject-session-KOFHS5K3.js.map
24
+ //# sourceMappingURL=inject-session-NNSCCIVP.js.map
25
+ //# sourceMappingURL=inject-session-NNSCCIVP.js.map
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/internal/session/inject-session.ts"],"names":[],"mappings":";;;;;;;AAWA,eAAsB,kBAAkB,IAAA,EAMtB;AAChB,EAAA,MAAM,oBAAoB,IAAA,CAAK,GAAA,CAAI,KAAK,IAAA,CAAK,GAAA,CAAI,SAAS,YAAY;AACpE,IAAA,MAAM,QAAQ,MAAM,IAAA,CAAK,MAAM,WAAA,CAAY,IAAA,CAAK,IAAI,OAAO,CAAA;AAC3D,IAAA,MAAM,UAAA,GAAa,iBAAA,CAAkB,WAAA,CAAY,KAAA,EAAO;AAAA,MACtD,GAAA,EAAK,KAAK,GAAA,CAAI,GAAA;AAAA,MACd,WAAW,IAAA,CAAK,SAAA;AAAA,MAChB,KAAA,EAAO,IAAA,CAAK,GAAA,CAAI,KAAA,IAAS;AAAA,KAC1B,CAAA;AACD,IAAA,UAAA,CAAW,cAAA,CAAe,KAAK,QAAQ,CAAA;AACvC,IAAA,UAAA,CAAW,mBAAA,CAAoB,EAAE,IAAA,EAAM,IAAA,CAAK,eAAe,CAAA;AAC3D,IAAA,MAAM,IAAA,CAAK,KAAA,CAAM,aAAA,CAAc,IAAA,CAAK,GAAA,CAAI,OAAA,EAAS,UAAA,CAAW,OAAA,EAAQ,CAAE,KAAA,CAAM,KAAA,CAAM,MAAM,CAAC,CAAA;AACzF,IAAA,sBAAA,CAAuB,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,IAAA,CAAK,IAAI,OAAO,CAAA;AAAA,EACvD,CAAC,CAAA;AACH","file":"inject-session-KOFHS5K3.js","sourcesContent":["/**\n * M51 (agent-builder) — inject a SYNTHETIC user+assistant pair into a session's persisted transcript\n * WITHOUT running an LLM turn. This is the Codex review-exit mechanism (`exit_success.xml` appended to\n * the parent thread history so follow-ups like \"fix finding 2\" work): the pair chains onto the DAG\n * leaf (M50 pattern) and the in-memory cache is invalidated so the NEXT send re-hydrates with it.\n */\nimport type { SessionStore } from \"../../types/session-store.js\";\nimport { SessionTranscript } from \"../persistence/session-transcript.js\";\nimport { enqueueSessionWrite, invalidateSessionCache } from \"./agent-session.js\";\nimport type { CompactLocation } from \"./compact-session.js\";\n\nexport async function injectSessionTurn(opts: {\n store: SessionStore;\n loc: CompactLocation;\n sessionId: string;\n userText: string;\n assistantText: string;\n}): Promise<void> {\n await enqueueSessionWrite(opts.loc.cwd, opts.loc.agentId, async () => {\n const prior = await opts.store.readRecords(opts.loc.agentId);\n const transcript = SessionTranscript.fromRecords(prior, {\n cwd: opts.loc.cwd,\n sessionId: opts.sessionId,\n model: opts.loc.model ?? \"unknown\",\n });\n transcript.appendUserTurn(opts.userText);\n transcript.appendAssistantTurn({ text: opts.assistantText });\n await opts.store.appendRecords(opts.loc.agentId, transcript.records().slice(prior.length));\n invalidateSessionCache(opts.loc.cwd, opts.loc.agentId);\n });\n}\n"]}
1
+ {"version":3,"sources":["../src/internal/session/inject-session.ts"],"names":[],"mappings":";;;;;;;AAWA,eAAsB,kBAAkB,IAAA,EAMtB;AAChB,EAAA,MAAM,oBAAoB,IAAA,CAAK,GAAA,CAAI,KAAK,IAAA,CAAK,GAAA,CAAI,SAAS,YAAY;AACpE,IAAA,MAAM,QAAQ,MAAM,IAAA,CAAK,MAAM,WAAA,CAAY,IAAA,CAAK,IAAI,OAAO,CAAA;AAC3D,IAAA,MAAM,UAAA,GAAa,iBAAA,CAAkB,WAAA,CAAY,KAAA,EAAO;AAAA,MACtD,GAAA,EAAK,KAAK,GAAA,CAAI,GAAA;AAAA,MACd,WAAW,IAAA,CAAK,SAAA;AAAA,MAChB,KAAA,EAAO,IAAA,CAAK,GAAA,CAAI,KAAA,IAAS;AAAA,KAC1B,CAAA;AACD,IAAA,UAAA,CAAW,cAAA,CAAe,KAAK,QAAQ,CAAA;AACvC,IAAA,UAAA,CAAW,mBAAA,CAAoB,EAAE,IAAA,EAAM,IAAA,CAAK,eAAe,CAAA;AAC3D,IAAA,MAAM,IAAA,CAAK,KAAA,CAAM,aAAA,CAAc,IAAA,CAAK,GAAA,CAAI,OAAA,EAAS,UAAA,CAAW,OAAA,EAAQ,CAAE,KAAA,CAAM,KAAA,CAAM,MAAM,CAAC,CAAA;AACzF,IAAA,sBAAA,CAAuB,IAAA,CAAK,GAAA,CAAI,GAAA,EAAK,IAAA,CAAK,IAAI,OAAO,CAAA;AAAA,EACvD,CAAC,CAAA;AACH","file":"inject-session-NNSCCIVP.js","sourcesContent":["/**\n * M51 (agent-builder) — inject a SYNTHETIC user+assistant pair into a session's persisted transcript\n * WITHOUT running an LLM turn. This is the Codex review-exit mechanism (`exit_success.xml` appended to\n * the parent thread history so follow-ups like \"fix finding 2\" work): the pair chains onto the DAG\n * leaf (M50 pattern) and the in-memory cache is invalidated so the NEXT send re-hydrates with it.\n */\nimport type { SessionStore } from \"../../types/session-store.js\";\nimport { SessionTranscript } from \"../persistence/session-transcript.js\";\nimport { enqueueSessionWrite, invalidateSessionCache } from \"./agent-session.js\";\nimport type { CompactLocation } from \"./compact-session.js\";\n\nexport async function injectSessionTurn(opts: {\n store: SessionStore;\n loc: CompactLocation;\n sessionId: string;\n userText: string;\n assistantText: string;\n}): Promise<void> {\n await enqueueSessionWrite(opts.loc.cwd, opts.loc.agentId, async () => {\n const prior = await opts.store.readRecords(opts.loc.agentId);\n const transcript = SessionTranscript.fromRecords(prior, {\n cwd: opts.loc.cwd,\n sessionId: opts.sessionId,\n model: opts.loc.model ?? \"unknown\",\n });\n transcript.appendUserTurn(opts.userText);\n transcript.appendAssistantTurn({ text: opts.assistantText });\n await opts.store.appendRecords(opts.loc.agentId, transcript.records().slice(prior.length));\n invalidateSessionCache(opts.loc.cwd, opts.loc.agentId);\n });\n}\n"]}
@@ -0,0 +1,29 @@
1
+ import type { LlmClient, LlmEvent, LlmFinish, LlmRequest } from "./types.js";
2
+ /** Teto de tentativas. Fixo em 3 — o DoD do M93 nomeia o número. */
3
+ export declare const MAX_TENTATIVAS = 3;
4
+ /**
5
+ * O erro é transitório, isto é: reexecutar pode mudar o resultado?
6
+ *
7
+ * `RateLimitError` cobre 429 **e** 402 (billing). 402 NÃO é transitório — cota de faturamento não se
8
+ * resolve em milissegundos, e é por isso que o `classifyAndDecide` do pool rotaciona em vez de esperar.
9
+ * Aqui, sem para onde rotacionar, 402 propaga.
10
+ */
11
+ export declare function ehTransitorio(err: unknown): boolean;
12
+ /**
13
+ * ## Por que NÃO há circuit breaker aqui
14
+ *
15
+ * O `CircuitBreaker` do pacote é **chaveado por credencial** (`recordSuccess(key)` /
16
+ * `recordTimeout(key)`): existe para o pool marcar uma chave como insalubre e **pular** para outra. Com
17
+ * uma chave só não há para onde pular, então um breaker aqui registraria estado que ninguém consulta.
18
+ *
19
+ * Rung 1 da parcimônia — "isto precisa existir?". Não: seria cerimônia com nome de resiliência. O que
20
+ * protege o caminho de chave única é o teto de tentativas e o backoff, e os dois estão abaixo.
21
+ */
22
+ export declare class RetryingLlmClient implements LlmClient {
23
+ #private;
24
+ constructor(inner: LlmClient, opts?: {
25
+ rng?: () => number;
26
+ });
27
+ get name(): string;
28
+ stream(request: LlmRequest, signal: AbortSignal): AsyncGenerator<LlmEvent, LlmFinish, void>;
29
+ }
@@ -1,9 +1,8 @@
1
1
  'use strict';
2
2
 
3
- var chunkHK7ZHSAX_cjs = require('../../chunk-HK7ZHSAX.cjs');
4
3
  var chunkPNVDQL5Y_cjs = require('../../chunk-PNVDQL5Y.cjs');
5
4
  var chunkOIYQBUW4_cjs = require('../../chunk-OIYQBUW4.cjs');
6
- var chunkC7PICHRF_cjs = require('../../chunk-C7PICHRF.cjs');
5
+ var chunkWQEQCJTZ_cjs = require('../../chunk-WQEQCJTZ.cjs');
7
6
  var chunkJD74LN7R_cjs = require('../../chunk-JD74LN7R.cjs');
8
7
  var chunkYLQQX5W2_cjs = require('../../chunk-YLQQX5W2.cjs');
9
8
  var chunkTIZ4TS5V_cjs = require('../../chunk-TIZ4TS5V.cjs');
@@ -36,22 +35,6 @@ function casUpdate(db, sql, params, expectedChanges = 1) {
36
35
  return result.changes === expectedChanges;
37
36
  }
38
37
 
39
- Object.defineProperty(exports, "JsonlParseError", {
40
- enumerable: true,
41
- get: function () { return chunkHK7ZHSAX_cjs.JsonlParseError; }
42
- });
43
- Object.defineProperty(exports, "appendJsonl", {
44
- enumerable: true,
45
- get: function () { return chunkHK7ZHSAX_cjs.appendJsonl; }
46
- });
47
- Object.defineProperty(exports, "loadJsonl", {
48
- enumerable: true,
49
- get: function () { return chunkHK7ZHSAX_cjs.loadJsonl; }
50
- });
51
- Object.defineProperty(exports, "readJsonlIds", {
52
- enumerable: true,
53
- get: function () { return chunkHK7ZHSAX_cjs.readJsonlIds; }
54
- });
55
38
  Object.defineProperty(exports, "PersistenceSchema", {
56
39
  enumerable: true,
57
40
  get: function () { return chunkPNVDQL5Y_cjs.PersistenceSchema; }
@@ -80,9 +63,25 @@ Object.defineProperty(exports, "writeVersionedJson", {
80
63
  enumerable: true,
81
64
  get: function () { return chunkOIYQBUW4_cjs.writeVersionedJson; }
82
65
  });
66
+ Object.defineProperty(exports, "JsonlParseError", {
67
+ enumerable: true,
68
+ get: function () { return chunkWQEQCJTZ_cjs.JsonlParseError; }
69
+ });
70
+ Object.defineProperty(exports, "appendJsonl", {
71
+ enumerable: true,
72
+ get: function () { return chunkWQEQCJTZ_cjs.appendJsonl; }
73
+ });
74
+ Object.defineProperty(exports, "loadJsonl", {
75
+ enumerable: true,
76
+ get: function () { return chunkWQEQCJTZ_cjs.loadJsonl; }
77
+ });
78
+ Object.defineProperty(exports, "readJsonlIds", {
79
+ enumerable: true,
80
+ get: function () { return chunkWQEQCJTZ_cjs.readJsonlIds; }
81
+ });
83
82
  Object.defineProperty(exports, "withFileLock", {
84
83
  enumerable: true,
85
- get: function () { return chunkC7PICHRF_cjs.withFileLock; }
84
+ get: function () { return chunkWQEQCJTZ_cjs.withFileLock; }
86
85
  });
87
86
  Object.defineProperty(exports, "applyWalWithFallback", {
88
87
  enumerable: true,
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/internal/persistence/exclusive-create.ts","../../../src/internal/persistence/sqlite-cas.ts"],"names":["open"],"mappings":";;;;;;;;;;;;;AAgCA,eAAsB,eAAA,CACpB,IAAA,EACA,IAAA,EACA,OAAA,EACkB;AAClB,EAAA,MAAM,IAAA,GAAO,SAAS,IAAA,IAAQ,GAAA;AAC9B,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,MAAMA,aAAA,CAAK,IAAA,EAAM,MAAM,IAAI,CAAA;AAC1C,IAAA,IAAI;AACF,MAAA,MAAM,MAAA,CAAO,UAAU,IAAI,CAAA;AAC3B,MAAA,OAAO,IAAA;AAAA,IACT,CAAA,SAAE;AACA,MAAA,MAAM,OAAO,KAAA,EAAM;AAAA,IACrB;AAAA,EACF,SAAS,GAAA,EAAK;AACZ,IAAA,IAAK,GAAA,CAA8B,SAAS,QAAA,EAAU;AACpD,MAAA,OAAO,KAAA;AAAA,IACT;AACA,IAAA,MAAM,GAAA;AAAA,EACR;AACF;;;ACjBO,SAAS,SAAA,CACd,EAAA,EACA,GAAA,EACA,MAAA,EACA,kBAA0B,CAAA,EACjB;AACT,EAAA,MAAM,IAAA,GAAO,EAAA,CAAG,OAAA,CAAQ,GAAG,CAAA;AAC3B,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,GAAA,CAAI,GAAI,MAAoB,CAAA;AAChD,EAAA,OAAO,OAAO,OAAA,KAAY,eAAA;AAC5B","file":"index.cjs","sourcesContent":["/**\n * O_EXCL exclusive file creation (ADR D82).\n *\n * `createExclusive(path, data, { mode })` creates a file in a single\n * syscall (`open(path, \"wx\", mode)`). Returns `true` if created, `false`\n * if it already existed (EEXIST swallowed — caller decides). All other\n * errors propagate.\n *\n * Default mode is 0o600 (owner-only) — EC-2 fix from edge-case review:\n * token files, lockfiles, and PID files MUST NOT default to world-\n * readable 0o644 under typical umask 022. Callers writing non-sensitive\n * files can pass `mode: 0o644` explicitly.\n *\n * NFS sem honor de O_EXCL é documentado (D61 — mesma postura do\n * `withFileLock`); SDK target é ext4/APFS/NTFS.\n *\n * @internal\n */\n\nimport { open } from \"node:fs/promises\";\n\nexport interface CreateExclusiveOptions {\n /** Unix mode for the new file (default 0o600 — owner-only). */\n mode?: number;\n}\n\n/**\n * Atomically create `path` with `data`. Returns true iff this call\n * created the file (race-free under POSIX-compliant filesystems).\n *\n * @internal\n */\nexport async function createExclusive(\n path: string,\n data: string | Uint8Array,\n options?: CreateExclusiveOptions,\n): Promise<boolean> {\n const mode = options?.mode ?? 0o600;\n try {\n const handle = await open(path, \"wx\", mode);\n try {\n await handle.writeFile(data);\n return true;\n } finally {\n await handle.close();\n }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"EEXIST\") {\n return false;\n }\n throw err;\n }\n}\n","/**\n * SQLite optimistic compare-and-swap (ADR D83).\n *\n * `casUpdate(db, sql, params, expectedChanges)` executes a prepared\n * UPDATE and returns true if `result.changes === expectedChanges`.\n * Caller provides the full SQL (including `WHERE version = ?` predicate);\n * helper does NOT generate SQL — DRY at the level of \"wrap the\n * convention\", not \"build queries\".\n *\n * Use case canonical (Hermes `kanban_db.py:1922-1934`):\n *\n * const won = casUpdate(\n * db,\n * \"UPDATE registry SET status = ?, version = version + 1 WHERE id = ? AND version = ?\",\n * [\"running\", \"agent-foo\", 3],\n * );\n * if (!won) { ... re-read and retry ... }\n *\n * Helper does NOT retry — caller responsible for backoff (avoids hidden\n * loops). Helper does NOT cache prepared statements — `better-sqlite3`\n * caches internally; SDK use is one-shot per mutation, not hot loops.\n *\n * @internal\n */\n\nimport type Database from \"better-sqlite3\";\n\ntype DatabaseInstance = InstanceType<typeof Database>;\n\n/**\n * Execute a CAS UPDATE. Returns true iff the actual changes count matches\n * `expectedChanges`. SQL errors (invalid syntax, closed db) propagate.\n *\n * @internal\n */\nexport function casUpdate(\n db: DatabaseInstance,\n sql: string,\n params: ReadonlyArray<unknown>,\n expectedChanges: number = 1,\n): boolean {\n const stmt = db.prepare(sql);\n const result = stmt.run(...(params as unknown[]));\n return result.changes === expectedChanges;\n}\n"]}
1
+ {"version":3,"sources":["../../../src/internal/persistence/exclusive-create.ts","../../../src/internal/persistence/sqlite-cas.ts"],"names":["open"],"mappings":";;;;;;;;;;;;AAgCA,eAAsB,eAAA,CACpB,IAAA,EACA,IAAA,EACA,OAAA,EACkB;AAClB,EAAA,MAAM,IAAA,GAAO,SAAS,IAAA,IAAQ,GAAA;AAC9B,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,MAAMA,aAAA,CAAK,IAAA,EAAM,MAAM,IAAI,CAAA;AAC1C,IAAA,IAAI;AACF,MAAA,MAAM,MAAA,CAAO,UAAU,IAAI,CAAA;AAC3B,MAAA,OAAO,IAAA;AAAA,IACT,CAAA,SAAE;AACA,MAAA,MAAM,OAAO,KAAA,EAAM;AAAA,IACrB;AAAA,EACF,SAAS,GAAA,EAAK;AACZ,IAAA,IAAK,GAAA,CAA8B,SAAS,QAAA,EAAU;AACpD,MAAA,OAAO,KAAA;AAAA,IACT;AACA,IAAA,MAAM,GAAA;AAAA,EACR;AACF;;;ACjBO,SAAS,SAAA,CACd,EAAA,EACA,GAAA,EACA,MAAA,EACA,kBAA0B,CAAA,EACjB;AACT,EAAA,MAAM,IAAA,GAAO,EAAA,CAAG,OAAA,CAAQ,GAAG,CAAA;AAC3B,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,GAAA,CAAI,GAAI,MAAoB,CAAA;AAChD,EAAA,OAAO,OAAO,OAAA,KAAY,eAAA;AAC5B","file":"index.cjs","sourcesContent":["/**\n * O_EXCL exclusive file creation (ADR D82).\n *\n * `createExclusive(path, data, { mode })` creates a file in a single\n * syscall (`open(path, \"wx\", mode)`). Returns `true` if created, `false`\n * if it already existed (EEXIST swallowed — caller decides). All other\n * errors propagate.\n *\n * Default mode is 0o600 (owner-only) — EC-2 fix from edge-case review:\n * token files, lockfiles, and PID files MUST NOT default to world-\n * readable 0o644 under typical umask 022. Callers writing non-sensitive\n * files can pass `mode: 0o644` explicitly.\n *\n * NFS sem honor de O_EXCL é documentado (D61 — mesma postura do\n * `withFileLock`); SDK target é ext4/APFS/NTFS.\n *\n * @internal\n */\n\nimport { open } from \"node:fs/promises\";\n\nexport interface CreateExclusiveOptions {\n /** Unix mode for the new file (default 0o600 — owner-only). */\n mode?: number;\n}\n\n/**\n * Atomically create `path` with `data`. Returns true iff this call\n * created the file (race-free under POSIX-compliant filesystems).\n *\n * @internal\n */\nexport async function createExclusive(\n path: string,\n data: string | Uint8Array,\n options?: CreateExclusiveOptions,\n): Promise<boolean> {\n const mode = options?.mode ?? 0o600;\n try {\n const handle = await open(path, \"wx\", mode);\n try {\n await handle.writeFile(data);\n return true;\n } finally {\n await handle.close();\n }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"EEXIST\") {\n return false;\n }\n throw err;\n }\n}\n","/**\n * SQLite optimistic compare-and-swap (ADR D83).\n *\n * `casUpdate(db, sql, params, expectedChanges)` executes a prepared\n * UPDATE and returns true if `result.changes === expectedChanges`.\n * Caller provides the full SQL (including `WHERE version = ?` predicate);\n * helper does NOT generate SQL — DRY at the level of \"wrap the\n * convention\", not \"build queries\".\n *\n * Use case canonical (Hermes `kanban_db.py:1922-1934`):\n *\n * const won = casUpdate(\n * db,\n * \"UPDATE registry SET status = ?, version = version + 1 WHERE id = ? AND version = ?\",\n * [\"running\", \"agent-foo\", 3],\n * );\n * if (!won) { ... re-read and retry ... }\n *\n * Helper does NOT retry — caller responsible for backoff (avoids hidden\n * loops). Helper does NOT cache prepared statements — `better-sqlite3`\n * caches internally; SDK use is one-shot per mutation, not hot loops.\n *\n * @internal\n */\n\nimport type Database from \"better-sqlite3\";\n\ntype DatabaseInstance = InstanceType<typeof Database>;\n\n/**\n * Execute a CAS UPDATE. Returns true iff the actual changes count matches\n * `expectedChanges`. SQL errors (invalid syntax, closed db) propagate.\n *\n * @internal\n */\nexport function casUpdate(\n db: DatabaseInstance,\n sql: string,\n params: ReadonlyArray<unknown>,\n expectedChanges: number = 1,\n): boolean {\n const stmt = db.prepare(sql);\n const result = stmt.run(...(params as unknown[]));\n return result.changes === expectedChanges;\n}\n"]}
@@ -1,7 +1,6 @@
1
- export { JsonlParseError, appendJsonl, loadJsonl, readJsonlIds } from '../../chunk-R6ZP6KNB.js';
2
1
  export { PersistenceSchema } from '../../chunk-CAH3G4IS.js';
3
2
  export { displayTheokitHome, getProfilesRoot, getTheokitHome, migrateSchema, readVersionedJson, writeVersionedJson } from '../../chunk-DGRZNMTU.js';
4
- export { withFileLock } from '../../chunk-HZQEDNF6.js';
3
+ export { JsonlParseError, appendJsonl, loadJsonl, readJsonlIds, withFileLock } from '../../chunk-ICSCKB3N.js';
5
4
  export { applyWalWithFallback, containsCjk, isCorruptionError, openSqliteResilient, sanitizeFts5Query } from '../../chunk-77FOZCOT.js';
6
5
  export { withCwdMutex } from '../../chunk-2XLKLVVR.js';
7
6
  export { atomicWriteJson, atomicWriteText, replaceFileAtomic } from '../../chunk-S2BBRVQX.js';
@@ -1 +1 @@
1
- {"version":3,"sources":["../../../src/internal/persistence/exclusive-create.ts","../../../src/internal/persistence/sqlite-cas.ts"],"names":[],"mappings":";;;;;;;;;;;AAgCA,eAAsB,eAAA,CACpB,IAAA,EACA,IAAA,EACA,OAAA,EACkB;AAClB,EAAA,MAAM,IAAA,GAAO,SAAS,IAAA,IAAQ,GAAA;AAC9B,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,IAAA,EAAM,MAAM,IAAI,CAAA;AAC1C,IAAA,IAAI;AACF,MAAA,MAAM,MAAA,CAAO,UAAU,IAAI,CAAA;AAC3B,MAAA,OAAO,IAAA;AAAA,IACT,CAAA,SAAE;AACA,MAAA,MAAM,OAAO,KAAA,EAAM;AAAA,IACrB;AAAA,EACF,SAAS,GAAA,EAAK;AACZ,IAAA,IAAK,GAAA,CAA8B,SAAS,QAAA,EAAU;AACpD,MAAA,OAAO,KAAA;AAAA,IACT;AACA,IAAA,MAAM,GAAA;AAAA,EACR;AACF;;;ACjBO,SAAS,SAAA,CACd,EAAA,EACA,GAAA,EACA,MAAA,EACA,kBAA0B,CAAA,EACjB;AACT,EAAA,MAAM,IAAA,GAAO,EAAA,CAAG,OAAA,CAAQ,GAAG,CAAA;AAC3B,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,GAAA,CAAI,GAAI,MAAoB,CAAA;AAChD,EAAA,OAAO,OAAO,OAAA,KAAY,eAAA;AAC5B","file":"index.js","sourcesContent":["/**\n * O_EXCL exclusive file creation (ADR D82).\n *\n * `createExclusive(path, data, { mode })` creates a file in a single\n * syscall (`open(path, \"wx\", mode)`). Returns `true` if created, `false`\n * if it already existed (EEXIST swallowed — caller decides). All other\n * errors propagate.\n *\n * Default mode is 0o600 (owner-only) — EC-2 fix from edge-case review:\n * token files, lockfiles, and PID files MUST NOT default to world-\n * readable 0o644 under typical umask 022. Callers writing non-sensitive\n * files can pass `mode: 0o644` explicitly.\n *\n * NFS sem honor de O_EXCL é documentado (D61 — mesma postura do\n * `withFileLock`); SDK target é ext4/APFS/NTFS.\n *\n * @internal\n */\n\nimport { open } from \"node:fs/promises\";\n\nexport interface CreateExclusiveOptions {\n /** Unix mode for the new file (default 0o600 — owner-only). */\n mode?: number;\n}\n\n/**\n * Atomically create `path` with `data`. Returns true iff this call\n * created the file (race-free under POSIX-compliant filesystems).\n *\n * @internal\n */\nexport async function createExclusive(\n path: string,\n data: string | Uint8Array,\n options?: CreateExclusiveOptions,\n): Promise<boolean> {\n const mode = options?.mode ?? 0o600;\n try {\n const handle = await open(path, \"wx\", mode);\n try {\n await handle.writeFile(data);\n return true;\n } finally {\n await handle.close();\n }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"EEXIST\") {\n return false;\n }\n throw err;\n }\n}\n","/**\n * SQLite optimistic compare-and-swap (ADR D83).\n *\n * `casUpdate(db, sql, params, expectedChanges)` executes a prepared\n * UPDATE and returns true if `result.changes === expectedChanges`.\n * Caller provides the full SQL (including `WHERE version = ?` predicate);\n * helper does NOT generate SQL — DRY at the level of \"wrap the\n * convention\", not \"build queries\".\n *\n * Use case canonical (Hermes `kanban_db.py:1922-1934`):\n *\n * const won = casUpdate(\n * db,\n * \"UPDATE registry SET status = ?, version = version + 1 WHERE id = ? AND version = ?\",\n * [\"running\", \"agent-foo\", 3],\n * );\n * if (!won) { ... re-read and retry ... }\n *\n * Helper does NOT retry — caller responsible for backoff (avoids hidden\n * loops). Helper does NOT cache prepared statements — `better-sqlite3`\n * caches internally; SDK use is one-shot per mutation, not hot loops.\n *\n * @internal\n */\n\nimport type Database from \"better-sqlite3\";\n\ntype DatabaseInstance = InstanceType<typeof Database>;\n\n/**\n * Execute a CAS UPDATE. Returns true iff the actual changes count matches\n * `expectedChanges`. SQL errors (invalid syntax, closed db) propagate.\n *\n * @internal\n */\nexport function casUpdate(\n db: DatabaseInstance,\n sql: string,\n params: ReadonlyArray<unknown>,\n expectedChanges: number = 1,\n): boolean {\n const stmt = db.prepare(sql);\n const result = stmt.run(...(params as unknown[]));\n return result.changes === expectedChanges;\n}\n"]}
1
+ {"version":3,"sources":["../../../src/internal/persistence/exclusive-create.ts","../../../src/internal/persistence/sqlite-cas.ts"],"names":[],"mappings":";;;;;;;;;;AAgCA,eAAsB,eAAA,CACpB,IAAA,EACA,IAAA,EACA,OAAA,EACkB;AAClB,EAAA,MAAM,IAAA,GAAO,SAAS,IAAA,IAAQ,GAAA;AAC9B,EAAA,IAAI;AACF,IAAA,MAAM,MAAA,GAAS,MAAM,IAAA,CAAK,IAAA,EAAM,MAAM,IAAI,CAAA;AAC1C,IAAA,IAAI;AACF,MAAA,MAAM,MAAA,CAAO,UAAU,IAAI,CAAA;AAC3B,MAAA,OAAO,IAAA;AAAA,IACT,CAAA,SAAE;AACA,MAAA,MAAM,OAAO,KAAA,EAAM;AAAA,IACrB;AAAA,EACF,SAAS,GAAA,EAAK;AACZ,IAAA,IAAK,GAAA,CAA8B,SAAS,QAAA,EAAU;AACpD,MAAA,OAAO,KAAA;AAAA,IACT;AACA,IAAA,MAAM,GAAA;AAAA,EACR;AACF;;;ACjBO,SAAS,SAAA,CACd,EAAA,EACA,GAAA,EACA,MAAA,EACA,kBAA0B,CAAA,EACjB;AACT,EAAA,MAAM,IAAA,GAAO,EAAA,CAAG,OAAA,CAAQ,GAAG,CAAA;AAC3B,EAAA,MAAM,MAAA,GAAS,IAAA,CAAK,GAAA,CAAI,GAAI,MAAoB,CAAA;AAChD,EAAA,OAAO,OAAO,OAAA,KAAY,eAAA;AAC5B","file":"index.js","sourcesContent":["/**\n * O_EXCL exclusive file creation (ADR D82).\n *\n * `createExclusive(path, data, { mode })` creates a file in a single\n * syscall (`open(path, \"wx\", mode)`). Returns `true` if created, `false`\n * if it already existed (EEXIST swallowed — caller decides). All other\n * errors propagate.\n *\n * Default mode is 0o600 (owner-only) — EC-2 fix from edge-case review:\n * token files, lockfiles, and PID files MUST NOT default to world-\n * readable 0o644 under typical umask 022. Callers writing non-sensitive\n * files can pass `mode: 0o644` explicitly.\n *\n * NFS sem honor de O_EXCL é documentado (D61 — mesma postura do\n * `withFileLock`); SDK target é ext4/APFS/NTFS.\n *\n * @internal\n */\n\nimport { open } from \"node:fs/promises\";\n\nexport interface CreateExclusiveOptions {\n /** Unix mode for the new file (default 0o600 — owner-only). */\n mode?: number;\n}\n\n/**\n * Atomically create `path` with `data`. Returns true iff this call\n * created the file (race-free under POSIX-compliant filesystems).\n *\n * @internal\n */\nexport async function createExclusive(\n path: string,\n data: string | Uint8Array,\n options?: CreateExclusiveOptions,\n): Promise<boolean> {\n const mode = options?.mode ?? 0o600;\n try {\n const handle = await open(path, \"wx\", mode);\n try {\n await handle.writeFile(data);\n return true;\n } finally {\n await handle.close();\n }\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"EEXIST\") {\n return false;\n }\n throw err;\n }\n}\n","/**\n * SQLite optimistic compare-and-swap (ADR D83).\n *\n * `casUpdate(db, sql, params, expectedChanges)` executes a prepared\n * UPDATE and returns true if `result.changes === expectedChanges`.\n * Caller provides the full SQL (including `WHERE version = ?` predicate);\n * helper does NOT generate SQL — DRY at the level of \"wrap the\n * convention\", not \"build queries\".\n *\n * Use case canonical (Hermes `kanban_db.py:1922-1934`):\n *\n * const won = casUpdate(\n * db,\n * \"UPDATE registry SET status = ?, version = version + 1 WHERE id = ? AND version = ?\",\n * [\"running\", \"agent-foo\", 3],\n * );\n * if (!won) { ... re-read and retry ... }\n *\n * Helper does NOT retry — caller responsible for backoff (avoids hidden\n * loops). Helper does NOT cache prepared statements — `better-sqlite3`\n * caches internally; SDK use is one-shot per mutation, not hot loops.\n *\n * @internal\n */\n\nimport type Database from \"better-sqlite3\";\n\ntype DatabaseInstance = InstanceType<typeof Database>;\n\n/**\n * Execute a CAS UPDATE. Returns true iff the actual changes count matches\n * `expectedChanges`. SQL errors (invalid syntax, closed db) propagate.\n *\n * @internal\n */\nexport function casUpdate(\n db: DatabaseInstance,\n sql: string,\n params: ReadonlyArray<unknown>,\n expectedChanges: number = 1,\n): boolean {\n const stmt = db.prepare(sql);\n const result = stmt.run(...(params as unknown[]));\n return result.changes === expectedChanges;\n}\n"]}
@@ -1,8 +1,7 @@
1
1
  'use strict';
2
2
 
3
- var chunkHK7ZHSAX_cjs = require('./chunk-HK7ZHSAX.cjs');
4
3
  var chunkPNVDQL5Y_cjs = require('./chunk-PNVDQL5Y.cjs');
5
- var chunkC7PICHRF_cjs = require('./chunk-C7PICHRF.cjs');
4
+ var chunkWQEQCJTZ_cjs = require('./chunk-WQEQCJTZ.cjs');
6
5
  var chunkJD74LN7R_cjs = require('./chunk-JD74LN7R.cjs');
7
6
  var chunkYLQQX5W2_cjs = require('./chunk-YLQQX5W2.cjs');
8
7
  var chunk4SXHEZIV_cjs = require('./chunk-4SXHEZIV.cjs');
@@ -110,29 +109,29 @@ function readJsonlTail(path, options = {}) {
110
109
  return options._stats === true ? Object.assign(out, { bytesRead }) : out;
111
110
  }
112
111
 
112
+ Object.defineProperty(exports, "PersistenceSchema", {
113
+ enumerable: true,
114
+ get: function () { return chunkPNVDQL5Y_cjs.PersistenceSchema; }
115
+ });
113
116
  Object.defineProperty(exports, "JsonlParseError", {
114
117
  enumerable: true,
115
- get: function () { return chunkHK7ZHSAX_cjs.JsonlParseError; }
118
+ get: function () { return chunkWQEQCJTZ_cjs.JsonlParseError; }
116
119
  });
117
120
  Object.defineProperty(exports, "appendJsonl", {
118
121
  enumerable: true,
119
- get: function () { return chunkHK7ZHSAX_cjs.appendJsonl; }
122
+ get: function () { return chunkWQEQCJTZ_cjs.appendJsonl; }
120
123
  });
121
124
  Object.defineProperty(exports, "loadJsonl", {
122
125
  enumerable: true,
123
- get: function () { return chunkHK7ZHSAX_cjs.loadJsonl; }
126
+ get: function () { return chunkWQEQCJTZ_cjs.loadJsonl; }
124
127
  });
125
128
  Object.defineProperty(exports, "readJsonlIds", {
126
129
  enumerable: true,
127
- get: function () { return chunkHK7ZHSAX_cjs.readJsonlIds; }
128
- });
129
- Object.defineProperty(exports, "PersistenceSchema", {
130
- enumerable: true,
131
- get: function () { return chunkPNVDQL5Y_cjs.PersistenceSchema; }
130
+ get: function () { return chunkWQEQCJTZ_cjs.readJsonlIds; }
132
131
  });
133
132
  Object.defineProperty(exports, "withFileLock", {
134
133
  enumerable: true,
135
- get: function () { return chunkC7PICHRF_cjs.withFileLock; }
134
+ get: function () { return chunkWQEQCJTZ_cjs.withFileLock; }
136
135
  });
137
136
  Object.defineProperty(exports, "applyWalWithFallback", {
138
137
  enumerable: true,
@@ -1 +1 @@
1
- {"version":3,"sources":["../src/internal/persistence/session-writer.ts","../src/internal/persistence/transcript-ops.ts"],"names":["TheokitAgentError","openSync","closeSync","rmSync","readFileSync","writeSync","statSync","readSync"],"mappings":"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","file":"persistence.cjs","sourcesContent":["/**\n * M81 — single-writer lease for a session transcript.\n *\n * ## The problem\n *\n * Nothing stops two processes appending to the same JSONL transcript. The concrete case: `exec\n * resume --last` can write into the TUI's live session. Two interleaved appends to an append-only\n * file produce lines that are each individually valid and whose SEQUENCE is fiction — and nothing\n * reports it, because every line parses.\n *\n * ## Why an exclusive lockfile rather than `withFileLock`\n *\n * The plan's ADR D2 said to compose `withFileLock`, and that was the right instinct — do not build a\n * second lock mechanism. It turned out not to fit the SHAPE: `withFileLock(path, fn)` is\n * scope-based — it holds the lock for the duration of a callback. A session lease is **held across\n * turns**, for as long as the process owns the session, with an explicit `release()`. Wrapping the\n * whole session lifetime in a callback would invert control of the entire agent loop.\n *\n * So this uses the same underlying primitive `withFileLock` uses (an exclusive-create lockfile,\n * `wx`) with lease semantics on top. That keeps the mechanism single — the file-existence lock —\n * while giving it the lifetime the caller needs. The deviation from D2 is recorded here because the\n * plan's rationale (no second mechanism) still holds; only its shape assumption did not.\n *\n * ## Fail fast, never wait\n *\n * A second writer that WAITED would block `exec` behind a TUI session that can last hours. The typed\n * error lets the caller choose: fork to a new id, or give up with a real diagnosis.\n *\n * @internal\n */\n\nimport { closeSync, openSync, rmSync } from \"node:fs\";\n\nimport { TheokitAgentError } from \"../../errors.js\";\n\n/**\n * M81 — another process already holds the writer lease for this session.\n *\n * Carries `sessionPath` because knowing WHICH session is busy is what lets the caller decide between\n * forking and waiting for the user to close the TUI (`rules/error-handling.md § 2` — context enough\n * to act on).\n */\nexport class SessionBusyError extends TheokitAgentError {\n override readonly name = \"SessionBusyError\";\n\n constructor(readonly sessionPath: string) {\n super(\n `another process is already writing this session: ${sessionPath}. ` +\n \"Fork it to a new id instead of appending — two writers interleave lines into a sequence \" +\n \"that parses but is not what either process wrote.\",\n { code: \"session_busy\", isRetryable: false },\n );\n }\n}\n\n/** A held writer lease. `release()` is idempotent. */\nexport interface SessionWriterLease {\n readonly sessionPath: string;\n release(): Promise<void>;\n}\n\n/**\n * Take the exclusive writer lease for `sessionPath`, or reject with {@link SessionBusyError}.\n *\n * The lock is a sibling `.lock` file created with `wx` — the same file-existence primitive the\n * SDK's `withFileLock` builds on. Exclusivity comes from the filesystem, so it holds across\n * processes, not just across async tasks in one process.\n */\nexport async function acquireSessionWriter(sessionPath: string): Promise<SessionWriterLease> {\n const lockPath = `${sessionPath}.lock`;\n let fd: number;\n try {\n fd = openSync(lockPath, \"wx\");\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"EEXIST\") {\n throw new SessionBusyError(sessionPath);\n }\n throw err;\n }\n closeSync(fd);\n\n let released = false;\n return {\n sessionPath,\n release: async (): Promise<void> => {\n if (released) return;\n released = true;\n rmSync(lockPath, { force: true });\n },\n };\n}\n","/**\n * M81 — transcript operations the consumer was doing by hand INSIDE the framework's own store.\n *\n * ## What this replaces\n *\n * `agents/lib/session/backtrack.ts:188` (agent-builder) wrote straight into the session store with a\n * bare `writeFileSync` — no atomicity, no lock, no API. 243 lines re-implementing parse, cut and\n * write for a format the framework owns. The consumer is not at fault: nothing here was reachable.\n *\n * ## The rule that travels WITH the operation\n *\n * `rules/audit-trail-rotation.md § Session transcripts (M60)` defines a NEVER-delete list — the live\n * pointer, the most recent transcript, and any active registry entry. That rule lived in the\n * CONSUMER. Moving the operation here without moving the rule would ship an API able to destroy\n * exactly what the rule protects — the same shape of defect as M80's `reconcileUpdateGoalStatus`:\n * critical knowledge outside the module that needs it, applied by convention.\n *\n * So `forkTranscript` takes `liveSessionPaths` and refuses, with a TYPED error, to write over any of\n * them. The caller supplies the list because only the caller knows which session is live; the\n * enforcement lives here because that is where the write happens.\n *\n * @internal\n */\n\nimport { closeSync, openSync, readFileSync, readSync, statSync, writeSync } from \"node:fs\";\n\nimport { TheokitAgentError } from \"../../errors.js\";\n\n/**\n * M81 — the target is a protected session (live pointer / most-recent transcript / active entry).\n *\n * Typed rather than a bare `Error` because the caller must distinguish \"this session is protected\"\n * from \"the disk is full\": the first is a correct refusal, the second is an incident.\n */\nexport class LiveSessionError extends TheokitAgentError {\n override readonly name = \"LiveSessionError\";\n\n constructor(readonly path: string) {\n super(\n `refusing to write over a live session transcript: ${path}. ` +\n \"Fork to a new id instead — the live pointer, the most recent transcript and any active \" +\n \"registry entry are never overwritten (audit-trail rotation, M60).\",\n { code: \"live_session_protected\", isRetryable: false },\n );\n }\n}\n\n/** Options for {@link forkTranscript}. */\nexport interface ForkTranscriptOptions {\n /** Keep records `[0, beforeRecordIndex)`. Omit to copy the whole transcript. */\n readonly beforeRecordIndex?: number;\n /**\n * Paths that must never be written over — the live pointer, the most recent transcript, any active\n * registry entry. The caller supplies them because only the caller knows which session is live.\n */\n readonly liveSessionPaths?: readonly string[];\n}\n\n/**\n * Copy `src` into `dst`, keeping the first `beforeRecordIndex` records. The SOURCE is never touched.\n *\n * Atomicity comes from `wx` (exclusive create): two concurrent forks to the same destination cannot\n * both succeed — the loser gets `EEXIST` rather than writing over a half-written file. That is also\n * why an existing destination is a refusal, not a silent overwrite: losing a transcript without an\n * error is the worst failure mode for an operation that touches user sessions.\n */\nexport function forkTranscript(\n src: string,\n dst: string,\n options: ForkTranscriptOptions = {},\n): void {\n for (const live of options.liveSessionPaths ?? []) {\n if (live === dst) throw new LiveSessionError(dst);\n }\n\n const lines = readFileSync(src, \"utf8\")\n .split(\"\\n\")\n .filter((l) => l.trim().length > 0);\n const kept =\n options.beforeRecordIndex === undefined ? lines : lines.slice(0, options.beforeRecordIndex);\n const body = kept.length > 0 ? `${kept.join(\"\\n\")}\\n` : \"\";\n\n // `wx` — fails with EEXIST instead of truncating. The exclusivity IS the concurrency guarantee.\n const fd = openSync(dst, \"wx\");\n try {\n writeSync(fd, body);\n } finally {\n closeSync(fd);\n }\n}\n\n/** Options for {@link readJsonlTail}. */\nexport interface ReadJsonlTailOptions {\n /** Maximum records to return, counted from the END. */\n readonly maxRecords?: number;\n /** Stop once a line contains this marker (exclusive). */\n readonly sinceMarker?: string;\n /** Test-only: also report how many bytes were read, to prove the read is not whole-file. */\n readonly _stats?: boolean;\n}\n\nconst TAIL_CHUNK = 64 * 1024;\n\n/**\n * Lê chunks de trás para frente até acumular linhas completas suficientes.\n *\n * Extraído de `readJsonlTail` porque o laço de leitura e a seleção de registros são duas\n * responsabilidades — e juntas passavam do teto de complexidade. A primeira linha do buffer pode\n * estar cortada ao meio quando a leitura parou antes do início do arquivo; por isso ela é descartada.\n */\nfunction lerCaudaBruta(path: string, want: number): { linhas: string[]; bytesRead: number } {\n const size = statSync(path).size;\n const fd = openSync(path, \"r\");\n let bytesRead = 0;\n let tail = \"\";\n let pos = size;\n try {\n while (pos > 0) {\n const len = Math.min(TAIL_CHUNK, pos);\n pos -= len;\n const buf = Buffer.alloc(len);\n readSync(fd, buf, 0, len, pos);\n bytesRead += len;\n tail = buf.toString(\"utf8\") + tail;\n if (naoVazias(tail).length > want) break;\n }\n } finally {\n closeSync(fd);\n }\n const linhas = naoVazias(tail);\n return { linhas: pos > 0 ? linhas.slice(1) : linhas, bytesRead };\n}\n\n/** Linhas com conteúdo, na ordem do arquivo. */\nfunction naoVazias(texto: string): string[] {\n return texto.split(\"\\n\").filter((l) => l.trim().length > 0);\n}\n\n/**\n * Read the LAST records of a JSONL file without loading the whole thing.\n *\n * Reads fixed-size chunks backwards from EOF until enough newlines have been seen. A session\n * transcript grows without bound; loading megabytes to show the last three turns is the cost this\n * exists to avoid — and a `slice` over a full read would be that same cost with a better name.\n */\nexport function readJsonlTail<T = Record<string, unknown>>(\n path: string,\n options: ReadJsonlTailOptions = {},\n): T[] {\n const want = options.maxRecords ?? Number.POSITIVE_INFINITY;\n const { linhas, bytesRead } = lerCaudaBruta(path, want);\n\n let sel = linhas;\n if (options.sinceMarker !== undefined) {\n const marcador = options.sinceMarker;\n const idx = sel.findLastIndex((l) => l.includes(marcador));\n if (idx >= 0) sel = sel.slice(idx + 1);\n }\n if (Number.isFinite(want)) sel = sel.slice(-want);\n\n const out = sel.map((l) => JSON.parse(l) as T);\n return options._stats === true ? (Object.assign(out, { bytesRead }) as T[]) : out;\n}\n"]}
1
+ {"version":3,"sources":["../src/internal/persistence/session-writer.ts","../src/internal/persistence/transcript-ops.ts"],"names":["TheokitAgentError","openSync","closeSync","rmSync","readFileSync","writeSync","statSync","readSync"],"mappings":"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","file":"persistence.cjs","sourcesContent":["/**\n * M81 — single-writer lease for a session transcript.\n *\n * ## The problem\n *\n * Nothing stops two processes appending to the same JSONL transcript. The concrete case: `exec\n * resume --last` can write into the TUI's live session. Two interleaved appends to an append-only\n * file produce lines that are each individually valid and whose SEQUENCE is fiction — and nothing\n * reports it, because every line parses.\n *\n * ## Why an exclusive lockfile rather than `withFileLock`\n *\n * The plan's ADR D2 said to compose `withFileLock`, and that was the right instinct — do not build a\n * second lock mechanism. It turned out not to fit the SHAPE: `withFileLock(path, fn)` is\n * scope-based — it holds the lock for the duration of a callback. A session lease is **held across\n * turns**, for as long as the process owns the session, with an explicit `release()`. Wrapping the\n * whole session lifetime in a callback would invert control of the entire agent loop.\n *\n * So this uses the same underlying primitive `withFileLock` uses (an exclusive-create lockfile,\n * `wx`) with lease semantics on top. That keeps the mechanism single — the file-existence lock —\n * while giving it the lifetime the caller needs. The deviation from D2 is recorded here because the\n * plan's rationale (no second mechanism) still holds; only its shape assumption did not.\n *\n * ## Fail fast, never wait\n *\n * A second writer that WAITED would block `exec` behind a TUI session that can last hours. The typed\n * error lets the caller choose: fork to a new id, or give up with a real diagnosis.\n *\n * @internal\n */\n\nimport { closeSync, openSync, rmSync } from \"node:fs\";\n\nimport { TheokitAgentError } from \"../../errors.js\";\n\n/**\n * M81 — another process already holds the writer lease for this session.\n *\n * Carries `sessionPath` because knowing WHICH session is busy is what lets the caller decide between\n * forking and waiting for the user to close the TUI (`rules/error-handling.md § 2` — context enough\n * to act on).\n */\nexport class SessionBusyError extends TheokitAgentError {\n override readonly name = \"SessionBusyError\";\n\n constructor(readonly sessionPath: string) {\n super(\n `another process is already writing this session: ${sessionPath}. ` +\n \"Fork it to a new id instead of appending — two writers interleave lines into a sequence \" +\n \"that parses but is not what either process wrote.\",\n { code: \"session_busy\", isRetryable: false },\n );\n }\n}\n\n/** A held writer lease. `release()` is idempotent. */\nexport interface SessionWriterLease {\n readonly sessionPath: string;\n release(): Promise<void>;\n}\n\n/**\n * Take the exclusive writer lease for `sessionPath`, or reject with {@link SessionBusyError}.\n *\n * The lock is a sibling `.lock` file created with `wx` — the same file-existence primitive the\n * SDK's `withFileLock` builds on. Exclusivity comes from the filesystem, so it holds across\n * processes, not just across async tasks in one process.\n */\nexport async function acquireSessionWriter(sessionPath: string): Promise<SessionWriterLease> {\n const lockPath = `${sessionPath}.lock`;\n let fd: number;\n try {\n fd = openSync(lockPath, \"wx\");\n } catch (err) {\n if ((err as NodeJS.ErrnoException).code === \"EEXIST\") {\n throw new SessionBusyError(sessionPath);\n }\n throw err;\n }\n closeSync(fd);\n\n let released = false;\n return {\n sessionPath,\n release: async (): Promise<void> => {\n if (released) return;\n released = true;\n rmSync(lockPath, { force: true });\n },\n };\n}\n","/**\n * M81 — transcript operations the consumer was doing by hand INSIDE the framework's own store.\n *\n * ## What this replaces\n *\n * `agents/lib/session/backtrack.ts:188` (agent-builder) wrote straight into the session store with a\n * bare `writeFileSync` — no atomicity, no lock, no API. 243 lines re-implementing parse, cut and\n * write for a format the framework owns. The consumer is not at fault: nothing here was reachable.\n *\n * ## The rule that travels WITH the operation\n *\n * `rules/audit-trail-rotation.md § Session transcripts (M60)` defines a NEVER-delete list — the live\n * pointer, the most recent transcript, and any active registry entry. That rule lived in the\n * CONSUMER. Moving the operation here without moving the rule would ship an API able to destroy\n * exactly what the rule protects — the same shape of defect as M80's `reconcileUpdateGoalStatus`:\n * critical knowledge outside the module that needs it, applied by convention.\n *\n * So `forkTranscript` takes `liveSessionPaths` and refuses, with a TYPED error, to write over any of\n * them. The caller supplies the list because only the caller knows which session is live; the\n * enforcement lives here because that is where the write happens.\n *\n * @internal\n */\n\nimport { closeSync, openSync, readFileSync, readSync, statSync, writeSync } from \"node:fs\";\n\nimport { TheokitAgentError } from \"../../errors.js\";\n\n/**\n * M81 — the target is a protected session (live pointer / most-recent transcript / active entry).\n *\n * Typed rather than a bare `Error` because the caller must distinguish \"this session is protected\"\n * from \"the disk is full\": the first is a correct refusal, the second is an incident.\n */\nexport class LiveSessionError extends TheokitAgentError {\n override readonly name = \"LiveSessionError\";\n\n constructor(readonly path: string) {\n super(\n `refusing to write over a live session transcript: ${path}. ` +\n \"Fork to a new id instead — the live pointer, the most recent transcript and any active \" +\n \"registry entry are never overwritten (audit-trail rotation, M60).\",\n { code: \"live_session_protected\", isRetryable: false },\n );\n }\n}\n\n/** Options for {@link forkTranscript}. */\nexport interface ForkTranscriptOptions {\n /** Keep records `[0, beforeRecordIndex)`. Omit to copy the whole transcript. */\n readonly beforeRecordIndex?: number;\n /**\n * Paths that must never be written over — the live pointer, the most recent transcript, any active\n * registry entry. The caller supplies them because only the caller knows which session is live.\n */\n readonly liveSessionPaths?: readonly string[];\n}\n\n/**\n * Copy `src` into `dst`, keeping the first `beforeRecordIndex` records. The SOURCE is never touched.\n *\n * Atomicity comes from `wx` (exclusive create): two concurrent forks to the same destination cannot\n * both succeed — the loser gets `EEXIST` rather than writing over a half-written file. That is also\n * why an existing destination is a refusal, not a silent overwrite: losing a transcript without an\n * error is the worst failure mode for an operation that touches user sessions.\n */\nexport function forkTranscript(\n src: string,\n dst: string,\n options: ForkTranscriptOptions = {},\n): void {\n for (const live of options.liveSessionPaths ?? []) {\n if (live === dst) throw new LiveSessionError(dst);\n }\n\n const lines = readFileSync(src, \"utf8\")\n .split(\"\\n\")\n .filter((l) => l.trim().length > 0);\n const kept =\n options.beforeRecordIndex === undefined ? lines : lines.slice(0, options.beforeRecordIndex);\n const body = kept.length > 0 ? `${kept.join(\"\\n\")}\\n` : \"\";\n\n // `wx` — fails with EEXIST instead of truncating. The exclusivity IS the concurrency guarantee.\n const fd = openSync(dst, \"wx\");\n try {\n writeSync(fd, body);\n } finally {\n closeSync(fd);\n }\n}\n\n/** Options for {@link readJsonlTail}. */\nexport interface ReadJsonlTailOptions {\n /** Maximum records to return, counted from the END. */\n readonly maxRecords?: number;\n /** Stop once a line contains this marker (exclusive). */\n readonly sinceMarker?: string;\n /** Test-only: also report how many bytes were read, to prove the read is not whole-file. */\n readonly _stats?: boolean;\n}\n\nconst TAIL_CHUNK = 64 * 1024;\n\n/**\n * Lê chunks de trás para frente até acumular linhas completas suficientes.\n *\n * Extraído de `readJsonlTail` porque o laço de leitura e a seleção de registros são duas\n * responsabilidades — e juntas passavam do teto de complexidade. A primeira linha do buffer pode\n * estar cortada ao meio quando a leitura parou antes do início do arquivo; por isso ela é descartada.\n */\nfunction lerCaudaBruta(path: string, want: number): { linhas: string[]; bytesRead: number } {\n const size = statSync(path).size;\n const fd = openSync(path, \"r\");\n let bytesRead = 0;\n let tail = \"\";\n let pos = size;\n try {\n while (pos > 0) {\n const len = Math.min(TAIL_CHUNK, pos);\n pos -= len;\n const buf = Buffer.alloc(len);\n readSync(fd, buf, 0, len, pos);\n bytesRead += len;\n tail = buf.toString(\"utf8\") + tail;\n if (naoVazias(tail).length > want) break;\n }\n } finally {\n closeSync(fd);\n }\n const linhas = naoVazias(tail);\n return { linhas: pos > 0 ? linhas.slice(1) : linhas, bytesRead };\n}\n\n/** Linhas com conteúdo, na ordem do arquivo. */\nfunction naoVazias(texto: string): string[] {\n return texto.split(\"\\n\").filter((l) => l.trim().length > 0);\n}\n\n/**\n * Read the LAST records of a JSONL file without loading the whole thing.\n *\n * Reads fixed-size chunks backwards from EOF until enough newlines have been seen. A session\n * transcript grows without bound; loading megabytes to show the last three turns is the cost this\n * exists to avoid — and a `slice` over a full read would be that same cost with a better name.\n */\nexport function readJsonlTail<T = Record<string, unknown>>(\n path: string,\n options: ReadJsonlTailOptions = {},\n): T[] {\n const want = options.maxRecords ?? Number.POSITIVE_INFINITY;\n const { linhas, bytesRead } = lerCaudaBruta(path, want);\n\n let sel = linhas;\n if (options.sinceMarker !== undefined) {\n const marcador = options.sinceMarker;\n const idx = sel.findLastIndex((l) => l.includes(marcador));\n if (idx >= 0) sel = sel.slice(idx + 1);\n }\n if (Number.isFinite(want)) sel = sel.slice(-want);\n\n const out = sel.map((l) => JSON.parse(l) as T);\n return options._stats === true ? (Object.assign(out, { bytesRead }) as T[]) : out;\n}\n"]}
@@ -1,6 +1,5 @@
1
- export { JsonlParseError, appendJsonl, loadJsonl, readJsonlIds } from './chunk-R6ZP6KNB.js';
2
1
  export { PersistenceSchema } from './chunk-CAH3G4IS.js';
3
- export { withFileLock } from './chunk-HZQEDNF6.js';
2
+ export { JsonlParseError, appendJsonl, loadJsonl, readJsonlIds, withFileLock } from './chunk-ICSCKB3N.js';
4
3
  export { applyWalWithFallback, isCorruptionError, openSqliteResilient, sanitizeFts5Query } from './chunk-77FOZCOT.js';
5
4
  export { withCwdMutex } from './chunk-2XLKLVVR.js';
6
5
  export { encodeProjectDir, transcriptPath } from './chunk-ZZWTY3RX.js';