@koda-sl/baker-cli 0.295.1 → 0.296.0-dev.952a85323

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.
@@ -92,9 +92,28 @@ function errorToPlain(err) {
92
92
  }
93
93
  return { message: String(err) };
94
94
  }
95
+ var invocationStartedAt;
95
96
  function logInvocation(argv) {
97
+ invocationStartedAt = Date.now();
96
98
  append({ kind: "invocation", argv, cwd: process.cwd() });
97
99
  }
100
+ function logExit(code) {
101
+ append({
102
+ kind: "exit",
103
+ code,
104
+ ...invocationStartedAt === void 0 ? {} : { durationMs: Date.now() - invocationStartedAt }
105
+ });
106
+ }
107
+ var exitHookInstalled = false;
108
+ function installExitRecord() {
109
+ if (exitHookInstalled || !isDebugLogEnabled()) {
110
+ return;
111
+ }
112
+ exitHookInstalled = true;
113
+ process.on("exit", (code) => {
114
+ logExit(typeof code === "number" ? code : 0);
115
+ });
116
+ }
98
117
  function debugLogHttp(entry) {
99
118
  if (!isDebugLogEnabled()) {
100
119
  return;
@@ -146,8 +165,9 @@ function installStreamTaps() {
146
165
 
147
166
  export {
148
167
  logInvocation,
168
+ installExitRecord,
149
169
  debugLogHttp,
150
170
  readBodyForLog,
151
171
  installStreamTaps
152
172
  };
153
- //# sourceMappingURL=chunk-2IB3IL4K.js.map
173
+ //# sourceMappingURL=chunk-SKSCXWHG.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 [/bk_[A-Za-z0-9]+/g, \"bk_[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":[]}
@@ -2,10 +2,10 @@ import {
2
2
  handleConnectionError,
3
3
  needsConnectionFix,
4
4
  writeAdsJson
5
- } from "./chunk-EX2OIOVL.js";
5
+ } from "./chunk-JYRBRAL4.js";
6
6
  import {
7
7
  ApiError
8
- } from "./chunk-GU7IWEBC.js";
8
+ } from "./chunk-63VDTPEZ.js";
9
9
  import {
10
10
  getEnv
11
11
  } from "./chunk-DZUVUGEP.js";
@@ -108,4 +108,4 @@ export {
108
108
  csvOrJson,
109
109
  resolveEffectiveStatus
110
110
  };
111
- //# sourceMappingURL=chunk-D3HHUBIL.js.map
111
+ //# sourceMappingURL=chunk-UQNSRE7A.js.map
package/dist/cli.js CHANGED
@@ -58,7 +58,7 @@ import {
58
58
  ulid,
59
59
  validateCanvasDeep,
60
60
  ytDlpBlockSignal
61
- } from "./chunk-YFQWCJX4.js";
61
+ } from "./chunk-LL2SD3HE.js";
62
62
  import {
63
63
  csvOrJson,
64
64
  daysAgoIso,
@@ -67,7 +67,7 @@ import {
67
67
  resolveAccountIdArg,
68
68
  resolveEffectiveStatus,
69
69
  todayIso
70
- } from "./chunk-D3HHUBIL.js";
70
+ } from "./chunk-UQNSRE7A.js";
71
71
  import {
72
72
  buildQueryCacheKey,
73
73
  cacheGet,
@@ -83,18 +83,19 @@ import {
83
83
  writeAdsJson,
84
84
  writeAdsOutput,
85
85
  writeJsonEnvelope
86
- } from "./chunk-EX2OIOVL.js";
86
+ } from "./chunk-JYRBRAL4.js";
87
87
  import {
88
88
  ApiError,
89
89
  apiGet,
90
90
  apiGetWithHeaders,
91
91
  apiPost,
92
92
  validateConvexId
93
- } from "./chunk-GU7IWEBC.js";
93
+ } from "./chunk-63VDTPEZ.js";
94
94
  import {
95
+ installExitRecord,
95
96
  installStreamTaps,
96
97
  logInvocation
97
- } from "./chunk-2IB3IL4K.js";
98
+ } from "./chunk-SKSCXWHG.js";
98
99
  import {
99
100
  captureBudgetMs,
100
101
  captureProxyCredentials,
@@ -4848,7 +4849,33 @@ var adEffectSchema = z13.object({
4848
4849
  */
4849
4850
  outcome: z13.enum(["applied", "simulated", "failed", "skipped"]).nullable(),
4850
4851
  /** Why it failed, verbatim from the platform. Null unless the op failed. */
4851
- error: z13.string().nullable()
4852
+ error: z13.string().nullable(),
4853
+ /**
4854
+ * Why the publish never attempted it — a dependency that failed first, a
4855
+ * connection that went read-only. Distinct from `error`, which is the
4856
+ * provider's refusal of an op that was actually sent: a reader that cannot
4857
+ * tell the two apart reads "we never tried" as "the platform said no".
4858
+ */
4859
+ skippedBecause: z13.string().nullable().optional()
4860
+ });
4861
+ var configEffectSchema = z13.object({
4862
+ op: effectOpSchema,
4863
+ staged: z13.boolean(),
4864
+ /** The full stored op kind, e.g. `tagManager.tag.create`, `ga4.keyEvent.update`. */
4865
+ operation: z13.string(),
4866
+ /** The entity class the op acts on, e.g. `tag`, `customDimension`. */
4867
+ entity: z13.string().nullable(),
4868
+ summary: z13.string(),
4869
+ ref: z13.string(),
4870
+ outcome: z13.enum(["applied", "failed", "skipped"]).nullable(),
4871
+ error: z13.string().nullable(),
4872
+ skippedBecause: z13.string().nullable(),
4873
+ /**
4874
+ * The post-publish read-back, when one ran. Annotation only — Tag Manager can
4875
+ * answer 200 to a write it silently dropped, so a fresh read is the only
4876
+ * thing that distinguishes "applied" from "accepted and discarded".
4877
+ */
4878
+ verified: z13.boolean().nullable()
4852
4879
  });
4853
4880
  var creativeEffectSchema = z13.object({
4854
4881
  op: effectOpSchema,
@@ -4868,7 +4895,51 @@ var chatEffectsSchema = z13.object({
4868
4895
  linkedin: z13.array(adEffectSchema),
4869
4896
  x: z13.array(adEffectSchema)
4870
4897
  }),
4871
- creatives: z13.array(creativeEffectSchema)
4898
+ creatives: z13.array(creativeEffectSchema),
4899
+ tagManager: z13.array(configEffectSchema),
4900
+ ga4: z13.array(configEffectSchema)
4901
+ });
4902
+ var publishSurfaceFailureSchema = z13.object({
4903
+ summary: z13.string(),
4904
+ /** The provider's own words, trimmed. Empty when it said nothing. */
4905
+ error: z13.string()
4906
+ });
4907
+ var publishSurfaceOutcomeSchema = z13.object({
4908
+ surface: z13.string(),
4909
+ label: z13.string(),
4910
+ total: z13.number(),
4911
+ landed: z13.number(),
4912
+ failed: z13.number(),
4913
+ /** True while this surface is still applying — not yet a verdict either way. */
4914
+ running: z13.boolean(),
4915
+ failures: z13.array(publishSurfaceFailureSchema)
4916
+ });
4917
+ var chatPublishSummarySchema = z13.object({
4918
+ complete: z13.boolean(),
4919
+ running: z13.boolean(),
4920
+ failedTotal: z13.number(),
4921
+ surfaces: z13.array(publishSurfaceOutcomeSchema)
4922
+ });
4923
+ var chatActivityEntrySchema = z13.object({
4924
+ action: z13.string(),
4925
+ actorType: z13.string(),
4926
+ createdAt: z13.number(),
4927
+ threadId: z13.string().nullable(),
4928
+ /** Compact truncates this; `--full` returns it whole. */
4929
+ metadata: z13.unknown().optional()
4930
+ });
4931
+ var chatThreadUsageSchema = z13.object({
4932
+ threadId: z13.string(),
4933
+ costUsd: z13.number(),
4934
+ model: z13.string().nullable()
4935
+ });
4936
+ var chatUsageSchema = z13.object({
4937
+ threads: z13.array(chatThreadUsageSchema),
4938
+ totalCostUsd: z13.number(),
4939
+ inputTokens: z13.number(),
4940
+ outputTokens: z13.number(),
4941
+ cacheReadTokens: z13.number(),
4942
+ cacheWriteTokens: z13.number()
4872
4943
  });
4873
4944
  var chatDetailSchema = z13.object({
4874
4945
  id: z13.string(),
@@ -4887,7 +4958,15 @@ var chatDetailSchema = z13.object({
4887
4958
  threads: z13.array(chatThreadSummarySchema),
4888
4959
  commits: z13.array(chatCommitSummarySchema),
4889
4960
  /** True when a real file-level diff is available via `baker chats diff`. */
4890
- diffAvailable: z13.boolean()
4961
+ diffAvailable: z13.boolean(),
4962
+ /** What the Publish did on each external surface. Absent when nothing was ever published. */
4963
+ publish: chatPublishSummarySchema.optional(),
4964
+ /** Why the Publish itself failed, as the backend recorded it. */
4965
+ publishFailureReason: z13.string().nullable().optional(),
4966
+ /** The chat's own timeline: status changes, publish start/fail, sandbox recoveries, timeouts. */
4967
+ activity: z13.array(chatActivityEntrySchema).optional(),
4968
+ /** What the Session cost, per thread and in total. */
4969
+ usage: chatUsageSchema.optional()
4891
4970
  });
4892
4971
  var chatsViewResponseSchema = z13.object({
4893
4972
  ok: z13.literal(true),
@@ -23076,10 +23155,10 @@ Example: baker ads meta ads retag 120252158038400247 --url-tags "utm_source={{si
23076
23155
  }
23077
23156
  },
23078
23157
  run: async ({ args }) => {
23079
- const { apiPost: apiPost2 } = await import("./client-VDCCDEHE.js");
23158
+ const { apiPost: apiPost2 } = await import("./client-FAOKSCYQ.js");
23080
23159
  const { requireChatId: requireChatId2 } = await import("./env-FWMZXMQK.js");
23081
- const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-4H2RNBXL.js");
23082
- const { handleMetaError: handleMetaError2 } = await import("./shared-UKL36AXT.js");
23160
+ const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-T3DULDPI.js");
23161
+ const { handleMetaError: handleMetaError2 } = await import("./shared-CQ24M7DY.js");
23083
23162
  try {
23084
23163
  const accountId = bareAccountId2(args);
23085
23164
  const urlTags = typeof args["url-tags"] === "string" ? args["url-tags"] : void 0;
@@ -23220,10 +23299,10 @@ function duplicateCommand2(entity, label) {
23220
23299
  replace: { type: "boolean", description: "Pause the original once the copy publishes" }
23221
23300
  },
23222
23301
  run: async ({ args }) => {
23223
- const { apiPost: apiPost2 } = await import("./client-VDCCDEHE.js");
23302
+ const { apiPost: apiPost2 } = await import("./client-FAOKSCYQ.js");
23224
23303
  const { requireChatId: requireChatId2 } = await import("./env-FWMZXMQK.js");
23225
- const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-4H2RNBXL.js");
23226
- const { handleMetaError: handleMetaError2 } = await import("./shared-UKL36AXT.js");
23304
+ const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-T3DULDPI.js");
23305
+ const { handleMetaError: handleMetaError2 } = await import("./shared-CQ24M7DY.js");
23227
23306
  try {
23228
23307
  const accountId = bareAccountId2(args);
23229
23308
  const chatId = requireChatId2();
@@ -38691,12 +38770,12 @@ var listCommand12 = defineCommand116({
38691
38770
  });
38692
38771
  registerSchema({
38693
38772
  command: "chats.view",
38694
- 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.",
38773
+ 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.",
38695
38774
  args: {
38696
38775
  id: { type: "positional", description: "The Session id (from `baker chats list`)", required: true },
38697
38776
  full: {
38698
38777
  type: "boolean",
38699
- description: "No-op today; view already returns full effect detail",
38778
+ description: "Untruncated effect lists and full activity metadata (compact caps each list at 25)",
38700
38779
  required: false,
38701
38780
  default: false
38702
38781
  }
@@ -38718,6 +38797,12 @@ var viewCommand = defineCommand116({
38718
38797
  ...args.full ? { full: true } : {}
38719
38798
  });
38720
38799
  const hints2 = [];
38800
+ if (response.data.publish && !response.data.publish.complete) {
38801
+ const failed = response.data.publish.failedTotal;
38802
+ hints2.push(
38803
+ `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.`
38804
+ );
38805
+ }
38721
38806
  if (response.data.diffAvailable) {
38722
38807
  hints2.push("See the real file-level diff of the git content with `baker chats diff <id> --full`.");
38723
38808
  } else if (response.data.status === "in_progress" || response.data.status === "publishing") {
@@ -60210,6 +60295,7 @@ Introspection: Run 'baker schema <command>' to inspect argument schemas.`
60210
60295
  process.argv = [...process.argv.slice(0, 2), ...normalizeCacheFlag(process.argv.slice(2))];
60211
60296
  installStreamTaps();
60212
60297
  logInvocation(process.argv.slice(2));
60298
+ installExitRecord();
60213
60299
  refuseUnknownFlags(main, process.argv.slice(2));
60214
60300
  process.argv = [...process.argv.slice(0, 2), ...cacheFlagForParser(process.argv.slice(2))];
60215
60301
  runMain(main);