@koda-sl/baker-cli 0.325.0 → 0.326.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 (28) hide show
  1. package/README.md +4 -1
  2. package/dist/{chunk-GJVXXYCX.js → chunk-4VP5WWPR.js} +13 -2
  3. package/dist/chunk-4VP5WWPR.js.map +1 -0
  4. package/dist/{chunk-HPRKO6P2.js → chunk-FFOURYP5.js} +7 -5
  5. package/dist/chunk-FFOURYP5.js.map +1 -0
  6. package/dist/{chunk-UWFF6WEV.js → chunk-JWMLQSGK.js} +4 -4
  7. package/dist/{chunk-MSZSDYOJ.js → chunk-KGDL7F7M.js} +3 -3
  8. package/dist/{chunk-6BD32M7K.js → chunk-PWGY347J.js} +26 -3
  9. package/dist/chunk-PWGY347J.js.map +1 -0
  10. package/dist/{chunk-KAE5M5R7.js → chunk-XPUSSDLR.js} +3 -3
  11. package/dist/cli.js +136 -27
  12. package/dist/cli.js.map +1 -1
  13. package/dist/{client-XUSSAB6O.js → client-PWRZOA3Q.js} +4 -4
  14. package/dist/engine/index.js +3 -3
  15. package/dist/{env-VIA5U56G.js → env-TQTHWLBN.js} +2 -2
  16. package/dist/{output-ZPACGSH2.js → output-HD63GTWI.js} +5 -5
  17. package/dist/{shared-OHOCOE2L.js → shared-5662SBDW.js} +6 -6
  18. package/package.json +1 -1
  19. package/dist/chunk-6BD32M7K.js.map +0 -1
  20. package/dist/chunk-GJVXXYCX.js.map +0 -1
  21. package/dist/chunk-HPRKO6P2.js.map +0 -1
  22. /package/dist/{chunk-UWFF6WEV.js.map → chunk-JWMLQSGK.js.map} +0 -0
  23. /package/dist/{chunk-MSZSDYOJ.js.map → chunk-KGDL7F7M.js.map} +0 -0
  24. /package/dist/{chunk-KAE5M5R7.js.map → chunk-XPUSSDLR.js.map} +0 -0
  25. /package/dist/{client-XUSSAB6O.js.map → client-PWRZOA3Q.js.map} +0 -0
  26. /package/dist/{env-VIA5U56G.js.map → env-TQTHWLBN.js.map} +0 -0
  27. /package/dist/{output-ZPACGSH2.js.map → output-HD63GTWI.js.map} +0 -0
  28. /package/dist/{shared-OHOCOE2L.js.map → shared-5662SBDW.js.map} +0 -0
@@ -2,13 +2,13 @@ import {
2
2
  handleConnectionError,
3
3
  needsConnectionFix,
4
4
  writeAdsJson
5
- } from "./chunk-MSZSDYOJ.js";
5
+ } from "./chunk-KGDL7F7M.js";
6
6
  import {
7
7
  ApiError
8
- } from "./chunk-KAE5M5R7.js";
8
+ } from "./chunk-XPUSSDLR.js";
9
9
  import {
10
10
  getEnv
11
- } from "./chunk-GJVXXYCX.js";
11
+ } from "./chunk-4VP5WWPR.js";
12
12
 
13
13
  // src/commands/ads/meta/shared.ts
14
14
  var DAY_MS = 864e5;
@@ -108,4 +108,4 @@ export {
108
108
  csvOrJson,
109
109
  resolveEffectiveStatus
110
110
  };
111
- //# sourceMappingURL=chunk-UWFF6WEV.js.map
111
+ //# sourceMappingURL=chunk-JWMLQSGK.js.map
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  ApiError,
3
3
  apiGet
4
- } from "./chunk-KAE5M5R7.js";
4
+ } from "./chunk-XPUSSDLR.js";
5
5
  import {
6
6
  getEnv
7
- } from "./chunk-GJVXXYCX.js";
7
+ } from "./chunk-4VP5WWPR.js";
8
8
 
9
9
  // src/error-handler.ts
10
10
  var REQUEST_CONNECTION_PLATFORM = {
@@ -294,4 +294,4 @@ export {
294
294
  writeAdsOutput,
295
295
  resolveCustomerId
296
296
  };
297
- //# sourceMappingURL=chunk-MSZSDYOJ.js.map
297
+ //# sourceMappingURL=chunk-KGDL7F7M.js.map
@@ -1,6 +1,6 @@
1
1
  import {
2
2
  debugLogSetting
3
- } from "./chunk-GJVXXYCX.js";
3
+ } from "./chunk-4VP5WWPR.js";
4
4
 
5
5
  // src/debugLog.ts
6
6
  import { appendFileSync, mkdirSync, renameSync, statSync } from "fs";
@@ -12,7 +12,10 @@ var MAX_BYTES = 64 * 1024 * 1024;
12
12
  var REDACTIONS = [
13
13
  [/Bearer\s+[A-Za-z0-9._-]+/g, "Bearer [redacted]"],
14
14
  // Authorization headers
15
- [/bk_[A-Za-z0-9]+/g, "bk_[redacted]"],
15
+ // Both prefixes, captured rather than listed twice: `bkr_` does not contain
16
+ // the literal `bk_`, so the company-key rule matched no part of the read-only
17
+ // credential a Session review runs with.
18
+ [/\b(bkr?)_[A-Za-z0-9]+/g, "$1_[redacted]"],
16
19
  // Baker API keys
17
20
  [/eyJ[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+\.[A-Za-z0-9_-]+/g, "[redacted-jwt]"],
18
21
  // JWTs / id tokens
@@ -92,9 +95,28 @@ function errorToPlain(err) {
92
95
  }
93
96
  return { message: String(err) };
94
97
  }
98
+ var invocationStartedAt;
95
99
  function logInvocation(argv) {
100
+ invocationStartedAt = Date.now();
96
101
  append({ kind: "invocation", argv, cwd: process.cwd() });
97
102
  }
103
+ function logExit(code) {
104
+ append({
105
+ kind: "exit",
106
+ code,
107
+ ...invocationStartedAt === void 0 ? {} : { durationMs: Date.now() - invocationStartedAt }
108
+ });
109
+ }
110
+ var exitHookInstalled = false;
111
+ function installExitRecord() {
112
+ if (exitHookInstalled || !isDebugLogEnabled()) {
113
+ return;
114
+ }
115
+ exitHookInstalled = true;
116
+ process.on("exit", (code) => {
117
+ logExit(typeof code === "number" ? code : 0);
118
+ });
119
+ }
98
120
  function debugLogHttp(entry) {
99
121
  if (!isDebugLogEnabled()) {
100
122
  return;
@@ -146,8 +168,9 @@ function installStreamTaps() {
146
168
 
147
169
  export {
148
170
  logInvocation,
171
+ installExitRecord,
149
172
  debugLogHttp,
150
173
  readBodyForLog,
151
174
  installStreamTaps
152
175
  };
153
- //# sourceMappingURL=chunk-6BD32M7K.js.map
176
+ //# sourceMappingURL=chunk-PWGY347J.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"sources":["../src/debugLog.ts"],"sourcesContent":["// Full-fidelity debug capture for the whole CLI.\n//\n// Set BAKER_DEBUG_LOG to turn it on:\n// BAKER_DEBUG_LOG=1 -> appends to ./baker-cli-debug.jsonl\n// BAKER_DEBUG_LOG=/tmp/baker.jsonl -> appends to that file\n// BAKER_DEBUG_LOG=0|false|off|no -> disabled (same as unset)\n//\n// When enabled, every HTTP request/response (both the REST client and the\n// canvas engine client), every byte written to stdout/stderr, and the command\n// invocation are appended as JSONL entries. Known secret shapes are redacted\n// before anything is written (best-effort — see redactSecrets). Logging is\n// always fail-open: a logging error is swallowed so it can never break a\n// command. The file rotates once past MAX_BYTES so an always-on capture cannot\n// fill the disk.\n\nimport { appendFileSync, mkdirSync, renameSync, statSync } from \"node:fs\";\nimport { dirname, isAbsolute, resolve } from \"node:path\";\nimport { debugLogSetting } from \"./env.ts\";\n\nconst DEFAULT_FILE = \"baker-cli-debug.jsonl\";\nconst BOOLEAN_ON = new Set([\"1\", \"true\", \"on\", \"yes\"]);\nconst BOOLEAN_OFF = new Set([\"0\", \"false\", \"off\", \"no\"]);\n\n// Rotate once the active file passes this size (one older generation, `<file>.1`,\n// is kept). Bounds growth for the always-on sandbox capture without a per-write stat.\nconst MAX_BYTES = 64 * 1024 * 1024;\n\n// Best-effort redaction. Response/request bodies are stored as escaped strings, so\n// key/value matching is unreliable there; instead we scrub the token *values*\n// themselves (quote-agnostic) plus the auth header and Baker keys. This is not\n// exhaustive — a secret in an unrecognized shape can still be written. See README.\nconst REDACTIONS: ReadonlyArray<readonly [RegExp, string]> = [\n [/Bearer\\s+[A-Za-z0-9._-]+/g, \"Bearer [redacted]\"], // Authorization headers\n // Both prefixes, captured rather than listed twice: `bkr_` does not contain\n // the literal `bk_`, so the company-key rule matched no part of the read-only\n // credential a Session review runs with.\n [/\\b(bkr?)_[A-Za-z0-9]+/g, \"$1_[redacted]\"], // Baker API keys\n [/eyJ[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+\\.[A-Za-z0-9_-]+/g, \"[redacted-jwt]\"], // JWTs / id tokens\n [/ya29\\.[A-Za-z0-9._-]+/g, \"[redacted-google-token]\"], // Google OAuth access tokens\n [/1\\/\\/[A-Za-z0-9._-]+/g, \"[redacted-google-refresh]\"], // Google refresh tokens\n [/EAA[A-Za-z0-9]{20,}/g, \"[redacted-meta-token]\"], // Meta/Facebook access tokens\n];\n\nexport function redactSecrets(input: string): string {\n let out = input;\n for (const [pattern, replacement] of REDACTIONS) {\n out = out.replace(pattern, replacement);\n }\n return out;\n}\n\nfunction resolveTarget(): string | undefined {\n const raw = debugLogSetting();\n if (!raw) {\n return undefined;\n }\n const lower = raw.toLowerCase();\n if (BOOLEAN_OFF.has(lower)) {\n return undefined;\n }\n const target = BOOLEAN_ON.has(lower) ? DEFAULT_FILE : raw;\n return isAbsolute(target) ? target : resolve(process.cwd(), target);\n}\n\nexport function isDebugLogEnabled(): boolean {\n return resolveTarget() !== undefined;\n}\n\nlet sessionId: string | undefined;\nfunction getSessionId(): string {\n if (!sessionId) {\n sessionId = `${process.pid}-${Date.now()}`;\n }\n return sessionId;\n}\n\n// Per-resolved-path bookkeeping so the hot path skips redundant syscalls: the\n// directory is ensured once and the current size is read once (via statSync),\n// then tracked in-process. Resets when the resolved path changes.\nlet trackedPath: string | undefined;\nlet bytesInFile = 0;\n\nfunction ensureReady(filePath: string): void {\n if (trackedPath !== filePath) {\n trackedPath = filePath;\n mkdirSync(dirname(filePath), { recursive: true });\n try {\n bytesInFile = statSync(filePath).size;\n } catch {\n bytesInFile = 0;\n }\n }\n}\n\nfunction append(entry: Record<string, unknown>): void {\n const filePath = resolveTarget();\n if (!filePath) {\n return;\n }\n try {\n const payload = { ts: new Date().toISOString(), session: getSessionId(), ...entry };\n const line = `${redactSecrets(JSON.stringify(payload))}\\n`;\n ensureReady(filePath);\n const size = Buffer.byteLength(line);\n if (bytesInFile + size > MAX_BYTES) {\n renameSync(filePath, `${filePath}.1`);\n bytesInFile = 0;\n }\n appendFileSync(filePath, line);\n bytesInFile += size;\n } catch {\n // Fail-open: debug logging must never break a command.\n }\n}\n\nfunction errorToPlain(err: unknown): Record<string, unknown> {\n if (err instanceof Error) {\n const code = (err as { code?: unknown }).code;\n return { name: err.name, message: err.message, ...(typeof code === \"string\" ? { code } : {}) };\n }\n return { message: String(err) };\n}\n\nlet invocationStartedAt: number | undefined;\n\nexport function logInvocation(argv: string[]): void {\n invocationStartedAt = Date.now();\n append({ kind: \"invocation\", argv, cwd: process.cwd() });\n}\n\n/**\n * Close an invocation with its outcome and its wall time.\n *\n * Until this existed the log could say what was called and what every HTTP hop\n * cost, and nothing at all about whether the command succeeded or how long the\n * whole thing took — so \"this verb is slow\" and \"this verb fails half the time\"\n * were both unanswerable from the one record that sees every call. `durationMs`\n * is measured from `logInvocation`, which runs before any command does.\n */\nexport function logExit(code: number): void {\n append({\n kind: \"exit\",\n code,\n ...(invocationStartedAt === undefined ? {} : { durationMs: Date.now() - invocationStartedAt }),\n });\n}\n\nlet exitHookInstalled = false;\n\n/**\n * Write the exit record however the process ends.\n *\n * `process.on(\"exit\")` is the only hook that sees all of them — a clean return, a\n * `process.exit` from the error handler, an unhandled rejection — and it is\n * synchronous-only, which is exactly what `appendFileSync` needs. Installed once,\n * and only when logging is on, so the disabled path adds no listener at all.\n */\nexport function installExitRecord(): void {\n if (exitHookInstalled || !isDebugLogEnabled()) {\n return;\n }\n exitHookInstalled = true;\n process.on(\"exit\", (code) => {\n logExit(typeof code === \"number\" ? code : 0);\n });\n}\n\nexport type HttpLogEntry = {\n source: \"cli\" | \"canvas\";\n method: string;\n url: string;\n requestBody?: unknown;\n status?: number;\n ok?: boolean;\n responseBody?: string;\n durationMs?: number;\n error?: unknown;\n};\n\nexport function debugLogHttp(entry: HttpLogEntry): void {\n if (!isDebugLogEnabled()) {\n return;\n }\n append({\n kind: \"http\",\n source: entry.source,\n method: entry.method,\n url: entry.url,\n durationMs: entry.durationMs,\n request: entry.requestBody,\n status: entry.status,\n ok: entry.ok,\n response: entry.responseBody,\n error: entry.error === undefined ? undefined : errorToPlain(entry.error),\n });\n}\n\n// Reads a response body for logging without consuming it for the real caller.\nexport async function readBodyForLog(response: Response): Promise<string | undefined> {\n if (!isDebugLogEnabled()) {\n return undefined;\n }\n try {\n return await response.clone().text();\n } catch {\n return undefined;\n }\n}\n\n// Method syntax (bivariant) so a real `process.stdout`/`stderr` and a plain\n// test double both satisfy it.\ntype Writable = { write(...args: unknown[]): boolean };\n\n// Wraps a stream's `write` so every chunk is mirrored into the debug log while\n// the original write semantics (args + return value) are preserved. A single\n// streaming TextDecoder per stream decodes byte chunks so a multi-byte character\n// split across two writes is reassembled instead of garbled.\nexport function tapStream(name: string, stream: Writable): void {\n const original = stream.write.bind(stream) as (...args: unknown[]) => boolean;\n const decoder = new TextDecoder(\"utf-8\");\n stream.write = ((chunk: unknown, ...rest: unknown[]): boolean => {\n try {\n const text =\n typeof chunk === \"string\"\n ? chunk\n : chunk instanceof Uint8Array\n ? decoder.decode(chunk, { stream: true })\n : String(chunk);\n append({ kind: \"output\", stream: name, text });\n } catch {\n // ignore capture failures\n }\n return original(chunk, ...rest);\n }) as typeof stream.write;\n}\n\nlet tapsInstalled = false;\n\n// Mirrors everything written to stdout/stderr into the debug log. Installed once,\n// only when enabled, so the common (disabled) path leaves the streams untouched.\nexport function installStreamTaps(): void {\n if (tapsInstalled || !isDebugLogEnabled()) {\n return;\n }\n tapsInstalled = true;\n tapStream(\"stdout\", process.stdout);\n tapStream(\"stderr\", process.stderr);\n}\n"],"mappings":"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","names":[]}
@@ -1,10 +1,10 @@
1
1
  import {
2
2
  debugLogHttp,
3
3
  readBodyForLog
4
- } from "./chunk-6BD32M7K.js";
4
+ } from "./chunk-PWGY347J.js";
5
5
  import {
6
6
  getEnv
7
- } from "./chunk-GJVXXYCX.js";
7
+ } from "./chunk-4VP5WWPR.js";
8
8
 
9
9
  // src/client.ts
10
10
  var MAX_RATE_LIMIT_RETRIES = 3;
@@ -205,4 +205,4 @@ export {
205
205
  apiGet,
206
206
  apiPost
207
207
  };
208
- //# sourceMappingURL=chunk-KAE5M5R7.js.map
208
+ //# sourceMappingURL=chunk-XPUSSDLR.js.map
package/dist/cli.js CHANGED
@@ -67,7 +67,7 @@ import {
67
67
  validateCanvasDeep,
68
68
  withoutCastName,
69
69
  ytDlpBlockSignal
70
- } from "./chunk-HPRKO6P2.js";
70
+ } from "./chunk-FFOURYP5.js";
71
71
  import {
72
72
  csvOrJson,
73
73
  daysAgoIso,
@@ -76,7 +76,7 @@ import {
76
76
  resolveAccountIdArg,
77
77
  resolveEffectiveStatus,
78
78
  todayIso
79
- } from "./chunk-UWFF6WEV.js";
79
+ } from "./chunk-JWMLQSGK.js";
80
80
  import {
81
81
  buildQueryCacheKey,
82
82
  cacheGet,
@@ -92,18 +92,19 @@ import {
92
92
  writeAdsJson,
93
93
  writeAdsOutput,
94
94
  writeJsonEnvelope
95
- } from "./chunk-MSZSDYOJ.js";
95
+ } from "./chunk-KGDL7F7M.js";
96
96
  import {
97
97
  ApiError,
98
98
  apiGet,
99
99
  apiGetWithHeaders,
100
100
  apiPost,
101
101
  validateConvexId
102
- } from "./chunk-KAE5M5R7.js";
102
+ } from "./chunk-XPUSSDLR.js";
103
103
  import {
104
+ installExitRecord,
104
105
  installStreamTaps,
105
106
  logInvocation
106
- } from "./chunk-6BD32M7K.js";
107
+ } from "./chunk-PWGY347J.js";
107
108
  import {
108
109
  captureBudgetMs,
109
110
  captureProxyCredentials,
@@ -117,7 +118,7 @@ import {
117
118
  requireChatId,
118
119
  resolveChatId,
119
120
  shouldEscalate
120
- } from "./chunk-GJVXXYCX.js";
121
+ } from "./chunk-4VP5WWPR.js";
121
122
 
122
123
  // src/cli.ts
123
124
  import { defineCommand as defineCommand244, runMain } from "citty";
@@ -4928,7 +4929,33 @@ var adEffectSchema = z13.object({
4928
4929
  */
4929
4930
  outcome: z13.enum(["applied", "simulated", "failed", "skipped"]).nullable(),
4930
4931
  /** Why it failed, verbatim from the platform. Null unless the op failed. */
4931
- error: z13.string().nullable()
4932
+ error: z13.string().nullable(),
4933
+ /**
4934
+ * Why the publish never attempted it — a dependency that failed first, a
4935
+ * connection that went read-only. Distinct from `error`, which is the
4936
+ * provider's refusal of an op that was actually sent: a reader that cannot
4937
+ * tell the two apart reads "we never tried" as "the platform said no".
4938
+ */
4939
+ skippedBecause: z13.string().nullable().optional()
4940
+ });
4941
+ var configEffectSchema = z13.object({
4942
+ op: effectOpSchema,
4943
+ staged: z13.boolean(),
4944
+ /** The full stored op kind, e.g. `tagManager.tag.create`, `ga4.keyEvent.update`. */
4945
+ operation: z13.string(),
4946
+ /** The entity class the op acts on, e.g. `tag`, `customDimension`. */
4947
+ entity: z13.string().nullable(),
4948
+ summary: z13.string(),
4949
+ ref: z13.string(),
4950
+ outcome: z13.enum(["applied", "failed", "skipped"]).nullable(),
4951
+ error: z13.string().nullable(),
4952
+ skippedBecause: z13.string().nullable(),
4953
+ /**
4954
+ * The post-publish read-back, when one ran. Annotation only — Tag Manager can
4955
+ * answer 200 to a write it silently dropped, so a fresh read is the only
4956
+ * thing that distinguishes "applied" from "accepted and discarded".
4957
+ */
4958
+ verified: z13.boolean().nullable()
4932
4959
  });
4933
4960
  var creativeEffectSchema = z13.object({
4934
4961
  op: effectOpSchema,
@@ -4948,7 +4975,51 @@ var chatEffectsSchema = z13.object({
4948
4975
  linkedin: z13.array(adEffectSchema),
4949
4976
  x: z13.array(adEffectSchema)
4950
4977
  }),
4951
- creatives: z13.array(creativeEffectSchema)
4978
+ creatives: z13.array(creativeEffectSchema),
4979
+ tagManager: z13.array(configEffectSchema),
4980
+ ga4: z13.array(configEffectSchema)
4981
+ });
4982
+ var publishSurfaceFailureSchema = z13.object({
4983
+ summary: z13.string(),
4984
+ /** The provider's own words, trimmed. Empty when it said nothing. */
4985
+ error: z13.string()
4986
+ });
4987
+ var publishSurfaceOutcomeSchema = z13.object({
4988
+ surface: z13.string(),
4989
+ label: z13.string(),
4990
+ total: z13.number(),
4991
+ landed: z13.number(),
4992
+ failed: z13.number(),
4993
+ /** True while this surface is still applying — not yet a verdict either way. */
4994
+ running: z13.boolean(),
4995
+ failures: z13.array(publishSurfaceFailureSchema)
4996
+ });
4997
+ var chatPublishSummarySchema = z13.object({
4998
+ complete: z13.boolean(),
4999
+ running: z13.boolean(),
5000
+ failedTotal: z13.number(),
5001
+ surfaces: z13.array(publishSurfaceOutcomeSchema)
5002
+ });
5003
+ var chatActivityEntrySchema = z13.object({
5004
+ action: z13.string(),
5005
+ actorType: z13.string(),
5006
+ createdAt: z13.number(),
5007
+ threadId: z13.string().nullable(),
5008
+ /** Compact truncates this; `--full` returns it whole. */
5009
+ metadata: z13.unknown().optional()
5010
+ });
5011
+ var chatThreadUsageSchema = z13.object({
5012
+ threadId: z13.string(),
5013
+ costUsd: z13.number(),
5014
+ model: z13.string().nullable()
5015
+ });
5016
+ var chatUsageSchema = z13.object({
5017
+ threads: z13.array(chatThreadUsageSchema),
5018
+ totalCostUsd: z13.number(),
5019
+ inputTokens: z13.number(),
5020
+ outputTokens: z13.number(),
5021
+ cacheReadTokens: z13.number(),
5022
+ cacheWriteTokens: z13.number()
4952
5023
  });
4953
5024
  var chatDetailSchema = z13.object({
4954
5025
  id: z13.string(),
@@ -4967,7 +5038,15 @@ var chatDetailSchema = z13.object({
4967
5038
  threads: z13.array(chatThreadSummarySchema),
4968
5039
  commits: z13.array(chatCommitSummarySchema),
4969
5040
  /** True when a real file-level diff is available via `baker chats diff`. */
4970
- diffAvailable: z13.boolean()
5041
+ diffAvailable: z13.boolean(),
5042
+ /** What the Publish did on each external surface. Absent when nothing was ever published. */
5043
+ publish: chatPublishSummarySchema.optional(),
5044
+ /** Why the Publish itself failed, as the backend recorded it. */
5045
+ publishFailureReason: z13.string().nullable().optional(),
5046
+ /** The chat's own timeline: status changes, publish start/fail, sandbox recoveries, timeouts. */
5047
+ activity: z13.array(chatActivityEntrySchema).optional(),
5048
+ /** What the Session cost, per thread and in total. */
5049
+ usage: chatUsageSchema.optional()
4971
5050
  });
4972
5051
  var chatsViewResponseSchema = z13.object({
4973
5052
  ok: z13.literal(true),
@@ -24823,10 +24902,10 @@ Example: baker ads meta ads retag 120252158038400247 --url-tags "utm_source={{si
24823
24902
  }
24824
24903
  },
24825
24904
  run: async ({ args: args4 }) => {
24826
- const { apiPost: apiPost2 } = await import("./client-XUSSAB6O.js");
24827
- const { requireChatId: requireChatId2 } = await import("./env-VIA5U56G.js");
24828
- const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-ZPACGSH2.js");
24829
- const { handleMetaError: handleMetaError2 } = await import("./shared-OHOCOE2L.js");
24905
+ const { apiPost: apiPost2 } = await import("./client-PWRZOA3Q.js");
24906
+ const { requireChatId: requireChatId2 } = await import("./env-TQTHWLBN.js");
24907
+ const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-HD63GTWI.js");
24908
+ const { handleMetaError: handleMetaError2 } = await import("./shared-5662SBDW.js");
24830
24909
  try {
24831
24910
  const accountId = bareAccountId2(args4);
24832
24911
  const urlTags = typeof args4["url-tags"] === "string" ? args4["url-tags"] : void 0;
@@ -24971,10 +25050,10 @@ function duplicateCommand2(entity, label) {
24971
25050
  replace: { type: "boolean", description: "Pause the original once the copy publishes" }
24972
25051
  },
24973
25052
  run: async ({ args: args4 }) => {
24974
- const { apiPost: apiPost2 } = await import("./client-XUSSAB6O.js");
24975
- const { requireChatId: requireChatId2 } = await import("./env-VIA5U56G.js");
24976
- const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-ZPACGSH2.js");
24977
- const { handleMetaError: handleMetaError2 } = await import("./shared-OHOCOE2L.js");
25053
+ const { apiPost: apiPost2 } = await import("./client-PWRZOA3Q.js");
25054
+ const { requireChatId: requireChatId2 } = await import("./env-TQTHWLBN.js");
25055
+ const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-HD63GTWI.js");
25056
+ const { handleMetaError: handleMetaError2 } = await import("./shared-5662SBDW.js");
24978
25057
  try {
24979
25058
  const accountId = bareAccountId2(args4);
24980
25059
  const chatId = requireChatId2();
@@ -43909,7 +43988,7 @@ var canvasCommand = defineCommand118({
43909
43988
  name: "canvas",
43910
43989
  description: `Run Baker creative canvas JSON files locally. Local nodes execute in-process; remote nodes POST to the Convex backend gateway.
43911
43990
 
43912
- Auth: BAKER_API_KEY (must start with bk_) + BAKER_API_URL (your Convex .convex.site URL).
43991
+ Auth: BAKER_API_KEY (bk_ or bkr_) + BAKER_API_URL (your Convex .convex.site URL).
43913
43992
 
43914
43993
  Subcommands:
43915
43994
  baker canvas validate <file.json> \u2014 schema/registry check + composition-meta deep check + cost preview
@@ -44119,12 +44198,12 @@ var listCommand13 = defineCommand120({
44119
44198
  });
44120
44199
  registerSchema({
44121
44200
  command: "chats.view",
44122
- description: "Inspect one Session's FULL picture of what it changed \u2014 the unified `effects`: git content (landings, creatives, flows, knowledge, brand), plus DB-only effects that never touch the repo \u2014 Actions, Scheduled Actions, Tags, and ad-platform writes \u2014 each resolved to real detail (names, descriptions, priorities, tag types, ad operations). Also the kickoff (how it was asked), threads, and commits. Effects are `staged` (in-progress draft) or applied. Use after `baker chats list` to decide whether to reuse it. Read-only.",
44201
+ description: "Inspect one Session's FULL picture of what it changed \u2014 the unified `effects`: git content (landings, creatives, flows, knowledge, brand), plus DB-only effects that never touch the repo \u2014 Actions, Scheduled Actions, Tags, Tag Manager, Google Analytics, and ad-platform writes \u2014 each resolved to real detail (names, descriptions, priorities, tag types, ad operations). Also `publish` (what each external surface actually did, with the provider's own error), `activity` (the chat's own timeline: status changes, publish start/fail, workspace recoveries, timeouts), `usage` (per-thread cost and the Session's token totals), the kickoff (how it was asked), threads, and commits. Effects are `staged` (in-progress draft) or applied. A completed Session is NOT proof its external changes landed \u2014 read `publish`. Use after `baker chats list` to decide whether to reuse it. Read-only.",
44123
44202
  args: {
44124
44203
  id: { type: "positional", description: "The Session id (from `baker chats list`)", required: true },
44125
44204
  full: {
44126
44205
  type: "boolean",
44127
- description: "No-op today; view already returns full effect detail",
44206
+ description: "Untruncated effect lists and full activity metadata (compact caps each list at 25)",
44128
44207
  required: false,
44129
44208
  default: false
44130
44209
  }
@@ -44146,6 +44225,12 @@ var viewCommand = defineCommand120({
44146
44225
  ...args4.full ? { full: true } : {}
44147
44226
  });
44148
44227
  const hints2 = [];
44228
+ if (response.data.publish && !response.data.publish.complete) {
44229
+ const failed = response.data.publish.failedTotal;
44230
+ hints2.push(
44231
+ `This Session's publish left ${failed} change${failed === 1 ? "" : "s"} behind \u2014 see \`publish.surfaces\` for the platform's own words. Do not report those changes as live.`
44232
+ );
44233
+ }
44149
44234
  if (response.data.diffAvailable) {
44150
44235
  hints2.push("See the real file-level diff of the git content with `baker chats diff <id> --full`.");
44151
44236
  } else if (response.data.status === "in_progress" || response.data.status === "publishing") {
@@ -44668,6 +44753,7 @@ async function readForms(root, slug) {
44668
44753
  }
44669
44754
 
44670
44755
  // src/commands/experiment/fold.ts
44756
+ import { statSync } from "fs";
44671
44757
  import { cp as cp3, mkdir as mkdir9, readdir as readdir12, readFile as readFile25, rm as rm8, stat as stat6, writeFile as writeFile12 } from "fs/promises";
44672
44758
  import path32 from "path";
44673
44759
 
@@ -44795,20 +44881,42 @@ async function archiveContents(opts) {
44795
44881
  return targets;
44796
44882
  }
44797
44883
  function repointIntoArchive(text2, sourceAbs, destAbs, archivedBySource) {
44798
- return text2.replace(QUOTED_RELATIVE2, (match, quote, spec) => {
44799
- const resolved = resolveWithExtensions(path32.resolve(path32.dirname(sourceAbs), spec), archivedBySource);
44884
+ const fromDir = path32.dirname(sourceAbs);
44885
+ const toDir = path32.dirname(destAbs);
44886
+ return text2.replace(QUOTED_RELATIVE2, (match, quote, spec, offset) => {
44887
+ const [specPath, suffix] = splitSuffix(spec);
44888
+ const target = path32.resolve(fromDir, specPath);
44889
+ const resolved = resolveInArchive(target, archivedBySource) ?? resolveOnDisk(target, isImportPosition(text2, offset));
44800
44890
  if (resolved === null) return match;
44801
- const rel = posix2(path32.relative(path32.dirname(destAbs), resolved));
44802
- return `${quote}${rel.startsWith(".") ? rel : `./${rel}`}${quote}`;
44891
+ const rel = posix2(path32.relative(toDir, resolved));
44892
+ return `${quote}${rel.startsWith(".") ? rel : `./${rel}`}${suffix}${quote}`;
44803
44893
  });
44804
44894
  }
44805
- function resolveWithExtensions(base, archivedBySource) {
44806
- for (const suffix of ["", ".astro", ".ts", ".tsx", ".js", ".jsx", ".mjs", "/index.astro", "/index.ts"]) {
44895
+ function splitSuffix(spec) {
44896
+ const cut = spec.search(/[?#]/);
44897
+ return cut === -1 ? [spec, ""] : [spec.slice(0, cut), spec.slice(cut)];
44898
+ }
44899
+ var EXTENSIONS = ["", ".astro", ".ts", ".tsx", ".js", ".jsx", ".mjs"];
44900
+ function resolveInArchive(base, archivedBySource) {
44901
+ for (const suffix of [...EXTENSIONS, "/index.astro", "/index.ts"]) {
44807
44902
  const hit = archivedBySource.get(base + suffix);
44808
44903
  if (hit !== void 0) return hit;
44809
44904
  }
44810
44905
  return null;
44811
44906
  }
44907
+ function isImportPosition(text2, offset) {
44908
+ return /\b(?:from|import|require)\s*\(?\s*$/.test(text2.slice(Math.max(0, offset - 64), offset));
44909
+ }
44910
+ function resolveOnDisk(base, allowDirectoryIndex) {
44911
+ const candidates = allowDirectoryIndex ? [...EXTENSIONS, "/index.astro", "/index.ts", "/index.js"] : EXTENSIONS;
44912
+ for (const suffix of candidates) {
44913
+ try {
44914
+ if (statSync(base + suffix).isFile()) return base + suffix;
44915
+ } catch {
44916
+ }
44917
+ }
44918
+ return null;
44919
+ }
44812
44920
  async function promoteVariantFiles(opts) {
44813
44921
  const { root, pageDir, variantDir } = opts;
44814
44922
  const written = [];
@@ -66637,7 +66745,7 @@ var winningAdsCommand = defineCommand243({
66637
66745
  name: "winning-ads",
66638
66746
  description: `Search the ad-dna corpus of scored "winning" ads for reference creatives to reproduce, and manage the brands your library tracks. Proxied through the Baker backend (BAKER_API_KEY) \u2014 no separate token needed.
66639
66747
 
66640
- Auth: BAKER_API_KEY (must start with bk_) + BAKER_API_URL (your Convex .convex.site URL).
66748
+ Auth: BAKER_API_KEY (bk_ or bkr_) + BAKER_API_URL (your Convex .convex.site URL).
66641
66749
 
66642
66750
  Subcommands:
66643
66751
  baker winning-ads search "<free text>" \u2014 semantic search across the corpus; lean shortlist (advertiser, summary, scores, media_url)
@@ -66916,6 +67024,7 @@ Introspection: Run 'baker schema <command>' to inspect argument schemas.`
66916
67024
  process.argv = [...process.argv.slice(0, 2), ...normalizeCacheFlag(process.argv.slice(2))];
66917
67025
  installStreamTaps();
66918
67026
  logInvocation(process.argv.slice(2));
67027
+ installExitRecord();
66919
67028
  refuseUnknownFlags(main, process.argv.slice(2));
66920
67029
  process.argv = [...process.argv.slice(0, 2), ...cacheFlagForParser(process.argv.slice(2))];
66921
67030
  runMain(main);