things-api 0.10.0 → 0.12.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 +50 -13
- package/dist/audit/schema.d.ts +7 -0
- package/dist/audit/schema.js.map +1 -1
- package/dist/cli/clock.d.ts +8 -0
- package/dist/cli/clock.js +24 -0
- package/dist/cli/clock.js.map +1 -0
- package/dist/cli/commands/area.d.ts +18 -11
- package/dist/cli/commands/area.js +61 -74
- package/dist/cli/commands/area.js.map +1 -1
- package/dist/cli/commands/doctor.d.ts +1 -2
- package/dist/cli/commands/doctor.js +11 -1
- package/dist/cli/commands/doctor.js.map +1 -1
- package/dist/cli/commands/install-skill.d.ts +60 -0
- package/dist/cli/commands/install-skill.js +256 -0
- package/dist/cli/commands/install-skill.js.map +1 -0
- package/dist/cli/commands/mcp.js +9 -0
- package/dist/cli/commands/mcp.js.map +1 -1
- package/dist/cli/commands/project.d.ts +1 -0
- package/dist/cli/commands/project.js +27 -34
- package/dist/cli/commands/project.js.map +1 -1
- package/dist/cli/commands/reads.d.ts +15 -2
- package/dist/cli/commands/reads.js +144 -44
- package/dist/cli/commands/reads.js.map +1 -1
- package/dist/cli/commands/setup.js +7 -2
- package/dist/cli/commands/setup.js.map +1 -1
- package/dist/cli/commands/show.js +38 -14
- package/dist/cli/commands/show.js.map +1 -1
- package/dist/cli/commands/todo.js +15 -9
- package/dist/cli/commands/todo.js.map +1 -1
- package/dist/cli/commands/writes.js +797 -174
- package/dist/cli/commands/writes.js.map +1 -1
- package/dist/cli/did-you-mean.d.ts +14 -3
- package/dist/cli/did-you-mean.js +26 -3
- package/dist/cli/did-you-mean.js.map +1 -1
- package/dist/cli/glyphs.d.ts +32 -2
- package/dist/cli/glyphs.js +83 -12
- package/dist/cli/glyphs.js.map +1 -1
- package/dist/cli/help.js +121 -16
- package/dist/cli/help.js.map +1 -1
- package/dist/cli/main.js +33 -2
- package/dist/cli/main.js.map +1 -1
- package/dist/cli/move-hint.d.ts +46 -0
- package/dist/cli/move-hint.js +196 -0
- package/dist/cli/move-hint.js.map +1 -0
- package/dist/cli/period.d.ts +2 -8
- package/dist/cli/period.js +44 -30
- package/dist/cli/period.js.map +1 -1
- package/dist/cli/read-driver.d.ts +43 -5
- package/dist/cli/read-driver.js +91 -15
- package/dist/cli/read-driver.js.map +1 -1
- package/dist/cli/render.d.ts +19 -8
- package/dist/cli/render.js +70 -27
- package/dist/cli/render.js.map +1 -1
- package/dist/cli/resolve-invocation.d.ts +2 -2
- package/dist/cli/resolve-invocation.js +3 -3
- package/dist/cli/resolve-invocation.js.map +1 -1
- package/dist/cli/skill-check.d.ts +27 -0
- package/dist/cli/skill-check.js +99 -0
- package/dist/cli/skill-check.js.map +1 -0
- package/dist/cli/skill.d.ts +70 -0
- package/dist/cli/skill.js +152 -0
- package/dist/cli/skill.js.map +1 -0
- package/dist/cli/tag-filters.d.ts +6 -2
- package/dist/cli/tag-filters.js +8 -6
- package/dist/cli/tag-filters.js.map +1 -1
- package/dist/cli/verb-hint.js +28 -3
- package/dist/cli/verb-hint.js.map +1 -1
- package/dist/cli/version.d.ts +4 -0
- package/dist/cli/version.js +18 -0
- package/dist/cli/version.js.map +1 -0
- package/dist/client.d.ts +171 -27
- package/dist/client.js +279 -40
- package/dist/client.js.map +1 -1
- package/dist/config.d.ts +66 -2
- package/dist/config.js +120 -12
- package/dist/config.js.map +1 -1
- package/dist/contracts.d.ts +186 -28
- package/dist/contracts.js +22 -1
- package/dist/contracts.js.map +1 -1
- package/dist/diagnose.d.ts +34 -2
- package/dist/diagnose.js +36 -1
- package/dist/diagnose.js.map +1 -1
- package/dist/index.d.ts +25 -9
- package/dist/index.js +22 -3
- package/dist/index.js.map +1 -1
- package/dist/mcp/server.d.ts +9 -0
- package/dist/mcp/server.js +1157 -684
- package/dist/mcp/server.js.map +1 -1
- package/dist/model/clock.d.ts +61 -0
- package/dist/model/clock.js +71 -0
- package/dist/model/clock.js.map +1 -0
- package/dist/model/dates.d.ts +26 -3
- package/dist/model/dates.js +84 -3
- package/dist/model/dates.js.map +1 -1
- package/dist/model/entities.d.ts +60 -3
- package/dist/model/entities.js.map +1 -1
- package/dist/model/mappers.d.ts +4 -2
- package/dist/model/mappers.js +66 -9
- package/dist/model/mappers.js.map +1 -1
- package/dist/model/recurrence.d.ts +8 -1
- package/dist/model/recurrence.js.map +1 -1
- package/dist/read/area-filter.d.ts +76 -0
- package/dist/read/area-filter.js +59 -0
- package/dist/read/area-filter.js.map +1 -0
- package/dist/read/area-view.d.ts +12 -12
- package/dist/read/area-view.js +58 -34
- package/dist/read/area-view.js.map +1 -1
- package/dist/read/detail.d.ts +1 -1
- package/dist/read/detail.js +26 -12
- package/dist/read/detail.js.map +1 -1
- package/dist/read/log-boundary.d.ts +1 -1
- package/dist/read/log-boundary.js +13 -3
- package/dist/read/log-boundary.js.map +1 -1
- package/dist/read/predicates.d.ts +18 -0
- package/dist/read/predicates.js +19 -0
- package/dist/read/predicates.js.map +1 -1
- package/dist/read/project-view.d.ts +32 -16
- package/dist/read/project-view.js +80 -45
- package/dist/read/project-view.js.map +1 -1
- package/dist/read/pseudo-area.d.ts +29 -0
- package/dist/read/pseudo-area.js +27 -0
- package/dist/read/pseudo-area.js.map +1 -0
- package/dist/read/queries.d.ts +108 -19
- package/dist/read/queries.js +212 -35
- package/dist/read/queries.js.map +1 -1
- package/dist/read/scope.d.ts +126 -0
- package/dist/read/scope.js +162 -0
- package/dist/read/scope.js.map +1 -0
- package/dist/read/search-rank.d.ts +2 -5
- package/dist/read/shape.d.ts +162 -0
- package/dist/read/shape.js +686 -0
- package/dist/read/shape.js.map +1 -0
- package/dist/read/show-target.d.ts +9 -1
- package/dist/read/show-target.js +45 -4
- package/dist/read/show-target.js.map +1 -1
- package/dist/read/snapshot.d.ts +1 -1
- package/dist/read/snapshot.js +9 -2
- package/dist/read/snapshot.js.map +1 -1
- package/dist/read/stage.d.ts +199 -0
- package/dist/read/stage.js +125 -0
- package/dist/read/stage.js.map +1 -0
- package/dist/read/truncation.d.ts +8 -6
- package/dist/read/truncation.js +35 -10
- package/dist/read/truncation.js.map +1 -1
- package/dist/read/views.d.ts +61 -20
- package/dist/read/views.js +240 -82
- package/dist/read/views.js.map +1 -1
- package/dist/surface-copy.d.ts +9 -0
- package/dist/surface-copy.js +9 -0
- package/dist/surface-copy.js.map +1 -1
- package/dist/write/accessibility-probe.d.ts +1 -1
- package/dist/write/accessibility-probe.js +8 -0
- package/dist/write/accessibility-probe.js.map +1 -1
- package/dist/write/automation-probe.d.ts +1 -1
- package/dist/write/automation-probe.js +8 -0
- package/dist/write/automation-probe.js.map +1 -1
- package/dist/write/batch.d.ts +49 -10
- package/dist/write/batch.js +423 -70
- package/dist/write/batch.js.map +1 -1
- package/dist/write/commands.d.ts +1 -1
- package/dist/write/commands.js +316 -66
- package/dist/write/commands.js.map +1 -1
- package/dist/write/guards.d.ts +1 -1
- package/dist/write/guards.js +94 -10
- package/dist/write/guards.js.map +1 -1
- package/dist/write/heading.d.ts +10 -1
- package/dist/write/heading.js +35 -5
- package/dist/write/heading.js.map +1 -1
- package/dist/write/make-repeating-project.d.ts +2 -2
- package/dist/write/make-repeating-project.js +9 -9
- package/dist/write/make-repeating-project.js.map +1 -1
- package/dist/write/move.d.ts +130 -0
- package/dist/write/move.js +1533 -0
- package/dist/write/move.js.map +1 -0
- package/dist/write/operations.d.ts +105 -19
- package/dist/write/operations.js +56 -7
- package/dist/write/operations.js.map +1 -1
- package/dist/write/opid.d.ts +31 -0
- package/dist/write/opid.js +30 -0
- package/dist/write/opid.js.map +1 -0
- package/dist/write/pipeline.d.ts +122 -3
- package/dist/write/pipeline.js +309 -52
- package/dist/write/pipeline.js.map +1 -1
- package/dist/write/planner.js +8 -1
- package/dist/write/planner.js.map +1 -1
- package/dist/write/pre-state.d.ts +197 -6
- package/dist/write/pre-state.js +427 -20
- package/dist/write/pre-state.js.map +1 -1
- package/dist/write/recurrence-rule-blob.d.ts +65 -0
- package/dist/write/recurrence-rule-blob.js +150 -0
- package/dist/write/recurrence-rule-blob.js.map +1 -0
- package/dist/write/reorder.d.ts +23 -3
- package/dist/write/reorder.js +1871 -85
- package/dist/write/reorder.js.map +1 -1
- package/dist/write/reversibility.js +19 -7
- package/dist/write/reversibility.js.map +1 -1
- package/dist/write/scope-guard.d.ts +31 -0
- package/dist/write/scope-guard.js +162 -0
- package/dist/write/scope-guard.js.map +1 -0
- package/dist/write/undo.js +120 -13
- package/dist/write/undo.js.map +1 -1
- package/dist/write/vectors/applescript.js +16 -7
- package/dist/write/vectors/applescript.js.map +1 -1
- package/dist/write/vectors/registry.d.ts +5 -7
- package/dist/write/vectors/registry.js +49 -2
- package/dist/write/vectors/registry.js.map +1 -1
- package/dist/write/vectors/shortcuts.js +1 -1
- package/dist/write/vectors/shortcuts.js.map +1 -1
- package/dist/write/vectors/simulator.d.ts +44 -0
- package/dist/write/vectors/simulator.js +1192 -0
- package/dist/write/vectors/simulator.js.map +1 -0
- package/dist/write/vectors/types.d.ts +46 -0
- package/dist/write/vectors/ui-certification.d.ts +10 -4
- package/dist/write/vectors/ui-certification.js +43 -10
- package/dist/write/vectors/ui-certification.js.map +1 -1
- package/dist/write/vectors/ui-drag.d.ts +21 -1
- package/dist/write/vectors/ui-drag.js +138 -27
- package/dist/write/vectors/ui-drag.js.map +1 -1
- package/dist/write/vectors/ui-recipes.d.ts +34 -1
- package/dist/write/vectors/ui-recipes.js +217 -6
- package/dist/write/vectors/ui-recipes.js.map +1 -1
- package/dist/write/vectors/ui.d.ts +40 -1
- package/dist/write/vectors/ui.js +196 -39
- package/dist/write/vectors/ui.js.map +1 -1
- package/dist/write/verify/delta.d.ts +127 -2
- package/dist/write/verify/delta.js +255 -16
- package/dist/write/verify/delta.js.map +1 -1
- package/dist/write/verify/poller.d.ts +7 -1
- package/dist/write/verify/poller.js +20 -1
- package/dist/write/verify/poller.js.map +1 -1
- package/package.json +24 -3
- package/schema/envelope.schema.json +383 -0
- package/skills/things-cli/SKILL.md +70 -0
- package/skills/things-cli/references/banner.md +35 -0
- package/skills/things-cli/references/contracts.md +62 -0
- package/skills/things-cli/references/errors.md +49 -0
- package/skills/things-cli/references/gui.md +11 -0
- package/skills/things-cli/references/model.md +60 -0
- package/skills/things-cli/references/ordering.md +71 -0
package/dist/config.d.ts
CHANGED
|
@@ -11,10 +11,40 @@ export interface ThingsApiConfig {
|
|
|
11
11
|
/** User-accepted drifted fingerprint (loud escape hatch; see design §6). */
|
|
12
12
|
acceptedFingerprint: string | null;
|
|
13
13
|
/**
|
|
14
|
-
*
|
|
15
|
-
*
|
|
14
|
+
* The Things app version the behavioral LAWS (docs/reference/assumption-register.md)
|
|
15
|
+
* were last certified against. Set when a baseline ships or by an explicit
|
|
16
|
+
* `things config set certified-app-version <X>`. The schema fingerprint cannot
|
|
17
|
+
* see BEHAVIORAL drift (an app update can move an insertion law with zero schema
|
|
18
|
+
* delta), so `things doctor` compares this against the installed version and
|
|
19
|
+
* emits a PASSIVE, non-blocking notice on a mismatch, pointing at the drift
|
|
20
|
+
* suite. Null when never certified (no notice). Precedent: the skill-version
|
|
21
|
+
* passive drift notice (src/cli/skill-check.ts).
|
|
22
|
+
*/
|
|
23
|
+
certifiedAppVersion: string | null;
|
|
24
|
+
/**
|
|
25
|
+
* Allow capabilities that ride the app's PRIVATE, UNDOCUMENTED sdef reorder
|
|
26
|
+
* command (default true). This is a private vendor surface, NOT a half-baked
|
|
27
|
+
* "experimental" one: every write is verify-per-write, fingerprint-gated, and
|
|
28
|
+
* canaried by the o-suite (incl. O17), which together detect any divergence.
|
|
29
|
+
* The bidirectional env/config off-switch is retained for hosts that want the
|
|
30
|
+
* private surface disabled; when off, the planner falls back to a proven bounce
|
|
31
|
+
* wherever one exists and refuses only where no enabled path remains.
|
|
16
32
|
*/
|
|
17
33
|
allowExperimental: boolean;
|
|
34
|
+
/**
|
|
35
|
+
* Whether the `when=`-bounce reorder protocols may run (default true). When
|
|
36
|
+
* false the move/reorder planner REFUSES every bounce-dependent placement
|
|
37
|
+
* (within-heading order, area-someday order, area-less loose anytime, and the
|
|
38
|
+
* top-level projects / evening scopes) with a teaching error naming this key —
|
|
39
|
+
* it never silently falls back to a destructive or unverified path.
|
|
40
|
+
*/
|
|
41
|
+
bounceEnabled: boolean;
|
|
42
|
+
/**
|
|
43
|
+
* Cap on the number of items a single bounce reorder may touch (default 30).
|
|
44
|
+
* Each item costs two verified mutations (~110 ms/item guest-local, BOUNCE2-t);
|
|
45
|
+
* the cap bounds the wall-clock and the Things-Cloud change-record fan-out.
|
|
46
|
+
*/
|
|
47
|
+
bounceMaxItems: number;
|
|
18
48
|
/**
|
|
19
49
|
* The Accessibility GUI ("ui") write vector. When disabled the vector does
|
|
20
50
|
* not exist on this machine: its GUI-only operations report unsupported.
|
|
@@ -25,6 +55,20 @@ export interface ThingsApiConfig {
|
|
|
25
55
|
ui: {
|
|
26
56
|
enabled: boolean;
|
|
27
57
|
};
|
|
58
|
+
/**
|
|
59
|
+
* Container-scoped sandbox: a raw ref (uuid / uuid-prefix / unique area or
|
|
60
|
+
* project name) plus where it came from, resolved to a pinned container at
|
|
61
|
+
* `openThings()`. Null when unscoped. A stored `scope` jails EVERY process on
|
|
62
|
+
* this host — including the owner's own terminal — so per-process scoping
|
|
63
|
+
* belongs on `THINGS_API_SCOPE` / the MCP `--scope` flag, not here (see
|
|
64
|
+
* docs/design/container-scope.md, Trust model). The MCP flag outranks env,
|
|
65
|
+
* which outranks this stored key. Optional in the type (a hand-built config
|
|
66
|
+
* omits it = unscoped); {@link loadConfig} always populates it.
|
|
67
|
+
*/
|
|
68
|
+
scope?: {
|
|
69
|
+
ref: string;
|
|
70
|
+
source: "env" | "config";
|
|
71
|
+
} | null;
|
|
28
72
|
host: string;
|
|
29
73
|
}
|
|
30
74
|
interface ConfigFile {
|
|
@@ -33,10 +77,30 @@ interface ConfigFile {
|
|
|
33
77
|
actor?: string;
|
|
34
78
|
auditEnabled?: boolean;
|
|
35
79
|
acceptedFingerprint?: string;
|
|
80
|
+
certifiedAppVersion?: string;
|
|
36
81
|
allowExperimental?: boolean;
|
|
82
|
+
bounceEnabled?: boolean;
|
|
83
|
+
bounceMaxItems?: number;
|
|
37
84
|
uiEnabled?: boolean;
|
|
85
|
+
scope?: string;
|
|
38
86
|
}
|
|
39
87
|
export declare function loadConfig(env?: NodeJS.ProcessEnv): ThingsApiConfig;
|
|
40
88
|
/** Persist one config key (CLI `things config set`). */
|
|
41
89
|
export declare function saveConfigKey(key: keyof ConfigFile, value: string | number | boolean | null, env?: NodeJS.ProcessEnv): void;
|
|
90
|
+
/**
|
|
91
|
+
* One config key's effective value and where it came from. `key` is the
|
|
92
|
+
* `things config set` / `things config get` spelling; `value` is the effective
|
|
93
|
+
* value after env override → stored file → built-in default; `source` says which
|
|
94
|
+
* layer supplied it. `derived` marks a read-only value computed from the
|
|
95
|
+
* environment (`host`) or from another key (the profile-derived `maxDisruption`
|
|
96
|
+
* default) rather than settable directly.
|
|
97
|
+
*/
|
|
98
|
+
export interface ConfigKeyView {
|
|
99
|
+
key: string;
|
|
100
|
+
value: string | number | boolean | null;
|
|
101
|
+
source: "env" | "stored" | "default" | "derived";
|
|
102
|
+
}
|
|
103
|
+
export declare function describeConfig(env?: NodeJS.ProcessEnv): ConfigKeyView[];
|
|
104
|
+
/** One key's effective view, or undefined for an unknown key (`config get <key>`). */
|
|
105
|
+
export declare function getConfigKey(key: string, env?: NodeJS.ProcessEnv): ConfigKeyView | undefined;
|
|
42
106
|
export {};
|
package/dist/config.js
CHANGED
|
@@ -13,6 +13,41 @@ const PROFILE_DEFAULT_TIER = {
|
|
|
13
13
|
workstation: 1,
|
|
14
14
|
"dedicated-server": 2,
|
|
15
15
|
};
|
|
16
|
+
/**
|
|
17
|
+
* A THINGS_API_* boolean override. Returns the forced value when the env var
|
|
18
|
+
* holds a recognized token, or undefined when unset/unrecognized (so the
|
|
19
|
+
* caller falls through to stored config, then the built-in default). The
|
|
20
|
+
* override is BIDIRECTIONAL — a recognized value always wins over stored
|
|
21
|
+
* config, so an env var can force a vector off as well as on. `trueToken` /
|
|
22
|
+
* `falseToken` let THINGS_API_AUDIT keep its legacy on/off vocabulary while
|
|
23
|
+
* the vectors use true/false.
|
|
24
|
+
*/
|
|
25
|
+
function boolEnvOverride(raw, trueToken, falseToken) {
|
|
26
|
+
if (raw === trueToken)
|
|
27
|
+
return true;
|
|
28
|
+
if (raw === falseToken)
|
|
29
|
+
return false;
|
|
30
|
+
return undefined;
|
|
31
|
+
}
|
|
32
|
+
/** THINGS_API_PROFILE override, or undefined when unset/unrecognized. */
|
|
33
|
+
function profileEnvOverride(raw) {
|
|
34
|
+
return raw === "workstation" || raw === "dedicated-server" ? raw : undefined;
|
|
35
|
+
}
|
|
36
|
+
/** THINGS_API_MAX_DISRUPTION override, or undefined when unset/unrecognized. */
|
|
37
|
+
function tierEnvOverride(raw) {
|
|
38
|
+
return raw !== undefined && /^[0-3]$/.test(raw) ? Number(raw) : undefined;
|
|
39
|
+
}
|
|
40
|
+
/**
|
|
41
|
+
* A THINGS_API_BOUNCE_MAX_ITEMS override, or undefined when unset/unrecognized.
|
|
42
|
+
* Only a positive integer is accepted (a bounce touches at least one item);
|
|
43
|
+
* anything else falls through to stored config, then the built-in default.
|
|
44
|
+
*/
|
|
45
|
+
function positiveIntEnvOverride(raw) {
|
|
46
|
+
if (raw === undefined || !/^[0-9]+$/.test(raw))
|
|
47
|
+
return undefined;
|
|
48
|
+
const n = Number(raw);
|
|
49
|
+
return Number.isInteger(n) && n > 0 ? n : undefined;
|
|
50
|
+
}
|
|
16
51
|
function configFilePath(env) {
|
|
17
52
|
return join(configDir(env), "config.json");
|
|
18
53
|
}
|
|
@@ -27,13 +62,12 @@ export function loadConfig(env = process.env) {
|
|
|
27
62
|
// Malformed config falls back to defaults; doctor reports it.
|
|
28
63
|
}
|
|
29
64
|
}
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
const
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
: (file.maxDisruption ?? PROFILE_DEFAULT_TIER[profile]));
|
|
65
|
+
// Precedence for every key: env > stored > default. A recognized env value
|
|
66
|
+
// always wins over stored config; an unset/unrecognized one falls through.
|
|
67
|
+
const profile = profileEnvOverride(env["THINGS_API_PROFILE"]) ?? file.profile ?? "workstation";
|
|
68
|
+
const maxDisruption = tierEnvOverride(env["THINGS_API_MAX_DISRUPTION"]) ??
|
|
69
|
+
file.maxDisruption ??
|
|
70
|
+
PROFILE_DEFAULT_TIER[profile];
|
|
37
71
|
let username = "unknown";
|
|
38
72
|
try {
|
|
39
73
|
username = userInfo().username;
|
|
@@ -41,16 +75,32 @@ export function loadConfig(env = process.env) {
|
|
|
41
75
|
catch {
|
|
42
76
|
// leave "unknown"
|
|
43
77
|
}
|
|
78
|
+
const auditEnv = boolEnvOverride(env["THINGS_API_AUDIT"], "on", "off");
|
|
79
|
+
const experimentalEnv = boolEnvOverride(env["THINGS_API_ALLOW_EXPERIMENTAL"], "true", "false");
|
|
80
|
+
const bounceEnabledEnv = boolEnvOverride(env["THINGS_API_BOUNCE_ENABLED"], "true", "false");
|
|
81
|
+
const bounceMaxItemsEnv = positiveIntEnvOverride(env["THINGS_API_BOUNCE_MAX_ITEMS"]);
|
|
82
|
+
const uiEnv = boolEnvOverride(env["THINGS_API_UI_ENABLED"], "true", "false");
|
|
83
|
+
// Scope precedence within the config layer: THINGS_API_SCOPE env > stored
|
|
84
|
+
// `scope` key. The MCP `--scope` flag outranks BOTH and is applied above this
|
|
85
|
+
// layer, at openThings(). Fail-closed resolution to a container happens there.
|
|
86
|
+
const scopeEnv = env["THINGS_API_SCOPE"];
|
|
87
|
+
const scope = scopeEnv !== undefined && scopeEnv !== ""
|
|
88
|
+
? { ref: scopeEnv, source: "env" }
|
|
89
|
+
: file.scope !== undefined && file.scope !== ""
|
|
90
|
+
? { ref: file.scope, source: "config" }
|
|
91
|
+
: null;
|
|
44
92
|
return {
|
|
45
93
|
profile,
|
|
46
94
|
maxDisruption,
|
|
47
95
|
actor: env["THINGS_API_ACTOR"] ?? file.actor ?? `${username}@cli`,
|
|
48
|
-
auditEnabled:
|
|
96
|
+
auditEnabled: auditEnv ?? file.auditEnabled ?? true,
|
|
49
97
|
acceptedFingerprint: file.acceptedFingerprint ?? null,
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
98
|
+
certifiedAppVersion: file.certifiedAppVersion ?? null,
|
|
99
|
+
allowExperimental: experimentalEnv ?? file.allowExperimental ?? true,
|
|
100
|
+
bounceEnabled: bounceEnabledEnv ?? file.bounceEnabled ?? true,
|
|
101
|
+
bounceMaxItems: bounceMaxItemsEnv ?? file.bounceMaxItems ?? 30,
|
|
102
|
+
ui: { enabled: uiEnv ?? file.uiEnabled ?? false },
|
|
103
|
+
scope,
|
|
54
104
|
host: hostname(),
|
|
55
105
|
};
|
|
56
106
|
}
|
|
@@ -76,4 +126,62 @@ export function saveConfigKey(key, value, env = process.env) {
|
|
|
76
126
|
}
|
|
77
127
|
writeFileSync(path, `${JSON.stringify(file, null, 2)}\n`);
|
|
78
128
|
}
|
|
129
|
+
function readConfigFile(env) {
|
|
130
|
+
const path = configFilePath(env);
|
|
131
|
+
if (existsSync(path)) {
|
|
132
|
+
try {
|
|
133
|
+
return JSON.parse(readFileSync(path, "utf8"));
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
// Malformed config → treated as no stored keys (doctor reports it).
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
return {};
|
|
140
|
+
}
|
|
141
|
+
/**
|
|
142
|
+
* The effective value + provenance of every config key, in a stable order —
|
|
143
|
+
* backing `things config get`. Env/stored/default detection mirrors
|
|
144
|
+
* {@link loadConfig} exactly, so a key reads `env` only when an env var actually
|
|
145
|
+
* overrode it (a THINGS_API_* value that loadConfig honors), `stored` when the
|
|
146
|
+
* on-disk config supplied it, `derived` for a read-only value computed from the
|
|
147
|
+
* environment or another key, and `default` otherwise.
|
|
148
|
+
*/
|
|
149
|
+
function configKeyView(key, value, stored, fromEnv) {
|
|
150
|
+
return { key, value, source: fromEnv ? "env" : stored ? "stored" : "default" };
|
|
151
|
+
}
|
|
152
|
+
export function describeConfig(env = process.env) {
|
|
153
|
+
const file = readConfigFile(env);
|
|
154
|
+
const cfg = loadConfig(env);
|
|
155
|
+
const view = configKeyView;
|
|
156
|
+
const tierFromEnv = tierEnvOverride(env["THINGS_API_MAX_DISRUPTION"]) !== undefined;
|
|
157
|
+
const maxDisruption = {
|
|
158
|
+
key: "maxDisruption",
|
|
159
|
+
value: cfg.maxDisruption,
|
|
160
|
+
// env > stored > profile-derived default (the built-in fallback is
|
|
161
|
+
// computed from `profile`, so it reports `derived`, not `default`).
|
|
162
|
+
source: tierFromEnv ? "env" : file.maxDisruption !== undefined ? "stored" : "derived",
|
|
163
|
+
};
|
|
164
|
+
return [
|
|
165
|
+
view("profile", cfg.profile, file.profile !== undefined, profileEnvOverride(env["THINGS_API_PROFILE"]) !== undefined),
|
|
166
|
+
maxDisruption,
|
|
167
|
+
view("actor", cfg.actor, file.actor !== undefined, env["THINGS_API_ACTOR"] !== undefined),
|
|
168
|
+
view("auditEnabled", cfg.auditEnabled, file.auditEnabled !== undefined, boolEnvOverride(env["THINGS_API_AUDIT"], "on", "off") !== undefined),
|
|
169
|
+
view("accepted-fingerprint", cfg.acceptedFingerprint, file.acceptedFingerprint !== undefined, false),
|
|
170
|
+
view("certified-app-version", cfg.certifiedAppVersion, file.certifiedAppVersion !== undefined, false),
|
|
171
|
+
view("allow-experimental", cfg.allowExperimental, file.allowExperimental !== undefined, boolEnvOverride(env["THINGS_API_ALLOW_EXPERIMENTAL"], "true", "false") !== undefined),
|
|
172
|
+
view("bounce-enabled", cfg.bounceEnabled, file.bounceEnabled !== undefined, boolEnvOverride(env["THINGS_API_BOUNCE_ENABLED"], "true", "false") !== undefined),
|
|
173
|
+
view("bounce-max-items", cfg.bounceMaxItems, file.bounceMaxItems !== undefined, positiveIntEnvOverride(env["THINGS_API_BOUNCE_MAX_ITEMS"]) !== undefined),
|
|
174
|
+
view("ui-enabled", cfg.ui.enabled, file.uiEnabled !== undefined, boolEnvOverride(env["THINGS_API_UI_ENABLED"], "true", "false") !== undefined),
|
|
175
|
+
// The container scope's RAW ref (resolved to a container at open); env >
|
|
176
|
+
// stored. A stored value jails every process on this host — see the
|
|
177
|
+
// trust-model note in docs/design/container-scope.md.
|
|
178
|
+
view("scope", cfg.scope?.ref ?? null, file.scope !== undefined, env["THINGS_API_SCOPE"] !== undefined && env["THINGS_API_SCOPE"] !== ""),
|
|
179
|
+
// Read-only, computed from the environment; not settable via `config set`.
|
|
180
|
+
{ key: "host", value: cfg.host, source: "derived" },
|
|
181
|
+
];
|
|
182
|
+
}
|
|
183
|
+
/** One key's effective view, or undefined for an unknown key (`config get <key>`). */
|
|
184
|
+
export function getConfigKey(key, env = process.env) {
|
|
185
|
+
return describeConfig(env).find((v) => v.key === key);
|
|
186
|
+
}
|
|
79
187
|
//# sourceMappingURL=config.js.map
|
package/dist/config.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;GAMG;AACH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC7E,OAAO,EAAE,QAAQ,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAC7C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAEjC,OAAO,EAAE,SAAS,EAAE,MAAM,YAAY,CAAC;
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"}
|
package/dist/contracts.d.ts
CHANGED
|
@@ -13,7 +13,7 @@ export declare const API_VERSION = 1;
|
|
|
13
13
|
* Package version, surfaced by `things --version` and the MCP serverInfo.
|
|
14
14
|
* Kept in lockstep with package.json by a contract test.
|
|
15
15
|
*/
|
|
16
|
-
export declare const PKG_VERSION = "0.
|
|
16
|
+
export declare const PKG_VERSION = "0.12.0";
|
|
17
17
|
/**
|
|
18
18
|
* Stable exit-code contract for the `things` CLI (mirrored by MCP error
|
|
19
19
|
* codes). Part of the public API surface consumed by agents and scripts —
|
|
@@ -51,21 +51,29 @@ export interface SectionCount {
|
|
|
51
51
|
total: number;
|
|
52
52
|
}
|
|
53
53
|
/**
|
|
54
|
-
*
|
|
55
|
-
*
|
|
56
|
-
* `
|
|
57
|
-
*
|
|
58
|
-
*
|
|
59
|
-
* `
|
|
60
|
-
*
|
|
54
|
+
* The single truncation-metadata shape for every read (the `meta.truncation`
|
|
55
|
+
* field). `shown` items were returned of `total` that matched after all
|
|
56
|
+
* filters; `limit` is the effective cap (null when the caller asked for all
|
|
57
|
+
* rows, and always null on a grouped view whose caps are per-block); `truncated`
|
|
58
|
+
* is the UNIVERSAL completeness check — true exactly when anything was dropped
|
|
59
|
+
* (`shown < total`, or any block hid rows). The dropped remainder is
|
|
60
|
+
* `total - shown`.
|
|
61
|
+
*
|
|
62
|
+
* Two optional per-shape breakdowns hang off it: `sections` for a split flat
|
|
63
|
+
* view (the Today split — per render-section shown/total), and `blocks` for a
|
|
64
|
+
* grouped view (anytime/someday/`area show` — the identity-carrying per-block
|
|
65
|
+
* nesting). Exactly one of them is present on the shapes that have it; both are
|
|
66
|
+
* absent on a plain flat view.
|
|
61
67
|
*/
|
|
62
68
|
export interface Truncation {
|
|
63
69
|
shown: number;
|
|
64
70
|
total: number;
|
|
65
71
|
limit: number | null;
|
|
66
72
|
truncated: boolean;
|
|
67
|
-
/** Per-section shown/total breakdown for a split flat view; absent otherwise. */
|
|
73
|
+
/** Per-section shown/total breakdown for a split flat view (Today); absent otherwise. */
|
|
68
74
|
sections?: SectionCount[];
|
|
75
|
+
/** Per-block nesting for a grouped view (anytime/someday/area card); absent otherwise. */
|
|
76
|
+
blocks?: GroupBlock[];
|
|
69
77
|
}
|
|
70
78
|
/**
|
|
71
79
|
* One identity-carrying block of a grouped catalogue (anytime/someday) or a
|
|
@@ -103,12 +111,6 @@ export interface GroupBlock {
|
|
|
103
111
|
/** Nested project blocks (anytime item-lists / someday active-project groups). Absent when none. */
|
|
104
112
|
children?: GroupBlock[];
|
|
105
113
|
}
|
|
106
|
-
/** Grouped-view truncation metadata (ADDITIVE); the per-block counterpart of {@link Truncation}. */
|
|
107
|
-
export interface GroupedTruncation {
|
|
108
|
-
/** True when any block hid items. */
|
|
109
|
-
truncated: boolean;
|
|
110
|
-
blocks: GroupBlock[];
|
|
111
|
-
}
|
|
112
114
|
export interface EnvelopeMeta {
|
|
113
115
|
/** Things database schema version (`Meta.databaseVersion`), null when no DB was opened. */
|
|
114
116
|
dbVersion: number | null;
|
|
@@ -116,10 +118,13 @@ export interface EnvelopeMeta {
|
|
|
116
118
|
fingerprint: "ok" | "drift" | "user-accepted" | "unknown";
|
|
117
119
|
/** Wall-clock duration of the command in milliseconds. */
|
|
118
120
|
elapsedMs: number;
|
|
119
|
-
/**
|
|
121
|
+
/**
|
|
122
|
+
* The read's completeness metadata (the single truncation shape). Present on
|
|
123
|
+
* any read that could drop rows — flat views (row `limit`), the Today split
|
|
124
|
+
* (`sections`), and grouped views (anytime/someday/`area show`, `blocks`).
|
|
125
|
+
* `meta.truncation.truncated` is the universal "did I see everything" check.
|
|
126
|
+
*/
|
|
120
127
|
truncation?: Truncation;
|
|
121
|
-
/** Per-block truncation metadata; present only on grouped views (anytime/someday). */
|
|
122
|
-
grouped?: GroupedTruncation;
|
|
123
128
|
/**
|
|
124
129
|
* The canonical `things …` command a sugar invocation normalized to (bare
|
|
125
130
|
* noun, keyword-in-show, uuid/share-link routing). Present only on routed
|
|
@@ -133,6 +138,42 @@ export interface EnvelopeMeta {
|
|
|
133
138
|
* (reads stay best-effort; run `things doctor`). Absent means none.
|
|
134
139
|
*/
|
|
135
140
|
warnings?: string[];
|
|
141
|
+
/**
|
|
142
|
+
* The effective clock this response's date boundaries were computed for
|
|
143
|
+
* (ADDITIVE honesty field). Present ONLY when a consumer zone (`THINGS_TZ` /
|
|
144
|
+
* the MCP `tz` argument) or a pinned `THINGS_NOW` is in effect; ABSENT on the
|
|
145
|
+
* host clock, so the wire shape is unchanged for ordinary consumers.
|
|
146
|
+
*/
|
|
147
|
+
clock?: {
|
|
148
|
+
timezone: string;
|
|
149
|
+
today: string;
|
|
150
|
+
};
|
|
151
|
+
/**
|
|
152
|
+
* The active content filter this response was scoped to (ADDITIVE). Present
|
|
153
|
+
* ONLY when a scope was applied — currently `area` (the `--area` view filter),
|
|
154
|
+
* carrying the resolved area's uuid + title; ABSENT otherwise, so the wire
|
|
155
|
+
* shape is unchanged for unscoped reads (the `meta.clock` precedent).
|
|
156
|
+
*/
|
|
157
|
+
filter?: {
|
|
158
|
+
area: {
|
|
159
|
+
uuid: string;
|
|
160
|
+
title: string;
|
|
161
|
+
};
|
|
162
|
+
};
|
|
163
|
+
/**
|
|
164
|
+
* The active container scope this response was jailed to (ADDITIVE). Present
|
|
165
|
+
* ONLY when a scope is in force (the MCP `--scope` flag / `THINGS_API_SCOPE` /
|
|
166
|
+
* a stored `scope`), naming the container + where the scope came from; ABSENT
|
|
167
|
+
* otherwise, so the wire shape is unchanged for unscoped reads. Lets an agent
|
|
168
|
+
* know its own jail — which is not an oracle for what lies outside it (the
|
|
169
|
+
* `meta.clock` / `meta.filter` additive precedent).
|
|
170
|
+
*/
|
|
171
|
+
scope?: {
|
|
172
|
+
kind: "area" | "project";
|
|
173
|
+
uuid: string;
|
|
174
|
+
title: string;
|
|
175
|
+
source: "flag" | "env" | "config";
|
|
176
|
+
};
|
|
136
177
|
}
|
|
137
178
|
export interface OkEnvelope<T> {
|
|
138
179
|
apiVersion: typeof API_VERSION;
|
|
@@ -142,13 +183,38 @@ export interface OkEnvelope<T> {
|
|
|
142
183
|
data: T;
|
|
143
184
|
meta: EnvelopeMeta;
|
|
144
185
|
}
|
|
186
|
+
/**
|
|
187
|
+
* The registry of stable machine-readable error codes an error envelope can
|
|
188
|
+
* carry — the compiler IS the registry. Every `error.code` value the surfaces
|
|
189
|
+
* emit is a member of this union, and the human-readable meaning of each is
|
|
190
|
+
* frozen at v1.0 (new codes may still be ADDED after v1.0 — that is
|
|
191
|
+
* non-breaking; a documented code's MEANING never changes). The canonical
|
|
192
|
+
* per-code table (meaning + the `detail` keys each may carry) lives in
|
|
193
|
+
* `docs/contract.md` (The error-code registry).
|
|
194
|
+
*
|
|
195
|
+
* Two members are template-literal families rather than fixed strings, because
|
|
196
|
+
* their suffix is minted in the write layer and the core deliberately never
|
|
197
|
+
* depends on it (see {@link blockedCode} / {@link verifyFailedCode}):
|
|
198
|
+
* - `verify-failed:${reason}` — a single mutation executed but read-after-write
|
|
199
|
+
* verification failed; the suffix is the reason (`timeout` | `mismatch` |
|
|
200
|
+
* `silent-noop`). The bare `verify-failed` (no suffix) is the multi-leg
|
|
201
|
+
* move/reorder failure.
|
|
202
|
+
* - `blocked:${suffix}` — a mutation refused before touching the app; the
|
|
203
|
+
* suffix is the specific hazard id (`H-…`) when one is named, else the block
|
|
204
|
+
* reason (`drift` | `disruption-tier` | `lock` | `environment` | `clock` |
|
|
205
|
+
* `scope`). The bare `blocked` is a policy refusal from the move planner.
|
|
206
|
+
*
|
|
207
|
+
* `blocked:drift` maps to exit code 5 (DriftBlocked); every other `blocked:*`
|
|
208
|
+
* maps to exit code 4 (Blocked).
|
|
209
|
+
*/
|
|
210
|
+
export type ErrorCode = "usage" | "not-found" | "ambiguous" | "unsupported" | "environment" | "unexpected" | "bounce-aborted" | "verify-failed" | "blocked" | `verify-failed:${string}` | `blocked:${string}`;
|
|
145
211
|
export interface ErrorEnvelope {
|
|
146
212
|
apiVersion: typeof API_VERSION;
|
|
147
213
|
ok: false;
|
|
148
214
|
kind: "error";
|
|
149
215
|
error: {
|
|
150
|
-
/** Stable machine-readable code
|
|
151
|
-
code:
|
|
216
|
+
/** Stable machine-readable code from the {@link ErrorCode} registry (mirrors the exit-code family, e.g. "verify-failed", "blocked:H-UNKNOWN-TAG"). */
|
|
217
|
+
code: ErrorCode;
|
|
152
218
|
message: string;
|
|
153
219
|
/**
|
|
154
220
|
* Advisory attribution when failure signals point somewhere: e.g.
|
|
@@ -158,25 +224,117 @@ export interface ErrorEnvelope {
|
|
|
158
224
|
likelyCause?: string;
|
|
159
225
|
/** Actionable next step for the caller, when one exists. */
|
|
160
226
|
remediation?: string;
|
|
161
|
-
detail?: unknown;
|
|
162
227
|
/**
|
|
163
|
-
*
|
|
164
|
-
*
|
|
165
|
-
*
|
|
166
|
-
*
|
|
167
|
-
*
|
|
168
|
-
*
|
|
228
|
+
* The SINGLE structured, machine-readable failure-context object (there is
|
|
229
|
+
* no separate `details` field — the two were reconciled into this one). Each
|
|
230
|
+
* key is present only for the failures that produce it:
|
|
231
|
+
* - `expected` / `observed` — a verify-failed mutation's expected delta and
|
|
232
|
+
* the observed post-write state.
|
|
233
|
+
* - `candidates` — the disambiguation list for a not-found / ambiguous
|
|
234
|
+
* resolution (or a show/bare-noun did-you-mean): the ONE fixed, flag-
|
|
235
|
+
* invariant candidate shape (`CandidateRef`; see docs/contract.md), a
|
|
236
|
+
* LIVE-scoped pool capped at 8, so an agent can self-correct without
|
|
237
|
+
* another round-trip.
|
|
238
|
+
* - `suggestions` — for a bare mutation verb (`things update <ref>`), the
|
|
239
|
+
* concrete namespaced command(s) to run instead.
|
|
240
|
+
* - `considered` — the vectors weighed (and why each was rejected) for an
|
|
241
|
+
* unsupported operation.
|
|
242
|
+
* - `placed` / `remaining` / `cause` — a bounce reorder that aborted
|
|
243
|
+
* part-way: the items already placed, those not yet placed, and the cause.
|
|
244
|
+
* - `failed` / `completed` — a multi-leg move that failed mid-way: the leg
|
|
245
|
+
* that failed and the legs already completed before it.
|
|
169
246
|
*/
|
|
170
|
-
|
|
247
|
+
detail?: {
|
|
248
|
+
expected?: unknown;
|
|
249
|
+
observed?: Record<string, unknown> | null;
|
|
171
250
|
candidates?: unknown[];
|
|
172
251
|
suggestions?: string[];
|
|
252
|
+
considered?: {
|
|
253
|
+
vector: string;
|
|
254
|
+
why: string;
|
|
255
|
+
}[];
|
|
256
|
+
placed?: string[];
|
|
257
|
+
remaining?: string[];
|
|
258
|
+
cause?: unknown;
|
|
259
|
+
failed?: unknown;
|
|
260
|
+
completed?: unknown[];
|
|
173
261
|
};
|
|
174
262
|
};
|
|
175
263
|
meta: EnvelopeMeta;
|
|
176
264
|
}
|
|
177
265
|
export type Envelope<T> = OkEnvelope<T> | ErrorEnvelope;
|
|
266
|
+
/**
|
|
267
|
+
* The envelope `kind` discriminators a SUCCESSFUL response carries today (the
|
|
268
|
+
* error envelope's `kind` is always the literal `"error"`). This union is the
|
|
269
|
+
* schema's record of the known payload classes — the flat-list reads
|
|
270
|
+
* (`data.items`), the sectioned reads (`data.sections`), the composite cards
|
|
271
|
+
* (`data.view`), the single-entity detail (`data.item`), the mutations/plans
|
|
272
|
+
* (flat `data` fields), and the diagnostic payloads.
|
|
273
|
+
*
|
|
274
|
+
* Per the compatibility covenant (docs/contract.md) a consumer MUST tolerate an
|
|
275
|
+
* UNKNOWN `kind`: adding a new kind is additive / non-breaking. So this union is
|
|
276
|
+
* "the kinds known to THIS build", not a closed set a generic reader may assume
|
|
277
|
+
* complete — the JSON Schema pins it as an enum so drift is caught, but a
|
|
278
|
+
* forward-compatible consumer routes on the wrapper it finds in `data`.
|
|
279
|
+
*/
|
|
280
|
+
export type WireOkKind = "inbox" | "upcoming" | "logbook" | "trash" | "changes" | "search" | "projects" | "areas" | "tags" | "today" | "anytime" | "someday" | "area-view" | "project-view" | "detail" | "mutation-result" | "move-result" | "mutation-plan" | "move-plan" | "project-reopen" | "doctor" | "capabilities" | "config" | "legend" | "setup-shortcuts" | "install-skill";
|
|
281
|
+
/**
|
|
282
|
+
* The `data` payload of a successful envelope. Its CONCRETE shape is
|
|
283
|
+
* command-specific — one of the R1/R2 read wrappers (`item` | `view` | `items` |
|
|
284
|
+
* `sections`) or a mutation's flat result fields — and, crucially, entity
|
|
285
|
+
* payloads are omit-empty pruned on the wire (docs/design/contracts.md).
|
|
286
|
+
*
|
|
287
|
+
* COVERAGE BOUNDARY: this schema does NOT model the per-kind payload shapes. It
|
|
288
|
+
* pins the ENVELOPE layer exactly (`apiVersion`, `ok`, `kind`, `meta`, and the
|
|
289
|
+
* whole `error` object) and treats `data` as an open JSON object. Fully typing
|
|
290
|
+
* every kind's payload against the omit-empty wire shape is a separate, larger
|
|
291
|
+
* effort; until then `src/contracts.ts` and `docs/contract.md` remain the
|
|
292
|
+
* authoritative description of what each `kind`'s `data` contains.
|
|
293
|
+
*/
|
|
294
|
+
export type WireData = Record<string, unknown>;
|
|
295
|
+
/** A successful `--json` envelope, exactly as emitted on stdout. */
|
|
296
|
+
export interface WireOkEnvelope {
|
|
297
|
+
apiVersion: typeof API_VERSION;
|
|
298
|
+
ok: true;
|
|
299
|
+
/** The payload class — see {@link WireOkKind}. */
|
|
300
|
+
kind: WireOkKind;
|
|
301
|
+
/** Command-specific payload; open at the schema layer (see {@link WireData}). */
|
|
302
|
+
data: WireData;
|
|
303
|
+
meta: EnvelopeMeta;
|
|
304
|
+
}
|
|
305
|
+
/**
|
|
306
|
+
* The machine-readable ROOT the envelope JSON Schema is generated from
|
|
307
|
+
* (`schema/envelope.schema.json`, produced by `npm run schema:gen`): the
|
|
308
|
+
* discriminated union — on the boolean `ok` — of a successful envelope and an
|
|
309
|
+
* {@link ErrorEnvelope}, exactly as written to stdout by the CLI `--json`
|
|
310
|
+
* surface and inherited by the MCP server. This is the same grammar
|
|
311
|
+
* docs/contract.md describes in prose; the schema is its generated, testable
|
|
312
|
+
* rendering. NB: the streaming commands (`batch`, `undo`) emit JSON Lines, a
|
|
313
|
+
* documented exception NOT covered by this envelope type.
|
|
314
|
+
*/
|
|
315
|
+
export type WireEnvelope = WireOkEnvelope | ErrorEnvelope;
|
|
178
316
|
export declare function okEnvelope<T>(kind: string, data: T, meta: EnvelopeMeta): OkEnvelope<T>;
|
|
179
317
|
export declare function errorEnvelope(error: ErrorEnvelope["error"], meta: EnvelopeMeta): ErrorEnvelope;
|
|
318
|
+
/**
|
|
319
|
+
* Project a successful mutation/reorder/move outcome to its ENVELOPE `data`
|
|
320
|
+
* shape. The wire's mutation-success discriminator is REDUNDANT and is not
|
|
321
|
+
* emitted: the envelope already carries call success (`ok: true`, and the
|
|
322
|
+
* envelope `kind` names the payload class — `mutation-result` / `move-result`).
|
|
323
|
+
* So the result's internal `kind` discriminator is STRIPPED here — the emitted
|
|
324
|
+
* `data` has no `result` and no `kind`, just the payload fields (`op`, `uuid`,
|
|
325
|
+
* `title`, `undoToken`, `observed`, `vector`, `tier`, `touched`, notes, …).
|
|
326
|
+
* Only the internal tags `"ok"` / `"move-ok"` ever reach this boundary
|
|
327
|
+
* (failures route to error envelopes, dry-runs to the `mutation-plan` /
|
|
328
|
+
* `move-plan` kinds), so nothing is lost by dropping it. The library keeps the
|
|
329
|
+
* idiomatic `kind` discriminator on its in-memory
|
|
330
|
+
* `MutationResult`/`ReorderResult`/`MoveResult` unions; it simply never appears
|
|
331
|
+
* on the wire. BOTH consumer surfaces emit through it: the CLI (`mutation-result`
|
|
332
|
+
* / `move-result` envelopes) and the MCP mutation/move content block (phase-2
|
|
333
|
+
* framing sweep, 2026-07-31) — a dry-run routes to the bare `plan` on both.
|
|
334
|
+
*/
|
|
335
|
+
export declare function mutationWireData<T extends {
|
|
336
|
+
kind: string;
|
|
337
|
+
}>(ok: T): Omit<T, "kind">;
|
|
180
338
|
/**
|
|
181
339
|
* Canonical machine-readable error CODE for a refused ("blocked") mutation: the
|
|
182
340
|
* specific hazard id when one is named, else the block reason. Every surface —
|
package/dist/contracts.js
CHANGED
|
@@ -13,7 +13,7 @@ export const API_VERSION = 1;
|
|
|
13
13
|
* Package version, surfaced by `things --version` and the MCP serverInfo.
|
|
14
14
|
* Kept in lockstep with package.json by a contract test.
|
|
15
15
|
*/
|
|
16
|
-
export const PKG_VERSION = "0.
|
|
16
|
+
export const PKG_VERSION = "0.12.0";
|
|
17
17
|
/**
|
|
18
18
|
* Stable exit-code contract for the `things` CLI (mirrored by MCP error
|
|
19
19
|
* codes). Part of the public API surface consumed by agents and scripts —
|
|
@@ -43,6 +43,27 @@ export function okEnvelope(kind, data, meta) {
|
|
|
43
43
|
export function errorEnvelope(error, meta) {
|
|
44
44
|
return { apiVersion: API_VERSION, ok: false, kind: "error", error, meta };
|
|
45
45
|
}
|
|
46
|
+
/**
|
|
47
|
+
* Project a successful mutation/reorder/move outcome to its ENVELOPE `data`
|
|
48
|
+
* shape. The wire's mutation-success discriminator is REDUNDANT and is not
|
|
49
|
+
* emitted: the envelope already carries call success (`ok: true`, and the
|
|
50
|
+
* envelope `kind` names the payload class — `mutation-result` / `move-result`).
|
|
51
|
+
* So the result's internal `kind` discriminator is STRIPPED here — the emitted
|
|
52
|
+
* `data` has no `result` and no `kind`, just the payload fields (`op`, `uuid`,
|
|
53
|
+
* `title`, `undoToken`, `observed`, `vector`, `tier`, `touched`, notes, …).
|
|
54
|
+
* Only the internal tags `"ok"` / `"move-ok"` ever reach this boundary
|
|
55
|
+
* (failures route to error envelopes, dry-runs to the `mutation-plan` /
|
|
56
|
+
* `move-plan` kinds), so nothing is lost by dropping it. The library keeps the
|
|
57
|
+
* idiomatic `kind` discriminator on its in-memory
|
|
58
|
+
* `MutationResult`/`ReorderResult`/`MoveResult` unions; it simply never appears
|
|
59
|
+
* on the wire. BOTH consumer surfaces emit through it: the CLI (`mutation-result`
|
|
60
|
+
* / `move-result` envelopes) and the MCP mutation/move content block (phase-2
|
|
61
|
+
* framing sweep, 2026-07-31) — a dry-run routes to the bare `plan` on both.
|
|
62
|
+
*/
|
|
63
|
+
export function mutationWireData(ok) {
|
|
64
|
+
const { kind: _kind, ...rest } = ok;
|
|
65
|
+
return rest;
|
|
66
|
+
}
|
|
46
67
|
/**
|
|
47
68
|
* Canonical machine-readable error CODE for a refused ("blocked") mutation: the
|
|
48
69
|
* specific hazard id when one is named, else the block reason. Every surface —
|
package/dist/contracts.js.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"contracts.js","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC;AAE7B;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,QAAQ,CAAC;AAEpC;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,eAAe;IACf,EAAE,EAAE,CAAC;IACL,4DAA4D;IAC5D,UAAU,EAAE,CAAC;IACb,kEAAkE;IAClE,KAAK,EAAE,CAAC;IACR,uGAAuG;IACvG,YAAY,EAAE,CAAC;IACf,wFAAwF;IACxF,OAAO,EAAE,CAAC;IACV,gGAAgG;IAChG,YAAY,EAAE,CAAC;IACf,6DAA6D;IAC7D,WAAW,EAAE,CAAC;IACd,kFAAkF;IAClF,WAAW,EAAE,CAAC;CACN,CAAC;
|
|
1
|
+
{"version":3,"file":"contracts.js","sourceRoot":"","sources":["../src/contracts.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AAEH,MAAM,CAAC,MAAM,WAAW,GAAG,CAAC,CAAC;AAE7B;;;GAGG;AACH,MAAM,CAAC,MAAM,WAAW,GAAG,QAAQ,CAAC;AAEpC;;;;GAIG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAG;IACtB,eAAe;IACf,EAAE,EAAE,CAAC;IACL,4DAA4D;IAC5D,UAAU,EAAE,CAAC;IACb,kEAAkE;IAClE,KAAK,EAAE,CAAC;IACR,uGAAuG;IACvG,YAAY,EAAE,CAAC;IACf,wFAAwF;IACxF,OAAO,EAAE,CAAC;IACV,gGAAgG;IAChG,YAAY,EAAE,CAAC;IACf,6DAA6D;IAC7D,WAAW,EAAE,CAAC;IACd,kFAAkF;IAClF,WAAW,EAAE,CAAC;CACN,CAAC;AAmUX,MAAM,UAAU,UAAU,CAAI,IAAY,EAAE,IAAO,EAAE,IAAkB;IACrE,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;AACjE,CAAC;AAED,MAAM,UAAU,aAAa,CAAC,KAA6B,EAAE,IAAkB;IAC7E,OAAO,EAAE,UAAU,EAAE,WAAW,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;AAC5E,CAAC;AAED;;;;;;;;;;;;;;;;GAgBG;AACH,MAAM,UAAU,gBAAgB,CAA6B,EAAK;IAChE,MAAM,EAAE,IAAI,EAAE,KAAK,EAAE,GAAG,IAAI,EAAE,GAAG,EAAE,CAAC;IACpC,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;GAOG;AACH,MAAM,UAAU,WAAW,CAAC,OAA4C;IACtE,OAAO,WAAW,OAAO,CAAC,MAAM,IAAI,OAAO,CAAC,MAAM,EAAE,CAAC;AACvD,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,gBAAgB,CAAmB,OAAsB;IACvE,OAAO,iBAAiB,OAAO,CAAC,MAAM,EAAE,CAAC;AAC3C,CAAC;AAED;;;;;;;;;;GAUG;AACH,MAAM,UAAU,iBAAiB,CAC/B,QAAsD;IAEtD,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,QAAQ,CAAC,EAAE,CAAC;IAC9C,MAAM,KAAK,GAAG,IAAI,GAAG,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;IACnD,IAAI,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,KAAK,SAAS,IAAI,CAAC,CAAC,MAAM,KAAK,OAAO,CAAC,EAAE,CAAC;QACvE,OAAO,QAAQ,CAAC,YAAY,CAAC;IAC/B,CAAC;IACD,IAAI,KAAK,CAAC,GAAG,CAAC,SAAS,CAAC;QAAE,OAAO,QAAQ,CAAC,OAAO,CAAC;IAClD,IAAI,KAAK,CAAC,GAAG,CAAC,aAAa,CAAC;QAAE,OAAO,QAAQ,CAAC,WAAW,CAAC;IAC1D,OAAO,QAAQ,CAAC,YAAY,CAAC;AAC/B,CAAC"}
|