@koda-sl/baker-cli 0.359.0-dev.d2f320fd3 → 0.360.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.
- package/README.md +14 -4
- package/canvas/avocado-tutorial.json +1 -1
- package/canvas/hello-world-overlay.json +1 -1
- package/dist/{chunk-K2IKLMCM.js → chunk-AI4HWQVN.js} +4 -4
- package/dist/chunk-AI4HWQVN.js.map +1 -0
- package/dist/{chunk-4QXKWIFC.js → chunk-MZQC4LII.js} +4 -1
- package/dist/chunk-MZQC4LII.js.map +1 -0
- package/dist/{chunk-NA5CPMUA.js → chunk-SR56QQTD.js} +4 -4
- package/dist/chunk-SR56QQTD.js.map +1 -0
- package/dist/{chunk-2IC3CGQO.js → chunk-VVQLRFCI.js} +2 -2
- package/dist/cli.js +165 -162
- package/dist/cli.js.map +1 -1
- package/dist/{client-ODCNYCP4.js → client-3DGBQ2H3.js} +2 -2
- package/dist/engine/index.js +1 -1
- package/dist/{output-2XBCYF7L.js → output-OSSBUGT7.js} +3 -3
- package/dist/{shared-RYAF7Y7H.js → shared-MSI4UMZ3.js} +4 -4
- package/package.json +1 -1
- package/dist/chunk-4QXKWIFC.js.map +0 -1
- package/dist/chunk-K2IKLMCM.js.map +0 -1
- package/dist/chunk-NA5CPMUA.js.map +0 -1
- /package/dist/{chunk-2IC3CGQO.js.map → chunk-VVQLRFCI.js.map} +0 -0
- /package/dist/{client-ODCNYCP4.js.map → client-3DGBQ2H3.js.map} +0 -0
- /package/dist/{output-2XBCYF7L.js.map → output-OSSBUGT7.js.map} +0 -0
- /package/dist/{shared-RYAF7Y7H.js.map → shared-MSI4UMZ3.js.map} +0 -0
|
@@ -85,6 +85,9 @@ function mapHttpError(status) {
|
|
|
85
85
|
if (status === 429) {
|
|
86
86
|
return "RATE_LIMITED";
|
|
87
87
|
}
|
|
88
|
+
if (status === 503) {
|
|
89
|
+
return "UNAVAILABLE";
|
|
90
|
+
}
|
|
88
91
|
return "INTERNAL_ERROR";
|
|
89
92
|
}
|
|
90
93
|
async function handleResponse(response) {
|
|
@@ -205,4 +208,4 @@ export {
|
|
|
205
208
|
apiGet,
|
|
206
209
|
apiPost
|
|
207
210
|
};
|
|
208
|
-
//# sourceMappingURL=chunk-
|
|
211
|
+
//# sourceMappingURL=chunk-MZQC4LII.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/client.ts"],"sourcesContent":["import { debugLogHttp, readBodyForLog } from \"./debugLog.ts\";\nimport { getEnv } from \"./env.ts\";\n\nconst MAX_RATE_LIMIT_RETRIES = 3;\nconst MAX_TOTAL_WAIT_MS = 2 * 60 * 1000;\n\nasync function fetchWithRateLimitRetry(url: string, init: RequestInit): Promise<Response> {\n let totalWaited = 0;\n\n for (let attempt = 0; attempt <= MAX_RATE_LIMIT_RETRIES; attempt++) {\n const response = await fetch(url, init);\n\n if (response.status !== 429 || attempt >= MAX_RATE_LIMIT_RETRIES) {\n return response;\n }\n\n const retryAfterHeader = response.headers.get(\"Retry-After\");\n const waitMs = retryAfterHeader ? Number(retryAfterHeader) * 1000 : 2000 * 2 ** attempt;\n\n if (totalWaited + waitMs > MAX_TOTAL_WAIT_MS) {\n return response;\n }\n\n totalWaited += waitMs;\n await new Promise((resolve) => setTimeout(resolve, waitMs));\n }\n\n return fetch(url, init);\n}\n\nexport type ErrorCode =\n | \"UNAUTHORIZED\"\n | \"FORBIDDEN\"\n | \"NOT_FOUND\"\n | \"CONFLICT\"\n | \"VALIDATION_ERROR\"\n | \"RATE_LIMITED\"\n | \"UNAVAILABLE\"\n | \"INTERNAL_ERROR\"\n | \"NETWORK_ERROR\"\n | \"TIMEOUT\"\n | \"IMAGE_PROCESSING_ERROR\";\n\nexport class ApiError extends Error {\n code: ErrorCode;\n\n constructor(code: ErrorCode, message: string) {\n super(message);\n this.name = \"ApiError\";\n this.code = code;\n }\n}\n\nconst CONVEX_ID_RE = /^[a-zA-Z0-9_]+$/;\n\nfunction hasControlCharacters(value: string): boolean {\n for (let i = 0; i < value.length; i++) {\n const code = value.charCodeAt(i);\n // Allow tab (9), newline (10), carriage return (13)\n if (code < 32 && code !== 9 && code !== 10 && code !== 13) {\n return true;\n }\n }\n return false;\n}\n\nfunction validateStringValue(value: string): void {\n if (hasControlCharacters(value)) {\n throw new ApiError(\"VALIDATION_ERROR\", \"String value contains invalid control characters\");\n }\n}\n\nexport function validateConvexId(id: string): void {\n if (!CONVEX_ID_RE.test(id)) {\n throw new ApiError(\"VALIDATION_ERROR\", `Invalid ID format: \"${id}\". Expected alphanumeric string.`);\n }\n}\n\nfunction sanitizeParams(params: Record<string, string>): Record<string, string> {\n const sanitized: Record<string, string> = {};\n for (const [key, value] of Object.entries(params)) {\n validateStringValue(value);\n sanitized[key] = value;\n }\n return sanitized;\n}\n\n/**\n * Sent on every call so the backend can attribute immediately-applied writes\n * (library images and videos, followed advertisers) to the Session they were\n * made from. Absent outside a chat-attached environment.\n */\nfunction chatHeader(): Record<string, string> {\n const chatId = getEnv().BAKER_CHAT_ID;\n return chatId ? { \"x-baker-chat-id\": chatId } : {};\n}\n\nfunction mapHttpError(status: number): ErrorCode {\n if (status === 401) {\n return \"UNAUTHORIZED\";\n }\n // 403 is never \"not connected\" — every backend `FORBIDDEN` means connected but\n // not allowed (an asset outside the granted scope, a capability the account\n // lacks). Folding it into UNAUTHORIZED sent agents down the reconnect path,\n // which cannot fix a permission gap and wastes the user's time.\n if (status === 403) {\n return \"FORBIDDEN\";\n }\n if (status === 404) {\n return \"NOT_FOUND\";\n }\n if (status === 422 || status === 400) {\n return \"VALIDATION_ERROR\";\n }\n // 409 is a state the caller has to change, never a fault to sit out. It is\n // what the backend returns for \"this workspace has not switched analytics on\n // yet\" and its siblings — folded into INTERNAL_ERROR, that reaches an agent\n // as a transient failure worth retrying, which it never is.\n if (status === 409) {\n return \"CONFLICT\";\n }\n if (status === 429) {\n return \"RATE_LIMITED\";\n }\n // 503 is the backend's `UNAVAILABLE`: a system it depends on did not answer\n // just now, and asking again is the fix. Folded into INTERNAL_ERROR, it reads\n // exactly like a fault of ours, and the agent cannot tell which one waits out.\n if (status === 503) {\n return \"UNAVAILABLE\";\n }\n return \"INTERNAL_ERROR\";\n}\n\nasync function handleResponse<T>(response: Response): Promise<T> {\n const body = await response.text();\n\n if (!response.ok) {\n let message = `HTTP ${response.status}: ${response.statusText}`;\n try {\n const parsed = JSON.parse(body) as { error?: string | { message?: string }; message?: string };\n if (typeof parsed.error === \"string\") {\n message = parsed.error;\n } else if (parsed.error?.message) {\n message = parsed.error.message;\n } else if (parsed.message) {\n message = parsed.message;\n }\n } catch {\n // Use default message\n }\n throw new ApiError(mapHttpError(response.status), message);\n }\n\n try {\n return JSON.parse(body) as T;\n } catch {\n throw new ApiError(\"INTERNAL_ERROR\", \"Failed to parse API response as JSON\");\n }\n}\n\n/**\n * A GET that also hands back the response headers.\n *\n * Some endpoints have to say something *about* the answer that the answer has\n * no room for — `GET /api/testimonials` returns a bare array and sets\n * `X-Baker-Next-Cursor` when rows past this page remain unexamined, so the rows\n * alone cannot tell one page of a library from the whole of it.\n */\nexport async function apiGetWithHeaders<T>(\n path: string,\n params?: Record<string, string>,\n): Promise<{ data: T; headers: Headers }> {\n const env = getEnv();\n const url = new URL(path, env.BAKER_API_URL);\n if (params) {\n const clean = sanitizeParams(params);\n for (const [key, value] of Object.entries(clean)) {\n url.searchParams.set(key, value);\n }\n }\n\n const urlStr = url.toString();\n const startedAt = Date.now();\n let response: Response;\n try {\n response = await fetchWithRateLimitRetry(urlStr, {\n method: \"GET\",\n headers: {\n Authorization: `Bearer ${env.BAKER_API_KEY}`,\n Accept: \"application/json\",\n ...chatHeader(),\n },\n signal: AbortSignal.timeout(60_000),\n });\n } catch (err) {\n debugLogHttp({ source: \"cli\", method: \"GET\", url: urlStr, durationMs: Date.now() - startedAt, error: err });\n if (err instanceof Error && (err.name === \"TimeoutError\" || err.name === \"AbortError\")) {\n throw new ApiError(\"TIMEOUT\", \"Request timed out after 60 seconds\");\n }\n throw new ApiError(\"NETWORK_ERROR\", `Request failed: ${err instanceof Error ? err.message : \"Unknown error\"}`);\n }\n\n debugLogHttp({\n source: \"cli\",\n method: \"GET\",\n url: urlStr,\n status: response.status,\n ok: response.ok,\n responseBody: await readBodyForLog(response),\n durationMs: Date.now() - startedAt,\n });\n return { data: await handleResponse<T>(response), headers: response.headers };\n}\n\nexport async function apiGet<T>(path: string, params?: Record<string, string>): Promise<T> {\n return (await apiGetWithHeaders<T>(path, params)).data;\n}\n\nexport async function apiPost<T>(path: string, body: unknown, opts?: { timeoutMs?: number }): Promise<T> {\n const env = getEnv();\n const timeoutMs = opts?.timeoutMs ?? 60_000;\n const urlStr = new URL(path, env.BAKER_API_URL).toString();\n const startedAt = Date.now();\n let response: Response;\n try {\n response = await fetchWithRateLimitRetry(urlStr, {\n method: \"POST\",\n headers: {\n Authorization: `Bearer ${env.BAKER_API_KEY}`,\n \"Content-Type\": \"application/json\",\n Accept: \"application/json\",\n ...chatHeader(),\n },\n body: JSON.stringify(body),\n signal: AbortSignal.timeout(timeoutMs),\n });\n } catch (err) {\n debugLogHttp({\n source: \"cli\",\n method: \"POST\",\n url: urlStr,\n requestBody: body,\n durationMs: Date.now() - startedAt,\n error: err,\n });\n if (err instanceof Error && (err.name === \"TimeoutError\" || err.name === \"AbortError\")) {\n throw new ApiError(\"TIMEOUT\", `Request timed out after ${Math.round(timeoutMs / 1000)} seconds`);\n }\n throw new ApiError(\"NETWORK_ERROR\", `Request failed: ${err instanceof Error ? err.message : \"Unknown error\"}`);\n }\n\n debugLogHttp({\n source: \"cli\",\n method: \"POST\",\n url: urlStr,\n requestBody: body,\n status: response.status,\n ok: response.ok,\n responseBody: await readBodyForLog(response),\n durationMs: Date.now() - startedAt,\n });\n return handleResponse<T>(response);\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-
|
|
5
|
+
} from "./chunk-VVQLRFCI.js";
|
|
6
6
|
import {
|
|
7
7
|
ApiError
|
|
8
|
-
} from "./chunk-
|
|
8
|
+
} from "./chunk-MZQC4LII.js";
|
|
9
9
|
import {
|
|
10
10
|
getEnv
|
|
11
11
|
} from "./chunk-2OKSJNLA.js";
|
|
@@ -35,7 +35,7 @@ function handleMetaError(err) {
|
|
|
35
35
|
code: err.code,
|
|
36
36
|
message: err.message,
|
|
37
37
|
fix: err.code === "FORBIDDEN" ? metaForbiddenFix(err.message) : { action: "reject", explanation: err.message },
|
|
38
|
-
retryable: err.code === "RATE_LIMITED" || err.code === "INTERNAL_ERROR"
|
|
38
|
+
retryable: err.code === "RATE_LIMITED" || err.code === "UNAVAILABLE" || err.code === "INTERNAL_ERROR"
|
|
39
39
|
}
|
|
40
40
|
};
|
|
41
41
|
writeAdsJson(envelope);
|
|
@@ -108,4 +108,4 @@ export {
|
|
|
108
108
|
csvOrJson,
|
|
109
109
|
resolveEffectiveStatus
|
|
110
110
|
};
|
|
111
|
-
//# sourceMappingURL=chunk-
|
|
111
|
+
//# sourceMappingURL=chunk-SR56QQTD.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/commands/ads/meta/shared.ts"],"sourcesContent":["import { ApiError } from \"../../../client.ts\";\nimport { getEnv } from \"../../../env.ts\";\nimport { handleConnectionError, needsConnectionFix } from \"../../../error-handler.ts\";\nimport { writeAdsJson } from \"../output.ts\";\nimport type { AdsErrorEnvelope, QueryFix } from \"../types.ts\";\n\nconst DAY_MS = 86_400_000;\n\n/**\n * Meta answers a permission refusal (Graph codes 200/10/294) with a bare\n * \"Permissions error\" that covers two causes needing opposite remedies: a\n * consent grant the connection never got — nothing validates Meta's granted\n * scopes after connect, unlike HubSpot's `requireCapability` — or a role the\n * user lacks on one asset, since a Pixel/Dataset, Page or catalog lives in a\n * Business and is assigned separately from the ad account. Only the blast radius\n * separates them, so hand the agent that test rather than a verdict: guessing\n * \"reconnect\" wastes the user's time on an unassigned asset, and ruling it out\n * strands a connection that really is short a scope.\n */\nexport function metaForbiddenFix(message: string): QueryFix {\n return {\n action: \"reject\",\n explanation: [\n message,\n \"This is a permission refusal, not a dead connection, and Meta returns the same code for two causes with opposite remedies. Tell them apart by how much else works before you answer.\",\n \"If other reads on this account are ALSO refused (campaigns, ad sets, insights), the connection is short a permission it was never granted. Only the user can widen it, by reconnecting Meta from the dashboard.\",\n \"If those reads work and only this object is refused, the asset (pixel/dataset, Page, or catalog) belongs to a Business the connected user holds no role in. Ad-account access does not carry asset access and reconnecting cannot grant it — the client assigns that asset to the connected user or partner in Meta Business settings, under the asset's own section (Data sources → Datasets for a pixel).\",\n \"Either way do not retry the same call, and do not abort the wider job. Continue with what you can read, and state in your answer that this specific check could not run and why — never present the task as verified when this step was skipped.\",\n ].join(\"\\n\\n\"),\n };\n}\n\nexport function handleMetaError(err: unknown): never {\n if (err instanceof ApiError) {\n if (needsConnectionFix(err.code, err.message)) {\n handleConnectionError(\"meta_ads\", err.message);\n }\n const envelope: AdsErrorEnvelope = {\n ok: false,\n error: {\n code: err.code,\n message: err.message,\n fix: err.code === \"FORBIDDEN\" ? metaForbiddenFix(err.message) : { action: \"reject\", explanation: err.message },\n retryable: err.code === \"RATE_LIMITED\" || err.code === \"UNAVAILABLE\" || err.code === \"INTERNAL_ERROR\",\n },\n };\n writeAdsJson(envelope);\n process.exit(1);\n }\n const message = err instanceof Error ? err.message : \"Unexpected error\";\n writeAdsJson({ ok: false, error: { code: \"NETWORK_ERROR\", message } });\n process.exit(1);\n}\n\nconst ACCOUNT_ID_RE = /^(act_)?[0-9]+$/;\n\n/** Pull the default Meta ad account ID from `--account-id` arg or `BAKER_META_AD_ACCOUNT_ID` env. */\nexport function resolveAccountIdArg(args: Record<string, unknown>): string {\n const fromArgs = args[\"account-id\"] as string | undefined;\n const id = fromArgs || getEnv().BAKER_META_AD_ACCOUNT_ID;\n if (!id) {\n writeAdsJson({\n ok: false,\n error: {\n code: \"MISSING_ACCOUNT_ID\",\n message: \"Pass --account-id or set BAKER_META_AD_ACCOUNT_ID. Run `baker ads meta accounts` to find IDs.\",\n },\n });\n process.exit(1);\n }\n if (!ACCOUNT_ID_RE.test(id)) {\n writeAdsJson({\n ok: false,\n error: {\n code: \"INVALID_ACCOUNT_ID\",\n message: `Invalid account ID \"${id}\". Expected numeric ID, optionally prefixed with \"act_\".`,\n },\n });\n process.exit(1);\n }\n return id.startsWith(\"act_\") ? id : `act_${id}`;\n}\n\nexport function getDateRange(args: Record<string, unknown>): { datePreset?: string; since?: string; until?: string } {\n const datePreset = args[\"date-preset\"] as string | undefined;\n const since = args.since as string | undefined;\n const until = args.until as string | undefined;\n if (since && until) return { since, until };\n return { datePreset: datePreset ?? \"last_7d\" };\n}\n\nexport function todayIso(): string {\n return new Date().toISOString().slice(0, 10);\n}\n\nexport function daysAgoIso(days: number): string {\n return new Date(Date.now() - days * DAY_MS).toISOString().slice(0, 10);\n}\n\nexport function csvOrJson(args: Record<string, unknown>): string {\n return (args.output as string | undefined) ?? \"json\";\n}\n\n/**\n * Default to ACTIVE-only on listings — that's almost always what an AI agent or\n * a human glance wants. Pass `--effective-status ACTIVE,PAUSED` to override, or\n * `--all-statuses` to drop the filter entirely.\n */\nexport function resolveEffectiveStatus(args: Record<string, unknown>): string | undefined {\n if (args[\"all-statuses\"]) {\n return undefined;\n }\n const explicit = args[\"effective-status\"] as string | undefined;\n if (explicit) {\n return explicit;\n }\n return \"ACTIVE\";\n}\n"],"mappings":";;;;;;;;;;;;;AAMA,IAAM,SAAS;AAaR,SAAS,iBAAiB,SAA2B;AAC1D,SAAO;AAAA,IACL,QAAQ;AAAA,IACR,aAAa;AAAA,MACX;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,MACA;AAAA,IACF,EAAE,KAAK,MAAM;AAAA,EACf;AACF;AAEO,SAAS,gBAAgB,KAAqB;AACnD,MAAI,eAAe,UAAU;AAC3B,QAAI,mBAAmB,IAAI,MAAM,IAAI,OAAO,GAAG;AAC7C,4BAAsB,YAAY,IAAI,OAAO;AAAA,IAC/C;AACA,UAAM,WAA6B;AAAA,MACjC,IAAI;AAAA,MACJ,OAAO;AAAA,QACL,MAAM,IAAI;AAAA,QACV,SAAS,IAAI;AAAA,QACb,KAAK,IAAI,SAAS,cAAc,iBAAiB,IAAI,OAAO,IAAI,EAAE,QAAQ,UAAU,aAAa,IAAI,QAAQ;AAAA,QAC7G,WAAW,IAAI,SAAS,kBAAkB,IAAI,SAAS,iBAAiB,IAAI,SAAS;AAAA,MACvF;AAAA,IACF;AACA,iBAAa,QAAQ;AACrB,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,QAAM,UAAU,eAAe,QAAQ,IAAI,UAAU;AACrD,eAAa,EAAE,IAAI,OAAO,OAAO,EAAE,MAAM,iBAAiB,QAAQ,EAAE,CAAC;AACrE,UAAQ,KAAK,CAAC;AAChB;AAEA,IAAM,gBAAgB;AAGf,SAAS,oBAAoB,MAAuC;AACzE,QAAM,WAAW,KAAK,YAAY;AAClC,QAAM,KAAK,YAAY,OAAO,EAAE;AAChC,MAAI,CAAC,IAAI;AACP,iBAAa;AAAA,MACX,IAAI;AAAA,MACJ,OAAO;AAAA,QACL,MAAM;AAAA,QACN,SAAS;AAAA,MACX;AAAA,IACF,CAAC;AACD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,MAAI,CAAC,cAAc,KAAK,EAAE,GAAG;AAC3B,iBAAa;AAAA,MACX,IAAI;AAAA,MACJ,OAAO;AAAA,QACL,MAAM;AAAA,QACN,SAAS,uBAAuB,EAAE;AAAA,MACpC;AAAA,IACF,CAAC;AACD,YAAQ,KAAK,CAAC;AAAA,EAChB;AACA,SAAO,GAAG,WAAW,MAAM,IAAI,KAAK,OAAO,EAAE;AAC/C;AAEO,SAAS,aAAa,MAAwF;AACnH,QAAM,aAAa,KAAK,aAAa;AACrC,QAAM,QAAQ,KAAK;AACnB,QAAM,QAAQ,KAAK;AACnB,MAAI,SAAS,MAAO,QAAO,EAAE,OAAO,MAAM;AAC1C,SAAO,EAAE,YAAY,cAAc,UAAU;AAC/C;AAEO,SAAS,WAAmB;AACjC,UAAO,oBAAI,KAAK,GAAE,YAAY,EAAE,MAAM,GAAG,EAAE;AAC7C;AAEO,SAAS,WAAW,MAAsB;AAC/C,SAAO,IAAI,KAAK,KAAK,IAAI,IAAI,OAAO,MAAM,EAAE,YAAY,EAAE,MAAM,GAAG,EAAE;AACvE;AAEO,SAAS,UAAU,MAAuC;AAC/D,SAAQ,KAAK,UAAiC;AAChD;AAOO,SAAS,uBAAuB,MAAmD;AACxF,MAAI,KAAK,cAAc,GAAG;AACxB,WAAO;AAAA,EACT;AACA,QAAM,WAAW,KAAK,kBAAkB;AACxC,MAAI,UAAU;AACZ,WAAO;AAAA,EACT;AACA,SAAO;AACT;","names":[]}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import {
|
|
2
2
|
ApiError,
|
|
3
3
|
apiGet
|
|
4
|
-
} from "./chunk-
|
|
4
|
+
} from "./chunk-MZQC4LII.js";
|
|
5
5
|
import {
|
|
6
6
|
getEnv
|
|
7
7
|
} from "./chunk-2OKSJNLA.js";
|
|
@@ -294,4 +294,4 @@ export {
|
|
|
294
294
|
writeAdsOutput,
|
|
295
295
|
resolveCustomerId
|
|
296
296
|
};
|
|
297
|
-
//# sourceMappingURL=chunk-
|
|
297
|
+
//# sourceMappingURL=chunk-VVQLRFCI.js.map
|
package/dist/cli.js
CHANGED
|
@@ -69,7 +69,7 @@ import {
|
|
|
69
69
|
validateCanvasDeep,
|
|
70
70
|
withoutCastName,
|
|
71
71
|
ytDlpBlockSignal
|
|
72
|
-
} from "./chunk-
|
|
72
|
+
} from "./chunk-AI4HWQVN.js";
|
|
73
73
|
import {
|
|
74
74
|
csvOrJson,
|
|
75
75
|
daysAgoIso,
|
|
@@ -78,7 +78,7 @@ import {
|
|
|
78
78
|
resolveAccountIdArg,
|
|
79
79
|
resolveEffectiveStatus,
|
|
80
80
|
todayIso
|
|
81
|
-
} from "./chunk-
|
|
81
|
+
} from "./chunk-SR56QQTD.js";
|
|
82
82
|
import {
|
|
83
83
|
buildQueryCacheKey,
|
|
84
84
|
cacheGet,
|
|
@@ -94,14 +94,14 @@ import {
|
|
|
94
94
|
writeAdsJson,
|
|
95
95
|
writeAdsOutput,
|
|
96
96
|
writeJsonEnvelope
|
|
97
|
-
} from "./chunk-
|
|
97
|
+
} from "./chunk-VVQLRFCI.js";
|
|
98
98
|
import {
|
|
99
99
|
ApiError,
|
|
100
100
|
apiGet,
|
|
101
101
|
apiGetWithHeaders,
|
|
102
102
|
apiPost,
|
|
103
103
|
validateConvexId
|
|
104
|
-
} from "./chunk-
|
|
104
|
+
} from "./chunk-MZQC4LII.js";
|
|
105
105
|
import {
|
|
106
106
|
installExitRecord,
|
|
107
107
|
installStreamTaps,
|
|
@@ -8052,7 +8052,6 @@ var testimonialDocSchema = z28.object({
|
|
|
8052
8052
|
sourceType: testimonialSourceTypeSchema,
|
|
8053
8053
|
reviewText: z28.string(),
|
|
8054
8054
|
reviewTitle: z28.string().optional(),
|
|
8055
|
-
searchText: z28.string().optional(),
|
|
8056
8055
|
reviewerName: z28.string().optional(),
|
|
8057
8056
|
reviewerImageUrl: z28.string().optional(),
|
|
8058
8057
|
reviewerImageId: z28.string().optional(),
|
|
@@ -8064,13 +8063,11 @@ var testimonialDocSchema = z28.object({
|
|
|
8064
8063
|
imageIds: z28.array(z28.string()).optional(),
|
|
8065
8064
|
videoIds: z28.array(z28.string()).optional(),
|
|
8066
8065
|
sourceUrl: z28.string().optional(),
|
|
8067
|
-
rawData: z28.unknown().optional(),
|
|
8068
8066
|
tags: z28.array(z28.string()),
|
|
8069
8067
|
highlight: z28.string().optional(),
|
|
8070
8068
|
language: z28.string().optional(),
|
|
8071
8069
|
summary: z28.string().optional(),
|
|
8072
8070
|
sentiment: testimonialSentimentSchema.optional(),
|
|
8073
|
-
textEmbedding: z28.array(z28.number()).optional(),
|
|
8074
8071
|
externalId: z28.string().optional(),
|
|
8075
8072
|
contentHash: z28.string().optional(),
|
|
8076
8073
|
status: testimonialStatusSchema,
|
|
@@ -19821,7 +19818,7 @@ function handleLinkedinError(err) {
|
|
|
19821
19818
|
explanation: explanation.message,
|
|
19822
19819
|
correctedCommand: explanation.correctedCommand
|
|
19823
19820
|
},
|
|
19824
|
-
retryable: err.code === "RATE_LIMITED" || err.code === "INTERNAL_ERROR"
|
|
19821
|
+
retryable: err.code === "RATE_LIMITED" || err.code === "UNAVAILABLE" || err.code === "INTERNAL_ERROR"
|
|
19825
19822
|
}
|
|
19826
19823
|
};
|
|
19827
19824
|
writeAdsJson(envelope);
|
|
@@ -26360,10 +26357,10 @@ Example: baker ads meta ads retag 120252158038400247 --url-tags "utm_source={{si
|
|
|
26360
26357
|
}
|
|
26361
26358
|
},
|
|
26362
26359
|
run: async ({ args: args5 }) => {
|
|
26363
|
-
const { apiPost: apiPost2 } = await import("./client-
|
|
26360
|
+
const { apiPost: apiPost2 } = await import("./client-3DGBQ2H3.js");
|
|
26364
26361
|
const { requireChatId: requireChatId2 } = await import("./env-BSG7TY5Y.js");
|
|
26365
|
-
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-
|
|
26366
|
-
const { handleMetaError: handleMetaError2 } = await import("./shared-
|
|
26362
|
+
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-OSSBUGT7.js");
|
|
26363
|
+
const { handleMetaError: handleMetaError2 } = await import("./shared-MSI4UMZ3.js");
|
|
26367
26364
|
try {
|
|
26368
26365
|
const accountId = bareAccountId2(args5);
|
|
26369
26366
|
const urlTags = typeof args5["url-tags"] === "string" ? args5["url-tags"] : void 0;
|
|
@@ -26508,10 +26505,10 @@ function duplicateCommand2(entity, label) {
|
|
|
26508
26505
|
replace: { type: "boolean", description: "Pause the original once the copy publishes" }
|
|
26509
26506
|
},
|
|
26510
26507
|
run: async ({ args: args5 }) => {
|
|
26511
|
-
const { apiPost: apiPost2 } = await import("./client-
|
|
26508
|
+
const { apiPost: apiPost2 } = await import("./client-3DGBQ2H3.js");
|
|
26512
26509
|
const { requireChatId: requireChatId2 } = await import("./env-BSG7TY5Y.js");
|
|
26513
|
-
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-
|
|
26514
|
-
const { handleMetaError: handleMetaError2 } = await import("./shared-
|
|
26510
|
+
const { writeJsonEnvelope: writeJsonEnvelope2 } = await import("./output-OSSBUGT7.js");
|
|
26511
|
+
const { handleMetaError: handleMetaError2 } = await import("./shared-MSI4UMZ3.js");
|
|
26515
26512
|
try {
|
|
26516
26513
|
const accountId = bareAccountId2(args5);
|
|
26517
26514
|
const chatId = requireChatId2();
|
|
@@ -36644,134 +36641,9 @@ var critiqueCommand = defineCommand109({
|
|
|
36644
36641
|
// src/commands/canvas/inspect.ts
|
|
36645
36642
|
import { execFile } from "child_process";
|
|
36646
36643
|
import { readdir as readdir2, readFile as readFile4, stat } from "fs/promises";
|
|
36647
|
-
import
|
|
36644
|
+
import path4 from "path";
|
|
36648
36645
|
import { promisify } from "util";
|
|
36649
36646
|
import { defineCommand as defineCommand110 } from "citty";
|
|
36650
|
-
|
|
36651
|
-
// src/commands/canvas/normalize-paths.ts
|
|
36652
|
-
import { existsSync as existsSync4, realpathSync } from "fs";
|
|
36653
|
-
import { writeFile as writeFile2 } from "fs/promises";
|
|
36654
|
-
import path5 from "path";
|
|
36655
|
-
|
|
36656
|
-
// src/commands/canvas/resolve-paths.ts
|
|
36657
|
-
import path4 from "path";
|
|
36658
|
-
function resolveRelativeCanvasPaths(canvas, baseDir) {
|
|
36659
|
-
if (!canvas || typeof canvas !== "object") return canvas;
|
|
36660
|
-
const c = canvas;
|
|
36661
|
-
if (!Array.isArray(c.nodes)) return canvas;
|
|
36662
|
-
return { ...canvas, nodes: c.nodes.map((n) => resolveNode(n, baseDir)) };
|
|
36663
|
-
}
|
|
36664
|
-
function localPathParam(node) {
|
|
36665
|
-
if (node.type === "ingest") return node.params?.source === "path" ? "path" : null;
|
|
36666
|
-
if (node.type === "hyperframe_render" || node.type === "hyperframe_snapshot") return "composition";
|
|
36667
|
-
return null;
|
|
36668
|
-
}
|
|
36669
|
-
function resolveNode(node, baseDir) {
|
|
36670
|
-
if (!node || typeof node !== "object") return node;
|
|
36671
|
-
const n = node;
|
|
36672
|
-
const params = n.params;
|
|
36673
|
-
if (!params || typeof params !== "object") return node;
|
|
36674
|
-
const key = localPathParam(n);
|
|
36675
|
-
if (key && isResolvableRelative(params[key])) {
|
|
36676
|
-
return { ...node, params: { ...params, [key]: path4.resolve(baseDir, params[key]) } };
|
|
36677
|
-
}
|
|
36678
|
-
return node;
|
|
36679
|
-
}
|
|
36680
|
-
function isResolvableRelative(value) {
|
|
36681
|
-
return typeof value === "string" && value.length > 0 && !value.includes("[TODO") && !looksLikeHttpUrl(value) && !path4.isAbsolute(value);
|
|
36682
|
-
}
|
|
36683
|
-
|
|
36684
|
-
// src/commands/canvas/normalize-paths.ts
|
|
36685
|
-
function findWorkspaceRoot(startDir, exists2 = existsSync4, maxDepth = 12) {
|
|
36686
|
-
let dir = path5.resolve(startDir);
|
|
36687
|
-
for (let i = 0; i < maxDepth; i++) {
|
|
36688
|
-
if (exists2(path5.join(dir, "package.json"))) return dir;
|
|
36689
|
-
const parent = path5.dirname(dir);
|
|
36690
|
-
if (parent === dir) break;
|
|
36691
|
-
dir = parent;
|
|
36692
|
-
}
|
|
36693
|
-
return null;
|
|
36694
|
-
}
|
|
36695
|
-
function canvasOutputsRoot(canvasFile, cwd = process.cwd(), exists2 = existsSync4) {
|
|
36696
|
-
const root = findWorkspaceRoot(path5.dirname(path5.resolve(cwd, canvasFile)), exists2) ?? cwd;
|
|
36697
|
-
return path5.join(root, "canvas");
|
|
36698
|
-
}
|
|
36699
|
-
function canonicalize(target2) {
|
|
36700
|
-
const abs = path5.resolve(target2);
|
|
36701
|
-
let dir = abs;
|
|
36702
|
-
for (; ; ) {
|
|
36703
|
-
try {
|
|
36704
|
-
const real = realpathSync(dir);
|
|
36705
|
-
return dir === abs ? real : path5.join(real, path5.relative(dir, abs));
|
|
36706
|
-
} catch {
|
|
36707
|
-
const parent = path5.dirname(dir);
|
|
36708
|
-
if (parent === dir) return abs;
|
|
36709
|
-
dir = parent;
|
|
36710
|
-
}
|
|
36711
|
-
}
|
|
36712
|
-
}
|
|
36713
|
-
function isInside(root, target2) {
|
|
36714
|
-
const rel = path5.relative(root, target2);
|
|
36715
|
-
return rel !== "" && !rel.startsWith("..") && !path5.isAbsolute(rel);
|
|
36716
|
-
}
|
|
36717
|
-
function toCanvasRelative(canvasDir, target2) {
|
|
36718
|
-
return path5.relative(canvasDir, target2).split(path5.sep).join("/");
|
|
36719
|
-
}
|
|
36720
|
-
var RUNTIME_WORKSPACE_ROOT = "/home/user/repo";
|
|
36721
|
-
function rewriteTarget(value, workspaceRoot) {
|
|
36722
|
-
if (typeof value !== "string" || value.length === 0) return null;
|
|
36723
|
-
if (value.includes("[TODO") || looksLikeHttpUrl(value) || !path5.isAbsolute(value)) return null;
|
|
36724
|
-
const target2 = canonicalize(value);
|
|
36725
|
-
if (isInside(workspaceRoot, target2)) return target2;
|
|
36726
|
-
const fromRuntime = path5.relative(RUNTIME_WORKSPACE_ROOT, path5.normalize(value));
|
|
36727
|
-
if (fromRuntime !== "" && !fromRuntime.startsWith("..") && !path5.isAbsolute(fromRuntime)) {
|
|
36728
|
-
return path5.join(workspaceRoot, fromRuntime);
|
|
36729
|
-
}
|
|
36730
|
-
return null;
|
|
36731
|
-
}
|
|
36732
|
-
function normalizeCanvasPaths(canvas, canvasDir, workspaceRoot) {
|
|
36733
|
-
if (!canvas || typeof canvas !== "object") return { canvas, rewrites: [] };
|
|
36734
|
-
const c = canvas;
|
|
36735
|
-
if (!Array.isArray(c.nodes)) return { canvas, rewrites: [] };
|
|
36736
|
-
const root = canonicalize(workspaceRoot);
|
|
36737
|
-
const dir = canonicalize(canvasDir);
|
|
36738
|
-
const rewrites = [];
|
|
36739
|
-
const nodes = c.nodes.map((node) => {
|
|
36740
|
-
if (!node || typeof node !== "object") return node;
|
|
36741
|
-
const n = node;
|
|
36742
|
-
const params = n.params;
|
|
36743
|
-
if (!params || typeof params !== "object") return node;
|
|
36744
|
-
const nodeId = typeof n.id === "string" ? n.id : "?";
|
|
36745
|
-
if (n.type === "ingest" && params.source === "path" && looksLikeHttpUrl(params.path)) {
|
|
36746
|
-
rewrites.push({ nodeId, param: "source", from: "path", to: "url" });
|
|
36747
|
-
return { ...node, params: coercePathUrlToUrl(params) };
|
|
36748
|
-
}
|
|
36749
|
-
const key = localPathParam(n);
|
|
36750
|
-
if (!key) return node;
|
|
36751
|
-
const target2 = rewriteTarget(params[key], root);
|
|
36752
|
-
if (target2 === null) return node;
|
|
36753
|
-
const to = toCanvasRelative(dir, target2);
|
|
36754
|
-
rewrites.push({ nodeId, param: key, from: params[key], to });
|
|
36755
|
-
return { ...node, params: { ...params, [key]: to } };
|
|
36756
|
-
});
|
|
36757
|
-
return rewrites.length === 0 ? { canvas, rewrites } : { canvas: { ...canvas, nodes }, rewrites };
|
|
36758
|
-
}
|
|
36759
|
-
async function healCanvasPaths(filePath, canvas) {
|
|
36760
|
-
const canvasDir = path5.dirname(filePath);
|
|
36761
|
-
const workspaceRoot = findWorkspaceRoot(canvasDir);
|
|
36762
|
-
if (!workspaceRoot) return { canvas, rewrites: [], text: null };
|
|
36763
|
-
const normalized = normalizeCanvasPaths(canvas, canvasDir, workspaceRoot);
|
|
36764
|
-
if (normalized.rewrites.length === 0) return { ...normalized, text: null };
|
|
36765
|
-
const text2 = `${JSON.stringify(normalized.canvas, null, 2)}
|
|
36766
|
-
`;
|
|
36767
|
-
await writeFile2(filePath, text2, "utf8");
|
|
36768
|
-
return { ...normalized, text: text2 };
|
|
36769
|
-
}
|
|
36770
|
-
function describeRewrites(rewrites) {
|
|
36771
|
-
return rewrites.map((r) => ` ${r.nodeId}.${r.param}: ${r.from} \u2192 ${r.to}`).join("\n");
|
|
36772
|
-
}
|
|
36773
|
-
|
|
36774
|
-
// src/commands/canvas/inspect.ts
|
|
36775
36647
|
var execFileAsync = promisify(execFile);
|
|
36776
36648
|
var inspectCommand = defineCommand110({
|
|
36777
36649
|
meta: {
|
|
@@ -36780,15 +36652,14 @@ var inspectCommand = defineCommand110({
|
|
|
36780
36652
|
},
|
|
36781
36653
|
args: {
|
|
36782
36654
|
run: { type: "positional", required: true, description: "Run id (e.g. r_01K...) or absolute run directory" },
|
|
36783
|
-
"outputs-dir": { type: "string", description: "Per-run outputs root (default
|
|
36655
|
+
"outputs-dir": { type: "string", description: "Per-run outputs root (default ./canvas)" },
|
|
36784
36656
|
thumbnails: {
|
|
36785
36657
|
type: "boolean",
|
|
36786
36658
|
description: "Extract start/middle/end frames from every video output (requires ffmpeg)"
|
|
36787
36659
|
}
|
|
36788
36660
|
},
|
|
36789
36661
|
async run({ args: args5 }) {
|
|
36790
|
-
const
|
|
36791
|
-
const outputsDir = args5["outputs-dir"] ? path6.resolve(String(args5["outputs-dir"])) : path6.join(findWorkspaceRoot(cwd) ?? cwd, "canvas");
|
|
36662
|
+
const outputsDir = path4.resolve(String(args5["outputs-dir"] ?? "canvas"));
|
|
36792
36663
|
const runArg = String(args5.run);
|
|
36793
36664
|
const runDir = await resolveRunDir(runArg, outputsDir);
|
|
36794
36665
|
const manifest = await loadManifest(runDir);
|
|
@@ -36800,7 +36671,7 @@ var inspectCommand = defineCommand110({
|
|
|
36800
36671
|
}
|
|
36801
36672
|
const summary = {
|
|
36802
36673
|
ok: true,
|
|
36803
|
-
run_id: manifest.run_id ??
|
|
36674
|
+
run_id: manifest.run_id ?? path4.basename(runDir),
|
|
36804
36675
|
run_dir: runDir,
|
|
36805
36676
|
stats: manifest.stats ?? null,
|
|
36806
36677
|
output: manifest.output ?? null,
|
|
@@ -36813,18 +36684,18 @@ var inspectCommand = defineCommand110({
|
|
|
36813
36684
|
}
|
|
36814
36685
|
});
|
|
36815
36686
|
async function resolveRunDir(run, outputsDir) {
|
|
36816
|
-
if (
|
|
36687
|
+
if (path4.isAbsolute(run)) {
|
|
36817
36688
|
const s2 = await stat(run).catch(() => null);
|
|
36818
36689
|
if (s2?.isDirectory()) return run;
|
|
36819
36690
|
throw new Error(`inspect: ${run} is not a directory`);
|
|
36820
36691
|
}
|
|
36821
|
-
const candidate =
|
|
36692
|
+
const candidate = path4.join(outputsDir, run);
|
|
36822
36693
|
const s = await stat(candidate).catch(() => null);
|
|
36823
36694
|
if (s?.isDirectory()) return candidate;
|
|
36824
36695
|
throw new Error(`inspect: no run directory at ${candidate}`);
|
|
36825
36696
|
}
|
|
36826
36697
|
async function loadManifest(runDir) {
|
|
36827
|
-
const manifestPath =
|
|
36698
|
+
const manifestPath = path4.join(runDir, "manifest.json");
|
|
36828
36699
|
try {
|
|
36829
36700
|
const raw = await readFile4(manifestPath, "utf-8");
|
|
36830
36701
|
return JSON.parse(raw);
|
|
@@ -36836,7 +36707,7 @@ async function listRunFiles(runDir) {
|
|
|
36836
36707
|
const out = [];
|
|
36837
36708
|
const names = await readdir2(runDir);
|
|
36838
36709
|
for (const name of names) {
|
|
36839
|
-
const abs =
|
|
36710
|
+
const abs = path4.join(runDir, name);
|
|
36840
36711
|
const s = await stat(abs).catch(() => null);
|
|
36841
36712
|
if (!s?.isFile()) continue;
|
|
36842
36713
|
out.push({ name, path: abs, size: s.size });
|
|
@@ -36889,6 +36760,95 @@ import { readFile as readFile12 } from "fs/promises";
|
|
|
36889
36760
|
import path16 from "path";
|
|
36890
36761
|
import { defineCommand as defineCommand111 } from "citty";
|
|
36891
36762
|
|
|
36763
|
+
// src/commands/canvas/normalize-paths.ts
|
|
36764
|
+
import { existsSync as existsSync4, realpathSync } from "fs";
|
|
36765
|
+
import { writeFile as writeFile2 } from "fs/promises";
|
|
36766
|
+
import path5 from "path";
|
|
36767
|
+
function findWorkspaceRoot(startDir, exists2 = existsSync4, maxDepth = 12) {
|
|
36768
|
+
let dir = path5.resolve(startDir);
|
|
36769
|
+
for (let i = 0; i < maxDepth; i++) {
|
|
36770
|
+
if (exists2(path5.join(dir, "package.json"))) return dir;
|
|
36771
|
+
const parent = path5.dirname(dir);
|
|
36772
|
+
if (parent === dir) break;
|
|
36773
|
+
dir = parent;
|
|
36774
|
+
}
|
|
36775
|
+
return null;
|
|
36776
|
+
}
|
|
36777
|
+
function canonicalize(target2) {
|
|
36778
|
+
const abs = path5.resolve(target2);
|
|
36779
|
+
let dir = abs;
|
|
36780
|
+
for (; ; ) {
|
|
36781
|
+
try {
|
|
36782
|
+
const real = realpathSync(dir);
|
|
36783
|
+
return dir === abs ? real : path5.join(real, path5.relative(dir, abs));
|
|
36784
|
+
} catch {
|
|
36785
|
+
const parent = path5.dirname(dir);
|
|
36786
|
+
if (parent === dir) return abs;
|
|
36787
|
+
dir = parent;
|
|
36788
|
+
}
|
|
36789
|
+
}
|
|
36790
|
+
}
|
|
36791
|
+
function isInside(root, target2) {
|
|
36792
|
+
const rel = path5.relative(root, target2);
|
|
36793
|
+
return rel !== "" && !rel.startsWith("..") && !path5.isAbsolute(rel);
|
|
36794
|
+
}
|
|
36795
|
+
function toCanvasRelative(canvasDir, target2) {
|
|
36796
|
+
return path5.relative(canvasDir, target2).split(path5.sep).join("/");
|
|
36797
|
+
}
|
|
36798
|
+
var RUNTIME_WORKSPACE_ROOT = "/home/user/repo";
|
|
36799
|
+
function rewriteTarget(value, workspaceRoot) {
|
|
36800
|
+
if (typeof value !== "string" || value.length === 0) return null;
|
|
36801
|
+
if (value.includes("[TODO") || looksLikeHttpUrl(value) || !path5.isAbsolute(value)) return null;
|
|
36802
|
+
const target2 = canonicalize(value);
|
|
36803
|
+
if (isInside(workspaceRoot, target2)) return target2;
|
|
36804
|
+
const fromRuntime = path5.relative(RUNTIME_WORKSPACE_ROOT, path5.normalize(value));
|
|
36805
|
+
if (fromRuntime !== "" && !fromRuntime.startsWith("..") && !path5.isAbsolute(fromRuntime)) {
|
|
36806
|
+
return path5.join(workspaceRoot, fromRuntime);
|
|
36807
|
+
}
|
|
36808
|
+
return null;
|
|
36809
|
+
}
|
|
36810
|
+
function normalizeCanvasPaths(canvas, canvasDir, workspaceRoot) {
|
|
36811
|
+
if (!canvas || typeof canvas !== "object") return { canvas, rewrites: [] };
|
|
36812
|
+
const c = canvas;
|
|
36813
|
+
if (!Array.isArray(c.nodes)) return { canvas, rewrites: [] };
|
|
36814
|
+
const root = canonicalize(workspaceRoot);
|
|
36815
|
+
const dir = canonicalize(canvasDir);
|
|
36816
|
+
const rewrites = [];
|
|
36817
|
+
const nodes = c.nodes.map((node) => {
|
|
36818
|
+
if (!node || typeof node !== "object") return node;
|
|
36819
|
+
const n = node;
|
|
36820
|
+
const params = n.params;
|
|
36821
|
+
if (!params || typeof params !== "object") return node;
|
|
36822
|
+
const nodeId = typeof n.id === "string" ? n.id : "?";
|
|
36823
|
+
if (n.type === "ingest" && params.source === "path" && looksLikeHttpUrl(params.path)) {
|
|
36824
|
+
rewrites.push({ nodeId, param: "source", from: "path", to: "url" });
|
|
36825
|
+
return { ...node, params: coercePathUrlToUrl(params) };
|
|
36826
|
+
}
|
|
36827
|
+
const key = n.type === "ingest" && params.source === "path" ? "path" : n.type === "hyperframe_render" ? "composition" : null;
|
|
36828
|
+
if (!key) return node;
|
|
36829
|
+
const target2 = rewriteTarget(params[key], root);
|
|
36830
|
+
if (target2 === null) return node;
|
|
36831
|
+
const to = toCanvasRelative(dir, target2);
|
|
36832
|
+
rewrites.push({ nodeId, param: key, from: params[key], to });
|
|
36833
|
+
return { ...node, params: { ...params, [key]: to } };
|
|
36834
|
+
});
|
|
36835
|
+
return rewrites.length === 0 ? { canvas, rewrites } : { canvas: { ...canvas, nodes }, rewrites };
|
|
36836
|
+
}
|
|
36837
|
+
async function healCanvasPaths(filePath, canvas) {
|
|
36838
|
+
const canvasDir = path5.dirname(filePath);
|
|
36839
|
+
const workspaceRoot = findWorkspaceRoot(canvasDir);
|
|
36840
|
+
if (!workspaceRoot) return { canvas, rewrites: [], text: null };
|
|
36841
|
+
const normalized = normalizeCanvasPaths(canvas, canvasDir, workspaceRoot);
|
|
36842
|
+
if (normalized.rewrites.length === 0) return { ...normalized, text: null };
|
|
36843
|
+
const text2 = `${JSON.stringify(normalized.canvas, null, 2)}
|
|
36844
|
+
`;
|
|
36845
|
+
await writeFile2(filePath, text2, "utf8");
|
|
36846
|
+
return { ...normalized, text: text2 };
|
|
36847
|
+
}
|
|
36848
|
+
function describeRewrites(rewrites) {
|
|
36849
|
+
return rewrites.map((r) => ` ${r.nodeId}.${r.param}: ${r.from} \u2192 ${r.to}`).join("\n");
|
|
36850
|
+
}
|
|
36851
|
+
|
|
36892
36852
|
// src/commands/canvas/placeholders.ts
|
|
36893
36853
|
function unsuppliedPlaceholderAssets(canvas) {
|
|
36894
36854
|
const nodes = canvas?.nodes;
|
|
@@ -36905,6 +36865,31 @@ function unsuppliedPlaceholderAssets(canvas) {
|
|
|
36905
36865
|
return out;
|
|
36906
36866
|
}
|
|
36907
36867
|
|
|
36868
|
+
// src/commands/canvas/resolve-paths.ts
|
|
36869
|
+
import path6 from "path";
|
|
36870
|
+
function resolveRelativeCanvasPaths(canvas, baseDir) {
|
|
36871
|
+
if (!canvas || typeof canvas !== "object") return canvas;
|
|
36872
|
+
const c = canvas;
|
|
36873
|
+
if (!Array.isArray(c.nodes)) return canvas;
|
|
36874
|
+
return { ...canvas, nodes: c.nodes.map((n) => resolveNode(n, baseDir)) };
|
|
36875
|
+
}
|
|
36876
|
+
function resolveNode(node, baseDir) {
|
|
36877
|
+
if (!node || typeof node !== "object") return node;
|
|
36878
|
+
const n = node;
|
|
36879
|
+
const params = n.params;
|
|
36880
|
+
if (!params || typeof params !== "object") return node;
|
|
36881
|
+
if (n.type === "ingest" && params.source === "path" && isResolvableRelative(params.path)) {
|
|
36882
|
+
return { ...node, params: { ...params, path: path6.resolve(baseDir, params.path) } };
|
|
36883
|
+
}
|
|
36884
|
+
if (n.type === "hyperframe_render" && isResolvableRelative(params.composition)) {
|
|
36885
|
+
return { ...node, params: { ...params, composition: path6.resolve(baseDir, params.composition) } };
|
|
36886
|
+
}
|
|
36887
|
+
return node;
|
|
36888
|
+
}
|
|
36889
|
+
function isResolvableRelative(value) {
|
|
36890
|
+
return typeof value === "string" && value.length > 0 && !value.includes("[TODO") && !looksLikeHttpUrl(value) && !path6.isAbsolute(value);
|
|
36891
|
+
}
|
|
36892
|
+
|
|
36908
36893
|
// src/commands/canvas/source-version.ts
|
|
36909
36894
|
import { readFile as readFile6 } from "fs/promises";
|
|
36910
36895
|
import path8 from "path";
|
|
@@ -41014,9 +40999,12 @@ function localPathRefsFromCanvas(parsed) {
|
|
|
41014
40999
|
const n = node;
|
|
41015
41000
|
const params = n.params;
|
|
41016
41001
|
if (!params || typeof params !== "object") continue;
|
|
41017
|
-
|
|
41018
|
-
|
|
41019
|
-
|
|
41002
|
+
if (n.type === "ingest" && params.source === "path" && isSnapshotablePath(params.path)) {
|
|
41003
|
+
refs.add(params.path);
|
|
41004
|
+
}
|
|
41005
|
+
if (n.type === "hyperframe_render" && isSnapshotablePath(params.composition)) {
|
|
41006
|
+
refs.add(params.composition);
|
|
41007
|
+
}
|
|
41020
41008
|
}
|
|
41021
41009
|
return [...refs];
|
|
41022
41010
|
}
|
|
@@ -41701,8 +41689,8 @@ var runCommand = defineCommand111({
|
|
|
41701
41689
|
type: "string",
|
|
41702
41690
|
description: "What the person asked for, IN THEIR OWN WORDS \u2014 paste their message, do not summarise it. The review compares the finished video against this and reports what they asked for that is missing or contradicted. Without it the review can only say whether the video is well made, not whether it is the one they wanted: every other check grades the render against the spec, and a spec that misread the request agrees with itself."
|
|
41703
41691
|
},
|
|
41704
|
-
"cache-dir": { type: "string", description: "Cache root (default
|
|
41705
|
-
"outputs-dir": { type: "string", description: "Per-run outputs root (default
|
|
41692
|
+
"cache-dir": { type: "string", description: "Cache root (default ./canvas/.cache)" },
|
|
41693
|
+
"outputs-dir": { type: "string", description: "Per-run outputs root (default ./canvas)" },
|
|
41706
41694
|
"run-id": { type: "string", description: "Override run id (also resumes that run, re-attaching its in-flight jobs)" },
|
|
41707
41695
|
fresh: {
|
|
41708
41696
|
type: "boolean",
|
|
@@ -41780,7 +41768,6 @@ function stopBeforeKinds(until) {
|
|
|
41780
41768
|
}
|
|
41781
41769
|
async function executeCanvasRun(opts) {
|
|
41782
41770
|
const filePath = path16.resolve(opts.file);
|
|
41783
|
-
const canvasRoot = canvasOutputsRoot(filePath);
|
|
41784
41771
|
const raw = await readFile12(filePath, "utf8");
|
|
41785
41772
|
let parsed;
|
|
41786
41773
|
try {
|
|
@@ -41792,7 +41779,7 @@ async function executeCanvasRun(opts) {
|
|
|
41792
41779
|
process.exit(2);
|
|
41793
41780
|
}
|
|
41794
41781
|
const attemptedSlug = creativeSlugFromCanvasPath(filePath);
|
|
41795
|
-
if (attemptedSlug) await clearCreativeDirty(attemptedSlug
|
|
41782
|
+
if (attemptedSlug) await clearCreativeDirty(attemptedSlug);
|
|
41796
41783
|
const healed = await healCanvasPaths(filePath, parsed);
|
|
41797
41784
|
parsed = healed.canvas;
|
|
41798
41785
|
const canvasText = healed.text ?? raw;
|
|
@@ -41888,8 +41875,8 @@ ${describeRewrites(healed.rewrites)}
|
|
|
41888
41875
|
}
|
|
41889
41876
|
}
|
|
41890
41877
|
const engine = createEngineFromEnv({
|
|
41891
|
-
cacheDir: opts.cacheDir
|
|
41892
|
-
outputsDir: opts.outputsDir
|
|
41878
|
+
cacheDir: opts.cacheDir,
|
|
41879
|
+
outputsDir: opts.outputsDir,
|
|
41893
41880
|
log: (line) => process.stdout.write(`${line}
|
|
41894
41881
|
`),
|
|
41895
41882
|
remoteCache: opts.remoteCache
|
|
@@ -41909,7 +41896,7 @@ ${describeRewrites(healed.rewrites)}
|
|
|
41909
41896
|
const canvasSha = sha256Hex(Buffer.from(canvasText));
|
|
41910
41897
|
const creativeSlug = creativeSlugFromCanvasPath(filePath) ?? void 0;
|
|
41911
41898
|
const client = opts.record === false ? null : buildBackendClient();
|
|
41912
|
-
const outputsDir = opts.outputsDir ? path16.resolve(opts.outputsDir) :
|
|
41899
|
+
const outputsDir = opts.outputsDir ? path16.resolve(opts.outputsDir) : path16.resolve("canvas");
|
|
41913
41900
|
const { runId, resumed, source, concurrentRunId } = await resolveRunId({
|
|
41914
41901
|
explicitRunId: opts.runId,
|
|
41915
41902
|
fresh: opts.fresh === true,
|
|
@@ -41943,7 +41930,7 @@ ${describeRewrites(healed.rewrites)}
|
|
|
41943
41930
|
const canvasSnapshotUrl = client && creativeSlug ? await uploadRunSnapshot(client, { canvasPath: filePath, raw: canvasText, creativeSlug, parsed }) ?? void 0 : void 0;
|
|
41944
41931
|
const recordMeta = {
|
|
41945
41932
|
creativeSlug,
|
|
41946
|
-
canvasPath: path16.relative(
|
|
41933
|
+
canvasPath: path16.relative(process.cwd(), filePath) || void 0,
|
|
41947
41934
|
canvasSha,
|
|
41948
41935
|
// The fingerprint the dashboard compares against the current source to flag
|
|
41949
41936
|
// "edited since last render". Computed from the on-disk canvas.json +
|
|
@@ -50615,7 +50602,7 @@ function loadJsonPayloads(args5) {
|
|
|
50615
50602
|
}
|
|
50616
50603
|
return parsed.map((entry, index) => asObject(entry, "json", index));
|
|
50617
50604
|
}
|
|
50618
|
-
var RETRYABLE_CODES = /* @__PURE__ */ new Set(["RATE_LIMITED", "INTERNAL_ERROR", "NETWORK_ERROR", "TIMEOUT"]);
|
|
50605
|
+
var RETRYABLE_CODES = /* @__PURE__ */ new Set(["RATE_LIMITED", "UNAVAILABLE", "INTERNAL_ERROR", "NETWORK_ERROR", "TIMEOUT"]);
|
|
50619
50606
|
function handleError5(err) {
|
|
50620
50607
|
if (err instanceof ApiError) {
|
|
50621
50608
|
const readOnly = err.code === "FORBIDDEN" && /read the property but not change it/i.test(err.message);
|
|
@@ -53867,6 +53854,22 @@ function parseAutoIngest(raw, max) {
|
|
|
53867
53854
|
return { ok: true, value };
|
|
53868
53855
|
}
|
|
53869
53856
|
|
|
53857
|
+
// src/commands/images/extractErrors.ts
|
|
53858
|
+
var RETRYABLE = /* @__PURE__ */ new Set(["UNAVAILABLE", "RATE_LIMITED", "TIMEOUT", "NETWORK_ERROR"]);
|
|
53859
|
+
function extractErrorEnvelope(err, url) {
|
|
53860
|
+
const retryable = RETRYABLE.has(err.code);
|
|
53861
|
+
const fallback = `use \`baker images screenshot ${url}\` to capture the page as one image, or \`baker images logo <domain>\` for the brand's mark, and carry on with the rest of the job.`;
|
|
53862
|
+
return {
|
|
53863
|
+
ok: false,
|
|
53864
|
+
error: {
|
|
53865
|
+
code: err.code,
|
|
53866
|
+
message: err.message,
|
|
53867
|
+
retryable,
|
|
53868
|
+
fix: retryable ? { action: "retry_once", explanation: `Run the same command once more. If it fails again, ${fallback}` } : { action: "use_fallback", explanation: `Retrying the same address will fail the same way \u2014 ${fallback}` }
|
|
53869
|
+
}
|
|
53870
|
+
};
|
|
53871
|
+
}
|
|
53872
|
+
|
|
53870
53873
|
// src/commands/images/extract.ts
|
|
53871
53874
|
registerSchema({
|
|
53872
53875
|
command: "images.extract",
|
|
@@ -53933,7 +53936,7 @@ var extractCommand = defineCommand149({
|
|
|
53933
53936
|
writeJson({ ok: true, data });
|
|
53934
53937
|
} catch (err) {
|
|
53935
53938
|
if (err instanceof ApiError) {
|
|
53936
|
-
writeJson(
|
|
53939
|
+
writeJson(extractErrorEnvelope(err, String(args5.url)));
|
|
53937
53940
|
process.exit(1);
|
|
53938
53941
|
}
|
|
53939
53942
|
writeJson({ ok: false, error: { code: "INTERNAL_ERROR", message: "Unexpected error" } });
|
|
@@ -65674,7 +65677,7 @@ function loadJsonArg2(args5, flag = "json") {
|
|
|
65674
65677
|
return failValidation5(`--${flag} is not valid JSON`);
|
|
65675
65678
|
}
|
|
65676
65679
|
}
|
|
65677
|
-
var RETRYABLE_CODES2 = /* @__PURE__ */ new Set(["RATE_LIMITED", "INTERNAL_ERROR", "NETWORK_ERROR", "TIMEOUT"]);
|
|
65680
|
+
var RETRYABLE_CODES2 = /* @__PURE__ */ new Set(["RATE_LIMITED", "UNAVAILABLE", "INTERNAL_ERROR", "NETWORK_ERROR", "TIMEOUT"]);
|
|
65678
65681
|
function handleError8(err) {
|
|
65679
65682
|
if (err instanceof ApiError) {
|
|
65680
65683
|
writeJsonEnvelope({
|