things-api 0.16.0 → 0.18.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 +1 -1
- package/deputy/VERSION +1 -0
- package/deputy/helpers-Info.plist +23 -0
- package/deputy/prebuilt/Things API Helper.app/Contents/CodeResources +0 -0
- package/deputy/prebuilt/Things API Helper.app/Contents/Helpers/things-reader.app/Contents/Info.plist +20 -0
- package/deputy/prebuilt/Things API Helper.app/Contents/Helpers/things-reader.app/Contents/MacOS/things-reader +0 -0
- package/deputy/prebuilt/Things API Helper.app/Contents/Helpers/things-reader.app/Contents/_CodeSignature/CodeResources +115 -0
- package/deputy/prebuilt/Things API Helper.app/Contents/Info.plist +23 -0
- package/deputy/prebuilt/Things API Helper.app/Contents/MacOS/things-deputy +0 -0
- package/deputy/prebuilt/Things API Helper.app/Contents/_CodeSignature/CodeResources +125 -0
- package/deputy/reader/Info.plist +20 -0
- package/deputy/reader/entitlements.plist +15 -0
- package/deputy/reader/main.swift +491 -0
- package/deputy/src/main.swift +133 -0
- package/deputy/src/osascript.swift +102 -0
- package/deputy/src/server.swift +350 -0
- package/deputy/src/sqlite.swift +121 -0
- package/dist/cli/commands/doctor.js +55 -2
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/helpers.d.ts +17 -0
- package/dist/cli/commands/helpers.js +148 -0
- package/dist/cli/commands/helpers.js.map +1 -0
- package/dist/cli/commands/op-result.d.ts +15 -0
- package/dist/cli/commands/op-result.js +39 -0
- package/dist/cli/commands/op-result.js.map +1 -0
- package/dist/cli/commands/repeat-flags.d.ts +3 -3
- package/dist/cli/commands/repeat-flags.js +90 -33
- package/dist/cli/commands/repeat-flags.js.map +1 -1
- package/dist/cli/commands/writes.js +79 -6
- package/dist/cli/commands/writes.js.map +1 -1
- package/dist/cli/help.js +13 -2
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/helpers-check.d.ts +10 -0
- package/dist/cli/helpers-check.js +59 -0
- package/dist/cli/helpers-check.js.map +1 -0
- package/dist/cli/interrupt.d.ts +42 -0
- package/dist/cli/interrupt.js +105 -0
- package/dist/cli/interrupt.js.map +1 -0
- package/dist/cli/main.js +27 -1
- package/dist/cli/main.js.map +1 -1
- package/dist/client.js +19 -2
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +70 -0
- package/dist/config.js +25 -1
- package/dist/config.js.map +1 -1
- package/dist/contracts.d.ts +9 -2
- package/dist/contracts.js +1 -1
- package/dist/contracts.js.map +1 -1
- package/dist/db/baselines/db-v26.js +8 -4
- package/dist/db/baselines/db-v26.js.map +1 -1
- package/dist/db/baselines/db-v27.d.ts +42 -0
- package/dist/db/baselines/db-v27.js +47 -0
- package/dist/db/baselines/db-v27.js.map +1 -0
- package/dist/db/baselines/index.js +2 -1
- package/dist/db/baselines/index.js.map +1 -1
- package/dist/db/locate.d.ts +4 -1
- package/dist/db/locate.js +3 -1
- package/dist/db/locate.js.map +1 -1
- package/dist/db/schema.d.ts +1 -1
- package/dist/db/schema.js +9 -0
- package/dist/db/schema.js.map +1 -1
- package/dist/deputy/bridge-worker.d.ts +1 -0
- package/dist/deputy/bridge-worker.js +79 -0
- package/dist/deputy/bridge-worker.js.map +1 -0
- package/dist/deputy/bridge.d.ts +14 -0
- package/dist/deputy/bridge.js +70 -0
- package/dist/deputy/bridge.js.map +1 -0
- package/dist/deputy/client.d.ts +19 -0
- package/dist/deputy/client.js +104 -0
- package/dist/deputy/client.js.map +1 -0
- package/dist/deputy/db-facade.d.ts +18 -0
- package/dist/deputy/db-facade.js +71 -0
- package/dist/deputy/db-facade.js.map +1 -0
- package/dist/deputy/files.d.ts +1 -0
- package/dist/deputy/files.js +16 -0
- package/dist/deputy/files.js.map +1 -0
- package/dist/deputy/install.d.ts +105 -0
- package/dist/deputy/install.js +467 -0
- package/dist/deputy/install.js.map +1 -0
- package/dist/deputy/notice.d.ts +6 -0
- package/dist/deputy/notice.js +28 -0
- package/dist/deputy/notice.js.map +1 -0
- package/dist/deputy/notices.d.ts +31 -0
- package/dist/deputy/notices.js +94 -0
- package/dist/deputy/notices.js.map +1 -0
- package/dist/deputy/osa.d.ts +21 -0
- package/dist/deputy/osa.js +72 -0
- package/dist/deputy/osa.js.map +1 -0
- package/dist/deputy/protocol.d.ts +86 -0
- package/dist/deputy/protocol.js +106 -0
- package/dist/deputy/protocol.js.map +1 -0
- package/dist/deputy/routing.d.ts +63 -0
- package/dist/deputy/routing.js +338 -0
- package/dist/deputy/routing.js.map +1 -0
- package/dist/deputy/shortcuts-exec.d.ts +10 -0
- package/dist/deputy/shortcuts-exec.js +50 -0
- package/dist/deputy/shortcuts-exec.js.map +1 -0
- package/dist/diagnose.d.ts +43 -1
- package/dist/diagnose.js +64 -2
- package/dist/diagnose.js.map +1 -1
- package/dist/index.d.ts +16 -2
- package/dist/index.js +17 -1
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.js +25 -7
- package/dist/mcp/server.js.map +1 -1
- package/dist/model/mappers.d.ts +12 -3
- package/dist/model/mappers.js +6 -1
- package/dist/model/mappers.js.map +1 -1
- package/dist/model/occurrences.d.ts +14 -1
- package/dist/model/occurrences.js +20 -4
- package/dist/model/occurrences.js.map +1 -1
- package/dist/model/recurrence.d.ts +64 -9
- package/dist/model/recurrence.js +94 -19
- package/dist/model/recurrence.js.map +1 -1
- package/dist/model/template-projection.d.ts +26 -0
- package/dist/model/template-projection.js +113 -0
- package/dist/model/template-projection.js.map +1 -0
- package/dist/op-result.d.ts +46 -0
- package/dist/op-result.js +156 -0
- package/dist/op-result.js.map +1 -0
- package/dist/paths.d.ts +8 -0
- package/dist/paths.js +10 -0
- package/dist/paths.js.map +1 -1
- package/dist/read/detail.js +7 -1
- package/dist/read/detail.js.map +1 -1
- package/dist/read/queries.js +8 -1
- package/dist/read/queries.js.map +1 -1
- package/dist/read/views.d.ts +6 -4
- package/dist/read/views.js +60 -18
- package/dist/read/views.js.map +1 -1
- package/dist/sync-health.js +8 -3
- package/dist/sync-health.js.map +1 -1
- package/dist/trace/tracer.d.ts +87 -0
- package/dist/trace/tracer.js +167 -0
- package/dist/trace/tracer.js.map +1 -0
- package/dist/write/accessibility-probe.js +4 -2
- package/dist/write/accessibility-probe.js.map +1 -1
- package/dist/write/automation-probe.js +5 -1
- package/dist/write/automation-probe.js.map +1 -1
- package/dist/write/availability.js +7 -3
- package/dist/write/availability.js.map +1 -1
- package/dist/write/clear-reminder.js +24 -21
- package/dist/write/clear-reminder.js.map +1 -1
- package/dist/write/commands.js +95 -45
- package/dist/write/commands.js.map +1 -1
- package/dist/write/completion-context.d.ts +57 -0
- package/dist/write/completion-context.js +49 -0
- package/dist/write/completion-context.js.map +1 -0
- package/dist/write/experimental.d.ts +19 -0
- package/dist/write/experimental.js +50 -0
- package/dist/write/experimental.js.map +1 -1
- package/dist/write/failure-hints.d.ts +10 -1
- package/dist/write/failure-hints.js +8 -0
- package/dist/write/failure-hints.js.map +1 -1
- package/dist/write/guards.d.ts +1 -1
- package/dist/write/guards.js +10 -0
- package/dist/write/guards.js.map +1 -1
- package/dist/write/move.js +14 -6
- package/dist/write/move.js.map +1 -1
- package/dist/write/operations.d.ts +40 -7
- package/dist/write/pipeline.d.ts +41 -0
- package/dist/write/pipeline.js +289 -19
- package/dist/write/pipeline.js.map +1 -1
- package/dist/write/pre-state.d.ts +1 -1
- package/dist/write/pre-state.js +35 -17
- package/dist/write/pre-state.js.map +1 -1
- package/dist/write/promote-clone.js +434 -19
- package/dist/write/promote-clone.js.map +1 -1
- package/dist/write/reorder.js +76 -27
- package/dist/write/reorder.js.map +1 -1
- package/dist/write/repeat-anchor.d.ts +140 -0
- package/dist/write/repeat-anchor.js +403 -0
- package/dist/write/repeat-anchor.js.map +1 -0
- package/dist/write/repeat-asserts.d.ts +28 -0
- package/dist/write/repeat-asserts.js +169 -0
- package/dist/write/repeat-asserts.js.map +1 -0
- package/dist/write/repeat-rule.js +37 -12
- package/dist/write/repeat-rule.js.map +1 -1
- package/dist/write/vectors/applescript.js +7 -16
- package/dist/write/vectors/applescript.js.map +1 -1
- package/dist/write/vectors/session-reachability.d.ts +133 -0
- package/dist/write/vectors/session-reachability.js +151 -0
- package/dist/write/vectors/session-reachability.js.map +1 -0
- package/dist/write/vectors/shortcuts.js +5 -14
- package/dist/write/vectors/shortcuts.js.map +1 -1
- package/dist/write/vectors/simulator.d.ts +16 -1
- package/dist/write/vectors/simulator.js +122 -32
- package/dist/write/vectors/simulator.js.map +1 -1
- package/dist/write/vectors/types.d.ts +183 -10
- package/dist/write/vectors/ui-recipes.d.ts +8 -0
- package/dist/write/vectors/ui-recipes.js +246 -58
- package/dist/write/vectors/ui-recipes.js.map +1 -1
- package/dist/write/vectors/ui.d.ts +156 -14
- package/dist/write/vectors/ui.js +846 -84
- package/dist/write/vectors/ui.js.map +1 -1
- package/dist/write/verify/delta.d.ts +12 -14
- package/dist/write/verify/delta.js +35 -34
- package/dist/write/verify/delta.js.map +1 -1
- package/dist/write/verify/poller.d.ts +13 -0
- package/dist/write/verify/poller.js +38 -0
- package/dist/write/verify/poller.js.map +1 -1
- package/package.json +8 -1
- package/schema/envelope.schema.json +22 -0
- package/scripts/build-helpers.sh +104 -0
- package/scripts/deputy-cert-setup.sh +60 -0
- package/skills/things-cli/SKILL.md +11 -3
- package/skills/things-cli/references/errors.md +4 -0
- package/skills/things-cli/references/repeating.md +69 -0
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `things helpers` — lifecycle for the optional helper pair (one installed
|
|
3
|
+
* bundle housing both):
|
|
4
|
+
*
|
|
5
|
+
* things-deputy — app automation (mutations), unsandboxed.
|
|
6
|
+
* things-reader — database/file reads, sandboxed to a user-granted folder.
|
|
7
|
+
*
|
|
8
|
+
* Running them means macOS permission prompts and grants attach to two stable
|
|
9
|
+
* identities instead of every terminal or agent runtime that invokes
|
|
10
|
+
* `things`, so grants stop re-prompting when those runtimes update. Routing is
|
|
11
|
+
* tri-state (`helpers-enabled`: auto | true | false, default auto —
|
|
12
|
+
* installation is the intent signal), overridable per invocation with
|
|
13
|
+
* THINGS_API_HELPERS or the global `--helpers`/`--no-helpers` flags; the CLI
|
|
14
|
+
* always falls back to direct execution when a helper is unavailable.
|
|
15
|
+
*/
|
|
16
|
+
import type { Command } from "commander";
|
|
17
|
+
export declare function registerHelpers(program: Command): void;
|
|
@@ -0,0 +1,148 @@
|
|
|
1
|
+
import { helpersStatus, ExitCode, grantReader, installHelpers, loadConfig, okEnvelope, restartHelpers, uninstallHelpers, } from "../../index.js";
|
|
2
|
+
function envelopeMeta(started) {
|
|
3
|
+
return { dbVersion: null, fingerprint: "unknown", elapsedMs: Date.now() - started };
|
|
4
|
+
}
|
|
5
|
+
/** One line describing what the configured mode means for this machine. */
|
|
6
|
+
function routingLine(status) {
|
|
7
|
+
switch (status.mode) {
|
|
8
|
+
case "true":
|
|
9
|
+
return "enabled — every process routes through the helpers, and reports when it cannot";
|
|
10
|
+
case "false":
|
|
11
|
+
return "disabled (things config set helpers-enabled auto)";
|
|
12
|
+
case "auto":
|
|
13
|
+
return status.bundleInstalled
|
|
14
|
+
? "auto — the installed helpers are used while healthy; a failure is reported, never silent"
|
|
15
|
+
: "auto — nothing installed, so everything runs direct (things helpers install to change that)";
|
|
16
|
+
}
|
|
17
|
+
}
|
|
18
|
+
function renderStatus(status) {
|
|
19
|
+
const deputy = status.deputy;
|
|
20
|
+
const lines = [`deputy: ${deputy.running ? "running" : "does not appear to be running"}`];
|
|
21
|
+
// The plain no-socket case needs no elaboration; a socket that exists but
|
|
22
|
+
// misbehaves (not answering, handshake refused) is worth its own line.
|
|
23
|
+
if (!deputy.running && !deputy.detail.startsWith("not running")) {
|
|
24
|
+
lines.push(` detail: ${deputy.detail}`);
|
|
25
|
+
}
|
|
26
|
+
if (deputy.hungSocket) {
|
|
27
|
+
lines.push(" next: `things helpers restart` — the socket is present but no handshake answers");
|
|
28
|
+
}
|
|
29
|
+
lines.push(` routing: ${routingLine(status)}`, ` launchd: ${deputy.plistInstalled ? (deputy.loaded ? "installed + loaded" : "installed, NOT loaded") : "not installed (things helpers install)"}`, ` bundle: ${status.bundleInstalled
|
|
30
|
+
? `installed${status.installedVersion !== null ? ` (v${status.installedVersion})` : ""}`
|
|
31
|
+
: "not installed"}`, ` socket: ${deputy.socketPath}`);
|
|
32
|
+
if (deputy.hello !== null) {
|
|
33
|
+
lines.push(` version: ${deputy.hello.deputyVersion} (protocol ${deputy.hello.protocol}, pid ${deputy.hello.pid})`);
|
|
34
|
+
}
|
|
35
|
+
if (deputy.signing !== null) {
|
|
36
|
+
lines.push(` signing: ${deputy.signing.state}${deputy.signing.authority !== null ? ` (${deputy.signing.authority})` : ""}`);
|
|
37
|
+
if (deputy.signing.state !== "signed") {
|
|
38
|
+
lines.push(" warning: an unsigned/ad-hoc helper loses its macOS grants on every rebuild — run scripts/deputy-cert-setup.sh once, rebuild, reinstall");
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
const reader = status.reader;
|
|
42
|
+
lines.push(`reader: ${reader.running ? (reader.granted ? "running, granted" : "running, NOT granted") : reader.installed ? reader.detail : "not installed"}`);
|
|
43
|
+
if (reader.running && !reader.granted) {
|
|
44
|
+
lines.push(" next: run `things helpers grant` and accept the panel (one time; the grant survives restarts, reboots, and rebuilds)");
|
|
45
|
+
}
|
|
46
|
+
if (reader.hungSocket) {
|
|
47
|
+
lines.push(" next: `things helpers restart` — the socket is present but no handshake answers");
|
|
48
|
+
}
|
|
49
|
+
return `${lines.join("\n")}\n`;
|
|
50
|
+
}
|
|
51
|
+
export function registerHelpers(program) {
|
|
52
|
+
const helpers = program
|
|
53
|
+
.command("helpers")
|
|
54
|
+
.description("Manage the optional helper pair that performs database reads and app automation " +
|
|
55
|
+
"on the CLI's behalf, so macOS permission grants attach to stable helpers instead " +
|
|
56
|
+
"of every terminal or agent runtime that runs `things`. Subcommands: status, " +
|
|
57
|
+
"install, grant, restart, uninstall.");
|
|
58
|
+
helpers
|
|
59
|
+
.command("status")
|
|
60
|
+
.description("Report both helpers' state: running or not, launchd installation, installed version, " +
|
|
61
|
+
"code-signing identity, the reader's grant, and the routing mode on this machine. " +
|
|
62
|
+
"Read-only.")
|
|
63
|
+
.option("--json", "emit versioned JSON envelope on stdout")
|
|
64
|
+
.action((opts) => {
|
|
65
|
+
const started = Date.now();
|
|
66
|
+
const status = helpersStatus(loadConfig().helpersMode);
|
|
67
|
+
if (opts.json === true) {
|
|
68
|
+
process.stdout.write(`${JSON.stringify(okEnvelope("helpers-status", status, envelopeMeta(started)))}\n`);
|
|
69
|
+
}
|
|
70
|
+
else {
|
|
71
|
+
process.stdout.write(renderStatus(status));
|
|
72
|
+
}
|
|
73
|
+
process.exitCode = ExitCode.Ok;
|
|
74
|
+
});
|
|
75
|
+
helpers
|
|
76
|
+
.command("install")
|
|
77
|
+
.description("Install the helper bundle: copy it to its stable location, register both helpers " +
|
|
78
|
+
"with launchd (starts now and on every login), and report signing + grant state. " +
|
|
79
|
+
"Under the default helpers-enabled auto, an installed and healthy helper is used from " +
|
|
80
|
+
"the next command on. Rerun after every rebuild.")
|
|
81
|
+
.option("--bundle <path>", "path to a built Things API Helper.app (default: deputy/build/Things API Helper.app in this package)")
|
|
82
|
+
.action((opts) => {
|
|
83
|
+
try {
|
|
84
|
+
const result = installHelpers(opts.bundle !== undefined ? { bundlePath: opts.bundle } : {});
|
|
85
|
+
process.stdout.write(`installed ${result.bundlePath}\nlaunchd agent: ${result.plistPath}\n`);
|
|
86
|
+
if (result.readerInstalled) {
|
|
87
|
+
process.stdout.write(result.readerGranted === true
|
|
88
|
+
? "reader: granted — file reads ride the scoped reader\n"
|
|
89
|
+
: result.readerGranted === false
|
|
90
|
+
? "reader: installed — run `things helpers grant` once to give it durable read access\n"
|
|
91
|
+
: "reader: installed, not answering yet — check `things helpers status`\n");
|
|
92
|
+
}
|
|
93
|
+
for (const warning of result.warnings) {
|
|
94
|
+
process.stderr.write(`warning: ${warning}\n`);
|
|
95
|
+
}
|
|
96
|
+
process.exitCode = ExitCode.Ok;
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
process.stderr.write(`error: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
100
|
+
process.exitCode = ExitCode.Environment;
|
|
101
|
+
}
|
|
102
|
+
});
|
|
103
|
+
helpers
|
|
104
|
+
.command("grant")
|
|
105
|
+
.description("One-time ceremony: opens a folder panel presented by the sandboxed reader helper, " +
|
|
106
|
+
"already showing the Things data folder. Accepting gives the reader durable read " +
|
|
107
|
+
"access to exactly that folder — it survives restarts, reboots, and updates, and " +
|
|
108
|
+
"macOS enforces that the reader can reach nothing else. Interactive: run this at " +
|
|
109
|
+
"the machine, not from an unattended session.")
|
|
110
|
+
.action(() => {
|
|
111
|
+
const result = grantReader();
|
|
112
|
+
if (result.granted) {
|
|
113
|
+
process.stdout.write("granted — file reads now ride the scoped reader\n");
|
|
114
|
+
process.exitCode = ExitCode.Ok;
|
|
115
|
+
}
|
|
116
|
+
else {
|
|
117
|
+
process.stderr.write(`not granted: ${result.detail}\n`);
|
|
118
|
+
process.exitCode = ExitCode.Environment;
|
|
119
|
+
}
|
|
120
|
+
});
|
|
121
|
+
helpers
|
|
122
|
+
.command("restart")
|
|
123
|
+
.description("Restart the launchd-managed helpers (picks up a rebuilt installed bundle).")
|
|
124
|
+
.action(() => {
|
|
125
|
+
try {
|
|
126
|
+
restartHelpers();
|
|
127
|
+
process.stdout.write("helpers restarted\n");
|
|
128
|
+
process.exitCode = ExitCode.Ok;
|
|
129
|
+
}
|
|
130
|
+
catch (err) {
|
|
131
|
+
process.stderr.write(`error: ${err instanceof Error ? err.message : String(err)}\n`);
|
|
132
|
+
process.exitCode = ExitCode.Environment;
|
|
133
|
+
}
|
|
134
|
+
});
|
|
135
|
+
helpers
|
|
136
|
+
.command("uninstall")
|
|
137
|
+
.description("Stop both helpers and remove their launchd registrations and the installed bundle. " +
|
|
138
|
+
"Local state (access token, logs, the reader's grant) is kept; routing config is " +
|
|
139
|
+
"untouched (commands fall back to direct execution).")
|
|
140
|
+
.action(() => {
|
|
141
|
+
const result = uninstallHelpers();
|
|
142
|
+
process.stdout.write(result.removed.length > 0
|
|
143
|
+
? `removed:\n${result.removed.map((p) => ` ${p}`).join("\n")}\n`
|
|
144
|
+
: "nothing installed\n");
|
|
145
|
+
process.exitCode = ExitCode.Ok;
|
|
146
|
+
});
|
|
147
|
+
}
|
|
148
|
+
//# sourceMappingURL=helpers.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"helpers.js","sourceRoot":"","sources":["../../../src/cli/commands/helpers.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `things op-result <op-id>` — a read-only CALLER-RECOVERY lookup over the local
|
|
3
|
+
* change history (RSPA1 deliverable 3). Thin surface over the library's opResult().
|
|
4
|
+
*
|
|
5
|
+
* When your environment kills long commands (a wall-time cap) before a write's
|
|
6
|
+
* result is printed — a `--dangerously-drive-gui` drive can run its full verify
|
|
7
|
+
* budget — dispatch the op with `--op-id <key>`, let it die, then run this in a
|
|
8
|
+
* fresh process to learn what ACTUALLY happened from the record the killed process
|
|
9
|
+
* already durably wrote. NEVER blind-retry a GUI drive.
|
|
10
|
+
*
|
|
11
|
+
* Always exit 0: this is a successful HISTORY READ regardless of the underlying
|
|
12
|
+
* op's outcome (which lives in `data.status` / `data.result`).
|
|
13
|
+
*/
|
|
14
|
+
import type { Command } from "commander";
|
|
15
|
+
export declare function registerOpResult(program: Command): void;
|
|
@@ -0,0 +1,39 @@
|
|
|
1
|
+
import { okEnvelope, opResult } from "../../index.js";
|
|
2
|
+
export function registerOpResult(program) {
|
|
3
|
+
program
|
|
4
|
+
.command("op-result")
|
|
5
|
+
.argument("<op-id>", "the --op-id / op_id the original write carried")
|
|
6
|
+
.description("Look up what happened to a write you dispatched with --op-id, from the local change " +
|
|
7
|
+
"history alone (opens no database, drives nothing). Use it to recover the outcome when " +
|
|
8
|
+
"your environment killed the command before it printed its result: let the command die, " +
|
|
9
|
+
"then run this. Reports FOUND (the final result + target + observation), INTENT-ONLY (the " +
|
|
10
|
+
"op started but no outcome was written — still running or the process died mid-flight, " +
|
|
11
|
+
"outcome UNCERTAIN), or UNKNOWN (no such op-id in history). Always exit 0 (a history read).")
|
|
12
|
+
.option("--json", "emit versioned JSON envelope on stdout")
|
|
13
|
+
.action((opId, opts) => {
|
|
14
|
+
const started = Date.now();
|
|
15
|
+
const data = opResult(opId);
|
|
16
|
+
const meta = {
|
|
17
|
+
dbVersion: null,
|
|
18
|
+
fingerprint: "unknown",
|
|
19
|
+
elapsedMs: Date.now() - started,
|
|
20
|
+
};
|
|
21
|
+
if (opts.json) {
|
|
22
|
+
process.stdout.write(`${JSON.stringify(okEnvelope("op-result", data, meta))}\n`);
|
|
23
|
+
}
|
|
24
|
+
else {
|
|
25
|
+
const head = data.status === "found"
|
|
26
|
+
? `${data.result} — ${data.op}${data.uuid !== null ? ` (${data.uuid})` : ""}`
|
|
27
|
+
: data.status === "intent-only"
|
|
28
|
+
? `intent-only — ${data.op} (no final outcome recorded)`
|
|
29
|
+
: "unknown op-id";
|
|
30
|
+
process.stdout.write(`op-result ${opId}: ${head}\n`);
|
|
31
|
+
process.stdout.write(` ${data.note}\n`);
|
|
32
|
+
if (data.status === "found" && data.observed !== null) {
|
|
33
|
+
process.stdout.write(` observed: ${JSON.stringify(data.observed)}\n`);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
process.exitCode = 0;
|
|
37
|
+
});
|
|
38
|
+
}
|
|
39
|
+
//# sourceMappingURL=op-result.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"op-result.js","sourceRoot":"","sources":["../../../src/cli/commands/op-result.ts"],"names":[],"mappings":"AAeA,OAAO,EAAE,UAAU,EAAE,QAAQ,EAAqB,MAAM,gBAAgB,CAAC;AAEzE,MAAM,UAAU,gBAAgB,CAAC,OAAgB;IAC/C,OAAO;SACJ,OAAO,CAAC,WAAW,CAAC;SACpB,QAAQ,CAAC,SAAS,EAAE,gDAAgD,CAAC;SACrE,WAAW,CACV,sFAAsF;QACpF,wFAAwF;QACxF,yFAAyF;QACzF,2FAA2F;QAC3F,wFAAwF;QACxF,4FAA4F,CAC/F;SACA,MAAM,CAAC,QAAQ,EAAE,wCAAwC,CAAC;SAC1D,MAAM,CAAC,CAAC,IAAY,EAAE,IAAwB,EAAE,EAAE;QACjD,MAAM,OAAO,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;QAC3B,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;QAC5B,MAAM,IAAI,GAAiB;YACzB,SAAS,EAAE,IAAI;YACf,WAAW,EAAE,SAAS;YACtB,SAAS,EAAE,IAAI,CAAC,GAAG,EAAE,GAAG,OAAO;SAChC,CAAC;QACF,IAAI,IAAI,CAAC,IAAI,EAAE,CAAC;YACd,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,IAAI,CAAC,SAAS,CAAC,UAAU,CAAC,WAAW,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC,IAAI,CAAC,CAAC;QACnF,CAAC;aAAM,CAAC;YACN,MAAM,IAAI,GACR,IAAI,CAAC,MAAM,KAAK,OAAO;gBACrB,CAAC,CAAC,GAAG,IAAI,CAAC,MAAM,MAAM,IAAI,CAAC,EAAE,GAAG,IAAI,CAAC,IAAI,KAAK,IAAI,CAAC,CAAC,CAAC,KAAK,IAAI,CAAC,IAAI,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE;gBAC7E,CAAC,CAAC,IAAI,CAAC,MAAM,KAAK,aAAa;oBAC7B,CAAC,CAAC,iBAAiB,IAAI,CAAC,EAAE,8BAA8B;oBACxD,CAAC,CAAC,eAAe,CAAC;YACxB,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,aAAa,IAAI,KAAK,IAAI,IAAI,CAAC,CAAC;YACrD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,IAAI,CAAC,IAAI,IAAI,CAAC,CAAC;YACzC,IAAI,IAAI,CAAC,MAAM,KAAK,OAAO,IAAI,IAAI,CAAC,QAAQ,KAAK,IAAI,EAAE,CAAC;gBACtD,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC;YACzE,CAAC;QACH,CAAC;QACD,OAAO,CAAC,QAAQ,GAAG,CAAC,CAAC;IACvB,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -23,8 +23,8 @@ export declare function addRepeatCalendarFlags(cmd: Command): Command;
|
|
|
23
23
|
export declare function addRepeatingRuleFieldsFromOpts(opts: Record<string, unknown>, frequency: RepeatFrequency, interval: number): AddRepeatingRuleFields;
|
|
24
24
|
/**
|
|
25
25
|
* Build the extended rule fields from CLI options (present keys only —
|
|
26
|
-
* exactOptionalPropertyTypes).
|
|
27
|
-
* (
|
|
28
|
-
*
|
|
26
|
+
* exactOptionalPropertyTypes). A wrong-frequency anchor flag is REFUSED here
|
|
27
|
+
* (UIC6-l), never silently dropped; other combination validity (e.g. weekdays on
|
|
28
|
+
* a non-weekly rule) is enforced downstream by assertRepeatRule.
|
|
29
29
|
*/
|
|
30
30
|
export declare function repeatRuleFlagsFromOpts(opts: Record<string, unknown>, frequency: RepeatFrequency): RepeatRuleFlagFields;
|
|
@@ -9,6 +9,8 @@ export function addRepeatRuleFlags(cmd) {
|
|
|
9
9
|
.option("--yearly-month <n>", "yearly only: the month (1–12)")
|
|
10
10
|
.option("--ends-after <n>", "stop after N occurrences (1–999)")
|
|
11
11
|
.option("--ends-on <date>", "YYYY-MM-DD — stop after this date")
|
|
12
|
+
.option("--when <date>", "YYYY-MM-DD — the first occurrence (drives the Repeat dialog's Next field); " +
|
|
13
|
+
"make-repeating defaults to the item's scheduled date")
|
|
12
14
|
.option("--reminder <time>", "HH:mm — a reminder time on each occurrence")
|
|
13
15
|
.option("--deadline", "give each occurrence a deadline")
|
|
14
16
|
.option("--start-days-earlier <n>", "with --deadline: start each occurrence N days before its deadline");
|
|
@@ -55,45 +57,100 @@ function dayAnchor(opts) {
|
|
|
55
57
|
return undefined;
|
|
56
58
|
}
|
|
57
59
|
/**
|
|
58
|
-
*
|
|
59
|
-
*
|
|
60
|
-
*
|
|
61
|
-
*
|
|
60
|
+
* The CALENDAR-ANCHOR flags that apply only to a SUBSET of frequencies, and the
|
|
61
|
+
* frequencies that consume each. A present anchor flag on any other frequency is
|
|
62
|
+
* a hard error — never a silent drop (UIC6-l). Exhaustive over the anchor flag
|
|
63
|
+
* set; a new anchor flag must earn a row here (and the mapper below consumes it).
|
|
64
|
+
* `weekdays` is intentionally ABSENT: it is mapped unconditionally and refused
|
|
65
|
+
* downstream by assertRepeatRule ("weekdays apply only to a weekly rule"), the
|
|
66
|
+
* mapped-contradiction path — this table is only for the SILENTLY-dropped anchors.
|
|
62
67
|
*/
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
68
|
+
const ANCHOR_FLAG_FREQUENCIES = {
|
|
69
|
+
onDay: ["monthly", "yearly"],
|
|
70
|
+
onWeekday: ["monthly", "yearly"],
|
|
71
|
+
onOrdinal: ["monthly", "yearly"],
|
|
72
|
+
yearlyMonth: ["yearly"],
|
|
73
|
+
};
|
|
74
|
+
/** The user-facing flag spelling for a camelCase option key (error messages). */
|
|
75
|
+
const ANCHOR_FLAG_SPELLING = {
|
|
76
|
+
onDay: "--on-day",
|
|
77
|
+
onWeekday: "--on-weekday",
|
|
78
|
+
onOrdinal: "--on-ordinal",
|
|
79
|
+
yearlyMonth: "--yearly-month",
|
|
80
|
+
};
|
|
81
|
+
/**
|
|
82
|
+
* Refuse a calendar-anchor flag supplied on a frequency that does not consume it
|
|
83
|
+
* (UIC6-l): `--frequency weekly --on-day 15` errors instead of silently running a
|
|
84
|
+
* plain weekly rule. Behavioral message — names the flag + the frequency it
|
|
85
|
+
* belongs to, never a mechanism.
|
|
86
|
+
*/
|
|
87
|
+
function assertAnchorFlagsMatchFrequency(opts, frequency) {
|
|
88
|
+
for (const [key, allowed] of Object.entries(ANCHOR_FLAG_FREQUENCIES)) {
|
|
89
|
+
if (opts[key] === undefined)
|
|
90
|
+
continue;
|
|
91
|
+
if (!allowed.includes(frequency)) {
|
|
92
|
+
const flag = ANCHOR_FLAG_SPELLING[key] ?? key;
|
|
93
|
+
throw new RangeError(`${flag} applies only to a ${allowed.join(" or ")} rule — this rule is ${frequency}`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
/**
|
|
98
|
+
* EXHAUSTIVE over every field of {@link RepeatRuleFlagFields}: each rule param is
|
|
99
|
+
* derived from the CLI options by exactly one entry, so a new param added to
|
|
100
|
+
* RepeatRuleParams breaks compilation here until it earns a flag mapping. This is
|
|
101
|
+
* what makes an accepted-but-dropped flag impossible for this vocabulary (the
|
|
102
|
+
* UIC6-l class) — the wrong-frequency guard above catches the inverse (a flag
|
|
103
|
+
* with no consuming frequency). Each entry returns the mapped value or
|
|
104
|
+
* `undefined` (absent — exactOptionalPropertyTypes).
|
|
105
|
+
*/
|
|
106
|
+
const FLAG_MAP = {
|
|
107
|
+
afterCompletion: (opts) => (opts["afterCompletion"] === true ? true : undefined),
|
|
108
|
+
weekdays: (opts) => typeof opts["weekdays"] === "string"
|
|
109
|
+
? opts["weekdays"]
|
|
69
110
|
.split(",")
|
|
70
111
|
.map((d) => d.trim().toLowerCase())
|
|
71
|
-
.filter((d) => d.length > 0)
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
if (frequency === "yearly") {
|
|
112
|
+
.filter((d) => d.length > 0)
|
|
113
|
+
: undefined,
|
|
114
|
+
monthly: (_opts, frequency, anchor) => frequency === "monthly" && anchor !== undefined ? anchor : undefined,
|
|
115
|
+
yearly: (opts, frequency, anchor) => {
|
|
116
|
+
if (frequency !== "yearly")
|
|
117
|
+
return undefined;
|
|
78
118
|
const month = opts["yearlyMonth"];
|
|
79
|
-
if (month
|
|
80
|
-
|
|
81
|
-
|
|
119
|
+
if (month === undefined && anchor === undefined)
|
|
120
|
+
return undefined;
|
|
121
|
+
const base = { month: Number(month) };
|
|
122
|
+
return (anchor === undefined ? base : { ...base, ...anchor });
|
|
123
|
+
},
|
|
124
|
+
ends: (opts) => {
|
|
125
|
+
if (opts["endsAfter"] !== undefined)
|
|
126
|
+
return { kind: "after", count: Number(opts["endsAfter"]) };
|
|
127
|
+
if (typeof opts["endsOn"] === "string")
|
|
128
|
+
return { kind: "on-date", date: opts["endsOn"] };
|
|
129
|
+
return undefined;
|
|
130
|
+
},
|
|
131
|
+
reminder: (opts) => (typeof opts["reminder"] === "string" ? opts["reminder"] : undefined),
|
|
132
|
+
next: (opts) => (typeof opts["when"] === "string" ? opts["when"] : undefined),
|
|
133
|
+
deadline: (opts) => (opts["deadline"] === true ? true : undefined),
|
|
134
|
+
startDaysEarlier: (opts) => opts["startDaysEarlier"] !== undefined ? Number(opts["startDaysEarlier"]) : undefined,
|
|
135
|
+
};
|
|
136
|
+
/**
|
|
137
|
+
* Build the extended rule fields from CLI options (present keys only —
|
|
138
|
+
* exactOptionalPropertyTypes). A wrong-frequency anchor flag is REFUSED here
|
|
139
|
+
* (UIC6-l), never silently dropped; other combination validity (e.g. weekdays on
|
|
140
|
+
* a non-weekly rule) is enforced downstream by assertRepeatRule.
|
|
141
|
+
*/
|
|
142
|
+
export function repeatRuleFlagsFromOpts(opts, frequency) {
|
|
143
|
+
assertAnchorFlagsMatchFrequency(opts, frequency);
|
|
144
|
+
const anchor = dayAnchor(opts);
|
|
145
|
+
const fields = {};
|
|
146
|
+
for (const key of Object.keys(FLAG_MAP)) {
|
|
147
|
+
const value = FLAG_MAP[key](opts, frequency, anchor);
|
|
148
|
+
if (value !== undefined) {
|
|
149
|
+
// The map's per-key return type is exactly RepeatRuleFlagFields[K]; the
|
|
150
|
+
// index write is safe but TS cannot narrow K across the loop.
|
|
151
|
+
fields[key] = value;
|
|
82
152
|
}
|
|
83
153
|
}
|
|
84
|
-
if (opts["endsAfter"] !== undefined) {
|
|
85
|
-
fields.ends = { kind: "after", count: Number(opts["endsAfter"]) };
|
|
86
|
-
}
|
|
87
|
-
else if (typeof opts["endsOn"] === "string") {
|
|
88
|
-
fields.ends = { kind: "on-date", date: opts["endsOn"] };
|
|
89
|
-
}
|
|
90
|
-
if (typeof opts["reminder"] === "string")
|
|
91
|
-
fields.reminder = opts["reminder"];
|
|
92
|
-
if (opts["deadline"] === true)
|
|
93
|
-
fields.deadline = true;
|
|
94
|
-
if (opts["startDaysEarlier"] !== undefined) {
|
|
95
|
-
fields.startDaysEarlier = Number(opts["startDaysEarlier"]);
|
|
96
|
-
}
|
|
97
154
|
return fields;
|
|
98
155
|
}
|
|
99
156
|
//# sourceMappingURL=repeat-flags.js.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"repeat-flags.js","sourceRoot":"","sources":["../../../src/cli/commands/repeat-flags.ts"],"names":[],"mappings":"AAsBA,8DAA8D;AAC9D,MAAM,UAAU,kBAAkB,CAAC,GAAY;IAC7C,OAAO,GAAG;SACP,MAAM,CACL,oBAAoB,EACpB,6EAA6E,CAC9E;SACA,MAAM,CACL,mBAAmB,EACnB,qEAAqE,CACtE;SACA,MAAM,CAAC,gBAAgB,EAAE,2DAA2D,CAAC;SACrF,MAAM,CACL,wBAAwB,EACxB,4EAA4E,CAC7E;SACA,MAAM,CACL,kBAAkB,EAClB,uEAAuE,CACxE;SACA,MAAM,CAAC,oBAAoB,EAAE,+BAA+B,CAAC;SAC7D,MAAM,CAAC,kBAAkB,EAAE,kCAAkC,CAAC;SAC9D,MAAM,CAAC,kBAAkB,EAAE,mCAAmC,CAAC;SAC/D,MAAM,CAAC,mBAAmB,EAAE,4CAA4C,CAAC;SACzE,MAAM,CAAC,YAAY,EAAE,iCAAiC,CAAC;SACvD,MAAM,CACL,0BAA0B,EAC1B,mEAAmE,CACpE,CAAC;AACN,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,sBAAsB,CAAC,GAAY;IACjD,OAAO,GAAG;SACP,MAAM,CACL,oBAAoB,EACpB,6EAA6E,CAC9E;SACA,MAAM,CACL,mBAAmB,EACnB,qEAAqE,CACtE;SACA,MAAM,CAAC,gBAAgB,EAAE,2DAA2D,CAAC;SACrF,MAAM,CACL,wBAAwB,EACxB,4EAA4E,CAC7E;SACA,MAAM,CACL,kBAAkB,EAClB,uEAAuE,CACxE;SACA,MAAM,CAAC,oBAAoB,EAAE,+BAA+B,CAAC;SAC7D,MAAM,CAAC,kBAAkB,EAAE,kCAAkC,CAAC;SAC9D,MAAM,CAAC,kBAAkB,EAAE,mCAAmC,CAAC,CAAC;AACrE,CAAC;AAED,+FAA+F;AAC/F,MAAM,UAAU,8BAA8B,CAC5C,IAA6B,EAC7B,SAA0B,EAC1B,QAAgB;IAEhB,MAAM,EACJ,QAAQ,EAAE,EAAE,EACZ,QAAQ,EAAE,EAAE,EACZ,gBAAgB,EAAE,EAAE,EACpB,GAAG,IAAI,EACR,GAAG,uBAAuB,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IAC7C,OAAO,EAAE,SAAS,EAAE,QAAQ,EAAE,GAAG,IAAI,EAAE,CAAC;AAC1C,CAAC;AAED,iFAAiF;AACjF,6EAA6E;AAC7E,gEAAgE;AAChE,SAAS,SAAS,CAAC,IAA6B;IAC9C,MAAM,KAAK,GAAG,IAAI,CAAC,OAAO,CAAuB,CAAC;IAClD,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,CAAuB,CAAC;IAC1D,MAAM,SAAS,GAAG,IAAI,CAAC,WAAW,CAAuB,CAAC;IAC1D,IAAI,KAAK,KAAK,SAAS,EAAE,CAAC;QACxB,OAAO,EAAE,GAAG,EAAE,KAAK,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,KAAK,CAAC,EAAE,CAAC;IAC5D,CAAC;IACD,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,KAAK,SAAS,EAAE,CAAC;QACvD,OAAO;YACL,OAAO,EAAE,SAAoB;YAC7B,OAAO,EAAE,CAAC,SAAS,KAAK,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,CAAC,SAAS,CAAC,CAAmB;SAC/E,CAAC;IACJ,CAAC;IACD,OAAO,SAAS,CAAC;AACnB,CAAC;AAED
|
|
1
|
+
{"version":3,"file":"repeat-flags.js","sourceRoot":"","sources":["../../../src/cli/commands/repeat-flags.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
import { readFileSync } from "node:fs";
|
|
2
|
+
import { armInterrupt, disarmInterrupt } from "../interrupt.js";
|
|
3
|
+
import { isDevVersion } from "../skill.js";
|
|
4
|
+
import { CLI_VERSION } from "../version.js";
|
|
2
5
|
import { addRepeatCalendarFlags, addRepeatingRuleFieldsFromOpts, addRepeatRuleFlags, repeatRuleFlagsFromOpts, } from "./repeat-flags.js";
|
|
3
|
-
import { aggregateExitCode, blockedCode, capabilitiesTable, ClockError, describeConfig, errorEnvelope, ExitCode, getConfigKey, mutationWireData, okEnvelope, openThings, OP_ID_RE, outcomeFailed, ReferenceResolutionError, saveConfigKey, splitWhenSugar, ThingsDbNotFoundError, ThingsDbOpenError, verifyFailedCode, } from "../../index.js";
|
|
6
|
+
import { aggregateExitCode, blockedCode, capabilitiesTable, ClockError, closeCliTrace, describeConfig, errorEnvelope, ExitCode, HELPERS_MODES, installCliTrace, getConfigKey, parseHelpersMode, mutationWireData, okEnvelope, openThings, OP_ID_RE, outcomeFailed, ReferenceResolutionError, saveConfigKey, splitWhenSugar, trace, ThingsDbNotFoundError, ThingsDbOpenError, verifyFailedCode, } from "../../index.js";
|
|
4
7
|
import { usageError } from "../read-driver.js";
|
|
5
8
|
import { dim } from "../style.js";
|
|
6
9
|
function addWriteFlags(cmd) {
|
|
@@ -145,7 +148,12 @@ function headingPlacement(c, projectUuid, opts) {
|
|
|
145
148
|
/** Add the mandatory GUI-drive acknowledgement to a ui-vector command. */
|
|
146
149
|
function addDriveGuiFlag(cmd) {
|
|
147
150
|
return cmd.option("--dangerously-drive-gui", "required: visibly drives the Things app to make a change it offers nowhere else; " +
|
|
148
|
-
"also needs `things config set ui-enabled true
|
|
151
|
+
"also needs `things config set ui-enabled true`. Driving the app can take over a " +
|
|
152
|
+
"minute on a large database, so allow a generous timeout (180s or more) — if your own " +
|
|
153
|
+
"timeout stops the command first you get empty output, not a result. A timeout or empty " +
|
|
154
|
+
"output is not a success: the change may still have landed, so re-check with " +
|
|
155
|
+
"`things show <ref>` before retrying, and never fire an identical retry (it can duplicate " +
|
|
156
|
+
"the change) — stop and report if the state is wrong or unclear");
|
|
149
157
|
}
|
|
150
158
|
function collect(value, previous) {
|
|
151
159
|
return [...previous, value];
|
|
@@ -186,6 +194,16 @@ async function runWrite(opts, fn, emitFn = emitResult) {
|
|
|
186
194
|
if (!opIdOk(opts))
|
|
187
195
|
return;
|
|
188
196
|
const started = Date.now();
|
|
197
|
+
// Dev-mode step-timeline trace + signal-safe interrupt guard (TRACE1, #487).
|
|
198
|
+
// Scoped to the write driver — the invocations where a per-step timeline earns
|
|
199
|
+
// its keep, and where a mid-drive kill would otherwise leave empty stdout. The
|
|
200
|
+
// sink is a no-op unless tracing is on (a `-dev` build, or config/env forced).
|
|
201
|
+
installCliTrace({
|
|
202
|
+
argv: process.argv.slice(1),
|
|
203
|
+
version: CLI_VERSION,
|
|
204
|
+
isDev: isDevVersion(CLI_VERSION),
|
|
205
|
+
});
|
|
206
|
+
armInterrupt(opts.json === true);
|
|
189
207
|
let client = null;
|
|
190
208
|
const meta = (client_) => {
|
|
191
209
|
let dbVersion = null;
|
|
@@ -239,6 +257,16 @@ async function runWrite(opts, fn, emitFn = emitResult) {
|
|
|
239
257
|
}
|
|
240
258
|
finally {
|
|
241
259
|
client?.close();
|
|
260
|
+
// Close the trace with a final result line (the exit code the caller sees),
|
|
261
|
+
// then disarm the interrupt guard so a later signal during teardown/reads
|
|
262
|
+
// emits nothing.
|
|
263
|
+
trace(() => ({
|
|
264
|
+
phase: "invocation-end",
|
|
265
|
+
exitCode: process.exitCode ?? 0,
|
|
266
|
+
elapsedMs: Date.now() - started,
|
|
267
|
+
}));
|
|
268
|
+
disarmInterrupt();
|
|
269
|
+
closeCliTrace();
|
|
242
270
|
}
|
|
243
271
|
}
|
|
244
272
|
/**
|
|
@@ -258,6 +286,26 @@ function emitPreserveNote(result) {
|
|
|
258
286
|
process.stderr.write(`warning: preserve-modified: ${f.uuid}: ${f.detail}\n`);
|
|
259
287
|
}
|
|
260
288
|
}
|
|
289
|
+
/**
|
|
290
|
+
* TTY disclosure for the HINTS1 completion-context on a verified complete/cancel:
|
|
291
|
+
* a dim line naming the OPEN work remaining in the to-do's project and/or Today,
|
|
292
|
+
* so an operator (or an agent reading the human render) sees an emptied container
|
|
293
|
+
* at a glance. Silent when neither arm applies (the field is absent).
|
|
294
|
+
*/
|
|
295
|
+
function emitContextNote(result) {
|
|
296
|
+
const context = result.context;
|
|
297
|
+
if (context === undefined)
|
|
298
|
+
return;
|
|
299
|
+
const parts = [];
|
|
300
|
+
if (context.project !== undefined) {
|
|
301
|
+
parts.push(`project "${context.project.title}": ${context.project.remainingOpen} open remaining`);
|
|
302
|
+
}
|
|
303
|
+
if (context.today !== undefined) {
|
|
304
|
+
parts.push(`today: ${context.today.remainingOpen} open remaining`);
|
|
305
|
+
}
|
|
306
|
+
if (parts.length > 0)
|
|
307
|
+
process.stdout.write(dim(` ${parts.join("; ")}\n`));
|
|
308
|
+
}
|
|
261
309
|
function emitResult(result, opts, meta) {
|
|
262
310
|
switch (result.kind) {
|
|
263
311
|
case "bounce-aborted": {
|
|
@@ -290,6 +338,7 @@ function emitResult(result, opts, meta) {
|
|
|
290
338
|
: `vector=${result.vector}, tier=${result.tier}, verified`;
|
|
291
339
|
process.stdout.write(`ok ${result.op}${uuid} (${status})\n`);
|
|
292
340
|
emitPreserveNote(result);
|
|
341
|
+
emitContextNote(result);
|
|
293
342
|
}
|
|
294
343
|
process.exitCode = ExitCode.Ok;
|
|
295
344
|
return;
|
|
@@ -305,6 +354,7 @@ function emitResult(result, opts, meta) {
|
|
|
305
354
|
` invocation: ${result.plan.invocation}`,
|
|
306
355
|
` hazards checked: ${result.plan.hazardsChecked.join(", ") || "none"}`,
|
|
307
356
|
` expected delta: ${JSON.stringify(result.plan.expectedDelta)}`,
|
|
357
|
+
...(result.plan.notes ?? []).map((n) => ` note: ${n}`),
|
|
308
358
|
"",
|
|
309
359
|
].join("\n"));
|
|
310
360
|
}
|
|
@@ -1374,7 +1424,12 @@ export function registerWriteCommands(program) {
|
|
|
1374
1424
|
.option("--notes <text>", "notes body")
|
|
1375
1425
|
.option("--when <value>", "today | evening | anytime | someday | YYYY-MM-DD")
|
|
1376
1426
|
.option("--reminder <time>", "HH:mm reminder (needs a schedulable --when)")
|
|
1377
|
-
.option("--deadline <date>", "YYYY-MM-DD"
|
|
1427
|
+
.option("--deadline <date>", "YYYY-MM-DD — deadlines EVERY occurrence: each starts (deadline − --when) days " +
|
|
1428
|
+
"before its own deadline (needs a concrete --when, on or before the deadline; " +
|
|
1429
|
+
"alternative spelling of --start-days-earlier — give one or the other, both must agree)")
|
|
1430
|
+
.option("--start-days-earlier <n>", "deadlines EVERY occurrence, naming the lead directly: each starts N days before " +
|
|
1431
|
+
"its own deadline (needs a concrete --when; alternative spelling of --deadline <date> — " +
|
|
1432
|
+
"give one or the other, both must agree)")
|
|
1378
1433
|
.option("--tag <name>", "tag to attach (repeatable)", collect, [])
|
|
1379
1434
|
.option("--checklist-item <title>", "checklist item (repeatable)", collect, [])
|
|
1380
1435
|
.option("--project <ref>", "destination project (uuid or unique name)")
|
|
@@ -1396,6 +1451,9 @@ export function registerWriteCommands(program) {
|
|
|
1396
1451
|
...(opts["when"] !== undefined && { when: opts["when"] }),
|
|
1397
1452
|
...(opts["reminder"] !== undefined && { reminder: opts["reminder"] }),
|
|
1398
1453
|
...(opts["deadline"] !== undefined && { deadline: opts["deadline"] }),
|
|
1454
|
+
...(opts["startDaysEarlier"] !== undefined && {
|
|
1455
|
+
startDaysEarlier: Number(opts["startDaysEarlier"]),
|
|
1456
|
+
}),
|
|
1399
1457
|
...(tags.length > 0 && { tags }),
|
|
1400
1458
|
...(checklistItems.length > 0 && { checklistItems }),
|
|
1401
1459
|
...(projectRef !== undefined && { project: projectRef }),
|
|
@@ -2106,7 +2164,8 @@ export function registerWriteCommands(program) {
|
|
|
2106
2164
|
.command("set <key> <value>")
|
|
2107
2165
|
.description("Persist a config key: profile | maxDisruption | actor | auditEnabled | " +
|
|
2108
2166
|
"accepted-fingerprint | certified-app-version | allow-experimental | bounce-enabled | " +
|
|
2109
|
-
"bounce-max-items | ui-enabled |
|
|
2167
|
+
"bounce-max-items | auto-launch | helpers-enabled (auto | true | false) | ui-enabled | " +
|
|
2168
|
+
"ui-drive-budget-ms | trace | scope")
|
|
2110
2169
|
.action((key, value, opts) => {
|
|
2111
2170
|
const map = {
|
|
2112
2171
|
profile: "profile",
|
|
@@ -2118,7 +2177,11 @@ export function registerWriteCommands(program) {
|
|
|
2118
2177
|
"allow-experimental": "allowExperimental",
|
|
2119
2178
|
"bounce-enabled": "bounceEnabled",
|
|
2120
2179
|
"bounce-max-items": "bounceMaxItems",
|
|
2180
|
+
"auto-launch": "autoLaunch",
|
|
2181
|
+
"helpers-enabled": "helpersMode",
|
|
2121
2182
|
"ui-enabled": "uiEnabled",
|
|
2183
|
+
"ui-drive-budget-ms": "uiDriveBudgetMs",
|
|
2184
|
+
trace: "traceEnabled",
|
|
2122
2185
|
scope: "scope",
|
|
2123
2186
|
};
|
|
2124
2187
|
const target = map[key];
|
|
@@ -2127,12 +2190,22 @@ export function registerWriteCommands(program) {
|
|
|
2127
2190
|
process.exitCode = ExitCode.Usage;
|
|
2128
2191
|
return;
|
|
2129
2192
|
}
|
|
2130
|
-
|
|
2193
|
+
// `helpers-enabled` is TRI-state (auto | true | false): anything else is
|
|
2194
|
+
// refused rather than silently coerced to a boolean, so a typo can never
|
|
2195
|
+
// read as "off" on a machine that meant "auto".
|
|
2196
|
+
if (target === "helpersMode" && parseHelpersMode(value) === undefined) {
|
|
2197
|
+
process.stderr.write(`error: helpers-enabled accepts ${HELPERS_MODES.join(" | ")} (got "${value}")\n`);
|
|
2198
|
+
process.exitCode = ExitCode.Usage;
|
|
2199
|
+
return;
|
|
2200
|
+
}
|
|
2201
|
+
const parsed = target === "maxDisruption" || target === "bounceMaxItems" || target === "uiDriveBudgetMs"
|
|
2131
2202
|
? Number(value)
|
|
2132
2203
|
: target === "auditEnabled" ||
|
|
2133
2204
|
target === "allowExperimental" ||
|
|
2134
2205
|
target === "bounceEnabled" ||
|
|
2135
|
-
target === "
|
|
2206
|
+
target === "autoLaunch" ||
|
|
2207
|
+
target === "uiEnabled" ||
|
|
2208
|
+
target === "traceEnabled"
|
|
2136
2209
|
? value === "true"
|
|
2137
2210
|
: value;
|
|
2138
2211
|
// Universal `--dry-run` (../dry-run.ts): `config set` writes local config
|