@tokenfactory/acc-runner 0.40.27 → 0.40.29

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 (64) hide show
  1. package/dist/attachments/allowlist.d.ts +16 -0
  2. package/dist/attachments/allowlist.d.ts.map +1 -0
  3. package/dist/attachments/allowlist.js +34 -0
  4. package/dist/attachments/allowlist.js.map +1 -0
  5. package/dist/attachments/content-block.d.ts +16 -0
  6. package/dist/attachments/content-block.d.ts.map +1 -0
  7. package/dist/attachments/content-block.js +38 -0
  8. package/dist/attachments/content-block.js.map +1 -0
  9. package/dist/attachments/fetch-attachment.d.ts +24 -0
  10. package/dist/attachments/fetch-attachment.d.ts.map +1 -0
  11. package/dist/attachments/fetch-attachment.js +55 -0
  12. package/dist/attachments/fetch-attachment.js.map +1 -0
  13. package/dist/attachments/index.d.ts +21 -0
  14. package/dist/attachments/index.d.ts.map +1 -0
  15. package/dist/attachments/index.js +20 -0
  16. package/dist/attachments/index.js.map +1 -0
  17. package/dist/attachments/types.d.ts +39 -0
  18. package/dist/attachments/types.d.ts.map +1 -0
  19. package/dist/attachments/types.js +9 -0
  20. package/dist/attachments/types.js.map +1 -0
  21. package/dist/chat-cancel/cancel-controller.d.ts +77 -0
  22. package/dist/chat-cancel/cancel-controller.d.ts.map +1 -0
  23. package/dist/chat-cancel/cancel-controller.js +148 -0
  24. package/dist/chat-cancel/cancel-controller.js.map +1 -0
  25. package/dist/chat-cancel/cancel-source.d.ts +37 -0
  26. package/dist/chat-cancel/cancel-source.d.ts.map +1 -0
  27. package/dist/chat-cancel/cancel-source.js +26 -0
  28. package/dist/chat-cancel/cancel-source.js.map +1 -0
  29. package/dist/chat-cancel/child-terminator.d.ts +37 -0
  30. package/dist/chat-cancel/child-terminator.d.ts.map +1 -0
  31. package/dist/chat-cancel/child-terminator.js +81 -0
  32. package/dist/chat-cancel/child-terminator.js.map +1 -0
  33. package/dist/chat-cancel/index.d.ts +21 -0
  34. package/dist/chat-cancel/index.d.ts.map +1 -0
  35. package/dist/chat-cancel/index.js +20 -0
  36. package/dist/chat-cancel/index.js.map +1 -0
  37. package/dist/chat-cancel/types.d.ts +69 -0
  38. package/dist/chat-cancel/types.d.ts.map +1 -0
  39. package/dist/chat-cancel/types.js +7 -0
  40. package/dist/chat-cancel/types.js.map +1 -0
  41. package/dist/claim-deadman/deadman.d.ts +152 -0
  42. package/dist/claim-deadman/deadman.d.ts.map +1 -0
  43. package/dist/claim-deadman/deadman.js +176 -0
  44. package/dist/claim-deadman/deadman.js.map +1 -0
  45. package/dist/claim-deadman/heartbeat-signal.d.ts +48 -0
  46. package/dist/claim-deadman/heartbeat-signal.d.ts.map +1 -0
  47. package/dist/claim-deadman/heartbeat-signal.js +31 -0
  48. package/dist/claim-deadman/heartbeat-signal.js.map +1 -0
  49. package/dist/claim-deadman/index.d.ts +19 -0
  50. package/dist/claim-deadman/index.d.ts.map +1 -0
  51. package/dist/claim-deadman/index.js +17 -0
  52. package/dist/claim-deadman/index.js.map +1 -0
  53. package/dist/clarification.d.ts +48 -0
  54. package/dist/clarification.d.ts.map +1 -0
  55. package/dist/clarification.js +114 -0
  56. package/dist/clarification.js.map +1 -0
  57. package/dist/cli.d.ts.map +1 -1
  58. package/dist/cli.js +20 -0
  59. package/dist/cli.js.map +1 -1
  60. package/dist/watch.d.ts +74 -0
  61. package/dist/watch.d.ts.map +1 -1
  62. package/dist/watch.js +289 -1
  63. package/dist/watch.js.map +1 -1
  64. package/package.json +1 -1
@@ -0,0 +1,16 @@
1
+ /**
2
+ * CX-1 UPLOADS — runner-side type guards + size ceiling.
3
+ *
4
+ * Deliberately MIRRORS api/chat/attachments-allowlist.ts (separate package, so
5
+ * it cannot import it). Keep the two in sync: the server is the authority and
6
+ * rejects first; this is the runner's defence-in-depth ceiling so a tampered or
7
+ * oversized object never reaches the engine.
8
+ */
9
+ import type { AttachmentKind } from "./types.js";
10
+ export declare const MAX_ATTACHMENT_BYTES: Record<AttachmentKind, number>;
11
+ export declare const ALLOWED_CONTENT_TYPES: Record<string, AttachmentKind>;
12
+ /** "text/plain; charset=utf-8" -> "text/plain". */
13
+ export declare function normalizeContentType(contentType: string): string;
14
+ export declare function kindForContentType(contentType: string): AttachmentKind | null;
15
+ export declare function isWithinSizeCeiling(kind: AttachmentKind, byteSize: number): boolean;
16
+ //# sourceMappingURL=allowlist.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"allowlist.d.ts","sourceRoot":"","sources":["../../src/attachments/allowlist.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAEH,OAAO,KAAK,EAAE,cAAc,EAAE,MAAM,YAAY,CAAC;AAEjD,eAAO,MAAM,oBAAoB,EAAE,MAAM,CAAC,cAAc,EAAE,MAAM,CAI/D,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,MAAM,CAAC,MAAM,EAAE,cAAc,CAShE,CAAC;AAEF,mDAAmD;AACnD,wBAAgB,oBAAoB,CAAC,WAAW,EAAE,MAAM,GAAG,MAAM,CAEhE;AAED,wBAAgB,kBAAkB,CAAC,WAAW,EAAE,MAAM,GAAG,cAAc,GAAG,IAAI,CAE7E;AAED,wBAAgB,mBAAmB,CAAC,IAAI,EAAE,cAAc,EAAE,QAAQ,EAAE,MAAM,GAAG,OAAO,CAEnF"}
@@ -0,0 +1,34 @@
1
+ /**
2
+ * CX-1 UPLOADS — runner-side type guards + size ceiling.
3
+ *
4
+ * Deliberately MIRRORS api/chat/attachments-allowlist.ts (separate package, so
5
+ * it cannot import it). Keep the two in sync: the server is the authority and
6
+ * rejects first; this is the runner's defence-in-depth ceiling so a tampered or
7
+ * oversized object never reaches the engine.
8
+ */
9
+ export const MAX_ATTACHMENT_BYTES = {
10
+ image: 20 * 1024 * 1024, // 20 MiB
11
+ pdf: 20 * 1024 * 1024, // 20 MiB
12
+ text: 5 * 1024 * 1024, // 5 MiB
13
+ };
14
+ export const ALLOWED_CONTENT_TYPES = {
15
+ "image/png": "image",
16
+ "image/jpeg": "image",
17
+ "image/gif": "image",
18
+ "image/webp": "image",
19
+ "application/pdf": "pdf",
20
+ "text/plain": "text",
21
+ "text/csv": "text",
22
+ "text/markdown": "text",
23
+ };
24
+ /** "text/plain; charset=utf-8" -> "text/plain". */
25
+ export function normalizeContentType(contentType) {
26
+ return (contentType ?? "").split(";")[0].trim().toLowerCase();
27
+ }
28
+ export function kindForContentType(contentType) {
29
+ return ALLOWED_CONTENT_TYPES[normalizeContentType(contentType)] ?? null;
30
+ }
31
+ export function isWithinSizeCeiling(kind, byteSize) {
32
+ return Number.isFinite(byteSize) && byteSize >= 0 && byteSize <= MAX_ATTACHMENT_BYTES[kind];
33
+ }
34
+ //# sourceMappingURL=allowlist.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"allowlist.js","sourceRoot":"","sources":["../../src/attachments/allowlist.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AAIH,MAAM,CAAC,MAAM,oBAAoB,GAAmC;IAClE,KAAK,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,SAAS;IAClC,GAAG,EAAE,EAAE,GAAG,IAAI,GAAG,IAAI,EAAE,SAAS;IAChC,IAAI,EAAE,CAAC,GAAG,IAAI,GAAG,IAAI,EAAE,QAAQ;CAChC,CAAC;AAEF,MAAM,CAAC,MAAM,qBAAqB,GAAmC;IACnE,WAAW,EAAE,OAAO;IACpB,YAAY,EAAE,OAAO;IACrB,WAAW,EAAE,OAAO;IACpB,YAAY,EAAE,OAAO;IACrB,iBAAiB,EAAE,KAAK;IACxB,YAAY,EAAE,MAAM;IACpB,UAAU,EAAE,MAAM;IAClB,eAAe,EAAE,MAAM;CACxB,CAAC;AAEF,mDAAmD;AACnD,MAAM,UAAU,oBAAoB,CAAC,WAAmB;IACtD,OAAO,CAAC,WAAW,IAAI,EAAE,CAAC,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;AAChE,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,WAAmB;IACpD,OAAO,qBAAqB,CAAC,oBAAoB,CAAC,WAAW,CAAC,CAAC,IAAI,IAAI,CAAC;AAC1E,CAAC;AAED,MAAM,UAAU,mBAAmB,CAAC,IAAoB,EAAE,QAAgB;IACxE,OAAO,MAAM,CAAC,QAAQ,CAAC,QAAQ,CAAC,IAAI,QAAQ,IAAI,CAAC,IAAI,QAAQ,IAAI,oBAAoB,CAAC,IAAI,CAAC,CAAC;AAC9F,CAAC"}
@@ -0,0 +1,16 @@
1
+ /**
2
+ * CX-1 UPLOADS — decode fetched bytes into a provider-neutral engine content
3
+ * block for genuine vision.
4
+ *
5
+ * image -> { type: "image", source: { base64 } } (vision)
6
+ * pdf -> { type: "document", source: { base64 } } (vision)
7
+ * text -> { type: "text", text } (inlined)
8
+ *
9
+ * A Track A follow-up hands the resulting block(s) to the frozen engine adapters
10
+ * via EngineStreamTurnOptions; this helper never touches those adapters.
11
+ */
12
+ import type { EngineContentBlock, FetchedAttachment } from "./types.js";
13
+ export declare function toEngineContentBlock(attachment: FetchedAttachment): EngineContentBlock;
14
+ /** Convenience: map a batch of fetched attachments to engine content blocks. */
15
+ export declare function toEngineContentBlocks(attachments: readonly FetchedAttachment[]): EngineContentBlock[];
16
+ //# sourceMappingURL=content-block.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-block.d.ts","sourceRoot":"","sources":["../../src/attachments/content-block.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,KAAK,EAAE,kBAAkB,EAAE,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAExE,wBAAgB,oBAAoB,CAAC,UAAU,EAAE,iBAAiB,GAAG,kBAAkB,CAqBtF;AAED,gFAAgF;AAChF,wBAAgB,qBAAqB,CACnC,WAAW,EAAE,SAAS,iBAAiB,EAAE,GACxC,kBAAkB,EAAE,CAEtB"}
@@ -0,0 +1,38 @@
1
+ /**
2
+ * CX-1 UPLOADS — decode fetched bytes into a provider-neutral engine content
3
+ * block for genuine vision.
4
+ *
5
+ * image -> { type: "image", source: { base64 } } (vision)
6
+ * pdf -> { type: "document", source: { base64 } } (vision)
7
+ * text -> { type: "text", text } (inlined)
8
+ *
9
+ * A Track A follow-up hands the resulting block(s) to the frozen engine adapters
10
+ * via EngineStreamTurnOptions; this helper never touches those adapters.
11
+ */
12
+ import { Buffer } from "node:buffer";
13
+ export function toEngineContentBlock(attachment) {
14
+ if (attachment.kind === "text") {
15
+ return { type: "text", text: Buffer.from(attachment.bytes).toString("utf-8") };
16
+ }
17
+ const data = Buffer.from(attachment.bytes).toString("base64");
18
+ if (attachment.kind === "pdf") {
19
+ return {
20
+ type: "document",
21
+ source: { type: "base64", media_type: "application/pdf", data },
22
+ };
23
+ }
24
+ // image
25
+ return {
26
+ type: "image",
27
+ source: {
28
+ type: "base64",
29
+ media_type: attachment.contentType || "image/png",
30
+ data,
31
+ },
32
+ };
33
+ }
34
+ /** Convenience: map a batch of fetched attachments to engine content blocks. */
35
+ export function toEngineContentBlocks(attachments) {
36
+ return attachments.map(toEngineContentBlock);
37
+ }
38
+ //# sourceMappingURL=content-block.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"content-block.js","sourceRoot":"","sources":["../../src/attachments/content-block.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAEH,OAAO,EAAE,MAAM,EAAE,MAAM,aAAa,CAAC;AAGrC,MAAM,UAAU,oBAAoB,CAAC,UAA6B;IAChE,IAAI,UAAU,CAAC,IAAI,KAAK,MAAM,EAAE,CAAC;QAC/B,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,OAAO,CAAC,EAAE,CAAC;IACjF,CAAC;IAED,MAAM,IAAI,GAAG,MAAM,CAAC,IAAI,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAC9D,IAAI,UAAU,CAAC,IAAI,KAAK,KAAK,EAAE,CAAC;QAC9B,OAAO;YACL,IAAI,EAAE,UAAU;YAChB,MAAM,EAAE,EAAE,IAAI,EAAE,QAAQ,EAAE,UAAU,EAAE,iBAAiB,EAAE,IAAI,EAAE;SAChE,CAAC;IACJ,CAAC;IACD,QAAQ;IACR,OAAO;QACL,IAAI,EAAE,OAAO;QACb,MAAM,EAAE;YACN,IAAI,EAAE,QAAQ;YACd,UAAU,EAAE,UAAU,CAAC,WAAW,IAAI,WAAW;YACjD,IAAI;SACL;KACF,CAAC;AACJ,CAAC;AAED,gFAAgF;AAChF,MAAM,UAAU,qBAAqB,CACnC,WAAyC;IAEzC,OAAO,WAAW,CAAC,GAAG,CAAC,oBAAoB,CAAC,CAAC;AAC/C,CAAC"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * CX-1 UPLOADS — resolve an attachment's bytes via a short-lived signed URL.
3
+ *
4
+ * Two hops, both authorized, never public:
5
+ * 1. POST /api/chat/attachments { op: "sign-download", attachment_id } with a
6
+ * Bearer token (CRON_SECRET in fleet serving, or a delegation bearer). The
7
+ * API mints a short-lived signed download URL from the private bucket.
8
+ * 2. GET the signed URL for the raw bytes.
9
+ *
10
+ * Self-contained: deps are injected, so this is unit-testable with a fake fetch
11
+ * and carries no dependency on watch.ts or the engine adapters. The Track A
12
+ * wiring decides which bearer to pass.
13
+ */
14
+ import type { FetchedAttachment } from "./types.js";
15
+ export interface FetchAttachmentDeps {
16
+ /** Base URL of the ACC API, e.g. cfg.publicUrl. Trailing slashes are trimmed. */
17
+ publicUrl: string;
18
+ /** Bearer read at call time (CRON_SECRET for fleet serving, or delegation). */
19
+ authToken: string;
20
+ /** Injectable for tests; defaults to the global fetch. */
21
+ fetchImpl?: typeof fetch;
22
+ }
23
+ export declare function fetchAttachment(attachmentId: string, deps: FetchAttachmentDeps): Promise<FetchedAttachment>;
24
+ //# sourceMappingURL=fetch-attachment.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch-attachment.d.ts","sourceRoot":"","sources":["../../src/attachments/fetch-attachment.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH,OAAO,KAAK,EAAkB,iBAAiB,EAAE,MAAM,YAAY,CAAC;AAGpE,MAAM,WAAW,mBAAmB;IAClC,iFAAiF;IACjF,SAAS,EAAE,MAAM,CAAC;IAClB,+EAA+E;IAC/E,SAAS,EAAE,MAAM,CAAC;IAClB,0DAA0D;IAC1D,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;CAC1B;AAWD,wBAAsB,eAAe,CACnC,YAAY,EAAE,MAAM,EACpB,IAAI,EAAE,mBAAmB,GACxB,OAAO,CAAC,iBAAiB,CAAC,CA6C5B"}
@@ -0,0 +1,55 @@
1
+ /**
2
+ * CX-1 UPLOADS — resolve an attachment's bytes via a short-lived signed URL.
3
+ *
4
+ * Two hops, both authorized, never public:
5
+ * 1. POST /api/chat/attachments { op: "sign-download", attachment_id } with a
6
+ * Bearer token (CRON_SECRET in fleet serving, or a delegation bearer). The
7
+ * API mints a short-lived signed download URL from the private bucket.
8
+ * 2. GET the signed URL for the raw bytes.
9
+ *
10
+ * Self-contained: deps are injected, so this is unit-testable with a fake fetch
11
+ * and carries no dependency on watch.ts or the engine adapters. The Track A
12
+ * wiring decides which bearer to pass.
13
+ */
14
+ import { kindForContentType, MAX_ATTACHMENT_BYTES } from "./allowlist.js";
15
+ export async function fetchAttachment(attachmentId, deps) {
16
+ if (!attachmentId)
17
+ throw new Error("fetchAttachment: attachmentId required");
18
+ const doFetch = deps.fetchImpl ?? fetch;
19
+ const base = deps.publicUrl.replace(/\/+$/, "");
20
+ const signRes = await doFetch(`${base}/api/chat/attachments`, {
21
+ method: "POST",
22
+ headers: {
23
+ "Content-Type": "application/json",
24
+ Authorization: `Bearer ${deps.authToken}`,
25
+ },
26
+ body: JSON.stringify({ op: "sign-download", attachment_id: attachmentId }),
27
+ });
28
+ if (!signRes.ok) {
29
+ throw new Error(`sign-download failed: HTTP ${signRes.status}`);
30
+ }
31
+ const json = (await signRes.json());
32
+ if (!json.ok || !json.signed_url) {
33
+ throw new Error(`sign-download rejected: ${json.error ?? "no signed_url"}`);
34
+ }
35
+ const kind = json.kind ?? kindForContentType(json.content_type ?? "");
36
+ if (!kind) {
37
+ throw new Error(`unsupported attachment content-type: ${json.content_type ?? "unknown"}`);
38
+ }
39
+ const fileRes = await doFetch(json.signed_url);
40
+ if (!fileRes.ok) {
41
+ throw new Error(`attachment fetch failed: HTTP ${fileRes.status}`);
42
+ }
43
+ const bytes = new Uint8Array(await fileRes.arrayBuffer());
44
+ if (bytes.byteLength > MAX_ATTACHMENT_BYTES[kind]) {
45
+ throw new Error(`attachment ${bytes.byteLength} bytes exceeds ${MAX_ATTACHMENT_BYTES[kind]}-byte ceiling for ${kind}`);
46
+ }
47
+ return {
48
+ attachmentId,
49
+ kind,
50
+ contentType: json.content_type ?? "",
51
+ filename: json.filename ?? "file",
52
+ bytes,
53
+ };
54
+ }
55
+ //# sourceMappingURL=fetch-attachment.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"fetch-attachment.js","sourceRoot":"","sources":["../../src/attachments/fetch-attachment.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAGH,OAAO,EAAE,kBAAkB,EAAE,oBAAoB,EAAE,MAAM,gBAAgB,CAAC;AAoB1E,MAAM,CAAC,KAAK,UAAU,eAAe,CACnC,YAAoB,EACpB,IAAyB;IAEzB,IAAI,CAAC,YAAY;QAAE,MAAM,IAAI,KAAK,CAAC,wCAAwC,CAAC,CAAC;IAC7E,MAAM,OAAO,GAAG,IAAI,CAAC,SAAS,IAAI,KAAK,CAAC;IACxC,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;IAEhD,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,GAAG,IAAI,uBAAuB,EAAE;QAC5D,MAAM,EAAE,MAAM;QACd,OAAO,EAAE;YACP,cAAc,EAAE,kBAAkB;YAClC,aAAa,EAAE,UAAU,IAAI,CAAC,SAAS,EAAE;SAC1C;QACD,IAAI,EAAE,IAAI,CAAC,SAAS,CAAC,EAAE,EAAE,EAAE,eAAe,EAAE,aAAa,EAAE,YAAY,EAAE,CAAC;KAC3E,CAAC,CAAC;IACH,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,8BAA8B,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAClE,CAAC;IACD,MAAM,IAAI,GAAG,CAAC,MAAM,OAAO,CAAC,IAAI,EAAE,CAAyB,CAAC;IAC5D,IAAI,CAAC,IAAI,CAAC,EAAE,IAAI,CAAC,IAAI,CAAC,UAAU,EAAE,CAAC;QACjC,MAAM,IAAI,KAAK,CAAC,2BAA2B,IAAI,CAAC,KAAK,IAAI,eAAe,EAAE,CAAC,CAAC;IAC9E,CAAC;IAED,MAAM,IAAI,GACP,IAAI,CAAC,IAAmC,IAAI,kBAAkB,CAAC,IAAI,CAAC,YAAY,IAAI,EAAE,CAAC,CAAC;IAC3F,IAAI,CAAC,IAAI,EAAE,CAAC;QACV,MAAM,IAAI,KAAK,CAAC,wCAAwC,IAAI,CAAC,YAAY,IAAI,SAAS,EAAE,CAAC,CAAC;IAC5F,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,OAAO,CAAC,IAAI,CAAC,UAAU,CAAC,CAAC;IAC/C,IAAI,CAAC,OAAO,CAAC,EAAE,EAAE,CAAC;QAChB,MAAM,IAAI,KAAK,CAAC,iCAAiC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IACrE,CAAC;IACD,MAAM,KAAK,GAAG,IAAI,UAAU,CAAC,MAAM,OAAO,CAAC,WAAW,EAAE,CAAC,CAAC;IAC1D,IAAI,KAAK,CAAC,UAAU,GAAG,oBAAoB,CAAC,IAAI,CAAC,EAAE,CAAC;QAClD,MAAM,IAAI,KAAK,CACb,cAAc,KAAK,CAAC,UAAU,kBAAkB,oBAAoB,CAAC,IAAI,CAAC,qBAAqB,IAAI,EAAE,CACtG,CAAC;IACJ,CAAC;IAED,OAAO;QACL,YAAY;QACZ,IAAI;QACJ,WAAW,EAAE,IAAI,CAAC,YAAY,IAAI,EAAE;QACpC,QAAQ,EAAE,IAAI,CAAC,QAAQ,IAAI,MAAM;QACjC,KAAK;KACN,CAAC;AACJ,CAAC"}
@@ -0,0 +1,21 @@
1
+ /**
2
+ * CX-1 UPLOADS: the runner attachment-vision barrel.
3
+ *
4
+ * Self-contained PRIMITIVES, intentionally `dead-until-wired`. A serving runner
5
+ * resolves an attachment's bytes via a short-lived signed URL and decodes them
6
+ * into a provider-neutral engine content block:
7
+ * - allowlist.ts — type guards + size ceiling mirroring the server.
8
+ * - fetch-attachment.ts — signed-URL resolve + authorized byte fetch.
9
+ * - content-block.ts — bytes -> provider-neutral vision/text block.
10
+ *
11
+ * Attachments are UNTRUSTED model input. These primitives only READ bytes and
12
+ * shape them for the engine; the propose-confirm firewall remains the sole
13
+ * mutation path. The Track A follow-up wires toEngineContentBlock output into
14
+ * the frozen engine adapters (EngineStreamTurnOptions) and mounts the fetch on
15
+ * the chat serve path.
16
+ */
17
+ export type { AttachmentKind, FetchedAttachment, EngineContentBlock, EngineBase64Source, } from "./types.js";
18
+ export { MAX_ATTACHMENT_BYTES, ALLOWED_CONTENT_TYPES, normalizeContentType, kindForContentType, isWithinSizeCeiling, } from "./allowlist.js";
19
+ export { fetchAttachment, type FetchAttachmentDeps } from "./fetch-attachment.js";
20
+ export { toEngineContentBlock, toEngineContentBlocks } from "./content-block.js";
21
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../src/attachments/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AAEH,YAAY,EACV,cAAc,EACd,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,GACnB,MAAM,YAAY,CAAC;AAEpB,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,eAAe,EAAE,KAAK,mBAAmB,EAAE,MAAM,uBAAuB,CAAC;AAElF,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,20 @@
1
+ /**
2
+ * CX-1 UPLOADS: the runner attachment-vision barrel.
3
+ *
4
+ * Self-contained PRIMITIVES, intentionally `dead-until-wired`. A serving runner
5
+ * resolves an attachment's bytes via a short-lived signed URL and decodes them
6
+ * into a provider-neutral engine content block:
7
+ * - allowlist.ts — type guards + size ceiling mirroring the server.
8
+ * - fetch-attachment.ts — signed-URL resolve + authorized byte fetch.
9
+ * - content-block.ts — bytes -> provider-neutral vision/text block.
10
+ *
11
+ * Attachments are UNTRUSTED model input. These primitives only READ bytes and
12
+ * shape them for the engine; the propose-confirm firewall remains the sole
13
+ * mutation path. The Track A follow-up wires toEngineContentBlock output into
14
+ * the frozen engine adapters (EngineStreamTurnOptions) and mounts the fetch on
15
+ * the chat serve path.
16
+ */
17
+ export { MAX_ATTACHMENT_BYTES, ALLOWED_CONTENT_TYPES, normalizeContentType, kindForContentType, isWithinSizeCeiling, } from "./allowlist.js";
18
+ export { fetchAttachment } from "./fetch-attachment.js";
19
+ export { toEngineContentBlock, toEngineContentBlocks } from "./content-block.js";
20
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/attachments/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;GAeG;AASH,OAAO,EACL,oBAAoB,EACpB,qBAAqB,EACrB,oBAAoB,EACpB,kBAAkB,EAClB,mBAAmB,GACpB,MAAM,gBAAgB,CAAC;AAExB,OAAO,EAAE,eAAe,EAA4B,MAAM,uBAAuB,CAAC;AAElF,OAAO,EAAE,oBAAoB,EAAE,qBAAqB,EAAE,MAAM,oBAAoB,CAAC"}
@@ -0,0 +1,39 @@
1
+ /**
2
+ * CX-1 UPLOADS — runner attachment primitive types.
3
+ *
4
+ * These are self-contained, provider-neutral shapes. A Track A follow-up hands
5
+ * an EngineContentBlock[] to the frozen engine adapters (EngineStreamTurnOptions);
6
+ * nothing here edits those adapters.
7
+ */
8
+ export type AttachmentKind = "image" | "pdf" | "text";
9
+ /** Bytes + metadata for one attachment the serving runner resolved. */
10
+ export interface FetchedAttachment {
11
+ attachmentId: string;
12
+ kind: AttachmentKind;
13
+ contentType: string;
14
+ filename: string;
15
+ bytes: Uint8Array;
16
+ }
17
+ /**
18
+ * Provider-neutral engine content block. The union mirrors the claude-native
19
+ * block shape the engine adapters already parse on the OUTPUT path
20
+ * (`{ type: "text" | "image" | "document", ... }`), so the Track A wiring can
21
+ * pass these straight through for genuine vision — the model answers about the
22
+ * chart/screenshot content, not OCR'd text.
23
+ */
24
+ export type EngineContentBlock = {
25
+ type: "text";
26
+ text: string;
27
+ } | {
28
+ type: "image";
29
+ source: EngineBase64Source;
30
+ } | {
31
+ type: "document";
32
+ source: EngineBase64Source;
33
+ };
34
+ export interface EngineBase64Source {
35
+ type: "base64";
36
+ media_type: string;
37
+ data: string;
38
+ }
39
+ //# sourceMappingURL=types.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/attachments/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AAEH,MAAM,MAAM,cAAc,GAAG,OAAO,GAAG,KAAK,GAAG,MAAM,CAAC;AAEtD,uEAAuE;AACvE,MAAM,WAAW,iBAAiB;IAChC,YAAY,EAAE,MAAM,CAAC;IACrB,IAAI,EAAE,cAAc,CAAC;IACrB,WAAW,EAAE,MAAM,CAAC;IACpB,QAAQ,EAAE,MAAM,CAAC;IACjB,KAAK,EAAE,UAAU,CAAC;CACnB;AAED;;;;;;GAMG;AACH,MAAM,MAAM,kBAAkB,GAC1B;IAAE,IAAI,EAAE,MAAM,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GAC9B;IAAE,IAAI,EAAE,OAAO,CAAC;IAAC,MAAM,EAAE,kBAAkB,CAAA;CAAE,GAC7C;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,MAAM,EAAE,kBAAkB,CAAA;CAAE,CAAC;AAErD,MAAM,WAAW,kBAAkB;IACjC,IAAI,EAAE,QAAQ,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,MAAM,CAAC;CACd"}
@@ -0,0 +1,9 @@
1
+ /**
2
+ * CX-1 UPLOADS — runner attachment primitive types.
3
+ *
4
+ * These are self-contained, provider-neutral shapes. A Track A follow-up hands
5
+ * an EngineContentBlock[] to the frozen engine adapters (EngineStreamTurnOptions);
6
+ * nothing here edits those adapters.
7
+ */
8
+ export {};
9
+ //# sourceMappingURL=types.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"types.js","sourceRoot":"","sources":["../../src/attachments/types.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
@@ -0,0 +1,77 @@
1
+ /**
2
+ * CX-3 STOP-CANCEL: the runner-side cancel controller.
3
+ *
4
+ * The browser's Stop calls acc.cancel_chat_turn (migration 0278), which makes the
5
+ * turn terminal-CANCELLED server-side. This controller is the local counterpart
6
+ * that tears the still-running engine down promptly so the child is provably dead
7
+ * and the runner's slot frees:
8
+ *
9
+ * • register(turn) — a companion registers each in-flight turn (its abort +
10
+ * optional engine-child handle) as it launches.
11
+ * • requestCancel(id) — abort the drive loop AND escalate-terminate the child
12
+ * (SIGTERM → grace → SIGKILL). Called on a direct signal
13
+ * (a broadcast, or a shutdown fan-out).
14
+ * • reconcile(source) — poll the server for which in-flight turns are now
15
+ * cancelled and requestCancel each. One deterministic
16
+ * pass; the e2e rig drives this directly.
17
+ * • start(source, ms) — production convenience: reconcile on an interval.
18
+ *
19
+ * Because acc.cancel_chat_turn already made the turn terminal, the driver's
20
+ * abort-path requeue no-ops against the cancelled row (api/chat/_lane-materialize
21
+ * requeueTurn is guarded to claimed/streaming) — so tearing down here never revives
22
+ * or double-completes the turn. Everything is injected, so the whole thing runs
23
+ * without a network or a real child.
24
+ *
25
+ * NOTE (scope): this module ships the primitives + a Supabase-backed source
26
+ * (cancel-source.ts). Wiring it into ChatCompanion.launch (registering each turn
27
+ * and starting the reconcile loop) is a follow-up, mirroring how the AS-3 resume
28
+ * controller and the FLEET-SERVE watch-chat primitives landed ahead of their
29
+ * watch.ts wiring.
30
+ */
31
+ import { type TerminateChildOptions } from "./child-terminator.js";
32
+ import type { CancellableTurn, CancelSource, ChatCancelReason, TurnCancelResult } from "./types.js";
33
+ export interface ChatCancelControllerOptions {
34
+ /** Options forwarded to terminateEngineChild (grace window + timer seam). */
35
+ terminate?: TerminateChildOptions;
36
+ /** Schedule a repeating callback; injected in tests. Defaults to unref'd setInterval. */
37
+ scheduleInterval?: (ms: number, cb: () => void) => () => void;
38
+ /** Best-effort structured log sink. */
39
+ onLog?: (line: string) => void;
40
+ /** Best-effort observability: fired after each local cancel settles. */
41
+ onCancel?: (result: TurnCancelResult) => void;
42
+ }
43
+ export declare class ChatCancelController {
44
+ private readonly opts;
45
+ private readonly turns;
46
+ /** Turns already cancelled here, so a repeated reconcile is a no-op (idempotent). */
47
+ private readonly cancelled;
48
+ private stopInterval;
49
+ private reconciling;
50
+ constructor(opts?: ChatCancelControllerOptions);
51
+ /** Register an in-flight turn as cancellable. Idempotent per turn id. */
52
+ register(turn: CancellableTurn): void;
53
+ /** Drop a turn once it settles (the companion calls this from its `finally`). */
54
+ unregister(turnId: string): void;
55
+ /** Turn ids currently registered as in flight. */
56
+ inFlightTurnIds(): string[];
57
+ /**
58
+ * Cancel one in-flight turn locally: fire its abort (stops the drive loop /
59
+ * SIGTERMs the child via the engine's signal) AND escalate-terminate the child
60
+ * handle if one was registered, so a SIGTERM-swallowing engine is still provably
61
+ * dead. Idempotent: a second call for the same turn is a no-op.
62
+ */
63
+ requestCancel(turnId: string, reason?: ChatCancelReason): Promise<TurnCancelResult>;
64
+ /**
65
+ * One reconcile pass: ask the source which registered turns the operator has
66
+ * cancelled server-side and tear each down. Returns the turn ids cancelled this
67
+ * pass. Never throws — a source read error logs and yields an empty pass so the
68
+ * loop survives a transient DB blip. Guarded against overlap so a slow pass does
69
+ * not stack on the interval.
70
+ */
71
+ reconcile(source: CancelSource): Promise<string[]>;
72
+ /** Start reconciling against `source` every `intervalMs`. Returns a stopper. */
73
+ start(source: CancelSource, intervalMs?: number): () => void;
74
+ /** Stop the reconcile loop (does not abort in-flight turns). */
75
+ stop(): void;
76
+ }
77
+ //# sourceMappingURL=cancel-controller.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cancel-controller.d.ts","sourceRoot":"","sources":["../../src/chat-cancel/cancel-controller.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;;;;;;;;;;;GA6BG;AACH,OAAO,EAAwB,KAAK,qBAAqB,EAAE,MAAM,uBAAuB,CAAC;AACzF,OAAO,KAAK,EACV,eAAe,EACf,YAAY,EACZ,gBAAgB,EAChB,gBAAgB,EACjB,MAAM,YAAY,CAAC;AAEpB,MAAM,WAAW,2BAA2B;IAC1C,6EAA6E;IAC7E,SAAS,CAAC,EAAE,qBAAqB,CAAC;IAClC,yFAAyF;IACzF,gBAAgB,CAAC,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,IAAI,KAAK,MAAM,IAAI,CAAC;IAC9D,uCAAuC;IACvC,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,wEAAwE;IACxE,QAAQ,CAAC,EAAE,CAAC,MAAM,EAAE,gBAAgB,KAAK,IAAI,CAAC;CAC/C;AAQD,qBAAa,oBAAoB;IAOnB,OAAO,CAAC,QAAQ,CAAC,IAAI;IANjC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAsC;IAC5D,qFAAqF;IACrF,OAAO,CAAC,QAAQ,CAAC,SAAS,CAAqB;IAC/C,OAAO,CAAC,YAAY,CAA6B;IACjD,OAAO,CAAC,WAAW,CAAS;gBAEC,IAAI,GAAE,2BAAgC;IAEnE,yEAAyE;IACzE,QAAQ,CAAC,IAAI,EAAE,eAAe,GAAG,IAAI;IAIrC,iFAAiF;IACjF,UAAU,CAAC,MAAM,EAAE,MAAM,GAAG,IAAI;IAKhC,kDAAkD;IAClD,eAAe,IAAI,MAAM,EAAE;IAI3B;;;;;OAKG;IACG,aAAa,CACjB,MAAM,EAAE,MAAM,EACd,MAAM,GAAE,gBAAuC,GAC9C,OAAO,CAAC,gBAAgB,CAAC;IA+B5B;;;;;;OAMG;IACG,SAAS,CAAC,MAAM,EAAE,YAAY,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC;IAwBxD,gFAAgF;IAChF,KAAK,CAAC,MAAM,EAAE,YAAY,EAAE,UAAU,SAAM,GAAG,MAAM,IAAI;IAazD,gEAAgE;IAChE,IAAI,IAAI,IAAI;CAGb"}
@@ -0,0 +1,148 @@
1
+ /**
2
+ * CX-3 STOP-CANCEL: the runner-side cancel controller.
3
+ *
4
+ * The browser's Stop calls acc.cancel_chat_turn (migration 0278), which makes the
5
+ * turn terminal-CANCELLED server-side. This controller is the local counterpart
6
+ * that tears the still-running engine down promptly so the child is provably dead
7
+ * and the runner's slot frees:
8
+ *
9
+ * • register(turn) — a companion registers each in-flight turn (its abort +
10
+ * optional engine-child handle) as it launches.
11
+ * • requestCancel(id) — abort the drive loop AND escalate-terminate the child
12
+ * (SIGTERM → grace → SIGKILL). Called on a direct signal
13
+ * (a broadcast, or a shutdown fan-out).
14
+ * • reconcile(source) — poll the server for which in-flight turns are now
15
+ * cancelled and requestCancel each. One deterministic
16
+ * pass; the e2e rig drives this directly.
17
+ * • start(source, ms) — production convenience: reconcile on an interval.
18
+ *
19
+ * Because acc.cancel_chat_turn already made the turn terminal, the driver's
20
+ * abort-path requeue no-ops against the cancelled row (api/chat/_lane-materialize
21
+ * requeueTurn is guarded to claimed/streaming) — so tearing down here never revives
22
+ * or double-completes the turn. Everything is injected, so the whole thing runs
23
+ * without a network or a real child.
24
+ *
25
+ * NOTE (scope): this module ships the primitives + a Supabase-backed source
26
+ * (cancel-source.ts). Wiring it into ChatCompanion.launch (registering each turn
27
+ * and starting the reconcile loop) is a follow-up, mirroring how the AS-3 resume
28
+ * controller and the FLEET-SERVE watch-chat primitives landed ahead of their
29
+ * watch.ts wiring.
30
+ */
31
+ import { terminateEngineChild } from "./child-terminator.js";
32
+ function defaultScheduleInterval(ms, cb) {
33
+ const t = setInterval(cb, ms);
34
+ t.unref?.();
35
+ return () => clearInterval(t);
36
+ }
37
+ export class ChatCancelController {
38
+ opts;
39
+ turns = new Map();
40
+ /** Turns already cancelled here, so a repeated reconcile is a no-op (idempotent). */
41
+ cancelled = new Set();
42
+ stopInterval = null;
43
+ reconciling = false;
44
+ constructor(opts = {}) {
45
+ this.opts = opts;
46
+ }
47
+ /** Register an in-flight turn as cancellable. Idempotent per turn id. */
48
+ register(turn) {
49
+ this.turns.set(turn.turnId, turn);
50
+ }
51
+ /** Drop a turn once it settles (the companion calls this from its `finally`). */
52
+ unregister(turnId) {
53
+ this.turns.delete(turnId);
54
+ this.cancelled.delete(turnId);
55
+ }
56
+ /** Turn ids currently registered as in flight. */
57
+ inFlightTurnIds() {
58
+ return [...this.turns.keys()];
59
+ }
60
+ /**
61
+ * Cancel one in-flight turn locally: fire its abort (stops the drive loop /
62
+ * SIGTERMs the child via the engine's signal) AND escalate-terminate the child
63
+ * handle if one was registered, so a SIGTERM-swallowing engine is still provably
64
+ * dead. Idempotent: a second call for the same turn is a no-op.
65
+ */
66
+ async requestCancel(turnId, reason = "operator_cancelled") {
67
+ const turn = this.turns.get(turnId);
68
+ if (!turn) {
69
+ return { turnId, aborted: false, notFound: true };
70
+ }
71
+ if (this.cancelled.has(turnId)) {
72
+ // Already torn down; report as handled without re-signalling.
73
+ return { turnId, aborted: true, notFound: false };
74
+ }
75
+ this.cancelled.add(turnId);
76
+ try {
77
+ turn.abort(reason);
78
+ }
79
+ catch (err) {
80
+ this.opts.onLog?.(`[acc-runner] chat cancel abort(${turnId}) threw: ${err.message}`);
81
+ }
82
+ const result = { turnId, aborted: true, notFound: false };
83
+ if (turn.child) {
84
+ try {
85
+ result.child = await terminateEngineChild(turn.child, this.opts.terminate);
86
+ }
87
+ catch (err) {
88
+ this.opts.onLog?.(`[acc-runner] chat cancel terminate(${turnId}) threw: ${err.message}`);
89
+ }
90
+ }
91
+ this.opts.onCancel?.(result);
92
+ return result;
93
+ }
94
+ /**
95
+ * One reconcile pass: ask the source which registered turns the operator has
96
+ * cancelled server-side and tear each down. Returns the turn ids cancelled this
97
+ * pass. Never throws — a source read error logs and yields an empty pass so the
98
+ * loop survives a transient DB blip. Guarded against overlap so a slow pass does
99
+ * not stack on the interval.
100
+ */
101
+ async reconcile(source) {
102
+ if (this.reconciling)
103
+ return [];
104
+ this.reconciling = true;
105
+ try {
106
+ const ids = this.inFlightTurnIds().filter((id) => !this.cancelled.has(id));
107
+ if (ids.length === 0)
108
+ return [];
109
+ let cancelledIds;
110
+ try {
111
+ cancelledIds = await source.listCancelled(ids);
112
+ }
113
+ catch (err) {
114
+ this.opts.onLog?.(`[acc-runner] chat cancel reconcile source failed: ${err.message}`);
115
+ return [];
116
+ }
117
+ const done = [];
118
+ for (const id of cancelledIds) {
119
+ const r = await this.requestCancel(id, "operator_cancelled");
120
+ if (r.aborted)
121
+ done.push(id);
122
+ }
123
+ return done;
124
+ }
125
+ finally {
126
+ this.reconciling = false;
127
+ }
128
+ }
129
+ /** Start reconciling against `source` every `intervalMs`. Returns a stopper. */
130
+ start(source, intervalMs = 750) {
131
+ if (this.stopInterval)
132
+ return this.stopInterval;
133
+ const schedule = this.opts.scheduleInterval ?? defaultScheduleInterval;
134
+ const cancel = schedule(intervalMs, () => {
135
+ void this.reconcile(source);
136
+ });
137
+ this.stopInterval = () => {
138
+ cancel();
139
+ this.stopInterval = null;
140
+ };
141
+ return this.stopInterval;
142
+ }
143
+ /** Stop the reconcile loop (does not abort in-flight turns). */
144
+ stop() {
145
+ this.stopInterval?.();
146
+ }
147
+ }
148
+ //# sourceMappingURL=cancel-controller.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cancel-controller.js","sourceRoot":"","sources":["../../src/chat-cancel/cancel-controller.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,37 @@
1
+ /**
2
+ * CX-3 STOP-CANCEL: the production CancelSource — reads acc.chat_turns to learn
3
+ * which in-flight turns the operator has cancelled server-side (status set to
4
+ * 'cancelled' by acc.cancel_chat_turn / migration 0278).
5
+ *
6
+ * The runner authenticates as the conversation owner (an org member), so the
7
+ * chat_turns_select RLS policy (0254) lets it SELECT its own turns. Kept behind a
8
+ * minimal client interface (not the full RunnerSupabaseClient) so it is trivially
9
+ * faked in tests and carries no heavyweight import.
10
+ */
11
+ import type { CancelSource } from "./types.js";
12
+ /** The sliver of a supabase-js query builder this source needs. */
13
+ export interface CancelQueryClient {
14
+ from(table: string): {
15
+ select(columns: string): {
16
+ in(column: string, values: readonly string[]): PromiseLike<{
17
+ data: Array<{
18
+ id: string;
19
+ status: string | null;
20
+ }> | null;
21
+ error: {
22
+ message: string;
23
+ } | null;
24
+ }>;
25
+ };
26
+ };
27
+ }
28
+ /**
29
+ * Build a CancelSource over a supabase client. Each reconcile pass reads the given
30
+ * in-flight turn ids and returns those whose status is a terminal 'cancelled'. A
31
+ * read error surfaces as a thrown error (the controller's reconcile swallows it as
32
+ * an empty pass), never a false "cancelled".
33
+ */
34
+ export declare function buildSupabaseCancelSource(client: CancelQueryClient, opts?: {
35
+ onLog?: (line: string) => void;
36
+ }): CancelSource;
37
+ //# sourceMappingURL=cancel-source.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cancel-source.d.ts","sourceRoot":"","sources":["../../src/chat-cancel/cancel-source.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,YAAY,CAAC;AAE/C,mEAAmE;AACnE,MAAM,WAAW,iBAAiB;IAChC,IAAI,CAAC,KAAK,EAAE,MAAM,GAAG;QACnB,MAAM,CAAC,OAAO,EAAE,MAAM,GAAG;YACvB,EAAE,CACA,MAAM,EAAE,MAAM,EACd,MAAM,EAAE,SAAS,MAAM,EAAE,GACxB,WAAW,CAAC;gBACb,IAAI,EAAE,KAAK,CAAC;oBAAE,EAAE,EAAE,MAAM,CAAC;oBAAC,MAAM,EAAE,MAAM,GAAG,IAAI,CAAA;iBAAE,CAAC,GAAG,IAAI,CAAC;gBAC1D,KAAK,EAAE;oBAAE,OAAO,EAAE,MAAM,CAAA;iBAAE,GAAG,IAAI,CAAC;aACnC,CAAC,CAAC;SACJ,CAAC;KACH,CAAC;CACH;AAED;;;;;GAKG;AACH,wBAAgB,yBAAyB,CACvC,MAAM,EAAE,iBAAiB,EACzB,IAAI,GAAE;IAAE,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAA;CAAO,GAC5C,YAAY,CAiBd"}
@@ -0,0 +1,26 @@
1
+ /**
2
+ * Build a CancelSource over a supabase client. Each reconcile pass reads the given
3
+ * in-flight turn ids and returns those whose status is a terminal 'cancelled'. A
4
+ * read error surfaces as a thrown error (the controller's reconcile swallows it as
5
+ * an empty pass), never a false "cancelled".
6
+ */
7
+ export function buildSupabaseCancelSource(client, opts = {}) {
8
+ return {
9
+ async listCancelled(turnIds) {
10
+ if (turnIds.length === 0)
11
+ return [];
12
+ const { data, error } = await client
13
+ .from("chat_turns")
14
+ .select("id, status")
15
+ .in("id", turnIds);
16
+ if (error) {
17
+ opts.onLog?.(`[acc-runner] cancel-source read failed: ${error.message}`);
18
+ throw new Error(error.message);
19
+ }
20
+ return (data ?? [])
21
+ .filter((row) => row.status === "cancelled")
22
+ .map((row) => row.id);
23
+ },
24
+ };
25
+ }
26
+ //# sourceMappingURL=cancel-source.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cancel-source.js","sourceRoot":"","sources":["../../src/chat-cancel/cancel-source.ts"],"names":[],"mappings":"AA2BA;;;;;GAKG;AACH,MAAM,UAAU,yBAAyB,CACvC,MAAyB,EACzB,OAA2C,EAAE;IAE7C,OAAO;QACL,KAAK,CAAC,aAAa,CAAC,OAA0B;YAC5C,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;gBAAE,OAAO,EAAE,CAAC;YACpC,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,MAAM,MAAM;iBACjC,IAAI,CAAC,YAAY,CAAC;iBAClB,MAAM,CAAC,YAAY,CAAC;iBACpB,EAAE,CAAC,IAAI,EAAE,OAAO,CAAC,CAAC;YACrB,IAAI,KAAK,EAAE,CAAC;gBACV,IAAI,CAAC,KAAK,EAAE,CAAC,2CAA2C,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;gBACzE,MAAM,IAAI,KAAK,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC;YACjC,CAAC;YACD,OAAO,CAAC,IAAI,IAAI,EAAE,CAAC;iBAChB,MAAM,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,KAAK,WAAW,CAAC;iBAC3C,GAAG,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,EAAE,CAAC,CAAC;QAC1B,CAAC;KACF,CAAC;AACJ,CAAC"}