things-api 0.5.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/LICENSE +21 -0
- package/README.md +77 -0
- package/bin/things.js +9 -0
- package/dist/audit/log.d.ts +10 -0
- package/dist/audit/log.js +31 -0
- package/dist/audit/log.js.map +1 -0
- package/dist/audit/schema.d.ts +37 -0
- package/dist/audit/schema.js +9 -0
- package/dist/audit/schema.js.map +1 -0
- package/dist/cli/commands/doctor.d.ts +9 -0
- package/dist/cli/commands/doctor.js +60 -0
- package/dist/cli/commands/doctor.js.map +1 -0
- package/dist/cli/commands/mcp.d.ts +7 -0
- package/dist/cli/commands/mcp.js +26 -0
- package/dist/cli/commands/mcp.js.map +1 -0
- package/dist/cli/commands/project.d.ts +5 -0
- package/dist/cli/commands/project.js +50 -0
- package/dist/cli/commands/project.js.map +1 -0
- package/dist/cli/commands/reads.d.ts +21 -0
- package/dist/cli/commands/reads.js +295 -0
- package/dist/cli/commands/reads.js.map +1 -0
- package/dist/cli/commands/snapshot.d.ts +7 -0
- package/dist/cli/commands/snapshot.js +22 -0
- package/dist/cli/commands/snapshot.js.map +1 -0
- package/dist/cli/commands/todo.d.ts +6 -0
- package/dist/cli/commands/todo.js +43 -0
- package/dist/cli/commands/todo.js.map +1 -0
- package/dist/cli/commands/writes.d.ts +9 -0
- package/dist/cli/commands/writes.js +994 -0
- package/dist/cli/commands/writes.js.map +1 -0
- package/dist/cli/exit-codes.d.ts +26 -0
- package/dist/cli/exit-codes.js +26 -0
- package/dist/cli/exit-codes.js.map +1 -0
- package/dist/cli/main.d.ts +4 -0
- package/dist/cli/main.js +73 -0
- package/dist/cli/main.js.map +1 -0
- package/dist/cli/output.d.ts +42 -0
- package/dist/cli/output.js +16 -0
- package/dist/cli/output.js.map +1 -0
- package/dist/cli/style.d.ts +6 -0
- package/dist/cli/style.js +25 -0
- package/dist/cli/style.js.map +1 -0
- package/dist/client.d.ts +184 -0
- package/dist/client.js +187 -0
- package/dist/client.js.map +1 -0
- package/dist/config.d.ts +31 -0
- package/dist/config.js +76 -0
- package/dist/config.js.map +1 -0
- package/dist/contracts.d.ts +79 -0
- package/dist/contracts.js +46 -0
- package/dist/contracts.js.map +1 -0
- package/dist/db/baselines/db-v26.d.ts +8 -0
- package/dist/db/baselines/db-v26.js +16 -0
- package/dist/db/baselines/db-v26.js.map +1 -0
- package/dist/db/baselines/index.d.ts +3 -0
- package/dist/db/baselines/index.js +4 -0
- package/dist/db/baselines/index.js.map +1 -0
- package/dist/db/connection.d.ts +22 -0
- package/dist/db/connection.js +40 -0
- package/dist/db/connection.js.map +1 -0
- package/dist/db/fingerprint.d.ts +42 -0
- package/dist/db/fingerprint.js +82 -0
- package/dist/db/fingerprint.js.map +1 -0
- package/dist/db/locate.d.ts +13 -0
- package/dist/db/locate.js +44 -0
- package/dist/db/locate.js.map +1 -0
- package/dist/db/schema.d.ts +37 -0
- package/dist/db/schema.js +81 -0
- package/dist/db/schema.js.map +1 -0
- package/dist/diagnose.d.ts +67 -0
- package/dist/diagnose.js +143 -0
- package/dist/diagnose.js.map +1 -0
- package/dist/index.d.ts +46 -0
- package/dist/index.js +23 -0
- package/dist/index.js.map +1 -0
- package/dist/mcp/server.d.ts +8 -0
- package/dist/mcp/server.js +1002 -0
- package/dist/mcp/server.js.map +1 -0
- package/dist/model/dates.d.ts +38 -0
- package/dist/model/dates.js +104 -0
- package/dist/model/dates.js.map +1 -0
- package/dist/model/entities.d.ts +117 -0
- package/dist/model/entities.js +21 -0
- package/dist/model/entities.js.map +1 -0
- package/dist/model/mappers.d.ts +55 -0
- package/dist/model/mappers.js +105 -0
- package/dist/model/mappers.js.map +1 -0
- package/dist/model/occurrences.d.ts +46 -0
- package/dist/model/occurrences.js +164 -0
- package/dist/model/occurrences.js.map +1 -0
- package/dist/model/recurrence.d.ts +52 -0
- package/dist/model/recurrence.js +164 -0
- package/dist/model/recurrence.js.map +1 -0
- package/dist/paths.d.ts +6 -0
- package/dist/paths.js +30 -0
- package/dist/paths.js.map +1 -0
- package/dist/read/detail.d.ts +8 -0
- package/dist/read/detail.js +34 -0
- package/dist/read/detail.js.map +1 -0
- package/dist/read/project-view.d.ts +34 -0
- package/dist/read/project-view.js +87 -0
- package/dist/read/project-view.js.map +1 -0
- package/dist/read/queries.d.ts +39 -0
- package/dist/read/queries.js +134 -0
- package/dist/read/queries.js.map +1 -0
- package/dist/read/snapshot.d.ts +25 -0
- package/dist/read/snapshot.js +39 -0
- package/dist/read/snapshot.js.map +1 -0
- package/dist/read/tags.d.ts +17 -0
- package/dist/read/tags.js +64 -0
- package/dist/read/tags.js.map +1 -0
- package/dist/read/views.d.ts +152 -0
- package/dist/read/views.js +322 -0
- package/dist/read/views.js.map +1 -0
- package/dist/surface-copy.d.ts +15 -0
- package/dist/surface-copy.js +16 -0
- package/dist/surface-copy.js.map +1 -0
- package/dist/write/automation-probe.d.ts +12 -0
- package/dist/write/automation-probe.js +59 -0
- package/dist/write/automation-probe.js.map +1 -0
- package/dist/write/batch.d.ts +51 -0
- package/dist/write/batch.js +97 -0
- package/dist/write/batch.js.map +1 -0
- package/dist/write/capabilities.d.ts +16 -0
- package/dist/write/capabilities.js +16 -0
- package/dist/write/capabilities.js.map +1 -0
- package/dist/write/commands.d.ts +32 -0
- package/dist/write/commands.js +1274 -0
- package/dist/write/commands.js.map +1 -0
- package/dist/write/environment.d.ts +29 -0
- package/dist/write/environment.js +105 -0
- package/dist/write/environment.js.map +1 -0
- package/dist/write/experimental.d.ts +7 -0
- package/dist/write/experimental.js +39 -0
- package/dist/write/experimental.js.map +1 -0
- package/dist/write/failure-hints.d.ts +32 -0
- package/dist/write/failure-hints.js +71 -0
- package/dist/write/failure-hints.js.map +1 -0
- package/dist/write/guards.d.ts +21 -0
- package/dist/write/guards.js +312 -0
- package/dist/write/guards.js.map +1 -0
- package/dist/write/lock.d.ts +10 -0
- package/dist/write/lock.js +70 -0
- package/dist/write/lock.js.map +1 -0
- package/dist/write/operations.d.ts +262 -0
- package/dist/write/operations.js +34 -0
- package/dist/write/operations.js.map +1 -0
- package/dist/write/pipeline.d.ts +90 -0
- package/dist/write/pipeline.js +375 -0
- package/dist/write/pipeline.js.map +1 -0
- package/dist/write/planner.d.ts +40 -0
- package/dist/write/planner.js +57 -0
- package/dist/write/planner.js.map +1 -0
- package/dist/write/pre-state.d.ts +125 -0
- package/dist/write/pre-state.js +299 -0
- package/dist/write/pre-state.js.map +1 -0
- package/dist/write/reopen.d.ts +29 -0
- package/dist/write/reopen.js +63 -0
- package/dist/write/reopen.js.map +1 -0
- package/dist/write/reorder.d.ts +19 -0
- package/dist/write/reorder.js +285 -0
- package/dist/write/reorder.js.map +1 -0
- package/dist/write/undo.d.ts +53 -0
- package/dist/write/undo.js +703 -0
- package/dist/write/undo.js.map +1 -0
- package/dist/write/vectors/applescript.d.ts +5 -0
- package/dist/write/vectors/applescript.js +216 -0
- package/dist/write/vectors/applescript.js.map +1 -0
- package/dist/write/vectors/registry.d.ts +2 -0
- package/dist/write/vectors/registry.js +11 -0
- package/dist/write/vectors/registry.js.map +1 -0
- package/dist/write/vectors/types.d.ts +48 -0
- package/dist/write/vectors/types.js +2 -0
- package/dist/write/vectors/types.js.map +1 -0
- package/dist/write/vectors/url-scheme.d.ts +3 -0
- package/dist/write/vectors/url-scheme.js +176 -0
- package/dist/write/vectors/url-scheme.js.map +1 -0
- package/dist/write/verify/delta.d.ts +126 -0
- package/dist/write/verify/delta.js +281 -0
- package/dist/write/verify/delta.js.map +1 -0
- package/dist/write/verify/poller.d.ts +24 -0
- package/dist/write/verify/poller.js +28 -0
- package/dist/write/verify/poller.js.map +1 -0
- package/package.json +52 -0
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Mike Greiling
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/README.md
ADDED
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
# things-api
|
|
2
|
+
|
|
3
|
+
A typed TypeScript library + CLI (`things`) for programmatic interaction with [Things 3](https://culturedcode.com/things/) by Cultured Code.
|
|
4
|
+
|
|
5
|
+
**Status: read + write + MCP layers live (v0.3.0 — see [CHANGELOG.md](CHANGELOG.md)).** Reads go straight to the local SQLite database (UI-exact Today ordering, decoded repeat rules, occurrence projections); writes run a verified pipeline over two lab-validated vectors (URL scheme + AppleScript) with hazard guards, disruption-tier policy, a JSONL audit trail, batch mode, audit-replay undo, full project lifecycle (complete/cancel/reopen/restore), container detach, granular stateful checklists, and tag hierarchy management incl. un-nesting. See [docs/design/](docs/design/) for the architecture and VM-lab design, [docs/lab/](docs/lab/harness.md) for the probe harness and campaign results the write layer is grounded in, and [docs/atlas/](docs/atlas/schema-v26.md) for the database↔UI map.
|
|
6
|
+
|
|
7
|
+
```sh
|
|
8
|
+
things today --json # read: your Today list, Evening split, UI order
|
|
9
|
+
things upcoming --horizon 5 # date plan incl. projected repeat occurrences
|
|
10
|
+
things todo add "Buy milk" --when today --tags errands --dry-run # plan without executing
|
|
11
|
+
things undo --dry-run # inverse plan for the last mutation (audit replay)
|
|
12
|
+
things capabilities --op todo.delete # what's possible, per vector, with evidence
|
|
13
|
+
```
|
|
14
|
+
|
|
15
|
+
## Requirements & first-run setup
|
|
16
|
+
|
|
17
|
+
Things 3 installed and launched once, Node ≥ 24, and a handful of one-time macOS consents / Things settings depending on what you use (file-access consent for reads; "Enable Things URLs" + Automation consents for writes). **See [docs/setup.md](docs/setup.md)** — including the dedicated-automation-Mac checklist. `things doctor` validates your setup and prints remediation for anything missing.
|
|
18
|
+
|
|
19
|
+
### Development install
|
|
20
|
+
|
|
21
|
+
To get a global `things` command that runs the live TypeScript source (no build step — Node ≥ 24 strips types natively):
|
|
22
|
+
|
|
23
|
+
```sh
|
|
24
|
+
npm link # symlink this checkout as the global things-api package
|
|
25
|
+
asdf reshim nodejs # once, if you use asdf: expose the new `things` shim
|
|
26
|
+
```
|
|
27
|
+
|
|
28
|
+
Edits under `src/` take effect immediately. The bin launcher ([bin/things.js](bin/things.js)) prefers `src/` when present and falls back to `dist/`, so published installs (`npm i -g things-api`, `npx things-api`) run the compiled output with identical behavior.
|
|
29
|
+
|
|
30
|
+
## Core principles
|
|
31
|
+
|
|
32
|
+
- **Reads** go directly to Things' local SQLite database (read-only, WAL-aware). **Writes** go exclusively through official app surfaces — URL scheme, AppleScript, Shortcuts — never direct DB writes (sync corruption).
|
|
33
|
+
- **Every mutation is verified**: pre-read → hazard guards → execute → poll re-read until the expected delta appears. Silent no-ops are failures.
|
|
34
|
+
- **Every mutation is audited**: JSONL trail (`~/.local/state/things-api/audit/`) with requested vs. observed deltas; auth tokens structurally redacted.
|
|
35
|
+
- **Schema drift is detected**: table/column fingerprints keyed by Things' database version; writes hard-block on mismatch ([drift runbook](docs/lab/drift-runbook.md)).
|
|
36
|
+
- **Disruption is explicit**: every operation×vector combination carries a disruption tier (0 = invisible → 3 = navigates UI/modals); disruptive operations require explicit opt-in flags.
|
|
37
|
+
- **Nothing is developed against production data**: probing and integration tests run in disposable Tart macOS VMs.
|
|
38
|
+
|
|
39
|
+
## For agents
|
|
40
|
+
|
|
41
|
+
The CLI is designed to be driven by coding agents with no out-of-band knowledge. The contract:
|
|
42
|
+
|
|
43
|
+
1. **Discovery**: `things --help` (ends with AGENT NOTES), per-command `--help` (states each write's vector, disruption tier, hazards, and exact acknowledgement flag names — regression-tested as API), and `things capabilities [--op <op>] --json` (the lab-validated operation × vector support matrix, with probe-evidence ids).
|
|
44
|
+
2. **Structured output**: every command takes `--json` → versioned envelope `{ apiVersion, ok, kind, data|error, meta }` on stdout; human chatter goes to stderr only.
|
|
45
|
+
3. **Stable exit codes**: `0` ok · `2` usage · `3` verify-failed (mutation executed, expected delta never appeared) · `4` blocked (hazard guard or disruption policy; error carries `remediation`) · `5` drift-blocked · `6` unsupported · `7` environment.
|
|
46
|
+
4. **Plan before executing**: every write supports `--dry-run` — compiled invocation (token-redacted), chosen vector, tier, hazards checked, expected delta. Nothing runs, nothing is audited.
|
|
47
|
+
5. **No prompts, ever**: risky semantics are explicit flags — `--children require-resolved|auto-complete` (project completion cascades), `--acknowledge-checklist-reset` (checklist replacement destroys per-item state), `--acknowledge-project-reopen` (open child reopens a resolved project), `--dangerously-permanent` (area/tag delete and empty-trash skip the Trash).
|
|
48
|
+
6. **Experimental surfaces are opt-in**: `things reorder` (ordering within Today/a project/an area) rides an undocumented AppleScript command that any Things update may remove. It requires `things config set allow-experimental true` and re-checks the app's sdef declaration before every dispatch; `things doctor` reports both gates. Evening reorders never touch it — they use verified `when=` round-trips (the "bounce", ≤10 items) instead.
|
|
49
|
+
|
|
50
|
+
A typical mutation flow:
|
|
51
|
+
|
|
52
|
+
```sh
|
|
53
|
+
things capabilities --op todo.move --json # is it possible, which vector, what tier?
|
|
54
|
+
things search "Buy milk" --json # resolve the uuid (open items; scope with --project/--area/--tag, widen with --logged/--trashed/--all)
|
|
55
|
+
things todo move <uuid> --project "Errands" --dry-run --json # inspect the plan
|
|
56
|
+
things todo move <uuid> --project "Errands" --json # execute, verified
|
|
57
|
+
things changes --since 2026-07-05T08:00 --json # what changed since the agent last looked
|
|
58
|
+
things batch inbox-triage.jsonl # N ops, each guarded+verified, JSONL results
|
|
59
|
+
things undo --dry-run # inverse plan for the last mutation (audit replay)
|
|
60
|
+
things undo # execute it — verified like any mutation
|
|
61
|
+
```
|
|
62
|
+
|
|
63
|
+
Failure modes are first-class: a `verify-failed:silent-noop` means the app accepted the command and did nothing (a real Things behavior the guards mostly prevent — see [docs/things-app-oddities.md](docs/things-app-oddities.md)); `blocked:*` responses include machine-readable remediation.
|
|
64
|
+
|
|
65
|
+
## Architecture: one library, thin surfaces
|
|
66
|
+
|
|
67
|
+
The TypeScript library (`import { openThings } from "things-api"`) is the product; the CLI and the MCP server are thin presentation layers over the same `ThingsClient` — every read view and every verified mutation is a client method first. Shared machine contracts (JSON envelope, exit codes) live in the core (`contracts.ts`), and `diagnose()` / `capabilitiesTable()` are library functions the surfaces merely render.
|
|
68
|
+
|
|
69
|
+
### MCP server
|
|
70
|
+
|
|
71
|
+
`things mcp` serves the Model Context Protocol over stdio. Configure it in any MCP client:
|
|
72
|
+
|
|
73
|
+
```json
|
|
74
|
+
{ "mcpServers": { "things": { "command": "things", "args": ["mcp"] } } }
|
|
75
|
+
```
|
|
76
|
+
|
|
77
|
+
The server instructions carry the user's live inventory (areas, tag hierarchy, open projects — read at server start) plus the reference/scheduling vocabulary, so models can name real destinations without a discovery round-trip. Tools mirror the client surface: reads (`read_view` — today/inbox/anytime/upcoming with occurrence horizon/someday/logbook/trash — `search`, `changes_since`, `get_item`, `get_project`, `list_collections`) and grouped semantic mutations (`add_todo`, `update_todo`, `set_todo_status`, `move_todo`, `set_tags`, `edit_checklist`; `delete_item`/`restore_item`/`duplicate_item` for to-dos and projects alike; `add_project`, `update_project`, `set_project_status`, `move_project`; area and tag CRUD incl. tag un-nesting and guarded subtree deletion; plus generic `run_operation` for the full 28-op catalog, `batch`, `reorder`, `undo`, `capabilities`, `doctor`). Every write tool takes `dry_run`; tools carry read-only/destructive annotations; hazard blocks come back as structured tool errors carrying the same remediation text the CLI prints. Tool descriptions follow the consumer-voice contract in [docs/design/surface-copy.md](docs/design/surface-copy.md).
|
package/bin/things.js
ADDED
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
#!/usr/bin/env -S node --disable-warning=ExperimentalWarning
|
|
2
|
+
// Dev checkouts (npm link) run live TS source via Node's type stripping;
|
|
3
|
+
// published tarballs ship only dist + bin, so src is absent and dist is used.
|
|
4
|
+
import { existsSync } from "node:fs";
|
|
5
|
+
|
|
6
|
+
const src = new URL("../src/cli/main.ts", import.meta.url);
|
|
7
|
+
const entry = existsSync(src) ? src : new URL("../dist/cli/main.js", import.meta.url);
|
|
8
|
+
const { runCli } = await import(entry.href);
|
|
9
|
+
runCli();
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import type { AuditRecord } from "./schema.ts";
|
|
2
|
+
export interface AuditWriter {
|
|
3
|
+
append(record: AuditRecord): void;
|
|
4
|
+
}
|
|
5
|
+
export declare function createAuditWriter(options: {
|
|
6
|
+
dir: string;
|
|
7
|
+
/** Secrets to structurally redact from every string field. */
|
|
8
|
+
secrets: string[];
|
|
9
|
+
enabled: boolean;
|
|
10
|
+
}): AuditWriter;
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* JSONL audit writer: monthly files, never auto-deleted, structural token
|
|
3
|
+
* redaction — the serializer refuses to emit any string containing the
|
|
4
|
+
* loaded auth token.
|
|
5
|
+
*/
|
|
6
|
+
import { appendFileSync, mkdirSync } from "node:fs";
|
|
7
|
+
import { join } from "node:path";
|
|
8
|
+
export function createAuditWriter(options) {
|
|
9
|
+
const secrets = options.secrets.filter((s) => s.length > 0);
|
|
10
|
+
return {
|
|
11
|
+
append(record) {
|
|
12
|
+
if (!options.enabled)
|
|
13
|
+
return;
|
|
14
|
+
mkdirSync(options.dir, { recursive: true });
|
|
15
|
+
const month = record.ts.slice(0, 7); // YYYY-MM
|
|
16
|
+
const line = JSON.stringify(record, (_key, value) => {
|
|
17
|
+
if (typeof value === "string") {
|
|
18
|
+
let out = value;
|
|
19
|
+
for (const secret of secrets) {
|
|
20
|
+
while (out.includes(secret))
|
|
21
|
+
out = out.replace(secret, "REDACTED");
|
|
22
|
+
}
|
|
23
|
+
return out;
|
|
24
|
+
}
|
|
25
|
+
return value;
|
|
26
|
+
});
|
|
27
|
+
appendFileSync(join(options.dir, `${month}.jsonl`), `${line}\n`);
|
|
28
|
+
},
|
|
29
|
+
};
|
|
30
|
+
}
|
|
31
|
+
//# sourceMappingURL=log.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log.js","sourceRoot":"","sources":["../../src/audit/log.ts"],"names":[],"mappings":"AAAA;;;;GAIG;AACH,OAAO,EAAE,cAAc,EAAE,SAAS,EAAE,MAAM,SAAS,CAAC;AACpD,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAQjC,MAAM,UAAU,iBAAiB,CAAC,OAKjC;IACC,MAAM,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC;IAC5D,OAAO;QACL,MAAM,CAAC,MAAmB;YACxB,IAAI,CAAC,OAAO,CAAC,OAAO;gBAAE,OAAO;YAC7B,SAAS,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;YAC5C,MAAM,KAAK,GAAG,MAAM,CAAC,EAAE,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC,UAAU;YAC/C,MAAM,IAAI,GAAG,IAAI,CAAC,SAAS,CAAC,MAAM,EAAE,CAAC,IAAI,EAAE,KAAK,EAAE,EAAE;gBAClD,IAAI,OAAO,KAAK,KAAK,QAAQ,EAAE,CAAC;oBAC9B,IAAI,GAAG,GAAG,KAAK,CAAC;oBAChB,KAAK,MAAM,MAAM,IAAI,OAAO,EAAE,CAAC;wBAC7B,OAAO,GAAG,CAAC,QAAQ,CAAC,MAAM,CAAC;4BAAE,GAAG,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;oBACrE,CAAC;oBACD,OAAO,GAAG,CAAC;gBACb,CAAC;gBACD,OAAO,KAAK,CAAC;YACf,CAAC,CAAC,CAAC;YACH,cAAc,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,EAAE,GAAG,KAAK,QAAQ,CAAC,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC;QACnE,CAAC;KACF,CAAC;AACJ,CAAC"}
|
|
@@ -0,0 +1,37 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit record v1 — one JSON object per line in
|
|
3
|
+
* ~/.local/state/things-api/audit/YYYY-MM.jsonl (see design §5).
|
|
4
|
+
*
|
|
5
|
+
* Every mutation ATTEMPT is recorded: successes, verification failures, and
|
|
6
|
+
* blocked decisions (with invocation null — the app was never touched).
|
|
7
|
+
*/
|
|
8
|
+
export interface AuditRecord {
|
|
9
|
+
v: 1;
|
|
10
|
+
ts: string;
|
|
11
|
+
actor: string;
|
|
12
|
+
host: string;
|
|
13
|
+
op: string;
|
|
14
|
+
/** Target uuid; null until discovered for creates that verify by probe. */
|
|
15
|
+
uuid: string | null;
|
|
16
|
+
vector: string | null;
|
|
17
|
+
disruption: number | null;
|
|
18
|
+
/** Compiled invocation with the auth token structurally redacted. */
|
|
19
|
+
invocation: string | null;
|
|
20
|
+
/** Normalized requested delta (params as given, post-normalization). */
|
|
21
|
+
requested: Record<string, unknown>;
|
|
22
|
+
/** Asserted-field subset of the pre-state (null when target didn't exist). */
|
|
23
|
+
pre: Record<string, unknown> | null;
|
|
24
|
+
/** Post-verify observation (best-effort on failure). */
|
|
25
|
+
observed: Record<string, unknown> | null;
|
|
26
|
+
result: "ok" | "verify-failed:timeout" | "verify-failed:mismatch" | "verify-failed:silent-noop" | `blocked:${string}` | "unsupported";
|
|
27
|
+
verify: {
|
|
28
|
+
attempts: number;
|
|
29
|
+
elapsedMs: number;
|
|
30
|
+
} | null;
|
|
31
|
+
durationMs: number;
|
|
32
|
+
env: {
|
|
33
|
+
pkg: string;
|
|
34
|
+
dbVersion: number | null;
|
|
35
|
+
fingerprint: "ok" | "drift" | "user-accepted" | "unknown";
|
|
36
|
+
};
|
|
37
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Audit record v1 — one JSON object per line in
|
|
3
|
+
* ~/.local/state/things-api/audit/YYYY-MM.jsonl (see design §5).
|
|
4
|
+
*
|
|
5
|
+
* Every mutation ATTEMPT is recorded: successes, verification failures, and
|
|
6
|
+
* blocked decisions (with invocation null — the app was never touched).
|
|
7
|
+
*/
|
|
8
|
+
export {};
|
|
9
|
+
//# sourceMappingURL=schema.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"schema.js","sourceRoot":"","sources":["../../src/audit/schema.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG"}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `things doctor` — thin CLI surface over the library's diagnose().
|
|
3
|
+
* Exit codes: 0 healthy; 5 drift/unknown-version; 7 environment problems.
|
|
4
|
+
*/
|
|
5
|
+
import type { Command } from "commander";
|
|
6
|
+
import { type DiagnoseReport, type DiagnoseResult } from "../../diagnose.ts";
|
|
7
|
+
export type DoctorReport = DiagnoseReport;
|
|
8
|
+
export declare const runDoctor: (dbPath?: string) => DiagnoseResult;
|
|
9
|
+
export declare function registerDoctor(program: Command): void;
|
|
@@ -0,0 +1,60 @@
|
|
|
1
|
+
import { diagnose } from "../../diagnose.js";
|
|
2
|
+
import { describeEnvironmentChanges } from "../../write/environment.js";
|
|
3
|
+
import { errorEnvelope, okEnvelope } from "../../contracts.js";
|
|
4
|
+
export const runDoctor = diagnose;
|
|
5
|
+
function environmentLine(env) {
|
|
6
|
+
if (env.lastVerifiedWrite === null) {
|
|
7
|
+
return "no verified write recorded yet (the tuple is recorded on the first successful write)";
|
|
8
|
+
}
|
|
9
|
+
if (env.changes.length === 0)
|
|
10
|
+
return "unchanged since the last verified write";
|
|
11
|
+
return (`CHANGED since the last verified write — ${describeEnvironmentChanges(env.changes)} ` +
|
|
12
|
+
"(a macOS consent prompt may reappear on the next automation call)");
|
|
13
|
+
}
|
|
14
|
+
export function registerDoctor(program) {
|
|
15
|
+
program
|
|
16
|
+
.command("doctor")
|
|
17
|
+
.description("Check environment health: database location, database schema compatibility, app " +
|
|
18
|
+
"presence, any one-time setup still needed (macOS permissions, the app's " +
|
|
19
|
+
"'Enable Things URLs' setting), and whether the environment changed since the last " +
|
|
20
|
+
"successful write — with steps to fix. " +
|
|
21
|
+
"Exit 0 healthy; 5 schema drift (writes disabled); 7 environment problem.")
|
|
22
|
+
.option("--json", "emit versioned JSON envelope on stdout")
|
|
23
|
+
.option("--db <path>", "explicit database path (overrides THINGS_DB and discovery)")
|
|
24
|
+
.option("--probe-automation", "actively test whether automation of Things is authorized (may show a one-time macOS " +
|
|
25
|
+
"consent prompt; skipped when Things is not running)")
|
|
26
|
+
.action((opts) => {
|
|
27
|
+
const started = Date.now();
|
|
28
|
+
const { report, error, exitCode, meta } = diagnose(opts.db, {
|
|
29
|
+
...(opts.probeAutomation === true && { probeAutomation: true }),
|
|
30
|
+
});
|
|
31
|
+
const fullMeta = { ...meta, elapsedMs: Date.now() - started };
|
|
32
|
+
if (opts.json) {
|
|
33
|
+
const envelope = report
|
|
34
|
+
? okEnvelope("doctor", report, fullMeta)
|
|
35
|
+
: errorEnvelope(error ?? { code: "unexpected", message: "no report" }, fullMeta);
|
|
36
|
+
process.stdout.write(`${JSON.stringify(envelope)}\n`);
|
|
37
|
+
}
|
|
38
|
+
else if (report) {
|
|
39
|
+
const lines = [
|
|
40
|
+
`db: ${report.db.path} (${report.db.source})`,
|
|
41
|
+
`db version: ${report.db.databaseVersion ?? "unknown"}`,
|
|
42
|
+
`fingerprint: ${report.fingerprint.status} (${report.fingerprint.value.slice(0, 23)}…)`,
|
|
43
|
+
...report.fingerprint.detail.map((d) => ` drift: ${d}`),
|
|
44
|
+
`app: ${report.app.installed ? "installed" : "NOT INSTALLED"}`,
|
|
45
|
+
`writes: ${report.writes.enabled ? "enabled" : "DISABLED"} — ${report.writes.reason}`,
|
|
46
|
+
`experimental: ${report.experimental.reason}`,
|
|
47
|
+
`environment: ${environmentLine(report.environment)}`,
|
|
48
|
+
`automation: ${report.automation.status}${report.automation.status === "granted" ? "" : ` — ${report.automation.detail}`}`,
|
|
49
|
+
];
|
|
50
|
+
process.stdout.write(`${lines.join("\n")}\n`);
|
|
51
|
+
}
|
|
52
|
+
else if (error) {
|
|
53
|
+
process.stderr.write(`doctor: ${error.message}\n`);
|
|
54
|
+
if (error.remediation)
|
|
55
|
+
process.stderr.write(` remediation: ${error.remediation}\n`);
|
|
56
|
+
}
|
|
57
|
+
process.exitCode = exitCode;
|
|
58
|
+
});
|
|
59
|
+
}
|
|
60
|
+
//# sourceMappingURL=doctor.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../../src/cli/commands/doctor.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* `things mcp` — serve the MCP surface over stdio. Agents configure this as
|
|
3
|
+
* their MCP server command: { "command": "things", "args": ["mcp"] }.
|
|
4
|
+
* MCP protocol traffic owns stdout; all logging goes to stderr.
|
|
5
|
+
*/
|
|
6
|
+
import type { Command } from "commander";
|
|
7
|
+
export declare function registerMcp(program: Command): void;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
export function registerMcp(program) {
|
|
2
|
+
program
|
|
3
|
+
.command("mcp")
|
|
4
|
+
.description("Serve the Things MCP server on stdio (Model Context Protocol). Tools cover the full " +
|
|
5
|
+
"surface: read views, search, changes, item detail, to-do/project/area/tag " +
|
|
6
|
+
"mutations, batch, reorder, undo, capabilities, doctor; the server instructions " +
|
|
7
|
+
"carry the user's live area/tag/project inventory. Configure in an MCP client as " +
|
|
8
|
+
'command `things` with args ["mcp"].')
|
|
9
|
+
.option("--db <path>", "explicit database path")
|
|
10
|
+
.action(async (opts) => {
|
|
11
|
+
// LAZY imports: the MCP SDK + zod load only when `things mcp` actually
|
|
12
|
+
// runs. Every other CLI command must work in environments that ship a
|
|
13
|
+
// minimal dependency set (the guest e2e bundle carries only commander).
|
|
14
|
+
const [{ createThingsMcpServer }, { StdioServerTransport }] = await Promise.all([
|
|
15
|
+
import("../../mcp/server.js"),
|
|
16
|
+
import("@modelcontextprotocol/sdk/server/stdio.js"),
|
|
17
|
+
]);
|
|
18
|
+
const server = createThingsMcpServer(opts.db !== undefined ? { dbPath: opts.db } : {});
|
|
19
|
+
const transport = new StdioServerTransport();
|
|
20
|
+
await server.connect(transport);
|
|
21
|
+
process.stderr.write("things-api MCP server listening on stdio\n");
|
|
22
|
+
// The transport keeps the process alive; exit cleanly when it closes.
|
|
23
|
+
transport.onclose = () => process.exit(0);
|
|
24
|
+
});
|
|
25
|
+
}
|
|
26
|
+
//# sourceMappingURL=mcp.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp.js","sourceRoot":"","sources":["../../../src/cli/commands/mcp.ts"],"names":[],"mappings":"AAOA,MAAM,UAAU,WAAW,CAAC,OAAgB;IAC1C,OAAO;SACJ,OAAO,CAAC,KAAK,CAAC;SACd,WAAW,CACV,sFAAsF;QACpF,4EAA4E;QAC5E,iFAAiF;QACjF,kFAAkF;QAClF,qCAAqC,CACxC;SACA,MAAM,CAAC,aAAa,EAAE,wBAAwB,CAAC;SAC/C,MAAM,CAAC,KAAK,EAAE,IAAqB,EAAE,EAAE;QACtC,uEAAuE;QACvE,sEAAsE;QACtE,wEAAwE;QACxE,MAAM,CAAC,EAAE,qBAAqB,EAAE,EAAE,EAAE,oBAAoB,EAAE,CAAC,GAAG,MAAM,OAAO,CAAC,GAAG,CAAC;YAC9E,MAAM,CAAC,qBAAqB,CAAC;YAC7B,MAAM,CAAC,2CAA2C,CAAC;SACpD,CAAC,CAAC;QACH,MAAM,MAAM,GAAG,qBAAqB,CAAC,IAAI,CAAC,EAAE,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;QACvF,MAAM,SAAS,GAAG,IAAI,oBAAoB,EAAE,CAAC;QAC7C,MAAM,MAAM,CAAC,OAAO,CAAC,SAAS,CAAC,CAAC;QAChC,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,4CAA4C,CAAC,CAAC;QACnE,sEAAsE;QACtE,SAAS,CAAC,OAAO,GAAG,GAAG,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;AACP,CAAC"}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { formatItem, withClient } from "./reads.js";
|
|
2
|
+
function renderProjectView(view) {
|
|
3
|
+
const everyItem = [
|
|
4
|
+
...view.active,
|
|
5
|
+
...view.headings.flatMap((g) => g.items),
|
|
6
|
+
...view.later.scheduled.flatMap((d) => d.items),
|
|
7
|
+
...view.later.repeating,
|
|
8
|
+
...view.later.someday,
|
|
9
|
+
...view.logged.slice(0, 10),
|
|
10
|
+
];
|
|
11
|
+
const w = everyItem.reduce((max, i) => Math.max(max, i.uuid.length), 0);
|
|
12
|
+
const fmt = (i) => formatItem(i, w);
|
|
13
|
+
const lines = [
|
|
14
|
+
`${view.project.uuid} ${view.project.title}`,
|
|
15
|
+
` area: ${view.project.area?.title ?? "—"} open: ${view.project.openUntrashedLeafActionsCount}/${view.project.untrashedLeafActionsCount}`,
|
|
16
|
+
];
|
|
17
|
+
lines.push("── Active ──", ...(view.active.length ? view.active.map(fmt) : ["(none)"]));
|
|
18
|
+
for (const group of view.headings) {
|
|
19
|
+
lines.push(`── ${group.heading.title} ──`, ...(group.items.length ? group.items.map(fmt) : ["(none)"]));
|
|
20
|
+
}
|
|
21
|
+
if (view.later.scheduled.length || view.later.repeating.length || view.later.someday.length) {
|
|
22
|
+
lines.push("── Later ──");
|
|
23
|
+
for (const day of view.later.scheduled) {
|
|
24
|
+
lines.push(` ${day.date}:`, ...day.items.map(fmt));
|
|
25
|
+
}
|
|
26
|
+
if (view.later.repeating.length) {
|
|
27
|
+
lines.push(" repeating templates:", ...view.later.repeating.map(fmt));
|
|
28
|
+
}
|
|
29
|
+
if (view.later.someday.length) {
|
|
30
|
+
lines.push(" someday:", ...view.later.someday.map(fmt));
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
if (view.logged.length)
|
|
34
|
+
lines.push(`── Logged (${view.logged.length}) ──`, ...view.logged.slice(0, 10).map(fmt));
|
|
35
|
+
if (view.trashed.length)
|
|
36
|
+
lines.push(`── Trashed (${view.trashed.length}) ──`);
|
|
37
|
+
return lines;
|
|
38
|
+
}
|
|
39
|
+
export function registerProjectCommands(program) {
|
|
40
|
+
const project = program.command("project").description("Project-scoped operations");
|
|
41
|
+
project
|
|
42
|
+
.command("show <uuid>")
|
|
43
|
+
.description("Composite project view mirroring the native UI: active items, headings, later (scheduled/repeating/someday), logged, trashed")
|
|
44
|
+
.option("--json", "emit versioned JSON envelope on stdout")
|
|
45
|
+
.option("--db <path>", "explicit database path")
|
|
46
|
+
.action((uuid, opts) => {
|
|
47
|
+
withClient(opts, "project-view", (c) => c.read.projectView(uuid), renderProjectView);
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
//# sourceMappingURL=project.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"project.js","sourceRoot":"","sources":["../../../src/cli/commands/project.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Read-only list commands. Each renders a compact human table (UUIDs always
|
|
3
|
+
* shown — agents and humans both need stable references) or a --json envelope.
|
|
4
|
+
*/
|
|
5
|
+
import type { Command } from "commander";
|
|
6
|
+
import { type ThingsClient } from "../../client.ts";
|
|
7
|
+
import { type ListItem } from "../../read/views.ts";
|
|
8
|
+
interface GlobalReadOpts {
|
|
9
|
+
json?: boolean;
|
|
10
|
+
db?: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function withClient(opts: GlobalReadOpts, kind: string, fn: (client: ThingsClient) => unknown, render: (data: never) => string[]): void;
|
|
13
|
+
/**
|
|
14
|
+
* One item line: `<uuid> <marker> [meta …] <title> (container)`. The uuid
|
|
15
|
+
* column pads to `uuidWidth` (uuids vary 21–22 chars) so the marker column
|
|
16
|
+
* aligns; exactly one space separates every following token. Meta tokens are
|
|
17
|
+
* colorized on a TTY only (see ../style.ts) — piped output stays plain.
|
|
18
|
+
*/
|
|
19
|
+
export declare function formatItem(item: ListItem, uuidWidth?: number): string;
|
|
20
|
+
export declare function registerReadCommands(program: Command): void;
|
|
21
|
+
export {};
|