@bli-cockpit/cli 0.2.237 → 0.2.238
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/dist/adapters/attribution-core-fallbacks.js +15 -11
- package/dist/adapters/attribution-core-score.js +111 -87
- package/dist/adapters/car-state.js +38 -35
- package/dist/adapters/claude-attribution-discovery.js +81 -56
- package/dist/adapters/claude-attribution-score.js +108 -94
- package/dist/adapters/claude-attribution-signals.js +52 -42
- package/dist/adapters/codex-attribution.js +42 -33
- package/dist/adapters/codex-session-signals.js +11 -9
- package/dist/adapters/git-state.js +56 -50
- package/dist/adapters/local-sources.js +52 -43
- package/dist/adapters/raw-evidence-git-diff.js +4 -2
- package/dist/adapters/raw-evidence-sanitize.js +15 -12
- package/dist/adapters/raw-evidence-transcript-file.js +32 -31
- package/dist/autostart-self-heal.js +18 -2
- package/dist/commands/agent-session-report.js +51 -59
- package/dist/commands/agent-setup-observed.js +30 -23
- package/dist/commands/agent-setup.js +96 -45
- package/dist/commands/autostart-heal.js +8 -2
- package/dist/commands/autostart-reading.js +3 -0
- package/dist/commands/backfill-evidence-outcomes.js +9 -6
- package/dist/commands/backfill-issues.js +3 -0
- package/dist/commands/backfill-scan.js +27 -22
- package/dist/commands/backfill-upload.js +69 -60
- package/dist/commands/backfill.js +26 -21
- package/dist/commands/brief-done.js +4 -1
- package/dist/commands/brief-edit.js +71 -46
- package/dist/commands/cal-detail.js +35 -0
- package/dist/commands/cal-overlay.js +73 -30
- package/dist/commands/cal.js +36 -23
- package/dist/commands/clean.js +4 -1
- package/dist/commands/docs-read.js +5 -2
- package/dist/commands/doctor-backfill.js +88 -71
- package/dist/commands/doctor-pipeline.js +59 -46
- package/dist/commands/heartbeat-post.js +116 -0
- package/dist/commands/heartbeat-token-lock.js +46 -33
- package/dist/commands/heartbeat.js +43 -125
- package/dist/commands/install-update.js +17 -15
- package/dist/commands/issue-show.js +27 -28
- package/dist/commands/issue-write.js +70 -23
- package/dist/commands/issue.js +68 -37
- package/dist/commands/jarvis-live-answer.js +99 -0
- package/dist/commands/jarvis-render.js +1 -94
- package/dist/commands/jarvis-trace.js +30 -22
- package/dist/commands/jarvis-turn-report.js +124 -0
- package/dist/commands/jarvis-turn.js +108 -182
- package/dist/commands/jarvis.js +26 -17
- package/dist/commands/local-args-collector-setup.js +82 -84
- package/dist/commands/local-args-collector-work.js +37 -38
- package/dist/commands/local-args-tower-admin.js +155 -142
- package/dist/commands/local-args-tower-cal.js +52 -50
- package/dist/commands/local-args-tower-careers.js +73 -54
- package/dist/commands/local-args-tower-docs-msg.js +55 -45
- package/dist/commands/local-args-tower-github.js +26 -20
- package/dist/commands/local-args-tower-hits.js +32 -20
- package/dist/commands/local-args-tower-manager.js +85 -4
- package/dist/commands/local-args-tower-memory.js +139 -117
- package/dist/commands/local-args-tower-notes.js +346 -0
- package/dist/commands/local-args-tower-pages.js +100 -378
- package/dist/commands/local-args-tower-settings.js +28 -29
- package/dist/commands/local-args-tower-work.js +52 -33
- package/dist/commands/local-args.js +80 -129
- package/dist/commands/local-help-commands-tower-ops.js +15 -4
- package/dist/commands/local-help-commands-tower.js +6 -2
- package/dist/commands/local-help-commands.js +342 -341
- package/dist/commands/local-help.js +87 -83
- package/dist/commands/local-run-guards.js +100 -0
- package/dist/commands/local.js +137 -206
- package/dist/commands/login.js +13 -9
- package/dist/commands/logs.js +55 -38
- package/dist/commands/mail-attachments.js +44 -26
- package/dist/commands/manager-render-home.js +208 -0
- package/dist/commands/manager-render.js +7 -3
- package/dist/commands/manager-requests.js +33 -0
- package/dist/commands/manager.js +39 -5
- package/dist/commands/memory-consolidation.js +18 -9
- package/dist/commands/memory-daemon-probe.js +37 -28
- package/dist/commands/memory-install-config.js +64 -60
- package/dist/commands/memory-install.js +21 -41
- package/dist/commands/memory-requeue.js +26 -19
- package/dist/commands/memory-rules.js +26 -18
- package/dist/commands/memory-search-print.js +26 -0
- package/dist/commands/memory-store.js +14 -30
- package/dist/commands/memory-verb-list.js +49 -48
- package/dist/commands/notes-accounts.js +49 -32
- package/dist/commands/notes-sync-loop.js +115 -89
- package/dist/commands/notes-wisprflow-login.js +44 -23
- package/dist/commands/notes-writes.js +115 -100
- package/dist/commands/notes.js +33 -55
- package/dist/commands/onboard-flows.js +69 -51
- package/dist/commands/onboard.js +11 -9
- package/dist/commands/ops-render-memory.js +10 -7
- package/dist/commands/ops-render.js +33 -30
- package/dist/commands/ops.js +3 -0
- package/dist/commands/public-root.js +1 -1
- package/dist/commands/session-sync-outside-roots.js +40 -36
- package/dist/commands/session-sync-plan.js +14 -10
- package/dist/commands/session-sync-upload.js +24 -22
- package/dist/commands/session-sync.js +19 -8
- package/dist/commands/slack.js +25 -16
- package/dist/commands/sources-check.js +13 -7
- package/dist/commands/sources-discovery.js +25 -17
- package/dist/commands/sources-verdict.js +19 -18
- package/dist/commands/speed.js +23 -19
- package/dist/commands/start.js +20 -16
- package/dist/commands/sync-doctor.js +52 -48
- package/dist/commands/sync.js +22 -16
- package/dist/commands/usage-telemetry-toml.js +71 -45
- package/dist/commands/usage.js +91 -67
- package/dist/commands/workbook-render.js +10 -7
- package/dist/evidence-reconcile-client.js +75 -64
- package/dist/evidence-redelivery-plan.js +37 -34
- package/dist/evidence-redelivery.js +32 -29
- package/dist/evidence-transcripts-client.js +20 -20
- package/dist/evidence-upload-object.js +86 -89
- package/dist/evidence-upload-plan.js +94 -83
- package/dist/evidence-upload-terminal.js +45 -50
- package/dist/image-description-session.js +156 -159
- package/dist/local-state-pairing-code.js +39 -31
- package/dist/local-state-status.js +9 -2
- package/dist/onboarding-roots.js +5 -8
- package/dist/process-runner.js +8 -8
- package/dist/raw-evidence-gc.js +33 -38
- package/dist/raw-evidence-stuck-summary.js +7 -14
- package/dist/repo-identity.js +26 -23
- package/dist/scheduled-self-update.js +11 -15
- package/dist/second-install.js +3 -0
- package/dist/slim/codex-rules.js +23 -36
- package/dist/sync-lock.js +5 -15
- package/dist/tower-client.js +36 -53
- package/dist/tower-stream.js +7 -24
- package/dist/upload-agent-artifacts.js +58 -64
- package/dist/upload-envelope-build.js +60 -59
- package/dist/upload-evidence-delivery-reconcile.js +58 -56
- package/dist/upload-evidence-delivery-summary.js +32 -34
- package/dist/upload-ingest-receipt.js +20 -23
- package/dist/upload-session-reports-queue.js +4 -1
- package/dist/upload-session-reports-wire.js +64 -68
- package/dist/upload-sync.js +171 -157
- package/package.json +2 -2
|
@@ -3,6 +3,8 @@
|
|
|
3
3
|
*
|
|
4
4
|
* cockpit manager clients
|
|
5
5
|
* cockpit manager client <client>
|
|
6
|
+
* cockpit manager home <client>
|
|
7
|
+
* cockpit manager summary <client> --version <v>|none [--health on_track|at_risk|blocked] [--headline <t>] [--bullet "YYYY-MM-DD: t"|"t"]... [--next <t>|none] [--blocker <t>|none]
|
|
6
8
|
* cockpit manager run <run-id>
|
|
7
9
|
* cockpit manager list <client> [--timeline] [--needs-review] [--status open|done|dropped|closed|all] [--owner <name> | --no-owner] [--overdue] [--kind <kind>] [--search <text>] [--archived] [--review dismissed|all]
|
|
8
10
|
* cockpit manager queue <client>
|
|
@@ -22,27 +24,36 @@
|
|
|
22
24
|
*/
|
|
23
25
|
import { optionalNonEmpty, optionalUrl, parseNamedArgs } from "./local-arg-values.js";
|
|
24
26
|
export const MANAGER_VERBS = [
|
|
25
|
-
"clients", "client", "run", "list", "queue", "show", "add", "edit", "done", "reopen", "link",
|
|
27
|
+
"clients", "client", "home", "summary", "run", "list", "queue", "show", "add", "edit", "done", "reopen", "link",
|
|
26
28
|
"approve", "dismiss", "proposal", "archive", "unarchive",
|
|
27
29
|
];
|
|
28
30
|
export const MANAGER_ACTION_STATUSES = ["open", "done", "dropped", "closed", "all"];
|
|
29
31
|
export const MANAGER_TIMELINE_KINDS = ["meeting", "document", "milestone", "internal"];
|
|
32
|
+
export const MANAGER_SUMMARY_HEALTHS = ["on_track", "at_risk", "blocked"];
|
|
33
|
+
/** The verbs whose one positional word is a client (its id or its exact name). */
|
|
34
|
+
const CLIENT_VERBS = new Set(["client", "home", "summary", "list", "queue", "add"]);
|
|
30
35
|
const ID = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
31
36
|
const VERSION = /^\d{4}-\d{2}-\d{2}T\d{2}:\d{2}/;
|
|
32
37
|
const ONE_VERB = `manager takes one verb: ${MANAGER_VERBS.join(", ")}. Example: \`cockpit manager clients\` or \`cockpit manager list <client>\`.`;
|
|
33
38
|
const OWN_FLAGS = [
|
|
34
39
|
"--timeline", "--needs-review", "--status", "--owner", "--owners", "--no-owner", "--kind", "--search", "--archived", "--review",
|
|
35
40
|
"--title", "--detail", "--due", "--date", "--meeting", "--none", "--version", "--request-id", "--restore", "--overdue", "--source-url", "--source-note",
|
|
41
|
+
"--health", "--headline", "--bullet", "--next", "--blocker",
|
|
36
42
|
];
|
|
37
43
|
const COMMON_FLAGS = ["--home", "--dashboard-url", "--json", "--help"];
|
|
38
44
|
const VALUE_FLAGS = [
|
|
39
45
|
"--status", "--owner", "--owners", "--kind", "--search", "--review", "--title", "--detail", "--due", "--date", "--meeting",
|
|
40
46
|
"--version", "--request-id", "--source-url", "--source-note", "--home", "--dashboard-url",
|
|
47
|
+
"--health", "--headline", "--bullet", "--next", "--blocker",
|
|
41
48
|
];
|
|
49
|
+
/** `summary --bullet` is given once per bullet: the one value flag that may repeat. */
|
|
50
|
+
const REPEATABLE_FLAGS = new Set(["--bullet"]);
|
|
42
51
|
/** Which flags each verb owns, so a flag on the wrong verb is refused by name rather than ignored. */
|
|
43
52
|
export const FLAGS_BY_VERB = {
|
|
44
53
|
clients: [],
|
|
45
54
|
client: [],
|
|
55
|
+
home: [],
|
|
56
|
+
summary: ["--version", "--health", "--headline", "--bullet", "--next", "--blocker"],
|
|
46
57
|
run: [],
|
|
47
58
|
list: ["--timeline", "--needs-review", "--status", "--owner", "--no-owner", "--overdue", "--kind", "--search", "--archived", "--review"],
|
|
48
59
|
queue: [],
|
|
@@ -62,6 +73,8 @@ export const FLAGS_BY_VERB = {
|
|
|
62
73
|
const POSITIONALS = {
|
|
63
74
|
clients: [],
|
|
64
75
|
client: ["client"],
|
|
76
|
+
home: ["client"],
|
|
77
|
+
summary: ["client"],
|
|
65
78
|
run: ["run id"],
|
|
66
79
|
list: ["client"],
|
|
67
80
|
queue: ["client"],
|
|
@@ -80,6 +93,8 @@ const POSITIONALS = {
|
|
|
80
93
|
/** A value flag given twice would silently keep only the last; say so instead. */
|
|
81
94
|
function refuseRepeatedFlags(args) {
|
|
82
95
|
for (const flag of VALUE_FLAGS) {
|
|
96
|
+
if (REPEATABLE_FLAGS.has(flag))
|
|
97
|
+
continue;
|
|
83
98
|
const times = args.filter((arg) => arg === flag || arg.startsWith(`${flag}=`)).length;
|
|
84
99
|
if (times > 1) {
|
|
85
100
|
throw new Error(flag === "--owners"
|
|
@@ -113,12 +128,12 @@ export function parseManagerArgs(args) {
|
|
|
113
128
|
if (rest.length !== wanted.length) {
|
|
114
129
|
throw new Error(wanted.length === 0
|
|
115
130
|
? `\`cockpit manager ${verb}\` takes no positional arguments.`
|
|
116
|
-
: `\`cockpit manager ${verb}\` takes exactly: ${wanted.map((word) => `<${word}>`).join(" ")}${verb
|
|
131
|
+
: `\`cockpit manager ${verb}\` takes exactly: ${wanted.map((word) => `<${word}>`).join(" ")}${CLIENT_VERBS.has(verb) ? " (quote a client's name that has spaces)" : ""}.`);
|
|
117
132
|
}
|
|
118
133
|
const timeline = values.booleans.has("--timeline");
|
|
119
134
|
const shape = { ...base, action: verb, timeline };
|
|
120
135
|
const flag = (name) => values.flags.get(name);
|
|
121
|
-
if (verb
|
|
136
|
+
if (CLIENT_VERBS.has(verb))
|
|
122
137
|
shape.client = rest[0];
|
|
123
138
|
else if (verb === "run")
|
|
124
139
|
shape.runId = readId(rest[0], "A run");
|
|
@@ -128,9 +143,11 @@ export function parseManagerArgs(args) {
|
|
|
128
143
|
shape.proposalId = rest[1];
|
|
129
144
|
shape.decision = readDecision(rest[2]);
|
|
130
145
|
}
|
|
131
|
-
const needsVersion = !["clients", "client", "run", "list", "queue", "show", "add"].includes(verb);
|
|
146
|
+
const needsVersion = !["clients", "client", "home", "summary", "run", "list", "queue", "show", "add"].includes(verb);
|
|
132
147
|
if (needsVersion)
|
|
133
148
|
shape.version = readVersion(flag("--version"), verb);
|
|
149
|
+
if (verb === "summary")
|
|
150
|
+
readSummaryFields(values, shape);
|
|
134
151
|
if (verb === "list")
|
|
135
152
|
readListFilters(values, shape);
|
|
136
153
|
if (verb === "add")
|
|
@@ -368,4 +385,68 @@ function readLink(values, shape) {
|
|
|
368
385
|
if (!meeting && !none)
|
|
369
386
|
throw new Error("`cockpit manager link` needs --meeting <timeline-id> to link, or --none to unlink.");
|
|
370
387
|
shape.timelineItemId = meeting ? readId(meeting, "A timeline item") : null;
|
|
388
|
+
}
|
|
389
|
+
/** `summary`'s version: the card's `summary.updatedAt` as `home --json` gives it, or `none` when the client has no card yet. */
|
|
390
|
+
function readSummaryVersion(raw) {
|
|
391
|
+
if (raw === undefined) {
|
|
392
|
+
throw new Error("`cockpit manager summary` needs --version: the card's summary.updatedAt from `cockpit manager home <client> --json`, or none when the client has no card yet. It keeps you from writing over a newer card.");
|
|
393
|
+
}
|
|
394
|
+
if (isNone(raw))
|
|
395
|
+
return null;
|
|
396
|
+
if (!VERSION.test(raw))
|
|
397
|
+
throw new Error("--version is the card's summary.updatedAt exactly as `cockpit manager home <client> --json` gives it, like 2026-10-09T17:03:11.123456+00:00, or none.");
|
|
398
|
+
return raw;
|
|
399
|
+
}
|
|
400
|
+
/** `--bullet "2026-10-14: Signed the SOW"` is a dated bullet; without a leading `YYYY-MM-DD: ` it is undated. */
|
|
401
|
+
export function readBullet(raw) {
|
|
402
|
+
// A bullet pasted from a list keeps no "- " or "* " of its own.
|
|
403
|
+
const value = raw.trim().replace(/^[-*•]\s+/u, "");
|
|
404
|
+
const dated = /^(\d{4}-\d{2}-\d{2}):\s*(.*)$/s.exec(value);
|
|
405
|
+
const dateLike = dated ? null : /^(\d{1,4}[-/.]\d{1,2}[-/.]\d{1,4})\s*:/.exec(value);
|
|
406
|
+
if (dateLike)
|
|
407
|
+
throw new Error(`--bullet "${raw}" starts with ${dateLike[1]}, which is not a YYYY-MM-DD day. Write it like 2026-10-14, or leave the date out for an undated bullet.`);
|
|
408
|
+
const date = dated ? dated[1] : null;
|
|
409
|
+
const text = (dated ? dated[2] : value).trim();
|
|
410
|
+
if (date !== null && !isCalendarDate(date))
|
|
411
|
+
throw new Error(`--bullet "${raw}" starts with ${date}, which is not a real day. Write the date YYYY-MM-DD, like 2026-10-14, or leave it out for an undated bullet.`);
|
|
412
|
+
if (text === "")
|
|
413
|
+
throw new Error("--bullet needs words after its date. Example: --bullet \"2026-10-14: Signed the SOW\".");
|
|
414
|
+
return { date, text };
|
|
415
|
+
}
|
|
416
|
+
/** The card's fields. Counts, lengths and "blocked needs a blocker" are the server's rules, refused there by name. */
|
|
417
|
+
function readSummaryFields(values, shape) {
|
|
418
|
+
shape.version = readSummaryVersion(values.flags.get("--version"));
|
|
419
|
+
let changes = 0;
|
|
420
|
+
const health = values.flags.get("--health");
|
|
421
|
+
if (health !== undefined) {
|
|
422
|
+
if (!MANAGER_SUMMARY_HEALTHS.includes(health))
|
|
423
|
+
throw new Error(`--health wants one of ${MANAGER_SUMMARY_HEALTHS.join(", ")}.`);
|
|
424
|
+
shape.health = health;
|
|
425
|
+
changes += 1;
|
|
426
|
+
}
|
|
427
|
+
const headline = values.flags.get("--headline");
|
|
428
|
+
if (headline !== undefined) {
|
|
429
|
+
if (headline.trim() === "")
|
|
430
|
+
throw new Error("--headline cannot be blank.");
|
|
431
|
+
shape.headline = headline.trim();
|
|
432
|
+
changes += 1;
|
|
433
|
+
}
|
|
434
|
+
const bullets = values.flagValues.get("--bullet");
|
|
435
|
+
if (bullets !== undefined && bullets.length > 0) {
|
|
436
|
+
shape.bullets = bullets.map(readBullet);
|
|
437
|
+
changes += 1;
|
|
438
|
+
}
|
|
439
|
+
const next = values.flags.get("--next");
|
|
440
|
+
if (next !== undefined) {
|
|
441
|
+
shape.next = isNone(next) ? null : next.trim();
|
|
442
|
+
changes += 1;
|
|
443
|
+
}
|
|
444
|
+
const blocker = values.flags.get("--blocker");
|
|
445
|
+
if (blocker !== undefined) {
|
|
446
|
+
shape.blocker = isNone(blocker) ? null : blocker.trim();
|
|
447
|
+
changes += 1;
|
|
448
|
+
}
|
|
449
|
+
if (changes === 0) {
|
|
450
|
+
throw new Error("`cockpit manager summary` has nothing to change. Give at least one of --health, --headline, --bullet (1 to 5 of them, replacing the list), --next, --blocker. A flag you leave out keeps its value; none clears --next or --blocker.");
|
|
451
|
+
}
|
|
371
452
|
}
|
|
@@ -119,6 +119,40 @@ export function parseMemoryStoreArgs(action, args) {
|
|
|
119
119
|
const values = parseNamedArgs(args, { allowedFlags: ALLOWED_FLAGS, valueFlags: VALUE_FLAGS });
|
|
120
120
|
const rest = values.positionals.slice(1);
|
|
121
121
|
const containers = values.flagValues.get("--container") ?? [];
|
|
122
|
+
rejectFlagsThatDoNotBelongTo(action, values, containers, rest);
|
|
123
|
+
const command = {
|
|
124
|
+
kind: "memory-store",
|
|
125
|
+
homeDir: optionalNonEmpty(values.flags.get("--home")),
|
|
126
|
+
dashboardUrl: optionalUrl(values.flags.get("--dashboard-url")),
|
|
127
|
+
workspace: optionalNonEmpty(workRootFlagValue(values)),
|
|
128
|
+
containerTags: containers
|
|
129
|
+
.map((tag) => tag.trim())
|
|
130
|
+
.filter((tag) => tag.length > 0),
|
|
131
|
+
json: values.booleans.has("--json"),
|
|
132
|
+
};
|
|
133
|
+
if (action === "requeue")
|
|
134
|
+
return parseRequeueVerb(command, values, rest);
|
|
135
|
+
if (action === "profile")
|
|
136
|
+
return parseProfileVerb(command, rest);
|
|
137
|
+
if (action === "search")
|
|
138
|
+
return parseSearchVerb(command, values, rest);
|
|
139
|
+
if (action === "consolidation")
|
|
140
|
+
return { ...command, action };
|
|
141
|
+
if (action === "exam")
|
|
142
|
+
return parseExamVerb(command, values, rest);
|
|
143
|
+
if (action === "source")
|
|
144
|
+
return parseSourceVerb(command, values, rest);
|
|
145
|
+
if (action === "private" || action === "public" || action === "chain") {
|
|
146
|
+
return parseOneMemoryIdVerb(command, action, rest);
|
|
147
|
+
}
|
|
148
|
+
if (action === "save")
|
|
149
|
+
return parseSaveVerb(command, values, rest);
|
|
150
|
+
if (action === "update")
|
|
151
|
+
return parseUpdateVerb(command, values, rest);
|
|
152
|
+
return parseForgetVerb(command, values, rest);
|
|
153
|
+
}
|
|
154
|
+
/** Every flag is legal to the parser; this says which verb each one belongs to. */
|
|
155
|
+
function rejectFlagsThatDoNotBelongTo(action, values, containers, rest) {
|
|
122
156
|
if (action !== "search" && action !== "consolidation" && containers.length > 1) {
|
|
123
157
|
throw new Error(`memory ${action} takes at most one --container.`);
|
|
124
158
|
}
|
|
@@ -166,130 +200,118 @@ export function parseMemoryStoreArgs(action, args) {
|
|
|
166
200
|
if (values.flags.has("--file") && action !== "save" && action !== "update") {
|
|
167
201
|
throw new Error("--file only applies to memory save and memory update.");
|
|
168
202
|
}
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
containerTags: containers
|
|
176
|
-
.map((tag) => tag.trim())
|
|
177
|
-
.filter((tag) => tag.length > 0),
|
|
178
|
-
json: values.booleans.has("--json"),
|
|
179
|
-
};
|
|
180
|
-
if (action === "requeue") {
|
|
181
|
-
// A window is REQUIRED. There is no requeue-everything: applying re-runs
|
|
182
|
-
// one model call per receipt, so the ceiling on a wrong filter is a bill.
|
|
183
|
-
if (rest.length > 0) {
|
|
184
|
-
throw new Error("memory requeue takes no words; name the window with --since and --until.");
|
|
185
|
-
}
|
|
186
|
-
const since = readInstant(values.flags.get("--since"), "--since");
|
|
187
|
-
if (!since) {
|
|
188
|
-
throw new Error("memory requeue needs --since <iso>, e.g. `cockpit memory requeue --since 2026-09-21T04:10:00Z --dry-run`.");
|
|
189
|
-
}
|
|
190
|
-
const until = readInstant(values.flags.get("--until"), "--until");
|
|
191
|
-
if (until && until < since)
|
|
192
|
-
throw new Error("--until is before --since; nothing could match.");
|
|
193
|
-
const source = optionalNonEmpty(values.flags.get("--source"));
|
|
194
|
-
if (source && source !== "hook" && source !== "harvest") {
|
|
195
|
-
throw new Error("--source is hook or harvest — the two values a receipt can carry.");
|
|
196
|
-
}
|
|
197
|
-
if (values.booleans.has("--dry-run") && values.booleans.has("--apply")) {
|
|
198
|
-
throw new Error("--dry-run and --apply are opposites; name one.");
|
|
199
|
-
}
|
|
200
|
-
return {
|
|
201
|
-
...command,
|
|
202
|
-
action,
|
|
203
|
-
since,
|
|
204
|
-
until,
|
|
205
|
-
...(source ? { source: source } : {}),
|
|
206
|
-
// The safe question unless somebody typed otherwise.
|
|
207
|
-
dryRun: !values.booleans.has("--apply"),
|
|
208
|
-
reason: optionalNonEmpty(values.flags.get("--reason")),
|
|
209
|
-
};
|
|
210
|
-
}
|
|
211
|
-
if (action === "profile") {
|
|
212
|
-
// A pure read of ONE container's compiled page. No positional: there is
|
|
213
|
-
// nothing to ask it, and a stray word would look like a query this verb
|
|
214
|
-
// silently ignored.
|
|
215
|
-
if (rest.length > 0) {
|
|
216
|
-
throw new Error("memory profile takes no words; it reads this repository's compiled page. Name another space with --container.");
|
|
217
|
-
}
|
|
218
|
-
return { ...command, action };
|
|
203
|
+
}
|
|
204
|
+
function parseRequeueVerb(command, values, rest) {
|
|
205
|
+
// A window is REQUIRED. There is no requeue-everything: applying re-runs
|
|
206
|
+
// one model call per receipt, so the ceiling on a wrong filter is a bill.
|
|
207
|
+
if (rest.length > 0) {
|
|
208
|
+
throw new Error("memory requeue takes no words; name the window with --since and --until.");
|
|
219
209
|
}
|
|
220
|
-
|
|
221
|
-
|
|
222
|
-
|
|
223
|
-
// search` and `cockpit cal find` already have.
|
|
224
|
-
const query = rest.join(" ").trim();
|
|
225
|
-
if (!query)
|
|
226
|
-
throw new Error("memory search needs a question, e.g. `cockpit memory search \"pagination rule\"`.");
|
|
227
|
-
// BLI-19246: both flags absent leaves the choice to the door (exact-detail questions reach the originals).
|
|
228
|
-
const includeOriginals = values.booleans.has("--include-originals") ? true : values.booleans.has("--no-originals") ? false : undefined;
|
|
229
|
-
// BLI-19255: the raw source behind the top hits; absent lets the door decide by the question.
|
|
230
|
-
const includeSource = values.booleans.has("--include-source") ? true : values.booleans.has("--no-source") ? false : undefined;
|
|
231
|
-
return {
|
|
232
|
-
...command, action, query, limit: readLimit(values.flags.get("--limit")), includeRecent: !values.booleans.has("--no-recent"),
|
|
233
|
-
...(includeOriginals === undefined ? {} : { includeOriginals }),
|
|
234
|
-
...(includeSource === undefined ? {} : { includeSource }),
|
|
235
|
-
};
|
|
210
|
+
const since = readInstant(values.flags.get("--since"), "--since");
|
|
211
|
+
if (!since) {
|
|
212
|
+
throw new Error("memory requeue needs --since <iso>, e.g. `cockpit memory requeue --since 2026-09-21T04:10:00Z --dry-run`.");
|
|
236
213
|
}
|
|
237
|
-
|
|
238
|
-
|
|
214
|
+
const until = readInstant(values.flags.get("--until"), "--until");
|
|
215
|
+
if (until && until < since)
|
|
216
|
+
throw new Error("--until is before --since; nothing could match.");
|
|
217
|
+
const source = optionalNonEmpty(values.flags.get("--source"));
|
|
218
|
+
if (source && source !== "hook" && source !== "harvest") {
|
|
219
|
+
throw new Error("--source is hook or harvest — the two values a receipt can carry.");
|
|
239
220
|
}
|
|
240
|
-
if (
|
|
241
|
-
|
|
242
|
-
throw new Error("memory exam takes no words: `cockpit memory exam [--night <YYYY-MM-DD>] [--misses] [--json]`.");
|
|
243
|
-
const night = optionalNonEmpty(values.flags.get("--night"));
|
|
244
|
-
if (night && !/^\d{4}-\d{2}-\d{2}$/.test(night))
|
|
245
|
-
throw new Error("--night must be a date like 2026-10-14.");
|
|
246
|
-
return { ...command, action, ...(night ? { night } : {}), misses: values.booleans.has("--misses") };
|
|
221
|
+
if (values.booleans.has("--dry-run") && values.booleans.has("--apply")) {
|
|
222
|
+
throw new Error("--dry-run and --apply are opposites; name one.");
|
|
247
223
|
}
|
|
248
|
-
|
|
249
|
-
|
|
250
|
-
|
|
251
|
-
|
|
252
|
-
|
|
253
|
-
|
|
254
|
-
|
|
255
|
-
|
|
256
|
-
|
|
257
|
-
|
|
258
|
-
|
|
259
|
-
|
|
224
|
+
return {
|
|
225
|
+
...command,
|
|
226
|
+
action: "requeue",
|
|
227
|
+
since,
|
|
228
|
+
until,
|
|
229
|
+
...(source ? { source: source } : {}),
|
|
230
|
+
// The safe question unless somebody typed otherwise.
|
|
231
|
+
dryRun: !values.booleans.has("--apply"),
|
|
232
|
+
reason: optionalNonEmpty(values.flags.get("--reason")),
|
|
233
|
+
};
|
|
234
|
+
}
|
|
235
|
+
function parseProfileVerb(command, rest) {
|
|
236
|
+
// A pure read of ONE container's compiled page. No positional: there is
|
|
237
|
+
// nothing to ask it, and a stray word would look like a query this verb
|
|
238
|
+
// silently ignored.
|
|
239
|
+
if (rest.length > 0) {
|
|
240
|
+
throw new Error("memory profile takes no words; it reads this repository's compiled page. Name another space with --container.");
|
|
260
241
|
}
|
|
261
|
-
|
|
262
|
-
|
|
263
|
-
|
|
264
|
-
|
|
265
|
-
|
|
266
|
-
|
|
267
|
-
|
|
268
|
-
|
|
269
|
-
|
|
242
|
+
return { ...command, action: "profile" };
|
|
243
|
+
}
|
|
244
|
+
function parseSearchVerb(command, values, rest) {
|
|
245
|
+
// Every remaining positional joined, so `cockpit memory search what did we
|
|
246
|
+
// decide about pagination` needs no quotes — the same shape `cockpit
|
|
247
|
+
// search` and `cockpit cal find` already have.
|
|
248
|
+
const query = rest.join(" ").trim();
|
|
249
|
+
if (!query)
|
|
250
|
+
throw new Error("memory search needs a question, e.g. `cockpit memory search \"pagination rule\"`.");
|
|
251
|
+
// BLI-19246: both flags absent leaves the choice to the door (exact-detail questions reach the originals).
|
|
252
|
+
const includeOriginals = values.booleans.has("--include-originals") ? true : values.booleans.has("--no-originals") ? false : undefined;
|
|
253
|
+
// BLI-19255: the raw source behind the top hits; absent lets the door decide by the question.
|
|
254
|
+
const includeSource = values.booleans.has("--include-source") ? true : values.booleans.has("--no-source") ? false : undefined;
|
|
255
|
+
return {
|
|
256
|
+
...command, action: "search", query, limit: readLimit(values.flags.get("--limit")), includeRecent: !values.booleans.has("--no-recent"),
|
|
257
|
+
...(includeOriginals === undefined ? {} : { includeOriginals }),
|
|
258
|
+
...(includeSource === undefined ? {} : { includeSource }),
|
|
259
|
+
};
|
|
260
|
+
}
|
|
261
|
+
function parseExamVerb(command, values, rest) {
|
|
262
|
+
if (rest.length > 0)
|
|
263
|
+
throw new Error("memory exam takes no words: `cockpit memory exam [--night <YYYY-MM-DD>] [--misses] [--json]`.");
|
|
264
|
+
const night = optionalNonEmpty(values.flags.get("--night"));
|
|
265
|
+
if (night && !/^\d{4}-\d{2}-\d{2}$/.test(night))
|
|
266
|
+
throw new Error("--night must be a date like 2026-10-14.");
|
|
267
|
+
return { ...command, action: "exam", ...(night ? { night } : {}), misses: values.booleans.has("--misses") };
|
|
268
|
+
}
|
|
269
|
+
function parseSourceVerb(command, values, rest) {
|
|
270
|
+
// BLI-19255: one memory, named by the id `cockpit memory search` printed; `--query` steers which part of the source.
|
|
271
|
+
const memoryId = optionalNonEmpty(rest[0]);
|
|
272
|
+
if (!memoryId)
|
|
273
|
+
throw new Error("memory source needs the memory id `cockpit memory search` printed.");
|
|
274
|
+
if (rest.length > 1)
|
|
275
|
+
throw new Error("memory source takes one id.");
|
|
276
|
+
const rawChars = values.flags.get("--chars");
|
|
277
|
+
const chars = rawChars === undefined ? undefined : Number(rawChars);
|
|
278
|
+
if (chars !== undefined && (!Number.isInteger(chars) || chars < 200 || chars > 6000))
|
|
279
|
+
throw new Error("--chars is a whole number from 200 to 6000.");
|
|
280
|
+
return { ...command, action: "source", memoryId, ...(values.flags.get("--query") ? { sourceQuery: values.flags.get("--query") } : {}), ...(chars === undefined ? {} : { sourceChars: chars }) };
|
|
281
|
+
}
|
|
282
|
+
function parseOneMemoryIdVerb(command, action, rest) {
|
|
283
|
+
// BLI-12927: one memory, named by the id `cockpit memory search` printed.
|
|
284
|
+
const memoryId = optionalNonEmpty(rest[0]);
|
|
285
|
+
if (!memoryId) {
|
|
286
|
+
throw new Error(`memory ${action} needs the memory id \`cockpit memory search\` printed.`);
|
|
270
287
|
}
|
|
271
|
-
if (
|
|
272
|
-
|
|
273
|
-
|
|
274
|
-
|
|
275
|
-
|
|
276
|
-
|
|
277
|
-
|
|
278
|
-
customId: optionalNonEmpty(values.flags.get("--custom-id")),
|
|
279
|
-
...(values.flagValues.has("--alias") ? { aliases: values.flagValues.get("--alias") } : {}),
|
|
280
|
-
extract: values.booleans.has("--extract"),
|
|
281
|
-
filePath: optionalNonEmpty(values.flags.get("--file")),
|
|
282
|
-
};
|
|
288
|
+
if (rest.length > 1)
|
|
289
|
+
throw new Error(`memory ${action} takes one id.`);
|
|
290
|
+
return { ...command, action, memoryId };
|
|
291
|
+
}
|
|
292
|
+
function parseSaveVerb(command, values, rest) {
|
|
293
|
+
if (rest.length > 0) {
|
|
294
|
+
throw new Error("memory save reads the memory from stdin or --file, never from the command line: `echo \"...\" | cockpit memory save`.");
|
|
283
295
|
}
|
|
284
|
-
|
|
285
|
-
|
|
286
|
-
|
|
287
|
-
|
|
288
|
-
|
|
289
|
-
|
|
290
|
-
|
|
291
|
-
|
|
296
|
+
return {
|
|
297
|
+
...command,
|
|
298
|
+
action: "save",
|
|
299
|
+
customId: optionalNonEmpty(values.flags.get("--custom-id")),
|
|
300
|
+
...(values.flagValues.has("--alias") ? { aliases: values.flagValues.get("--alias") } : {}),
|
|
301
|
+
extract: values.booleans.has("--extract"),
|
|
302
|
+
filePath: optionalNonEmpty(values.flags.get("--file")),
|
|
303
|
+
};
|
|
304
|
+
}
|
|
305
|
+
function parseUpdateVerb(command, values, rest) {
|
|
306
|
+
const memoryId = optionalNonEmpty(rest[0]);
|
|
307
|
+
if (!memoryId)
|
|
308
|
+
throw new Error("memory update needs the memory id `cockpit memory search` printed.");
|
|
309
|
+
if (rest.length > 1) {
|
|
310
|
+
throw new Error("memory update takes one id; the replacement text comes from stdin or --file, never from the command line.");
|
|
292
311
|
}
|
|
312
|
+
return { ...command, action: "update", memoryId, filePath: optionalNonEmpty(values.flags.get("--file")) };
|
|
313
|
+
}
|
|
314
|
+
function parseForgetVerb(command, values, rest) {
|
|
293
315
|
const memoryId = optionalNonEmpty(rest[0]);
|
|
294
316
|
if (rest.length > 1)
|
|
295
317
|
throw new Error("memory forget takes one id, or --content-stdin with a --container.");
|
|
@@ -302,7 +324,7 @@ export function parseMemoryStoreArgs(action, args) {
|
|
|
302
324
|
}
|
|
303
325
|
return {
|
|
304
326
|
...command,
|
|
305
|
-
action,
|
|
327
|
+
action: "forget",
|
|
306
328
|
memoryId,
|
|
307
329
|
contentStdin,
|
|
308
330
|
reason: optionalNonEmpty(values.flags.get("--reason")),
|