@koda-sl/baker-cli 0.231.0 → 0.232.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 CHANGED
@@ -2198,6 +2198,8 @@ baker images ingest https://img.freepik.com/free-photo/xyz.jpg --source magnific
2198
2198
  baker images ingest https://acme.com/hero.png --source firecrawl --external-url https://acme.com/pricing --context "competitor pricing hero"
2199
2199
  ```
2200
2200
 
2201
+ `--source` is a closed set, validated before the request so a wrong value costs nothing: `uploaded`, `website`, `google_testimonial`, `trustpilot_testimonial`, `instagram`, `magnific`, `brandfetch`, `google_images`, `firecrawl`, `screenshotone`, `iconify`, `giphy`, `pinterest`, `ai_generated`, `layer_edit`. Use `website` for an asset pulled off a company's own site.
2202
+
2201
2203
  Returns `{ imageId, deduped, contentHash }`. When `deduped: true`, an existing library row is returned — no new bytes are stored. Max ingest size 25MB.
2202
2204
 
2203
2205
  **Flags:**
@@ -2404,8 +2406,11 @@ Width, height, aspect ratio, and format — read from the image header without f
2404
2406
  ```bash
2405
2407
  baker images dimensions ./logo.png
2406
2408
  baker images dimensions https://acme.com/hero.png
2409
+ baker images dimensions ./logo.png --output md --fields width,height
2407
2410
  ```
2408
2411
 
2412
+ Takes `--output json|md` and `--fields <a,b>` like the other image reads. As everywhere else in the CLI, `--fields` projects only the `md` and `files` formats — the default `json` output always returns the whole envelope.
2413
+
2409
2414
  Response:
2410
2415
 
2411
2416
  ```json
@@ -2980,6 +2985,7 @@ baker actions list # default: bucketed (claimable, myCla
2980
2985
  # then most recent. The `blocked` bucket is ordered closest-to-ready first.
2981
2986
  baker actions list --bucketed=false --status pending
2982
2987
  baker actions list --bucketed=false --sort priority # flat list, do-first order (default); use --sort recent for newest-first
2988
+ baker actions list --output md # id-first Markdown; works for both the bucketed and flat shapes
2983
2989
  # With BAKER_CHAT_ID, the bucketed list folds in THIS chat's draft: staged creates appear in
2984
2990
  # `draftCreates`; published actions being completed/discarded/updated carry a `draftStatus` marker.
2985
2991
  # Only the caller's own chat draft is reflected — never another chat's staged work.
package/dist/cli.js CHANGED
@@ -7114,7 +7114,8 @@ registerSchema({
7114
7114
  type: "string",
7115
7115
  description: `How many Tasks a flat list reads, newest first (only with --bucketed=false). Default: ${ACTIONS_LIST_DEFAULT_LIMIT}. When the read comes back full, hints[] says so \u2014 raise --limit to reach older Tasks.`,
7116
7116
  required: false
7117
- }
7117
+ },
7118
+ output: { type: "string", description: "Output format: json|md. Default: json", required: false }
7118
7119
  }
7119
7120
  });
7120
7121
  var listCommand2 = defineCommand8({
@@ -7126,33 +7127,102 @@ var listCommand2 = defineCommand8({
7126
7127
  bucketed: { type: "boolean", description: "Pre-bucket by chat", required: false, default: true },
7127
7128
  status: { type: "string", description: "Status filter (raw mode)", required: false },
7128
7129
  sort: { type: "string", description: "Order (raw mode): priority|recent", required: false },
7129
- limit: { type: "string", description: "How many Tasks to read (raw mode)", required: false }
7130
+ limit: { type: "string", description: "How many Tasks to read (raw mode)", required: false },
7131
+ output: { type: "string", description: "Output format: json|md", required: false }
7130
7132
  },
7131
7133
  run: async ({ args }) => {
7132
7134
  try {
7133
- const env = getEnv();
7134
7135
  const bucketed = args.bucketed !== false;
7135
- const body = { bucketed };
7136
- if (bucketed && env.BAKER_CHAT_ID) {
7137
- body.chatId = env.BAKER_CHAT_ID;
7138
- }
7139
7136
  const parsedLimit = args.limit === void 0 ? Number.NaN : Number.parseInt(String(args.limit), 10);
7140
7137
  const limit = Number.isFinite(parsedLimit) && parsedLimit > 0 ? parsedLimit : ACTIONS_LIST_DEFAULT_LIMIT;
7141
- if (!bucketed) {
7142
- if (args.status) {
7143
- body.status = args.status;
7144
- }
7145
- body.sort = args.sort === "recent" ? "recent" : "priority";
7146
- body.limit = limit;
7147
- }
7138
+ const body = buildRequestBody(args, bucketed, limit);
7148
7139
  const response = await apiPost("/api/actions/list", body);
7149
7140
  const hints = !bucketed && response.ok && Array.isArray(response.data) ? buildListHints({ returned: response.data.length, limit }) : [];
7150
- writeJson(hints.length > 0 ? { ...response, hints } : response);
7141
+ const envelope = hints.length > 0 ? { ...response, hints } : response;
7142
+ if (args.output === "md" && envelope.ok) {
7143
+ process.stdout.write(renderMarkdown(envelope.data, hints));
7144
+ return;
7145
+ }
7146
+ writeJson(envelope);
7151
7147
  } catch (err) {
7152
7148
  failApi(err);
7153
7149
  }
7154
7150
  }
7155
7151
  });
7152
+ function buildRequestBody(args, bucketed, limit) {
7153
+ const env = getEnv();
7154
+ const body = { bucketed };
7155
+ if (bucketed) {
7156
+ if (env.BAKER_CHAT_ID) {
7157
+ body.chatId = env.BAKER_CHAT_ID;
7158
+ }
7159
+ return body;
7160
+ }
7161
+ if (args.status) {
7162
+ body.status = args.status;
7163
+ }
7164
+ body.sort = args.sort === "recent" ? "recent" : "priority";
7165
+ body.limit = limit;
7166
+ return body;
7167
+ }
7168
+ function toRow(entry) {
7169
+ const nested = entry.action;
7170
+ const doc = nested && typeof nested === "object" ? nested : entry;
7171
+ const id = doc.id ?? doc._id ?? entry.id ?? entry._id ?? entry.tempId ?? "?";
7172
+ const status = doc.status ?? entry.status ?? entry.draftStatus ?? "";
7173
+ let hint = typeof entry.hint === "string" ? entry.hint.trim() : "";
7174
+ if (!hint && entry.isBlocked === true) {
7175
+ const open = typeof entry.openBlockerCount === "number" ? entry.openBlockerCount : null;
7176
+ hint = open === null ? "blocked" : `blocked by ${open} open Task${open === 1 ? "" : "s"}`;
7177
+ }
7178
+ return {
7179
+ id: String(id),
7180
+ name: String(doc.name ?? entry.name ?? "(unnamed)"),
7181
+ status: String(status),
7182
+ hint
7183
+ };
7184
+ }
7185
+ function renderEntry(entry) {
7186
+ const row = toRow(entry);
7187
+ const suffix = row.status ? ` [${row.status}]` : "";
7188
+ const lines = [`- \`${row.id}\` ${row.name}${suffix}`];
7189
+ if (row.hint) {
7190
+ lines.push(` ${row.hint}`);
7191
+ }
7192
+ return lines;
7193
+ }
7194
+ function renderBuckets(data) {
7195
+ const lines = [];
7196
+ for (const [bucket, entries] of Object.entries(data)) {
7197
+ if (!Array.isArray(entries) || entries.length === 0) {
7198
+ continue;
7199
+ }
7200
+ lines.push(`## ${bucket} (${entries.length})`);
7201
+ for (const entry of entries) {
7202
+ lines.push(...renderEntry(entry));
7203
+ }
7204
+ lines.push("");
7205
+ }
7206
+ return lines;
7207
+ }
7208
+ function renderMarkdown(data, hints) {
7209
+ let lines;
7210
+ if (Array.isArray(data)) {
7211
+ lines = data.flatMap((entry) => renderEntry(entry));
7212
+ } else if (data && typeof data === "object") {
7213
+ lines = renderBuckets(data);
7214
+ } else {
7215
+ lines = [];
7216
+ }
7217
+ if (lines.length === 0) {
7218
+ return "No Tasks matched.\n";
7219
+ }
7220
+ for (const hint of hints) {
7221
+ lines.push(`> ${hint}`);
7222
+ }
7223
+ return `${lines.join("\n").trimEnd()}
7224
+ `;
7225
+ }
7156
7226
 
7157
7227
  // src/commands/actions/log.ts
7158
7228
  import { defineCommand as defineCommand9 } from "citty";
@@ -14278,7 +14348,7 @@ function sortFindings(findings) {
14278
14348
  return SEVERITY_RANK[a.severity] - SEVERITY_RANK[b.severity];
14279
14349
  });
14280
14350
  }
14281
- function renderMarkdown(result) {
14351
+ function renderMarkdown2(result) {
14282
14352
  const lines = [];
14283
14353
  lines.push(`# LinkedIn Ads Audit \u2014 ${result.account.name} (${result.account.id})`);
14284
14354
  lines.push("");
@@ -14363,7 +14433,7 @@ Examples:
14363
14433
  const result = { ...data, findings: sorted };
14364
14434
  const fmt = args.format ?? "json";
14365
14435
  if (fmt === "md") {
14366
- process.stdout.write(`${renderMarkdown(result)}
14436
+ process.stdout.write(`${renderMarkdown2(result)}
14367
14437
  `);
14368
14438
  return;
14369
14439
  }
@@ -32200,7 +32270,7 @@ function outputRows(rows, args, response, cached) {
32200
32270
  }
32201
32271
  writeJsonEnvelope({ ...response, ...cached && { cached: true } });
32202
32272
  }
32203
- function buildRequestBody(args, propertyId, useCache) {
32273
+ function buildRequestBody2(args, propertyId, useCache) {
32204
32274
  const body = { propertyId };
32205
32275
  if (args.preset) body.preset = args.preset;
32206
32276
  if (args.dimensions) body.dimensions = args.dimensions.split(",").map((d) => d.trim());
@@ -32275,7 +32345,7 @@ Free-form (escape hatch):
32275
32345
  }
32276
32346
  const propertyId = await resolvePropertyId(args);
32277
32347
  const useCache = !args["no-cache"];
32278
- const body = buildRequestBody(args, propertyId, useCache);
32348
+ const body = buildRequestBody2(args, propertyId, useCache);
32279
32349
  const cacheKey = buildQueryCacheKey(propertyId, JSON.stringify(body));
32280
32350
  if (useCache) {
32281
32351
  const cached = cacheGet("ga4-queries", cacheKey);
@@ -32871,7 +32941,7 @@ function outputRows2(rows, args, response, cached) {
32871
32941
  }
32872
32942
  writeJsonEnvelope({ ...response, ...cached && { cached: true } });
32873
32943
  }
32874
- function buildRequestBody2(args, siteUrl, useCache) {
32944
+ function buildRequestBody3(args, siteUrl, useCache) {
32875
32945
  const body = { siteUrl };
32876
32946
  if (args.preset) body.preset = args.preset;
32877
32947
  if (args.brand) body.brand = args.brand;
@@ -32955,7 +33025,7 @@ Free-form (escape hatch):
32955
33025
  }
32956
33026
  const siteUrl = await resolveSiteUrl(args);
32957
33027
  const useCache = !args["no-cache"];
32958
- const body = buildRequestBody2(args, siteUrl, useCache);
33028
+ const body = buildRequestBody3(args, siteUrl, useCache);
32959
33029
  const cacheKey = buildQueryCacheKey(siteUrl, JSON.stringify(body));
32960
33030
  if (useCache) {
32961
33031
  const cached = cacheGet("gsc-queries", cacheKey);
@@ -34121,7 +34191,13 @@ registerSchema({
34121
34191
  command: "images.dimensions",
34122
34192
  description: "Return width, height, aspect ratio, and format for a local file or remote URL.",
34123
34193
  args: {
34124
- target: { type: "string", description: "Local file path or remote http(s) URL", required: true }
34194
+ target: { type: "string", description: "Local file path or remote http(s) URL", required: true },
34195
+ output: { type: "string", description: "Output format: json|md. Default: json", required: false },
34196
+ fields: {
34197
+ type: "string",
34198
+ description: "Comma-separated field names to include (e.g. width,height)",
34199
+ required: false
34200
+ }
34125
34201
  }
34126
34202
  });
34127
34203
  var dimensionsCommand = defineCommand130({
@@ -34130,7 +34206,13 @@ var dimensionsCommand = defineCommand130({
34130
34206
  description: "Read image dimensions without decoding the full file.\n\nExample: baker images dimensions ./logo.png\nExample: baker images dimensions https://acme.com/hero.png"
34131
34207
  },
34132
34208
  args: {
34133
- target: { type: "positional", description: "Local file path or remote http(s) URL", required: false }
34209
+ target: { type: "positional", description: "Local file path or remote http(s) URL", required: false },
34210
+ output: { type: "string", description: "Output format: json|md", required: false },
34211
+ // --fields is the flag an agent reaches for when it wants two numbers out of
34212
+ // six. It used to be accepted silently and ignored (citty drops unknown
34213
+ // flags), so the caller assumed the projection had failed and fell back to
34214
+ // regexing raw JSON. Accepting it is cheaper than explaining it.
34215
+ fields: { type: "string", description: "Comma-separated field names to include", required: false }
34134
34216
  },
34135
34217
  run: async ({ args }) => {
34136
34218
  try {
@@ -34148,17 +34230,23 @@ var dimensionsCommand = defineCommand130({
34148
34230
  });
34149
34231
  process.exit(1);
34150
34232
  }
34151
- writeJson({
34152
- ok: true,
34153
- data: {
34154
- target,
34155
- source: isRemoteUrl(target) ? "url" : "file",
34156
- width: dims.width,
34157
- height: dims.height,
34158
- aspectRatio: Math.round(dims.aspectRatio * 1e4) / 1e4,
34159
- format: dims.format
34160
- }
34161
- });
34233
+ writeOutput(
34234
+ {
34235
+ ok: true,
34236
+ data: {
34237
+ target,
34238
+ source: isRemoteUrl(target) ? "url" : "file",
34239
+ width: dims.width,
34240
+ height: dims.height,
34241
+ aspectRatio: Math.round(dims.aspectRatio * 1e4) / 1e4,
34242
+ format: dims.format
34243
+ }
34244
+ },
34245
+ args.output || "json",
34246
+ args.fields ? args.fields.split(",") : void 0,
34247
+ false,
34248
+ (record) => record
34249
+ );
34162
34250
  } catch (err) {
34163
34251
  const message = err instanceof Error ? err.message : "Unexpected error";
34164
34252
  writeJson({ ok: false, error: { code: "IMAGE_PROCESSING_ERROR", message } });
@@ -35216,12 +35304,13 @@ var iconCommand = defineCommand138({
35216
35304
 
35217
35305
  // src/commands/images/ingest.ts
35218
35306
  import { defineCommand as defineCommand139 } from "citty";
35307
+ var SOURCE_VALUES = imageSourceSchema.options.join(" | ");
35219
35308
  registerSchema({
35220
35309
  command: "images.ingest",
35221
35310
  description: "Ingest a remote image URL into the library (full describe + embed).",
35222
35311
  args: {
35223
35312
  url: { type: "string", description: "Image URL to ingest", required: true },
35224
- source: { type: "string", description: "Image source enum", required: true },
35313
+ source: { type: "string", description: `Where the image came from. One of: ${SOURCE_VALUES}`, required: true },
35225
35314
  "external-id": { type: "string", description: "Provider asset id", required: false },
35226
35315
  "external-url": { type: "string", description: "Canonical page URL", required: false },
35227
35316
  context: { type: "string", description: "Description context hint", required: false },
@@ -35236,7 +35325,7 @@ var ingestCommand = defineCommand139({
35236
35325
  },
35237
35326
  args: {
35238
35327
  url: { type: "positional", description: "Image URL", required: false },
35239
- source: { type: "string", description: "Source enum", required: false },
35328
+ source: { type: "string", description: `Where the image came from. One of: ${SOURCE_VALUES}`, required: false },
35240
35329
  "external-id": { type: "string", description: "Provider asset id", required: false },
35241
35330
  "external-url": { type: "string", description: "Canonical page URL", required: false },
35242
35331
  context: { type: "string", description: "Description context", required: false },
@@ -35252,10 +35341,29 @@ var ingestCommand = defineCommand139({
35252
35341
  process.exit(1);
35253
35342
  }
35254
35343
  if (!source) {
35255
- writeJson({ ok: false, error: { code: "VALIDATION_ERROR", message: "--source is required" } });
35344
+ writeJson({
35345
+ ok: false,
35346
+ error: {
35347
+ code: "VALIDATION_ERROR",
35348
+ message: "--source is required",
35349
+ fix: `Pass one of: ${SOURCE_VALUES}. Use "website" for an asset pulled off a company's own site.`
35350
+ }
35351
+ });
35352
+ process.exit(1);
35353
+ }
35354
+ const parsedSource = imageSourceSchema.safeParse(source);
35355
+ if (!parsedSource.success) {
35356
+ writeJson({
35357
+ ok: false,
35358
+ error: {
35359
+ code: "VALIDATION_ERROR",
35360
+ message: `--source "${source}" is not a known image source`,
35361
+ fix: `Pass one of: ${SOURCE_VALUES}. Use "website" for an asset pulled off a company's own site.`
35362
+ }
35363
+ });
35256
35364
  process.exit(1);
35257
35365
  }
35258
- const body = { url, source };
35366
+ const body = { url, source: parsedSource.data };
35259
35367
  if (args["external-id"]) body.externalId = args["external-id"];
35260
35368
  if (args["external-url"]) body.externalUrl = args["external-url"];
35261
35369
  if (args.context) body.descriptionContext = args.context;