@koda-sl/baker-cli 0.361.0-dev.abddfd7be → 0.361.0-dev.d766dc120

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
@@ -110,6 +110,18 @@ question — and nothing in the output said so. Both spellings of an option work
110
110
  that lists every option: `baker schema <command>` (`check_schema`) when the command
111
111
  registers a schema, `baker <command> --help` (`check_help`) when it does not.
112
112
 
113
+ ### Narrowing a result: `--fields`
114
+
115
+ `--fields a,b,c` works on every command that prints the JSON envelope. It keeps only
116
+ those keys of each record in `data` — the rows when `data` is a list or wraps one
117
+ (`baker chats list --fields id,title`), `data` itself when it is a single record
118
+ (`baker experiment plan ... --fields traffic,warning`). `meta`, `hints` and warnings are
119
+ kept, and a name no record carries is reported in `hints` alongside the keys that do
120
+ exist. Commands that declare `--fields` themselves keep their own meaning
121
+ (`ads meta insights` chooses which metrics to request; `ads linkedin creatives` takes dotted
122
+ paths). A command whose default output is text needs `--output json` for there to be an
123
+ envelope to narrow; without it a note on stderr says the flag changed nothing.
124
+
113
125
  ### Fresh reads: `--no-cache`
114
126
 
115
127
  Every command that caches takes `--no-cache`, and it skips **both** cache layers — the
@@ -3567,6 +3579,7 @@ See everything a chat can reach — managed integrations, custom servers, and co
3567
3579
  baker mcp connected
3568
3580
  baker mcp list
3569
3581
  baker mcp add --name weather --url https://mcp.example.com/mcp
3582
+ baker mcp add --name acme --url https://acme.dev/mcp --header "Authorization: Bearer sk-…"
3570
3583
  baker mcp add --name mine --url https://my.dev/mcp --scope user
3571
3584
  baker mcp remove --name weather
3572
3585
  ```
@@ -3578,7 +3591,7 @@ baker mcp remove --name weather
3578
3591
  - `--scope org` — everyone across the org; needs an admin API key.
3579
3592
  - `--scope user` — only you, in this company; binds to the current message sender (requires a chat turn — the bridge supplies the sender via `BAKER_ACTING_USER_ID`).
3580
3593
  - `--scope user_org` — only you, across every company in the org; also binds to the sender (no admin needed — it only affects your own turns).
3581
- - Repeat `--header "Key: Value"` for extra request headers. Never pass a key, token or password with it, and never ask the user for one in chat: a server that needs a key is added by the user in the dashboard (Brain → Integrations → MCPs → Add custom server), where the model never sees it. Header values are stored server-side and ride the MCP transport — `list` returns only the header keys, never the values.
3594
+ - Repeat `--header "Key: Value"` for multiple auth headers. Header values are stored server-side and ride the MCP transport — `list` returns only the header keys, never the values.
3582
3595
 
3583
3596
  ---
3584
3597
 
package/dist/cli.js CHANGED
@@ -42841,12 +42841,12 @@ function fail3(code, message) {
42841
42841
  process.exit(2);
42842
42842
  }
42843
42843
  function resolveModels(args5) {
42844
- const pick = (flag, kind, fallback) => args5[flag] ? String(args5[flag]) : resolveModel(kind, fallback);
42844
+ const pick2 = (flag, kind, fallback) => args5[flag] ? String(args5[flag]) : resolveModel(kind, fallback);
42845
42845
  return {
42846
- describeModel: pick("describe-model", "image_describe", "~google/gemini-pro-latest"),
42847
- selectModel: pick("select-model", "text_generate", "~google/gemini-flash-latest"),
42848
- layoutModel: pick("layout-model", "text_generate", "~google/gemini-flash-latest"),
42849
- genModel: pick("gen-model", "image_generate", "openai/gpt-image-2")
42846
+ describeModel: pick2("describe-model", "image_describe", "~google/gemini-pro-latest"),
42847
+ selectModel: pick2("select-model", "text_generate", "~google/gemini-flash-latest"),
42848
+ layoutModel: pick2("layout-model", "text_generate", "~google/gemini-flash-latest"),
42849
+ genModel: pick2("gen-model", "image_generate", "openai/gpt-image-2")
42850
42850
  };
42851
42851
  }
42852
42852
  var PLATFORM_PLACEMENTS = {
@@ -44866,18 +44866,18 @@ function parseBudget(raw) {
44866
44866
  throw new Error(`--budget must be one of ${VIDEO_BUDGETS.join(", ")} (got "${v}")`);
44867
44867
  }
44868
44868
  function resolveModels2(args5) {
44869
- const pick = (flag, kind, fallback) => args5[flag] ? String(args5[flag]) : resolveModel2(kind, fallback);
44869
+ const pick2 = (flag, kind, fallback) => args5[flag] ? String(args5[flag]) : resolveModel2(kind, fallback);
44870
44870
  return {
44871
44871
  // Flash by default: ~2-3× faster per call than Pro, which keeps each
44872
44872
  // per-scene deconstruct step well inside the action time budget and turns a
44873
44873
  // ~9 min run into ~3-4 min. Override with --deconstruct-model
44874
44874
  // ~google/gemini-pro-latest for the densest extraction when speed matters less.
44875
- deconstructModel: pick("deconstruct-model", "video_deconstruct", "~google/gemini-flash-latest"),
44876
- selectModel: pick("select-model", "text_generate", "~google/gemini-flash-latest"),
44875
+ deconstructModel: pick2("deconstruct-model", "video_deconstruct", "~google/gemini-flash-latest"),
44876
+ selectModel: pick2("select-model", "text_generate", "~google/gemini-flash-latest"),
44877
44877
  // Default to the strongest image model (matches the static-ad scaffold); the
44878
44878
  // frame generators need the most faithful text/identity reproduction. Override
44879
44879
  // with --image-model for a cheaper/faster pass.
44880
- imageModel: pick("image-model", "image_generate", "openai/gpt-image-2.5-sunburst")
44880
+ imageModel: pick2("image-model", "image_generate", "openai/gpt-image-2.5-sunburst")
44881
44881
  };
44882
44882
  }
44883
44883
  function hasPhotorealCast(elements) {
@@ -61796,7 +61796,7 @@ A tool or platform the user names that is NOT listed anywhere here is simply not
61796
61796
  );
61797
61797
  }
61798
61798
  hints2.push(
61799
- 'Not listed anywhere = not connected. Ask for it in the chat with the `request_connection` tool: { app: "Google Sheets", reason } for an app (Slack, Attio, Gmail, \u2026), { platform, reason } for a platform (HubSpot, Google Ads, GA4, \u2026), { server, url?, headerName?, reason } for a custom tool server \u2014 the user connects it on the card, key included. Never send them to the dashboard, and never ask for a key in chat.'
61799
+ "Not listed anywhere = not connected. Managed app (Slack, Attio, \u2026) or platform (HubSpot, Google Ads, GA4, \u2026) \u2192 the user connects it in the dashboard: Brain \u2192 Integrations \u2192 Tools. Custom HTTPS MCP endpoint \u2192 `baker mcp add`."
61800
61800
  );
61801
61801
  writeJson({
61802
61802
  ok: true,
@@ -61836,10 +61836,9 @@ var listCommand16 = defineCommand183({
61836
61836
  }
61837
61837
  }
61838
61838
  });
61839
- var HEADER_DESCRIPTION = 'Extra request header "Key: Value" (repeatable). Never a key, token or password: never ask the user for one in chat \u2014 a server that needs a key is added by the user on the `request_connection` card ({ server, url, headerName, reason }).';
61840
61839
  registerSchema({
61841
61840
  command: "mcp.add",
61842
- description: "Register a custom MCP server. To connect one FOR the user, call the `request_connection` tool with { server, url?, headerName?, reason } instead \u2014 they add it on the card, key included. Tools appear as mcp__<name>__* on the next message. URL must be HTTPS. Scope: company (default, all chats) | org (org admin key) | user (only the current sender).",
61841
+ description: "Register a custom MCP server. Tools appear as mcp__<name>__* on the next message. URL must be HTTPS. Scope: company (default, all chats) | org (org admin key) | user (only the current sender).",
61843
61842
  args: {
61844
61843
  name: { type: "string", description: "Server name \u2192 tools appear as mcp__<name>__*", required: true },
61845
61844
  url: {
@@ -61848,7 +61847,7 @@ registerSchema({
61848
61847
  required: true
61849
61848
  },
61850
61849
  scope: { type: "string", description: "user | user_org | company | org (default company)", required: false },
61851
- header: { type: "string", description: HEADER_DESCRIPTION, required: false }
61850
+ header: { type: "string", description: 'Auth header "Key: Value" (repeatable)', required: false }
61852
61851
  }
61853
61852
  });
61854
61853
  var addCommand2 = defineCommand183({
@@ -61856,13 +61855,11 @@ var addCommand2 = defineCommand183({
61856
61855
  name: "add",
61857
61856
  description: `Register a custom MCP server. Tools appear as mcp__<name>__* on the NEXT message.
61858
61857
 
61859
- To connect a server FOR the user, call the \`request_connection\` tool with { server, url?, headerName?, reason }
61860
- instead: they add it on the card in the chat, key included, and you never see the key.
61861
-
61862
61858
  Scope: company (default \u2014 every chat in the company) | org (all companies in the org; needs an admin key) | user (only the current message sender).
61863
61859
 
61864
61860
  Examples:
61865
61861
  baker mcp add --name weather --url https://mcp.example.com/mcp
61862
+ baker mcp add --name acme --url https://acme.dev/mcp --header "Authorization: Bearer sk-\u2026"
61866
61863
  baker mcp add --name mine --url https://my.dev/mcp --scope user`
61867
61864
  },
61868
61865
  args: {
@@ -61873,7 +61870,7 @@ Examples:
61873
61870
  required: true
61874
61871
  },
61875
61872
  scope: { type: "string", description: "user | user_org | company | org (default company)", required: false },
61876
- header: { type: "string", description: HEADER_DESCRIPTION, required: false }
61873
+ header: { type: "string", description: 'Auth header "Key: Value" (repeatable)', required: false }
61877
61874
  },
61878
61875
  run: async ({ args: args5, rawArgs }) => {
61879
61876
  try {
@@ -61940,6 +61937,7 @@ Start here:
61940
61937
 
61941
61938
  Examples:
61942
61939
  baker mcp add --name weather --url https://mcp.example.com/mcp
61940
+ baker mcp add --name acme --url https://acme.dev/mcp --header "Authorization: Bearer sk-\u2026"
61943
61941
  baker mcp remove --name weather
61944
61942
  Full guide: __tooling__/docs/tools/baker/mcp.md`
61945
61943
  },
@@ -69067,6 +69065,134 @@ function outputFlagForCommand(root, argv) {
69067
69065
  });
69068
69066
  }
69069
69067
 
69068
+ // src/field-mask.ts
69069
+ var FLAG2 = "--fields";
69070
+ function parseFields(value) {
69071
+ return value.split(",").map((field) => field.trim()).filter((field) => field.length > 0);
69072
+ }
69073
+ function takeFieldsFlag(root, argv) {
69074
+ const end = argv.indexOf("--");
69075
+ const limit = end === -1 ? argv.length : end;
69076
+ const taken = /* @__PURE__ */ new Set();
69077
+ const fields = [];
69078
+ for (let index = 0; index < limit; index++) {
69079
+ const token = argv[index] ?? "";
69080
+ if (token.startsWith(`${FLAG2}=`)) {
69081
+ taken.add(index);
69082
+ fields.push(...parseFields(token.slice(FLAG2.length + 1)));
69083
+ } else if (token === FLAG2) {
69084
+ const value = argv[index + 1];
69085
+ if (value === void 0 || index + 1 >= limit || value.startsWith("-")) {
69086
+ return { argv, fields: null };
69087
+ }
69088
+ taken.add(index).add(index + 1);
69089
+ fields.push(...parseFields(value));
69090
+ index++;
69091
+ }
69092
+ }
69093
+ if (taken.size === 0 || fields.length === 0) {
69094
+ return { argv, fields: null };
69095
+ }
69096
+ const command = commandFor(root, argv);
69097
+ if (!command || declaredArg(command, "fields") || PRINTS_NO_ENVELOPE.has(commandPathOf(root, argv))) {
69098
+ return { argv, fields: null };
69099
+ }
69100
+ return { argv: argv.filter((_, index) => !taken.has(index)), fields };
69101
+ }
69102
+ function isRecord3(value) {
69103
+ return typeof value === "object" && value !== null && !Array.isArray(value);
69104
+ }
69105
+ function pick(record, fields) {
69106
+ return Object.fromEntries(fields.filter((field) => field in record).map((field) => [field, record[field]]));
69107
+ }
69108
+ function wrappedList(data, fields) {
69109
+ if (fields.some((field) => field in data)) {
69110
+ return null;
69111
+ }
69112
+ const lists = Object.entries(data).filter(
69113
+ ([, value]) => Array.isArray(value) && value.every((item) => isRecord3(item))
69114
+ );
69115
+ return lists.length === 1 ? lists[0]?.[0] ?? null : null;
69116
+ }
69117
+ function recordsOf(data, fields) {
69118
+ if (Array.isArray(data)) {
69119
+ return data;
69120
+ }
69121
+ if (!isRecord3(data)) {
69122
+ return [];
69123
+ }
69124
+ const list = wrappedList(data, fields);
69125
+ return list === null ? [data] : data[list];
69126
+ }
69127
+ function maskData(data, fields) {
69128
+ const mask = (item) => isRecord3(item) ? pick(item, fields) : item;
69129
+ if (Array.isArray(data)) {
69130
+ return data.map(mask);
69131
+ }
69132
+ if (!isRecord3(data)) {
69133
+ return data;
69134
+ }
69135
+ const list = wrappedList(data, fields);
69136
+ return list === null ? pick(data, fields) : { ...data, [list]: recordsOf(data, fields).map(mask) };
69137
+ }
69138
+ function unmatchedHint(data, fields) {
69139
+ const records = recordsOf(data, fields).filter(isRecord3);
69140
+ if (records.length === 0) {
69141
+ return null;
69142
+ }
69143
+ const carried = new Set(records.flatMap((record) => Object.keys(record)));
69144
+ const unmatched = fields.filter((field) => !carried.has(field));
69145
+ if (unmatched.length === 0) {
69146
+ return null;
69147
+ }
69148
+ return `--fields matched nothing for: ${unmatched.join(", ")}. The keys data carries are: ${[...carried].join(", ")}.`;
69149
+ }
69150
+ function maskPrintedEnvelope(text2, fields) {
69151
+ let parsed;
69152
+ try {
69153
+ parsed = JSON.parse(text2);
69154
+ } catch {
69155
+ return null;
69156
+ }
69157
+ if (!isRecord3(parsed) || typeof parsed.ok !== "boolean") {
69158
+ return null;
69159
+ }
69160
+ if (parsed.ok !== true || !("data" in parsed) || "dryRun" in parsed) {
69161
+ return text2;
69162
+ }
69163
+ const masked = { ...parsed, data: maskData(parsed.data, fields) };
69164
+ const miss = unmatchedHint(parsed.data, fields);
69165
+ if (miss) {
69166
+ masked.hints = [...Array.isArray(parsed.hints) ? parsed.hints : [], miss];
69167
+ }
69168
+ const indent = text2.trimStart().startsWith("{\n") ? 2 : void 0;
69169
+ return `${JSON.stringify(masked, null, indent)}${text2.endsWith("\n") ? "\n" : ""}`;
69170
+ }
69171
+ function maskWrites(stream, fields) {
69172
+ let applied = false;
69173
+ const write = stream.write.bind(stream);
69174
+ stream.write = (chunk, ...rest) => {
69175
+ const masked = typeof chunk === "string" ? maskPrintedEnvelope(chunk, fields) : null;
69176
+ if (masked === null) {
69177
+ return write(chunk, ...rest);
69178
+ }
69179
+ applied = true;
69180
+ return write(masked, ...rest);
69181
+ };
69182
+ return { sawEnvelope: () => applied };
69183
+ }
69184
+ function installFieldMask(fields, commandPath) {
69185
+ const mask = maskWrites(process.stdout, fields);
69186
+ process.on("exit", () => {
69187
+ if (!mask.sawEnvelope()) {
69188
+ process.stderr.write(
69189
+ `--fields was not applied: \`baker ${commandPath}\` printed no JSON envelope to narrow. Add --output json to get the envelope, or drop --fields.
69190
+ `
69191
+ );
69192
+ }
69193
+ });
69194
+ }
69195
+
69070
69196
  // src/version.ts
69071
69197
  import { readFileSync as readFileSync21 } from "fs";
69072
69198
  function packageJsonUrl() {
@@ -69093,6 +69219,7 @@ var main = defineCommand248({
69093
69219
  Auth: Set BAKER_API_KEY (starts with bk_) and BAKER_API_URL environment variables.
69094
69220
  Chat: Set BAKER_CHAT_ID for action and scheduled-agent commands that stage changes against a chat.
69095
69221
  Output: All commands return JSON envelopes: { ok: true, data: ... } or { ok: false, error: { code, message } }.
69222
+ Fields: --fields a,b,c keeps only those keys of each record in data, on every command that prints the envelope.
69096
69223
  Formats: --output json works on every command that prints the envelope. --output md|files only where 'baker schema <command>' lists output. (The research commands additionally accept csv and jsonl.)
69097
69224
  Introspection: Run 'baker schema <command>' to inspect argument schemas.`
69098
69225
  },
@@ -69132,6 +69259,11 @@ installStreamTaps();
69132
69259
  logInvocation(process.argv.slice(2));
69133
69260
  installExitRecord();
69134
69261
  process.argv = [...process.argv.slice(0, 2), ...outputFlagForCommand(main, process.argv.slice(2))];
69262
+ var fieldsFlag = takeFieldsFlag(main, process.argv.slice(2));
69263
+ if (fieldsFlag.fields) {
69264
+ process.argv = [...process.argv.slice(0, 2), ...fieldsFlag.argv];
69265
+ installFieldMask(fieldsFlag.fields, commandPathOf(main, fieldsFlag.argv));
69266
+ }
69135
69267
  refuseUnknownFlags(main, process.argv.slice(2));
69136
69268
  process.argv = [...process.argv.slice(0, 2), ...cacheFlagForParser(process.argv.slice(2))];
69137
69269
  runMain(main);