@koda-sl/baker-cli 0.349.0-dev.c05788ee3 → 0.349.0-dev.fe6a04f5a
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 +2 -1
- package/dist/cli.js +32 -46
- package/dist/cli.js.map +1 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -742,7 +742,7 @@ Use `--no-cache` on any command to bypass **both** the local file cache and the
|
|
|
742
742
|
|------|-----------|---------|
|
|
743
743
|
| `FIELD_NOT_FOUND` | No | Invalid field in GAQL query |
|
|
744
744
|
| `WRONG_RESOURCE` | No | Field queried from wrong resource |
|
|
745
|
-
| `INVALID_OPERATOR` | No | Unsupported operator (e.g. CONTAINS
|
|
745
|
+
| `INVALID_OPERATOR` | No | Unsupported operator (e.g. CONTAINS) |
|
|
746
746
|
| `CUSTOMER_NOT_FOUND` | No | Invalid customer ID — run `baker ads google accounts` to find valid IDs |
|
|
747
747
|
| `MISSING_MANAGER_ID` | No | Account not accessible (may need MCC login-customer-id) |
|
|
748
748
|
| `INCOMPATIBLE_FIELDS` | No | Fields can't be in same query |
|
|
@@ -3422,6 +3422,7 @@ baker actions list # default: bucketed (claimable, myCla
|
|
|
3422
3422
|
baker actions list --bucketed=false --status pending
|
|
3423
3423
|
baker actions list --bucketed=false --sort priority # flat list, do-first order (default); use --sort recent for newest-first
|
|
3424
3424
|
baker actions list --output md # id-first Markdown; works for both the bucketed and flat shapes
|
|
3425
|
+
baker actions list --search "conversion goal" --output md # find Tasks by words in name/description/tags (flat, best match first)
|
|
3425
3426
|
# With BAKER_CHAT_ID, the bucketed list folds in THIS chat's draft: staged creates appear in
|
|
3426
3427
|
# `draftCreates`; published actions being completed/discarded/updated carry a `draftStatus` marker.
|
|
3427
3428
|
# Only the caller's own chat draft is reflected — never another chat's staged work.
|
package/dist/cli.js
CHANGED
|
@@ -7880,7 +7880,7 @@ function buildListHints({ returned, limit }) {
|
|
|
7880
7880
|
return [];
|
|
7881
7881
|
}
|
|
7882
7882
|
return [
|
|
7883
|
-
`This list is capped at ${limit} Tasks and came back full, so older Tasks exist that are NOT shown. Do not treat it as the whole backlog \u2014 re-run with --limit ${limit * 2} (or narrow with --status / --
|
|
7883
|
+
`This list is capped at ${limit} Tasks and came back full, so older Tasks exist that are NOT shown. Do not treat it as the whole backlog \u2014 re-run with --limit ${limit * 2} (or narrow with --status / --search).`
|
|
7884
7884
|
];
|
|
7885
7885
|
}
|
|
7886
7886
|
|
|
@@ -8490,8 +8490,13 @@ var linkCommand = defineCommand7({
|
|
|
8490
8490
|
import { defineCommand as defineCommand8 } from "citty";
|
|
8491
8491
|
registerSchema({
|
|
8492
8492
|
command: "actions.list",
|
|
8493
|
-
description:
|
|
8493
|
+
description: 'List actions for the current company. Default: pre-bucketed (claimable/myClaims/blocked/claimedByOthers/completed/discarded), each bucket ordered do-first (blockers before blocked, then highest-leverage). The bucketed view reads the whole open backlog, so nothing pending is ever hidden from it. Set --bucketed=false for a flat list filterable by --status, orderable by --sort, and windowed by --limit. Looking for one Task by name? --search "conversion goal" --output md returns only the matching Tasks instead of the whole backlog.',
|
|
8494
8494
|
args: {
|
|
8495
|
+
search: {
|
|
8496
|
+
type: "string",
|
|
8497
|
+
description: 'Find Tasks by words in their name, description or tags, searched on the server (e.g. --search "conversion goal"). Returns a flat list, best match first; by default it covers pending, in-progress and completed Tasks. Add --status to search one status instead, including discarded Tasks (--status discarded). Implies --bucketed=false.',
|
|
8498
|
+
required: false
|
|
8499
|
+
},
|
|
8495
8500
|
bucketed: {
|
|
8496
8501
|
type: "boolean",
|
|
8497
8502
|
description: "Pre-bucket the results based on the current chat (default: true)",
|
|
@@ -8519,9 +8524,10 @@ registerSchema({
|
|
|
8519
8524
|
var listCommand2 = defineCommand8({
|
|
8520
8525
|
meta: {
|
|
8521
8526
|
name: "list",
|
|
8522
|
-
description: "List actions. Default: bucketed view (claimable, myClaims, blocked, claimedByOthers). Use --bucketed=false for raw filter by --status."
|
|
8527
|
+
description: "List actions. Default: bucketed view (claimable, myClaims, blocked, claimedByOthers). Use --bucketed=false for raw filter by --status, or --search <text> to find Tasks by name."
|
|
8523
8528
|
},
|
|
8524
8529
|
args: {
|
|
8530
|
+
search: { type: "string", description: "Find Tasks by words in name/description/tags", required: false },
|
|
8525
8531
|
bucketed: { type: "boolean", description: "Pre-bucket by chat", required: false, default: true },
|
|
8526
8532
|
status: { type: "string", description: "Status filter (raw mode)", required: false },
|
|
8527
8533
|
sort: { type: "string", description: "Order (raw mode): priority|recent", required: false },
|
|
@@ -8530,12 +8536,9 @@ var listCommand2 = defineCommand8({
|
|
|
8530
8536
|
},
|
|
8531
8537
|
run: async ({ args: args5 }) => {
|
|
8532
8538
|
try {
|
|
8533
|
-
const
|
|
8534
|
-
const parsedLimit = args5.limit === void 0 ? Number.NaN : Number.parseInt(String(args5.limit), 10);
|
|
8535
|
-
const limit = Number.isFinite(parsedLimit) && parsedLimit > 0 ? parsedLimit : ACTIONS_LIST_DEFAULT_LIMIT;
|
|
8536
|
-
const body = buildRequestBody(args5, bucketed, limit);
|
|
8539
|
+
const body = buildListRequest(args5, getEnv().BAKER_CHAT_ID);
|
|
8537
8540
|
const response = await apiPost("/api/actions/list", body);
|
|
8538
|
-
const hints2 =
|
|
8541
|
+
const hints2 = body.bucketed === false && body.limit !== void 0 && response.ok && Array.isArray(response.data) ? buildListHints({ returned: response.data.length, limit: body.limit }) : [];
|
|
8539
8542
|
const envelope = hints2.length > 0 ? { ...response, hints: hints2 } : response;
|
|
8540
8543
|
if (args5.output === "md" && envelope.ok) {
|
|
8541
8544
|
process.stdout.write(renderMarkdown(envelope.data, hints2));
|
|
@@ -8547,20 +8550,25 @@ var listCommand2 = defineCommand8({
|
|
|
8547
8550
|
}
|
|
8548
8551
|
}
|
|
8549
8552
|
});
|
|
8550
|
-
function
|
|
8551
|
-
const
|
|
8552
|
-
|
|
8553
|
-
|
|
8554
|
-
|
|
8555
|
-
|
|
8556
|
-
|
|
8557
|
-
|
|
8553
|
+
function buildListRequest(args5, chatId) {
|
|
8554
|
+
const q = args5.search?.trim();
|
|
8555
|
+
if (args5.bucketed !== false && !q) {
|
|
8556
|
+
return chatId ? { bucketed: true, chatId } : { bucketed: true };
|
|
8557
|
+
}
|
|
8558
|
+
const parsedLimit = args5.limit === void 0 ? Number.NaN : Number.parseInt(String(args5.limit), 10);
|
|
8559
|
+
const body = {
|
|
8560
|
+
bucketed: false,
|
|
8561
|
+
// Default to do-first ordering so the flat list matches its documented
|
|
8562
|
+
// contract; only "recent" opts out. A search keeps relevance order.
|
|
8563
|
+
sort: args5.sort === "recent" ? "recent" : "priority",
|
|
8564
|
+
limit: Number.isFinite(parsedLimit) && parsedLimit > 0 ? parsedLimit : ACTIONS_LIST_DEFAULT_LIMIT
|
|
8565
|
+
};
|
|
8566
|
+
if (q) {
|
|
8567
|
+
body.q = q;
|
|
8558
8568
|
}
|
|
8559
8569
|
if (args5.status) {
|
|
8560
8570
|
body.status = args5.status;
|
|
8561
8571
|
}
|
|
8562
|
-
body.sort = args5.sort === "recent" ? "recent" : "priority";
|
|
8563
|
-
body.limit = limit;
|
|
8564
8572
|
return body;
|
|
8565
8573
|
}
|
|
8566
8574
|
function toRow(entry) {
|
|
@@ -9848,27 +9856,6 @@ var CORRECTION_RULES = [
|
|
|
9848
9856
|
};
|
|
9849
9857
|
}
|
|
9850
9858
|
},
|
|
9851
|
-
// 0b. OPERATOR_FIELD_MISMATCH — the field refuses this operator, and Google names the
|
|
9852
|
-
// ones it takes. Kept ahead of the field-specific rules for the same reason as rule 0.
|
|
9853
|
-
// A repeated field (final_urls, labels, …) takes only CONTAINS ALL/ANY/NONE, so it has
|
|
9854
|
-
// no null test at all: read it unfiltered and filter the rows instead.
|
|
9855
|
-
{
|
|
9856
|
-
matchApiError: /OPERATOR_FIELD_MISMATCH|is not a valid operator to use with/i,
|
|
9857
|
-
fix: (ctx) => {
|
|
9858
|
-
const message = ctx.apiErrorMessage ?? "";
|
|
9859
|
-
const field = message.match(/valid operator to use with '([\w.]+)'/i)?.[1] ?? "this field";
|
|
9860
|
-
const operator = message.match(/([A-Z][A-Z_ =!<>]*?) is not a valid operator/)?.[1]?.trim();
|
|
9861
|
-
const valid = message.match(/Valid operators: (.+?)\.?(?:"|$)/i)?.[1]?.trim();
|
|
9862
|
-
const refused = operator ? `${operator} cannot be used on ${field}` : `${field} does not take that operator`;
|
|
9863
|
-
const allowed = valid ? `; its valid operators are ${valid}` : "";
|
|
9864
|
-
const repeated = valid?.split(",").every((op) => /^CONTAINS (ALL|ANY|NONE)$/i.test(op.trim())) ?? false;
|
|
9865
|
-
const guidance = repeated ? `. ${field} is a list field, so it cannot be tested for null or compared with =: to find rows that have it, drop that condition, keep ${field} in SELECT and filter the rows (rows without it omit the key); to match values, use ${field} CONTAINS ANY ('value')` : ". Rewrite that condition with one of them, or drop it and filter the rows";
|
|
9866
|
-
return {
|
|
9867
|
-
action: "change_operator",
|
|
9868
|
-
explanation: `${refused}${allowed}${guidance}`
|
|
9869
|
-
};
|
|
9870
|
-
}
|
|
9871
|
-
},
|
|
9872
9859
|
// 1. bare keyword.text → ad_group_criterion.keyword.text (leaves <resource>.keyword.text untouched)
|
|
9873
9860
|
{
|
|
9874
9861
|
matchQuery: /(?<![\w.])keyword\.text\b/,
|
|
@@ -9911,11 +9898,10 @@ var CORRECTION_RULES = [
|
|
|
9911
9898
|
};
|
|
9912
9899
|
}
|
|
9913
9900
|
},
|
|
9914
|
-
// 4. CONTAINS → LIKE
|
|
9915
|
-
// invalid argument … Valid operators: CONTAINS ANY") matches any loose error pattern, and this
|
|
9916
|
-
// advice only makes sense when the query actually wrote CONTAINS(…).
|
|
9901
|
+
// 4. CONTAINS → LIKE
|
|
9917
9902
|
{
|
|
9918
9903
|
matchQuery: /CONTAINS\s*\(/i,
|
|
9904
|
+
matchApiError: /CONTAINS.*not.*supported|invalid.*operator.*CONTAINS/i,
|
|
9919
9905
|
fix: (ctx) => {
|
|
9920
9906
|
const match = ctx.originalQuery.match(/CONTAINS\s*\(\s*([^,]+),\s*'([^']+)'\s*\)/i);
|
|
9921
9907
|
if (match) {
|
|
@@ -50013,7 +49999,7 @@ function outputRows(rows, args5, response, cached) {
|
|
|
50013
49999
|
}
|
|
50014
50000
|
writeJsonEnvelope({ ...response, ...cached && { cached: true } });
|
|
50015
50001
|
}
|
|
50016
|
-
function
|
|
50002
|
+
function buildRequestBody(args5, propertyId, useCache) {
|
|
50017
50003
|
const body = { propertyId };
|
|
50018
50004
|
if (args5.preset) body.preset = args5.preset;
|
|
50019
50005
|
if (args5.dimensions) body.dimensions = args5.dimensions.split(",").map((d) => d.trim());
|
|
@@ -50088,7 +50074,7 @@ Free-form (escape hatch):
|
|
|
50088
50074
|
}
|
|
50089
50075
|
const propertyId = await resolvePropertyId(args5);
|
|
50090
50076
|
const useCache = !args5["no-cache"];
|
|
50091
|
-
const body =
|
|
50077
|
+
const body = buildRequestBody(args5, propertyId, useCache);
|
|
50092
50078
|
const cacheKey = buildQueryCacheKey(propertyId, JSON.stringify(body));
|
|
50093
50079
|
if (useCache) {
|
|
50094
50080
|
const cached = cacheGet("ga4-queries", cacheKey);
|
|
@@ -51013,7 +50999,7 @@ function outputRows2(rows, args5, response, cached) {
|
|
|
51013
50999
|
}
|
|
51014
51000
|
writeJsonEnvelope({ ...response, ...cached && { cached: true } });
|
|
51015
51001
|
}
|
|
51016
|
-
function
|
|
51002
|
+
function buildRequestBody2(args5, siteUrl, useCache) {
|
|
51017
51003
|
const body = { siteUrl };
|
|
51018
51004
|
if (args5.preset) body.preset = args5.preset;
|
|
51019
51005
|
if (args5.brand) body.brand = args5.brand;
|
|
@@ -51097,7 +51083,7 @@ Free-form (escape hatch):
|
|
|
51097
51083
|
}
|
|
51098
51084
|
const siteUrl = await resolveSiteUrl(args5);
|
|
51099
51085
|
const useCache = !args5["no-cache"];
|
|
51100
|
-
const body =
|
|
51086
|
+
const body = buildRequestBody2(args5, siteUrl, useCache);
|
|
51101
51087
|
const cacheKey = buildQueryCacheKey(siteUrl, JSON.stringify(body));
|
|
51102
51088
|
if (useCache) {
|
|
51103
51089
|
const cached = cacheGet("gsc-queries", cacheKey);
|