@coderifts/agent-guard 6.0.0 → 6.2.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 (76) hide show
  1. package/README.md +105 -4
  2. package/dist/cjs/adapters/anthropic.d.ts +26 -0
  3. package/dist/cjs/adapters/anthropic.d.ts.map +1 -1
  4. package/dist/cjs/adapters/anthropic.js +68 -0
  5. package/dist/cjs/adapters/anthropic.js.map +1 -1
  6. package/dist/cjs/adapters/gemini.d.ts +39 -0
  7. package/dist/cjs/adapters/gemini.d.ts.map +1 -1
  8. package/dist/cjs/adapters/gemini.js +83 -0
  9. package/dist/cjs/adapters/gemini.js.map +1 -1
  10. package/dist/cjs/adapters/langgraph.d.ts +29 -0
  11. package/dist/cjs/adapters/langgraph.d.ts.map +1 -1
  12. package/dist/cjs/adapters/langgraph.js +70 -0
  13. package/dist/cjs/adapters/langgraph.js.map +1 -1
  14. package/dist/cjs/adapters/openai.d.ts +44 -0
  15. package/dist/cjs/adapters/openai.d.ts.map +1 -1
  16. package/dist/cjs/adapters/openai.js +86 -0
  17. package/dist/cjs/adapters/openai.js.map +1 -1
  18. package/dist/cjs/cas-adapters/fs.d.ts +79 -0
  19. package/dist/cjs/cas-adapters/fs.d.ts.map +1 -0
  20. package/dist/cjs/cas-adapters/fs.js +224 -0
  21. package/dist/cjs/cas-adapters/fs.js.map +1 -0
  22. package/dist/cjs/conditional-write.d.ts +66 -0
  23. package/dist/cjs/conditional-write.d.ts.map +1 -1
  24. package/dist/cjs/conditional-write.js +72 -1
  25. package/dist/cjs/conditional-write.js.map +1 -1
  26. package/dist/cjs/execution-time-fingerprint.d.ts +65 -0
  27. package/dist/cjs/execution-time-fingerprint.d.ts.map +1 -0
  28. package/dist/cjs/execution-time-fingerprint.js +129 -0
  29. package/dist/cjs/execution-time-fingerprint.js.map +1 -0
  30. package/dist/cjs/guard.d.ts.map +1 -1
  31. package/dist/cjs/guard.js +35 -0
  32. package/dist/cjs/guard.js.map +1 -1
  33. package/dist/cjs/index.d.ts +13 -10
  34. package/dist/cjs/index.d.ts.map +1 -1
  35. package/dist/cjs/index.js +33 -3
  36. package/dist/cjs/index.js.map +1 -1
  37. package/dist/cjs/types.d.ts +23 -1
  38. package/dist/cjs/types.d.ts.map +1 -1
  39. package/dist/esm/adapters/anthropic.d.ts +26 -0
  40. package/dist/esm/adapters/anthropic.d.ts.map +1 -1
  41. package/dist/esm/adapters/anthropic.js +66 -0
  42. package/dist/esm/adapters/anthropic.js.map +1 -1
  43. package/dist/esm/adapters/gemini.d.ts +39 -0
  44. package/dist/esm/adapters/gemini.d.ts.map +1 -1
  45. package/dist/esm/adapters/gemini.js +81 -0
  46. package/dist/esm/adapters/gemini.js.map +1 -1
  47. package/dist/esm/adapters/langgraph.d.ts +29 -0
  48. package/dist/esm/adapters/langgraph.d.ts.map +1 -1
  49. package/dist/esm/adapters/langgraph.js +68 -0
  50. package/dist/esm/adapters/langgraph.js.map +1 -1
  51. package/dist/esm/adapters/openai.d.ts +44 -0
  52. package/dist/esm/adapters/openai.d.ts.map +1 -1
  53. package/dist/esm/adapters/openai.js +84 -0
  54. package/dist/esm/adapters/openai.js.map +1 -1
  55. package/dist/esm/cas-adapters/fs.d.ts +79 -0
  56. package/dist/esm/cas-adapters/fs.d.ts.map +1 -0
  57. package/dist/esm/cas-adapters/fs.js +185 -0
  58. package/dist/esm/cas-adapters/fs.js.map +1 -0
  59. package/dist/esm/conditional-write.d.ts +66 -0
  60. package/dist/esm/conditional-write.d.ts.map +1 -1
  61. package/dist/esm/conditional-write.js +69 -0
  62. package/dist/esm/conditional-write.js.map +1 -1
  63. package/dist/esm/execution-time-fingerprint.d.ts +65 -0
  64. package/dist/esm/execution-time-fingerprint.d.ts.map +1 -0
  65. package/dist/esm/execution-time-fingerprint.js +123 -0
  66. package/dist/esm/execution-time-fingerprint.js.map +1 -0
  67. package/dist/esm/guard.d.ts.map +1 -1
  68. package/dist/esm/guard.js +35 -0
  69. package/dist/esm/guard.js.map +1 -1
  70. package/dist/esm/index.d.ts +13 -10
  71. package/dist/esm/index.d.ts.map +1 -1
  72. package/dist/esm/index.js +15 -6
  73. package/dist/esm/index.js.map +1 -1
  74. package/dist/esm/types.d.ts +23 -1
  75. package/dist/esm/types.d.ts.map +1 -1
  76. package/package.json +1 -1
@@ -33,6 +33,7 @@
33
33
  * Mirrors src/adapters/openai.ts and anthropic.ts — only the target tool shape differs.
34
34
  */
35
35
  import { withCodeRifts } from '../with-coderifts.js';
36
+ import { attachProofToAgentResponse } from '../final-answer-proof.js';
36
37
  /** Empty JSON Schema object — used when a ProtectedTool has no inputSchema. */
37
38
  const EMPTY_SCHEMA = Object.freeze({
38
39
  type: 'object',
@@ -104,4 +105,71 @@ export function langGraphToolAdapter(result) {
104
105
  }
105
106
  return out;
106
107
  }
108
+ export function defaultSerializeLangGraphToolResult(result) {
109
+ if (typeof result === 'string')
110
+ return result;
111
+ if (typeof result === 'number'
112
+ || typeof result === 'boolean'
113
+ || typeof result === 'bigint'
114
+ || result === null
115
+ || result === undefined) {
116
+ return String(result);
117
+ }
118
+ try {
119
+ return JSON.stringify(result);
120
+ }
121
+ catch {
122
+ return String(result);
123
+ }
124
+ }
125
+ /**
126
+ * Map a full GuardOutcome into a LangGraph/LangChain ToolMessage shape with proof embedded.
127
+ * Same arm mapping as bindOpenAIGuardOutcome; id field is tool_call_id.
128
+ */
129
+ export function bindLangGraphGuardOutcome(outcome, args) {
130
+ const tool_call_id = args.tool_call_id;
131
+ const serialize = args.serialize ?? defaultSerializeLangGraphToolResult;
132
+ let body;
133
+ if (outcome.executed === true) {
134
+ body = serialize(outcome.result);
135
+ }
136
+ else if (outcome.executionAttempted === false) {
137
+ const kind = verdictKind(outcome);
138
+ body =
139
+ `CodeRifts gate did not permit execution (verdict: ${kind}). `
140
+ + 'No tool result was produced.';
141
+ }
142
+ else {
143
+ const err = 'error' in outcome ? outcome.error : undefined;
144
+ const kind = verdictKind(outcome);
145
+ body =
146
+ `Tool execution failed after gate decision (verdict: ${kind}): ${formatGuardError(err)}`;
147
+ }
148
+ const content = attachProofToAgentResponse(body, outcome.proof);
149
+ const msg = {
150
+ content,
151
+ tool_call_id,
152
+ };
153
+ if (args.name != null && args.name !== '') {
154
+ msg.name = args.name;
155
+ }
156
+ return msg;
157
+ }
158
+ function verdictKind(outcome) {
159
+ return outcome.verdict && typeof outcome.verdict === 'object' && 'kind' in outcome.verdict
160
+ ? String(outcome.verdict.kind)
161
+ : 'UNKNOWN';
162
+ }
163
+ function formatGuardError(err) {
164
+ if (err instanceof Error)
165
+ return err.message || err.name || 'Error';
166
+ if (typeof err === 'string')
167
+ return err;
168
+ try {
169
+ return JSON.stringify(err);
170
+ }
171
+ catch {
172
+ return String(err);
173
+ }
174
+ }
107
175
  //# sourceMappingURL=langgraph.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"langgraph.js","sourceRoot":"","sources":["../../../src/adapters/langgraph.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GAiCG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AA8DrD,+EAA+E;AAC/E,MAAM,YAAY,GAA4B,MAAM,CAAC,MAAM,CAAC;IAC1D,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE,EAAE;CACf,CAAC,CAAC;AAEH;;;;GAIG;AACH,MAAM,UAAU,wBAAwB,CAAC,IAAmB;IAC1D,MAAM,MAAM,GACV,IAAI,CAAC,WAAW,IAAI,IAAI;WACrB,OAAO,IAAI,CAAC,WAAW,KAAK,QAAQ;WACpC,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC;QACjC,CAAC,CAAE,IAAI,CAAC,WAAuC;QAC/C,CAAC,CAAC,EAAE,GAAG,YAAY,EAAE,CAAC;IAE1B,yDAAyD;IACzD,MAAM,OAAO,GAAG,CAAC,IAAa,EAAE,EAAE,CAAC,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IAEvE,MAAM,GAAG,GAA4B;QACnC,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,MAAM;QACN,IAAI,EAAE,OAAO;QACb,MAAM,EAAE,OAAO;KAChB,CAAC;IACF,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,IAAI,IAAI,CAAC,WAAW,KAAK,EAAE,EAAE,CAAC;QACxD,GAAG,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;IACrC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,gBAAgB,CAAC,cAAwC;IACvE,OAAO,cAAc,CAAC,GAAG,CAAC,wBAAwB,CAAC,CAAC;AACtD,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,sBAAsB,CAAC,KAAyB;IAC9D,MAAM,IAAI,GAAwB,aAAa,CAAC,KAAK,CAAC,CAAC;IACvD,OAAO,oBAAoB,CAAC,IAAI,CAAC,CAAC;AACpC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,oBAAoB,CAAC,MAA2B;IAC9D,MAAM,eAAe,GAAG,MAAM,CAAC,KAAK,CAAC;IACrC,MAAM,KAAK,GAAG,gBAAgB,CAAC,eAAe,CAAC,CAAC;IAChD,MAAM,GAAG,GAAiC;QACxC,KAAK;QACL,eAAe;QACf,eAAe,EAAE,MAAM,CAAC,eAAe;QACvC,qBAAqB,EAAE,MAAM,CAAC,qBAAqB;QACnD,cAAc,EAAE,MAAM,CAAC,cAAc;KACtC,CAAC;IACF,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QACpC,GAAG,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;IACrC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
1
+ {"version":3,"file":"langgraph.js","sourceRoot":"","sources":["../../../src/adapters/langgraph.ts"],"names":[],"mappings":"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"}
@@ -23,6 +23,7 @@
23
23
  */
24
24
  import type { WithCodeRiftsInput, WithCodeRiftsResult, CompositionAssurance, ReceiptThreadHandle } from '../with-coderifts.js';
25
25
  import type { ProtectedTool, RegistryCoverageReport } from '../tool-registry.js';
26
+ import type { GuardOutcome } from '../types.js';
26
27
  /**
27
28
  * OpenAI chat.completions `tools[]` element (function tool).
28
29
  * @see https://platform.openai.com/docs/guides/function-calling
@@ -90,4 +91,47 @@ export declare function withCodeRiftsOpenAI(input: WithCodeRiftsInput): WithCode
90
91
  * Does not re-run the guard; does not invent assurance.
91
92
  */
92
93
  export declare function openAIToolAdapter(result: WithCodeRiftsResult): WithCodeRiftsOpenAIResult;
94
+ /**
95
+ * Minimal OpenAI chat tool-message (role tool). No openai SDK dependency.
96
+ * @see https://platform.openai.com/docs/guides/function-calling
97
+ */
98
+ export type OpenAIToolMessage = {
99
+ role: 'tool';
100
+ tool_call_id: string;
101
+ content: string;
102
+ };
103
+ /**
104
+ * Brand for proof-bound OpenAI tool messages (compile-time detection of proof-forgotten paths).
105
+ * Type-level only — same pattern as ReceiptVerifiedEnvelope; not a runtime wire field.
106
+ */
107
+ declare const __proofBoundBrand: unique symbol;
108
+ export type ProofBoundOpenAIToolMessage = OpenAIToolMessage & {
109
+ readonly __proofBound: typeof __proofBoundBrand;
110
+ };
111
+ export type BindOpenAIGuardOutcomeArgs<T> = {
112
+ /** OpenAI tool_call_id this message answers. */
113
+ tool_call_id: string;
114
+ /** Override result serialization (default: JSON.stringify objects, String() primitives). */
115
+ serialize?: (result: T) => string;
116
+ };
117
+ /**
118
+ * Default result → content body serializer (pure).
119
+ * Objects/arrays → JSON.stringify; strings unchanged; other primitives → String().
120
+ */
121
+ export declare function defaultSerializeOpenAIToolResult<T>(result: T): string;
122
+ /**
123
+ * Map a full GuardOutcome into an OpenAI tool message with the execution proof embedded.
124
+ *
125
+ * Option B (proof-binding helper): host still calls guardToolCall; this only binds
126
+ * outcome → framework tool-result. Pure and non-mutating. Always embeds outcome.proof
127
+ * (present on every arm) via attachProofToAgentResponse / renderFinalAnswerProof —
128
+ * does not reinvent proof formatting.
129
+ *
130
+ * Arms:
131
+ * - executed (result): serialized result + rendered proof
132
+ * - blocked before factory: gate-denied text (no fabricated result) + proof
133
+ * - factory threw: error indication + proof
134
+ */
135
+ export declare function bindOpenAIGuardOutcome<T>(outcome: GuardOutcome<T>, args: BindOpenAIGuardOutcomeArgs<T>): ProofBoundOpenAIToolMessage;
136
+ export {};
93
137
  //# sourceMappingURL=openai.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../../src/adapters/openai.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,KAAK,EACV,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AAEjF;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,2EAA2E;QAC3E,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACrC,CAAC;CACH,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,yBAAyB,GAAG;IACtC,+EAA+E;IAC/E,KAAK,EAAE,kBAAkB,EAAE,CAAC;IAC5B;;;OAGG;IACH,eAAe,EAAE,aAAa,EAAE,CAAC;IACjC,wDAAwD;IACxD,eAAe,EAAE,sBAAsB,CAAC;IACxC;;;;OAIG;IACH,qBAAqB,EAAE,oBAAoB,CAAC;IAC5C,yEAAyE;IACzE,cAAc,EAAE,mBAAmB,CAAC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAQF;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,aAAa,GAAG,kBAAkB,CAgB7E;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,cAAc,EAAE,SAAS,aAAa,EAAE,GAAG,kBAAkB,EAAE,CAE5F;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,kBAAkB,GAAG,yBAAyB,CAGxF;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,mBAAmB,GAAG,yBAAyB,CAcxF"}
1
+ {"version":3,"file":"openai.d.ts","sourceRoot":"","sources":["../../../src/adapters/openai.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAGH,OAAO,KAAK,EACV,kBAAkB,EAClB,mBAAmB,EACnB,oBAAoB,EACpB,mBAAmB,EACpB,MAAM,sBAAsB,CAAC;AAC9B,OAAO,KAAK,EAAE,aAAa,EAAE,sBAAsB,EAAE,MAAM,qBAAqB,CAAC;AACjF,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,aAAa,CAAC;AAGhD;;;GAGG;AACH,MAAM,MAAM,kBAAkB,GAAG;IAC/B,IAAI,EAAE,UAAU,CAAC;IACjB,QAAQ,EAAE;QACR,IAAI,EAAE,MAAM,CAAC;QACb,WAAW,CAAC,EAAE,MAAM,CAAC;QACrB,2EAA2E;QAC3E,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;KACrC,CAAC;CACH,CAAC;AAEF;;;;;GAKG;AACH,MAAM,MAAM,yBAAyB,GAAG;IACtC,+EAA+E;IAC/E,KAAK,EAAE,kBAAkB,EAAE,CAAC;IAC5B;;;OAGG;IACH,eAAe,EAAE,aAAa,EAAE,CAAC;IACjC,wDAAwD;IACxD,eAAe,EAAE,sBAAsB,CAAC;IACxC;;;;OAIG;IACH,qBAAqB,EAAE,oBAAoB,CAAC;IAC5C,yEAAyE;IACzE,cAAc,EAAE,mBAAmB,CAAC;IACpC,UAAU,CAAC,EAAE,MAAM,CAAC;CACrB,CAAC;AAQF;;;GAGG;AACH,wBAAgB,qBAAqB,CAAC,IAAI,EAAE,aAAa,GAAG,kBAAkB,CAgB7E;AAED;;;GAGG;AACH,wBAAgB,aAAa,CAAC,cAAc,EAAE,SAAS,aAAa,EAAE,GAAG,kBAAkB,EAAE,CAE5F;AAED;;;;;;;;;GASG;AACH,wBAAgB,mBAAmB,CAAC,KAAK,EAAE,kBAAkB,GAAG,yBAAyB,CAGxF;AAED;;;;;GAKG;AACH,wBAAgB,iBAAiB,CAAC,MAAM,EAAE,mBAAmB,GAAG,yBAAyB,CAcxF;AAID;;;GAGG;AACH,MAAM,MAAM,iBAAiB,GAAG;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,YAAY,EAAE,MAAM,CAAC;IACrB,OAAO,EAAE,MAAM,CAAC;CACjB,CAAC;AAEF;;;GAGG;AACH,OAAO,CAAC,MAAM,iBAAiB,EAAE,OAAO,MAAM,CAAC;AAC/C,MAAM,MAAM,2BAA2B,GAAG,iBAAiB,GAAG;IAC5D,QAAQ,CAAC,YAAY,EAAE,OAAO,iBAAiB,CAAC;CACjD,CAAC;AAEF,MAAM,MAAM,0BAA0B,CAAC,CAAC,IAAI;IAC1C,gDAAgD;IAChD,YAAY,EAAE,MAAM,CAAC;IACrB,4FAA4F;IAC5F,SAAS,CAAC,EAAE,CAAC,MAAM,EAAE,CAAC,KAAK,MAAM,CAAC;CACnC,CAAC;AAEF;;;GAGG;AACH,wBAAgB,gCAAgC,CAAC,CAAC,EAAE,MAAM,EAAE,CAAC,GAAG,MAAM,CAgBrE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,sBAAsB,CAAC,CAAC,EACtC,OAAO,EAAE,YAAY,CAAC,CAAC,CAAC,EACxB,IAAI,EAAE,0BAA0B,CAAC,CAAC,CAAC,GAClC,2BAA2B,CAqC7B"}
@@ -22,6 +22,7 @@
22
22
  * LangGraph / Anthropic adapters follow the same thin-converter pattern later.
23
23
  */
24
24
  import { withCodeRifts } from '../with-coderifts.js';
25
+ import { attachProofToAgentResponse } from '../final-answer-proof.js';
25
26
  /** Empty JSON Schema object — used when a ProtectedTool has no inputSchema. */
26
27
  const EMPTY_PARAMETERS = Object.freeze({
27
28
  type: 'object',
@@ -88,4 +89,87 @@ export function openAIToolAdapter(result) {
88
89
  }
89
90
  return out;
90
91
  }
92
+ /**
93
+ * Default result → content body serializer (pure).
94
+ * Objects/arrays → JSON.stringify; strings unchanged; other primitives → String().
95
+ */
96
+ export function defaultSerializeOpenAIToolResult(result) {
97
+ if (typeof result === 'string')
98
+ return result;
99
+ if (typeof result === 'number'
100
+ || typeof result === 'boolean'
101
+ || typeof result === 'bigint'
102
+ || result === null
103
+ || result === undefined) {
104
+ return String(result);
105
+ }
106
+ try {
107
+ return JSON.stringify(result);
108
+ }
109
+ catch {
110
+ return String(result);
111
+ }
112
+ }
113
+ /**
114
+ * Map a full GuardOutcome into an OpenAI tool message with the execution proof embedded.
115
+ *
116
+ * Option B (proof-binding helper): host still calls guardToolCall; this only binds
117
+ * outcome → framework tool-result. Pure and non-mutating. Always embeds outcome.proof
118
+ * (present on every arm) via attachProofToAgentResponse / renderFinalAnswerProof —
119
+ * does not reinvent proof formatting.
120
+ *
121
+ * Arms:
122
+ * - executed (result): serialized result + rendered proof
123
+ * - blocked before factory: gate-denied text (no fabricated result) + proof
124
+ * - factory threw: error indication + proof
125
+ */
126
+ export function bindOpenAIGuardOutcome(outcome, args) {
127
+ const tool_call_id = args.tool_call_id;
128
+ const serialize = args.serialize ?? defaultSerializeOpenAIToolResult;
129
+ let body;
130
+ if (outcome.executed === true) {
131
+ // Executed arms (enforced or not): result is present.
132
+ body = serialize(outcome.result);
133
+ }
134
+ else if (outcome.executionAttempted === false) {
135
+ // Blocked before factory — no result; never fabricate one.
136
+ const kind = outcome.verdict && typeof outcome.verdict === 'object' && 'kind' in outcome.verdict
137
+ ? String(outcome.verdict.kind)
138
+ : 'UNKNOWN';
139
+ body =
140
+ `CodeRifts gate did not permit execution (verdict: ${kind}). `
141
+ + 'No tool result was produced.';
142
+ }
143
+ else {
144
+ // executionAttempted && !executed → factory threw; error is present.
145
+ const err = 'error' in outcome ? outcome.error : undefined;
146
+ const errText = formatGuardError(err);
147
+ const kind = outcome.verdict && typeof outcome.verdict === 'object' && 'kind' in outcome.verdict
148
+ ? String(outcome.verdict.kind)
149
+ : 'UNKNOWN';
150
+ body =
151
+ `Tool execution failed after gate decision (verdict: ${kind}): ${errText}`;
152
+ }
153
+ // Reuse public proof render path (string append) — same separator/render as final-answer attach.
154
+ const content = attachProofToAgentResponse(body, outcome.proof);
155
+ // Type brand only (no extra wire keys — OpenAI tool messages stay {role, tool_call_id, content}).
156
+ const msg = {
157
+ role: 'tool',
158
+ tool_call_id,
159
+ content,
160
+ };
161
+ return msg;
162
+ }
163
+ function formatGuardError(err) {
164
+ if (err instanceof Error)
165
+ return err.message || err.name || 'Error';
166
+ if (typeof err === 'string')
167
+ return err;
168
+ try {
169
+ return JSON.stringify(err);
170
+ }
171
+ catch {
172
+ return String(err);
173
+ }
174
+ }
91
175
  //# sourceMappingURL=openai.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"openai.js","sourceRoot":"","sources":["../../../src/adapters/openai.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;GAsBG;AAEH,OAAO,EAAE,aAAa,EAAE,MAAM,sBAAsB,CAAC;AAkDrD,+EAA+E;AAC/E,MAAM,gBAAgB,GAA4B,MAAM,CAAC,MAAM,CAAC;IAC9D,IAAI,EAAE,QAAQ;IACd,UAAU,EAAE,EAAE;CACf,CAAC,CAAC;AAEH;;;GAGG;AACH,MAAM,UAAU,qBAAqB,CAAC,IAAmB;IACvD,MAAM,UAAU,GACd,IAAI,CAAC,WAAW,IAAI,IAAI;WACrB,OAAO,IAAI,CAAC,WAAW,KAAK,QAAQ;WACpC,CAAC,KAAK,CAAC,OAAO,CAAC,IAAI,CAAC,WAAW,CAAC;QACjC,CAAC,CAAE,IAAI,CAAC,WAAuC;QAC/C,CAAC,CAAC,EAAE,GAAG,gBAAgB,EAAE,CAAC;IAE9B,MAAM,EAAE,GAAmC;QACzC,IAAI,EAAE,IAAI,CAAC,IAAI;QACf,UAAU;KACX,CAAC;IACF,IAAI,IAAI,CAAC,WAAW,IAAI,IAAI,IAAI,IAAI,CAAC,WAAW,KAAK,EAAE,EAAE,CAAC;QACxD,EAAE,CAAC,WAAW,GAAG,IAAI,CAAC,WAAW,CAAC;IACpC,CAAC;IACD,OAAO,EAAE,IAAI,EAAE,UAAU,EAAE,QAAQ,EAAE,EAAE,EAAE,CAAC;AAC5C,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,aAAa,CAAC,cAAwC;IACpE,OAAO,cAAc,CAAC,GAAG,CAAC,qBAAqB,CAAC,CAAC;AACnD,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,mBAAmB,CAAC,KAAyB;IAC3D,MAAM,IAAI,GAAwB,aAAa,CAAC,KAAK,CAAC,CAAC;IACvD,OAAO,iBAAiB,CAAC,IAAI,CAAC,CAAC;AACjC,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,iBAAiB,CAAC,MAA2B;IAC3D,MAAM,eAAe,GAAG,MAAM,CAAC,KAAK,CAAC;IACrC,MAAM,KAAK,GAAG,aAAa,CAAC,eAAe,CAAC,CAAC;IAC7C,MAAM,GAAG,GAA8B;QACrC,KAAK;QACL,eAAe;QACf,eAAe,EAAE,MAAM,CAAC,eAAe;QACvC,qBAAqB,EAAE,MAAM,CAAC,qBAAqB;QACnD,cAAc,EAAE,MAAM,CAAC,cAAc;KACtC,CAAC;IACF,IAAI,MAAM,CAAC,UAAU,KAAK,SAAS,EAAE,CAAC;QACpC,GAAG,CAAC,UAAU,GAAG,MAAM,CAAC,UAAU,CAAC;IACrC,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC"}
1
+ {"version":3,"file":"openai.js","sourceRoot":"","sources":["../../../src/adapters/openai.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,79 @@
1
+ /**
2
+ * Filesystem CAS adapter — mtime + content-hash VersionToken and atomic-rename write.
3
+ *
4
+ * Uses the host contract helper executeIfUnchanged (conditional-write.ts). Does not invent
5
+ * a parallel outcome shape. Token format is opaque to the guard (string equality only).
6
+ *
7
+ * Token encoding (this adapter only; not interpreted by the core):
8
+ * fs:v1:<mtime_ms>:<sha256_hex_of_file_bytes>
9
+ * Missing file → createFsVersionToken still works for "absent" via a dedicated absent token
10
+ * only if we choose; for create we require the file to exist (ENOENT throws) so hosts
11
+ * measure an existing prior. For write of new files, expected_token may be ABSENT_TOKEN.
12
+ */
13
+ import { tokensEqual, type ExecuteIfUnchangedOutcome, type VersionToken, type VersionedContent } from '../conditional-write.js';
14
+ import type { PriorContentResolver } from '../freshness.js';
15
+ /** Prefix for this adapter's opaque tokens (equality-only outside this module). */
16
+ export declare const FS_VERSION_TOKEN_PREFIX = "fs:v1:";
17
+ /**
18
+ * Token used when the path does not exist yet (create-if-absent CAS).
19
+ * Hosts that measured absence should pass this as expected_token for first write.
20
+ */
21
+ export declare const FS_ABSENT_TOKEN: VersionToken;
22
+ /** Extract content-hash segment from an fs:v1 token (null if absent/malformed). */
23
+ export declare function fsTokenContentHash(token: VersionToken | null | undefined): string | null;
24
+ /**
25
+ * Build a VersionToken from path: mtime (ms) + sha256 of file bytes.
26
+ * Throws on I/O errors other than callers may catch. ENOENT → returns FS_ABSENT_TOKEN
27
+ * so hosts can CAS create vs create-raced.
28
+ */
29
+ export declare function createFsVersionToken(filePath: string): Promise<VersionToken>;
30
+ /**
31
+ * Read file content + version token for VersionedContent (host reporting / preflight prior).
32
+ * ENOENT → content '' and FS_ABSENT_TOKEN.
33
+ */
34
+ export declare function readVersionedFile(filePath: string): Promise<VersionedContent>;
35
+ export type WriteFileIfUnchangedArgs = {
36
+ path: string;
37
+ /** Token measured before the host decided to write (from createFsVersionToken). */
38
+ expected_token: VersionToken;
39
+ /** Full new file contents (utf8 string or Buffer). */
40
+ content: string | Buffer;
41
+ };
42
+ /**
43
+ * Conditional write: re-stat+re-hash; if token matches expected → temp file + atomic rename.
44
+ *
45
+ * MEASURED windows (pre-fix, 2fcd74e-era):
46
+ * 1. executeIfUnchanged: current_token() then await write() — no re-check in between.
47
+ * 2. write(): writeFile(tmp) then rename(tmp,target) with NO re-stat of target before rename
48
+ * (fs.ts former lines 106–108) — concurrent mutation of target is clobbered by rename.
49
+ *
50
+ * Closures:
51
+ * - Pre-rename: re-createFsVersionToken(target); on mismatch abort rename, unlink tmp,
52
+ * throw StaleVersionTokenAbort → refused/stale_version_token (write did not land).
53
+ * - Post-rename: detect_stale_during_commit — content-hash of path must match sha256(body);
54
+ * mismatch → committed_stale_detected (write landed; someone overwrote after rename).
55
+ *
56
+ * Wired through executeIfUnchanged — not a parallel path.
57
+ */
58
+ export declare function writeFileIfUnchanged(args: WriteFileIfUnchangedArgs): Promise<ExecuteIfUnchangedOutcome<{
59
+ path: string;
60
+ bytes: number;
61
+ written_content_hash: string;
62
+ }>>;
63
+ /**
64
+ * Opt-in PriorContentResolver that reads a file path from tool arguments.
65
+ * Returns file utf8 content for freshness measurement (string only — tokens travel separately
66
+ * via versioned_content / conditioned_on_token on the call context).
67
+ *
68
+ * Plug-in: pass as GuardConfig.resolvePriorContent / withCodeRifts({ resolvePriorContent }).
69
+ */
70
+ export declare function createFsPriorContentResolver(options?: {
71
+ /**
72
+ * Map artifactId → absolute or relative file path.
73
+ * If omitted, uses req.path or arguments-style path when provided on the resolve request.
74
+ */
75
+ pathForArtifact?: (artifactId: string) => string | null | undefined;
76
+ }): PriorContentResolver;
77
+ /** Re-export equality helper for hosts comparing tokens without importing core module. */
78
+ export { tokensEqual };
79
+ //# sourceMappingURL=fs.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs.d.ts","sourceRoot":"","sources":["../../../src/cas-adapters/fs.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;GAWG;AAOH,OAAO,EAGL,WAAW,EACX,KAAK,yBAAyB,EAC9B,KAAK,YAAY,EACjB,KAAK,gBAAgB,EACtB,MAAM,yBAAyB,CAAC;AACjC,OAAO,KAAK,EAAE,oBAAoB,EAAE,MAAM,iBAAiB,CAAC;AAE5D,mFAAmF;AACnF,eAAO,MAAM,uBAAuB,WAAW,CAAC;AAEhD;;;GAGG;AACH,eAAO,MAAM,eAAe,EAAE,YAA6B,CAAC;AAM5D,mFAAmF;AACnF,wBAAgB,kBAAkB,CAAC,KAAK,EAAE,YAAY,GAAG,IAAI,GAAG,SAAS,GAAG,MAAM,GAAG,IAAI,CAQxF;AAED;;;;GAIG;AACH,wBAAsB,oBAAoB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,YAAY,CAAC,CAmBlF;AAED;;;GAGG;AACH,wBAAsB,iBAAiB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAOnF;AAED,MAAM,MAAM,wBAAwB,GAAG;IACrC,IAAI,EAAE,MAAM,CAAC;IACb,mFAAmF;IACnF,cAAc,EAAE,YAAY,CAAC;IAC7B,sDAAsD;IACtD,OAAO,EAAE,MAAM,GAAG,MAAM,CAAC;CAC1B,CAAC;AAEF;;;;;;;;;;;;;;;GAeG;AACH,wBAAsB,oBAAoB,CACxC,IAAI,EAAE,wBAAwB,GAC7B,OAAO,CAAC,yBAAyB,CAAC;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,oBAAoB,EAAE,MAAM,CAAA;CAAE,CAAC,CAAC,CAsDnG;AAED;;;;;;GAMG;AACH,wBAAgB,4BAA4B,CAAC,OAAO,CAAC,EAAE;IACrD;;;OAGG;IACH,eAAe,CAAC,EAAE,CAAC,UAAU,EAAE,MAAM,KAAK,MAAM,GAAG,IAAI,GAAG,SAAS,CAAC;CACrE,GAAG,oBAAoB,CAoBvB;AAED,0FAA0F;AAC1F,OAAO,EAAE,WAAW,EAAE,CAAC"}
@@ -0,0 +1,185 @@
1
+ /**
2
+ * Filesystem CAS adapter — mtime + content-hash VersionToken and atomic-rename write.
3
+ *
4
+ * Uses the host contract helper executeIfUnchanged (conditional-write.ts). Does not invent
5
+ * a parallel outcome shape. Token format is opaque to the guard (string equality only).
6
+ *
7
+ * Token encoding (this adapter only; not interpreted by the core):
8
+ * fs:v1:<mtime_ms>:<sha256_hex_of_file_bytes>
9
+ * Missing file → createFsVersionToken still works for "absent" via a dedicated absent token
10
+ * only if we choose; for create we require the file to exist (ENOENT throws) so hosts
11
+ * measure an existing prior. For write of new files, expected_token may be ABSENT_TOKEN.
12
+ */
13
+ 'use strict';
14
+ import { createHash, randomBytes } from 'node:crypto';
15
+ import { promises as fsp } from 'node:fs';
16
+ import * as path from 'node:path';
17
+ import { executeIfUnchanged, StaleVersionTokenAbort, tokensEqual, } from '../conditional-write.js';
18
+ /** Prefix for this adapter's opaque tokens (equality-only outside this module). */
19
+ export const FS_VERSION_TOKEN_PREFIX = 'fs:v1:';
20
+ /**
21
+ * Token used when the path does not exist yet (create-if-absent CAS).
22
+ * Hosts that measured absence should pass this as expected_token for first write.
23
+ */
24
+ export const FS_ABSENT_TOKEN = 'fs:v1:absent';
25
+ function sha256hex(buf) {
26
+ return createHash('sha256').update(buf).digest('hex');
27
+ }
28
+ /** Extract content-hash segment from an fs:v1 token (null if absent/malformed). */
29
+ export function fsTokenContentHash(token) {
30
+ if (typeof token !== 'string' || !token.startsWith(FS_VERSION_TOKEN_PREFIX))
31
+ return null;
32
+ if (token === FS_ABSENT_TOKEN)
33
+ return null;
34
+ const rest = token.slice(FS_VERSION_TOKEN_PREFIX.length);
35
+ const colon = rest.indexOf(':');
36
+ if (colon < 0)
37
+ return null;
38
+ const hash = rest.slice(colon + 1);
39
+ return /^[a-f0-9]{64}$/.test(hash) ? hash : null;
40
+ }
41
+ /**
42
+ * Build a VersionToken from path: mtime (ms) + sha256 of file bytes.
43
+ * Throws on I/O errors other than callers may catch. ENOENT → returns FS_ABSENT_TOKEN
44
+ * so hosts can CAS create vs create-raced.
45
+ */
46
+ export async function createFsVersionToken(filePath) {
47
+ let st;
48
+ try {
49
+ st = await fsp.stat(filePath);
50
+ }
51
+ catch (err) {
52
+ const code = err && typeof err === 'object' && 'code' in err
53
+ ? String(err.code)
54
+ : '';
55
+ if (code === 'ENOENT')
56
+ return FS_ABSENT_TOKEN;
57
+ throw err;
58
+ }
59
+ if (!st.isFile()) {
60
+ // Directories / specials are not content CAS targets for this adapter.
61
+ throw new Error(`createFsVersionToken: not a regular file: ${filePath}`);
62
+ }
63
+ const buf = await fsp.readFile(filePath);
64
+ const hash = sha256hex(buf);
65
+ const mtimeMs = Math.trunc(st.mtimeMs);
66
+ return `${FS_VERSION_TOKEN_PREFIX}${mtimeMs}:${hash}`;
67
+ }
68
+ /**
69
+ * Read file content + version token for VersionedContent (host reporting / preflight prior).
70
+ * ENOENT → content '' and FS_ABSENT_TOKEN.
71
+ */
72
+ export async function readVersionedFile(filePath) {
73
+ const version_token = await createFsVersionToken(filePath);
74
+ if (version_token === FS_ABSENT_TOKEN) {
75
+ return { content: '', version_token };
76
+ }
77
+ const content = await fsp.readFile(filePath, 'utf8');
78
+ return { content, version_token };
79
+ }
80
+ /**
81
+ * Conditional write: re-stat+re-hash; if token matches expected → temp file + atomic rename.
82
+ *
83
+ * MEASURED windows (pre-fix, 2fcd74e-era):
84
+ * 1. executeIfUnchanged: current_token() then await write() — no re-check in between.
85
+ * 2. write(): writeFile(tmp) then rename(tmp,target) with NO re-stat of target before rename
86
+ * (fs.ts former lines 106–108) — concurrent mutation of target is clobbered by rename.
87
+ *
88
+ * Closures:
89
+ * - Pre-rename: re-createFsVersionToken(target); on mismatch abort rename, unlink tmp,
90
+ * throw StaleVersionTokenAbort → refused/stale_version_token (write did not land).
91
+ * - Post-rename: detect_stale_during_commit — content-hash of path must match sha256(body);
92
+ * mismatch → committed_stale_detected (write landed; someone overwrote after rename).
93
+ *
94
+ * Wired through executeIfUnchanged — not a parallel path.
95
+ */
96
+ export async function writeFileIfUnchanged(args) {
97
+ const target = path.resolve(args.path);
98
+ const body = typeof args.content === 'string' ? Buffer.from(args.content, 'utf8') : args.content;
99
+ const writtenHash = sha256hex(body);
100
+ return executeIfUnchanged({
101
+ expected_token: args.expected_token,
102
+ current_token: () => createFsVersionToken(target),
103
+ detect_stale_during_commit: true,
104
+ // Post-commit: token content-hash must equal sha256 of what we wrote (mtime may vary).
105
+ expected_after_commit: async (result) => {
106
+ // Synthesize a comparable token: re-read path; equality is content-hash based via tokensEqual
107
+ // only if full token matches — mtime always changes on write, so we return the LIVE post
108
+ // token only when its hash matches writtenHash; else return a sentinel that cannot match.
109
+ const post = await createFsVersionToken(target);
110
+ const postHash = fsTokenContentHash(post);
111
+ if (postHash === result.written_content_hash)
112
+ return post;
113
+ // Force mismatch → committed_stale_detected (detection, not rollback).
114
+ return `${FS_VERSION_TOKEN_PREFIX}0:stale_during_commit_mismatch`;
115
+ },
116
+ write: async () => {
117
+ const dir = path.dirname(target);
118
+ await fsp.mkdir(dir, { recursive: true });
119
+ const tmp = path.join(dir, `.coderifts-cas-${path.basename(target)}-${process.pid}-${randomBytes(6).toString('hex')}.tmp`);
120
+ try {
121
+ await fsp.writeFile(tmp, body);
122
+ // Close pre-rename window: if target moved since the executeIfUnchanged check, do not clobber.
123
+ const still = await createFsVersionToken(target);
124
+ if (!tokensEqual(args.expected_token, still)) {
125
+ try {
126
+ await fsp.unlink(tmp);
127
+ }
128
+ catch {
129
+ /* ignore */
130
+ }
131
+ throw new StaleVersionTokenAbort(still);
132
+ }
133
+ // Atomic replace on same filesystem (POSIX rename; Windows overwrite where supported).
134
+ await fsp.rename(tmp, target);
135
+ }
136
+ catch (err) {
137
+ if (err instanceof StaleVersionTokenAbort)
138
+ throw err;
139
+ // Best-effort cleanup of temp — never leave partial target from failed rename.
140
+ try {
141
+ await fsp.unlink(tmp);
142
+ }
143
+ catch {
144
+ /* ignore */
145
+ }
146
+ throw err;
147
+ }
148
+ return { path: target, bytes: body.length, written_content_hash: writtenHash };
149
+ },
150
+ });
151
+ }
152
+ /**
153
+ * Opt-in PriorContentResolver that reads a file path from tool arguments.
154
+ * Returns file utf8 content for freshness measurement (string only — tokens travel separately
155
+ * via versioned_content / conditioned_on_token on the call context).
156
+ *
157
+ * Plug-in: pass as GuardConfig.resolvePriorContent / withCodeRifts({ resolvePriorContent }).
158
+ */
159
+ export function createFsPriorContentResolver(options) {
160
+ const pathForArtifact = options?.pathForArtifact;
161
+ return async (req) => {
162
+ let filePath = typeof req.path === 'string' && req.path.length > 0 ? req.path : undefined;
163
+ if (!filePath && pathForArtifact) {
164
+ const mapped = pathForArtifact(req.artifactId);
165
+ if (typeof mapped === 'string' && mapped.length > 0)
166
+ filePath = mapped;
167
+ }
168
+ if (!filePath)
169
+ return null;
170
+ try {
171
+ return await fsp.readFile(filePath, 'utf8');
172
+ }
173
+ catch (err) {
174
+ const code = err && typeof err === 'object' && 'code' in err
175
+ ? String(err.code)
176
+ : '';
177
+ if (code === 'ENOENT')
178
+ return null;
179
+ throw err;
180
+ }
181
+ };
182
+ }
183
+ /** Re-export equality helper for hosts comparing tokens without importing core module. */
184
+ export { tokensEqual };
185
+ //# sourceMappingURL=fs.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fs.js","sourceRoot":"","sources":["../../../src/cas-adapters/fs.ts"],"names":[],"mappings":"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"}
@@ -89,4 +89,70 @@ export declare function conditionalWriteResidual(input: {
89
89
  writeStyle: boolean;
90
90
  conditionalWrite: ConditionalWriteReport;
91
91
  }): string | null;
92
+ /**
93
+ * Outcome of a conditional write attempt.
94
+ * - committed: write ran under the expected token; post-check (if any) agreed
95
+ * - refused / stale_version_token: resource token moved BEFORE write; write did NOT run
96
+ * - committed_stale_detected / stale_during_commit: write DID run, but a post-commit
97
+ * re-check found the resource no longer matches the write's expected post-state
98
+ * (detection only — not a rollback)
99
+ */
100
+ export type ExecuteIfUnchangedOutcome<T> = {
101
+ status: 'committed';
102
+ result: T;
103
+ version_token: VersionToken;
104
+ } | {
105
+ status: 'refused';
106
+ reason: 'stale_version_token';
107
+ expected_token: VersionToken;
108
+ current_token: VersionToken | null;
109
+ } | {
110
+ status: 'committed_stale_detected';
111
+ reason: 'stale_during_commit';
112
+ result: T;
113
+ expected_token: VersionToken;
114
+ post_commit_token: VersionToken | null;
115
+ };
116
+ /**
117
+ * Thrown from write() when the adapter aborts BEFORE applying the mutation
118
+ * (e.g. pre-rename re-check). executeIfUnchanged maps this to status:'refused'.
119
+ * Not a public host API — adapters use it to stay on the single helper path.
120
+ */
121
+ export declare class StaleVersionTokenAbort extends Error {
122
+ readonly current_token: VersionToken | null;
123
+ constructor(current_token: VersionToken | null);
124
+ }
125
+ export type ExecuteIfUnchangedArgs<T> = {
126
+ /** Token the host measured before deciding to write (opaque string). */
127
+ expected_token: VersionToken;
128
+ /**
129
+ * Re-read the resource's token immediately before commit.
130
+ * Return null when the resource is gone / unreadable (treated as mismatch).
131
+ */
132
+ current_token: () => VersionToken | null | Promise<VersionToken | null>;
133
+ /** Mutation applied ONLY when current_token equals expected_token. */
134
+ write: () => T | Promise<T>;
135
+ /**
136
+ * Opt-in post-commit detection (default false — byte-identical old paths).
137
+ * When true AND expected_after_commit is provided: after write(), re-read
138
+ * current_token and compare to expected_after_commit(result). Mismatch →
139
+ * committed_stale_detected (write already happened; honest report only).
140
+ *
141
+ * NOTE: do NOT compare post-commit to expected_token for content-changing
142
+ * writes — the token is supposed to change. Supply the token of the written state.
143
+ */
144
+ detect_stale_during_commit?: boolean;
145
+ /**
146
+ * Token that should hold after a successful write (the written state's token).
147
+ * Required when detect_stale_during_commit is true; ignored otherwise.
148
+ */
149
+ expected_after_commit?: (result: T) => VersionToken | null | Promise<VersionToken | null>;
150
+ };
151
+ /**
152
+ * Host contract helper: re-check version token, then write or refuse.
153
+ * Equality via tokensEqual only — never interprets token format.
154
+ * Never throws for stale tokens (returns refused / committed_stale_detected);
155
+ * write/current_token errors (other than StaleVersionTokenAbort) propagate.
156
+ */
157
+ export declare function executeIfUnchanged<T>(args: ExecuteIfUnchangedArgs<T>): Promise<ExecuteIfUnchangedOutcome<T>>;
92
158
  //# sourceMappingURL=conditional-write.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"conditional-write.d.ts","sourceRoot":"","sources":["../../src/conditional-write.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;GAiBG;AAIH,2EAA2E;AAC3E,MAAM,MAAM,YAAY,GAAG,MAAM,CAAC;AAElC;;;GAGG;AACH,MAAM,MAAM,gBAAgB,GAAG;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,aAAa,EAAE,YAAY,CAAC;CAC7B,CAAC;AAEF;;;;GAIG;AACH,MAAM,MAAM,sBAAsB,GAAG,IAAI,GAAG,KAAK,GAAG,cAAc,CAAC;AAEnE;;;GAGG;AACH,MAAM,MAAM,qBAAqB,GAAG;IAClC,iBAAiB,EAAE,sBAAsB,CAAC;IAC1C;;;OAGG;IACH,oBAAoB,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IAC3C,6DAA6D;IAC7D,yBAAyB,EAAE,OAAO,CAAC;IACnC,oDAAoD;IACpD,WAAW,EAAE,OAAO,CAAC;CACtB,CAAC;AAEF;;;GAGG;AACH,MAAM,MAAM,2BAA2B,GAAG;IACxC,iBAAiB,CAAC,EAAE,sBAAsB,CAAC;IAC3C,oBAAoB,CAAC,EAAE,YAAY,GAAG,IAAI,CAAC;IAC3C,kEAAkE;IAClE,iBAAiB,CAAC,EAAE,gBAAgB,GAAG,IAAI,CAAC;CAC7C,CAAC;AAEF,0EAA0E;AAC1E,wBAAgB,WAAW,CACzB,CAAC,EAAE,YAAY,GAAG,IAAI,GAAG,SAAS,EAClC,CAAC,EAAE,YAAY,GAAG,IAAI,GAAG,SAAS,GACjC,OAAO,CAIT;AASD;;;;;;;;GAQG;AACH,wBAAgB,0BAA0B,CAAC,KAAK,EAAE;IAChD,UAAU,EAAE,OAAO,CAAC;IACpB,uBAAuB,EAAE,OAAO,CAAC;IACjC,GAAG,CAAC,EAAE,2BAA2B,GAAG,IAAI,CAAC;CAC1C,GAAG;IACF,KAAK,EAAE,qBAAqB,CAAC;IAC7B,mDAAmD;IACnD,UAAU,CAAC,EAAE,4BAA4B,CAAC;CAC3C,CAgCA;AAED,yFAAyF;AACzF,eAAO,MAAM,4BAA4B,iDAAiD,CAAC;AAE3F;;;GAGG;AACH,wBAAgB,wBAAwB,CAAC,KAAK,EAAE;IAC9C,uBAAuB,EAAE,OAAO,CAAC;IACjC,UAAU,EAAE,OAAO,CAAC;IACpB,gBAAgB,EAAE,sBAAsB,CAAC;CAC1C,GAAG,MAAM,GAAG,IAAI,CAKhB"}
1
+ {"version":3,"file":"conditional-write.d.ts","sourceRoot":"","sources":["../../src/conditional-write.ts"],"names":[],"mappings":"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"}