@davidorex/pi-context-cli 0.28.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/CHANGELOG.md ADDED
@@ -0,0 +1,13 @@
1
+ # Changelog
2
+
3
+ All notable changes to this package are documented here. Format follows [Keep a Changelog](https://keepachangelog.com/). This package has not yet been published to npm; the accumulated surface below sits under `[Unreleased]` and becomes its first published version's section at first publish.
4
+
5
+ ## [Unreleased]
6
+
7
+ ## [0.28.0] - 2026-06-03
8
+
9
+ ### Added
10
+ - Runtime-reflecting CLI over pi-context's op-registry: the command surface is derived from the registered operations rather than hand-maintained (`b0a831e`)
11
+
12
+ ### Fixed
13
+ - String-enum union flags derive as strings rather than JSON (DEFECT-1) (`37f3f31`)
package/README.md ADDED
@@ -0,0 +1,60 @@
1
+ # @davidorex/pi-context-cli
2
+
3
+ A command-line interface over the [`@davidorex/pi-context`](https://github.com/davidorex/pi-project-workflows/tree/main/packages/pi-context) substrate operations.
4
+
5
+ The command set is **auto-tracking**: every operation in pi-context's op-registry whose `surface` is `"use"` surfaces as a CLI command by reflection. There is no hardcoded command list — adding an op to pi-context makes a new CLI command appear with zero changes to this package. Operations that depend on a pi runtime handle (e.g. `list-tools`) carry `surface: "process"` and are not surfaced here.
6
+
7
+ ## Install
8
+
9
+ ```bash
10
+ npm i -g @davidorex/pi-context-cli
11
+ ```
12
+
13
+ This provides a `pi-context` binary.
14
+
15
+ ## Usage
16
+
17
+ ```bash
18
+ pi-context --help # list every surfaced op + global flags
19
+ pi-context <op> --help # per-op help: declared flags with TYPE tags
20
+ pi-context <op> [flags] # run an op
21
+ ```
22
+
23
+ Each op's flags derive from its parameter schema:
24
+
25
+ - scalar fields take `--field value` (`string` / `number`); `boolean` fields are presence flags (`--flag`, or `--flag true|false`)
26
+ - object / array / typeless fields take a JSON argument: `--field '<inline json>'` or `--field @path/to.json`
27
+
28
+ Example:
29
+
30
+ ```bash
31
+ pi-context read-block --block tasks
32
+ pi-context append-block-item --block issues --arrayKey issues --item @new-issue.json --autoId
33
+ pi-context read-block-page --block framework-gaps --offset 0 --limit 50
34
+ ```
35
+
36
+ ## Global flags
37
+
38
+ - `--cwd <dir>` — substrate root (default: current working directory; relative paths resolve against it)
39
+ - `--json` — emit a `{ ok, op, output }` envelope on success (`{ ok: false, op, error }` on failure) instead of raw output
40
+ - `--yes`, `--force` — pre-authorize an auth-gated op in a non-interactive context
41
+ - `--writer <json>` — override the auto-resolved writer identity
42
+ - `--help`, `-h` — top-level help, or per-op help after an op name
43
+
44
+ ## Writer identity
45
+
46
+ Ops that declare a `writer` parameter (e.g. `promote-item`, `write-schema-migration`) get it injected automatically when not passed via `--writer`. The identity is resolved by cascade: `git config user.email`, then `$USER`, then the literal `"operator"`. Pass `--writer '{"kind":"human","user":"you@example.com"}'` to override.
47
+
48
+ ## Auth-gated ops
49
+
50
+ Ops marked `authGated` (writes that mutate config / schemas / migrations) require authorization, mirroring the in-pi dispatch gate:
51
+
52
+ - `--yes` / `--force` proceeds immediately
53
+ - on an interactive terminal you are prompted (`Authorize <op>? [y/N]`)
54
+ - in a non-interactive context without `--yes` the op refuses
55
+
56
+ ## Exit codes
57
+
58
+ - `0` — success
59
+ - `1` — op/runtime error, or declined authorization
60
+ - `2` — usage error (unknown op, unknown flag, missing required field)
package/dist/cli.d.ts ADDED
@@ -0,0 +1,104 @@
1
+ #!/usr/bin/env node
2
+ import { type OpDefinition } from "@davidorex/pi-context/ops";
3
+ /**
4
+ * The surfaced command set: every op the CLI exposes. Derived by reflection —
5
+ * NOT a hardcoded list. A `surface: "process"` op (currently only list-tools)
6
+ * is excluded here by the partition, never by name.
7
+ */
8
+ export declare const useOps: OpDefinition[];
9
+ /** Field-type tag rendered in help and used to pick a coercion strategy. */
10
+ export type FieldType = "string" | "number" | "boolean" | "json";
11
+ interface FieldSchema {
12
+ type?: string;
13
+ description?: string;
14
+ anyOf?: Array<{
15
+ type?: string;
16
+ const?: unknown;
17
+ enum?: unknown[];
18
+ }>;
19
+ }
20
+ /**
21
+ * Extract the literal string values of a string-enum field, or null for any
22
+ * non-enum shape. A typebox `Type.Union([Type.Literal("eq"), …])` serializes at
23
+ * runtime to `{ anyOf: [{ type: "string", const: "eq" }, …] }` with no
24
+ * top-level `type` — so the union members must be read off `anyOf`.
25
+ *
26
+ * Returns the string values only when `anyOf` is a non-empty array and EVERY
27
+ * element contributes string members (a `const` string, or — for forward
28
+ * safety against an element-level `enum` shape — string members of an `enum`
29
+ * array). Any element that fails to contribute makes the whole shape non-enum
30
+ * (returns null), so mixed unions and non-string literals are left untouched
31
+ * and continue to flow through the JSON path.
32
+ */
33
+ export declare function stringEnumValues(field: FieldSchema): string[] | null;
34
+ /**
35
+ * Map a typebox field schema to a CLI field type. Scalars carry an explicit
36
+ * `type`; Type.Unknown() has no `type`; Type.Record/Type.Object report
37
+ * `type:"object"`; arrays `type:"array"` — all of which are JSON-arg fields.
38
+ */
39
+ export declare function fieldType(field: FieldSchema): FieldType;
40
+ /** Look up a surfaced op by name. Returns undefined for unknown/non-use ops. */
41
+ export declare function resolveOp(name: string): OpDefinition | undefined;
42
+ /** True when `name` is a real op but not surfaced via the CLI (surface!=="use"). */
43
+ export declare function isProcessOnlyOp(name: string): boolean;
44
+ /**
45
+ * Resolve the operator identity for schema-driven writer injection. Cascade
46
+ * (replicated from pi-agent-dispatch getVerifiedOperatorIdentity, which is not
47
+ * importable without dragging the dispatch tree):
48
+ * (1) `git config user.email`, trimmed, if non-empty
49
+ * (2) process.env.USER, if non-empty
50
+ * (3) null
51
+ * Dependencies are injectable for unit testing.
52
+ */
53
+ export declare function resolveIdentity(deps?: {
54
+ gitEmail?: () => string | null;
55
+ envUser?: string | undefined;
56
+ }): string | null;
57
+ export interface ParsedArgs {
58
+ cwd: string;
59
+ json: boolean;
60
+ yes: boolean;
61
+ help: boolean;
62
+ explicitWriter?: unknown;
63
+ params: Record<string, unknown>;
64
+ }
65
+ export declare class UsageError extends Error {
66
+ }
67
+ /**
68
+ * Parse the argv tail (everything after the op name) against the op's schema.
69
+ * Throws UsageError on unknown flags, missing required fields, or malformed
70
+ * values. Does NOT inject the writer or evaluate the auth gate — callers do
71
+ * that after parsing so those concerns stay independently testable.
72
+ */
73
+ export declare function parseOpArgs(op: OpDefinition, argv: string[], cwdBase?: string): ParsedArgs;
74
+ /**
75
+ * Schema-driven writer injection: when the op declares a `writer` field and the
76
+ * caller did not pass `--writer`, fill params.writer from the resolved operator
77
+ * identity (falling back to "operator"). Mutates and returns `params`.
78
+ */
79
+ export declare function injectWriter(op: OpDefinition, params: Record<string, unknown>, identity: string | null): Record<string, unknown>;
80
+ export type AuthDecision = {
81
+ allow: true;
82
+ } | {
83
+ allow: false;
84
+ reason: string;
85
+ needsPrompt: boolean;
86
+ };
87
+ /**
88
+ * Pure auth-gate decision (no I/O). Mirrors the pi-agent-dispatch gate:
89
+ * - not gated → allow
90
+ * - --yes/--force → allow
91
+ * - interactive TTY → defer to a prompt (needsPrompt)
92
+ * - non-interactive without --yes → refuse
93
+ */
94
+ export declare function authDecision(op: OpDefinition, opts: {
95
+ yes: boolean;
96
+ interactive: boolean;
97
+ }): AuthDecision;
98
+ /** Per-op help text: description + one line per declared field. */
99
+ export declare function deriveHelp(op: OpDefinition): string;
100
+ /** Top-level help: one line per surfaced op + global flag notes. */
101
+ export declare function deriveTopHelp(): string;
102
+ export declare function main(argv: string[]): Promise<number>;
103
+ export {};
104
+ //# sourceMappingURL=cli.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":";AA+BA,OAAO,EAAE,KAAK,YAAY,EAAO,MAAM,2BAA2B,CAAC;AAEnE;;;;GAIG;AACH,eAAO,MAAM,MAAM,EAAE,YAAY,EAA2C,CAAC;AAE7E,4EAA4E;AAC5E,MAAM,MAAM,SAAS,GAAG,QAAQ,GAAG,QAAQ,GAAG,SAAS,GAAG,MAAM,CAAC;AAEjE,UAAU,WAAW;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,WAAW,CAAC,EAAE,MAAM,CAAC;IACrB,KAAK,CAAC,EAAE,KAAK,CAAC;QAAE,IAAI,CAAC,EAAE,MAAM,CAAC;QAAC,KAAK,CAAC,EAAE,OAAO,CAAC;QAAC,IAAI,CAAC,EAAE,OAAO,EAAE,CAAA;KAAE,CAAC,CAAC;CACpE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,gBAAgB,CAAC,KAAK,EAAE,WAAW,GAAG,MAAM,EAAE,GAAG,IAAI,CAmBpE;AAYD;;;;GAIG;AACH,wBAAgB,SAAS,CAAC,KAAK,EAAE,WAAW,GAAG,SAAS,CAgBvD;AAED,gFAAgF;AAChF,wBAAgB,SAAS,CAAC,IAAI,EAAE,MAAM,GAAG,YAAY,GAAG,SAAS,CAEhE;AAED,oFAAoF;AACpF,wBAAgB,eAAe,CAAC,IAAI,EAAE,MAAM,GAAG,OAAO,CAErD;AAED;;;;;;;;GAQG;AACH,wBAAgB,eAAe,CAAC,IAAI,CAAC,EAAE;IACtC,QAAQ,CAAC,EAAE,MAAM,MAAM,GAAG,IAAI,CAAC;IAC/B,OAAO,CAAC,EAAE,MAAM,GAAG,SAAS,CAAC;CAC7B,GAAG,MAAM,GAAG,IAAI,CAmBhB;AAED,MAAM,WAAW,UAAU;IAC1B,GAAG,EAAE,MAAM,CAAC;IACZ,IAAI,EAAE,OAAO,CAAC;IACd,GAAG,EAAE,OAAO,CAAC;IACb,IAAI,EAAE,OAAO,CAAC;IACd,cAAc,CAAC,EAAE,OAAO,CAAC;IACzB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;CAChC;AAED,qBAAa,UAAW,SAAQ,KAAK;CAAG;AAExC;;;;;GAKG;AACH,wBAAgB,WAAW,CAAC,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE,MAAM,EAAE,EAAE,OAAO,SAAgB,GAAG,UAAU,CAwGjG;AAED;;;;GAIG;AACH,wBAAgB,YAAY,CAC3B,EAAE,EAAE,YAAY,EAChB,MAAM,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,EAC/B,QAAQ,EAAE,MAAM,GAAG,IAAI,GACrB,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAMzB;AAED,MAAM,MAAM,YAAY,GAAG;IAAE,KAAK,EAAE,IAAI,CAAA;CAAE,GAAG;IAAE,KAAK,EAAE,KAAK,CAAC;IAAC,MAAM,EAAE,MAAM,CAAC;IAAC,WAAW,EAAE,OAAO,CAAA;CAAE,CAAC;AAEpG;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,EAAE,EAAE,YAAY,EAAE,IAAI,EAAE;IAAE,GAAG,EAAE,OAAO,CAAC;IAAC,WAAW,EAAE,OAAO,CAAA;CAAE,GAAG,YAAY,CASzG;AAED,mEAAmE;AACnE,wBAAgB,UAAU,CAAC,EAAE,EAAE,YAAY,GAAG,MAAM,CAoBnD;AAED,oEAAoE;AACpE,wBAAgB,aAAa,IAAI,MAAM,CAgBtC;AAcD,wBAAsB,IAAI,CAAC,IAAI,EAAE,MAAM,EAAE,GAAG,OAAO,CAAC,MAAM,CAAC,CAsE1D"}
package/dist/cli.js ADDED
@@ -0,0 +1,427 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * pi-context — auto-tracking command-line interface over the pi-context
4
+ * op-registry.
5
+ *
6
+ * The command set is derived by REFLECTION over the imported `ops` array
7
+ * (`@davidorex/pi-context/ops`): every OpDefinition whose `surface === "use"`
8
+ * becomes a CLI command. Adding an op to pi-context surfaces a new CLI command
9
+ * with zero edits here — there is intentionally NO hardcoded op-name list. The
10
+ * one op that depends on a pi-runtime handle (list-tools) carries
11
+ * `surface: "process"` at source and is therefore filtered out by the same
12
+ * partition, not by name.
13
+ *
14
+ * Per-op flags are derived from each op's typebox `parameters` schema: scalar
15
+ * fields (string/number/boolean) take `--field value` (boolean is a presence
16
+ * flag); object/array/typeless fields take a JSON argument (`--field '<json>'`
17
+ * or `--field @file.json`). Required fields (op.parameters.required) are
18
+ * enforced before invocation, except `writer`, which is schema-driven
19
+ * auto-injected from the resolved operator identity when not passed explicitly.
20
+ *
21
+ * authGated ops mirror the pi-agent-dispatch auth-gate: `--yes`/`--force`
22
+ * proceeds; interactive TTY prompts; non-interactive without `--yes` refuses.
23
+ *
24
+ * The pure pieces (resolveOp / parseOpArgs / deriveHelp / deriveTopHelp /
25
+ * resolveIdentity / authDecision / useOps) are exported for unit testing.
26
+ */
27
+ import { execSync } from "node:child_process";
28
+ import { readFileSync } from "node:fs";
29
+ import path from "node:path";
30
+ import { createInterface } from "node:readline";
31
+ import { fileURLToPath } from "node:url";
32
+ import { ops } from "@davidorex/pi-context/ops";
33
+ /**
34
+ * The surfaced command set: every op the CLI exposes. Derived by reflection —
35
+ * NOT a hardcoded list. A `surface: "process"` op (currently only list-tools)
36
+ * is excluded here by the partition, never by name.
37
+ */
38
+ export const useOps = ops.filter((o) => o.surface === "use");
39
+ /**
40
+ * Extract the literal string values of a string-enum field, or null for any
41
+ * non-enum shape. A typebox `Type.Union([Type.Literal("eq"), …])` serializes at
42
+ * runtime to `{ anyOf: [{ type: "string", const: "eq" }, …] }` with no
43
+ * top-level `type` — so the union members must be read off `anyOf`.
44
+ *
45
+ * Returns the string values only when `anyOf` is a non-empty array and EVERY
46
+ * element contributes string members (a `const` string, or — for forward
47
+ * safety against an element-level `enum` shape — string members of an `enum`
48
+ * array). Any element that fails to contribute makes the whole shape non-enum
49
+ * (returns null), so mixed unions and non-string literals are left untouched
50
+ * and continue to flow through the JSON path.
51
+ */
52
+ export function stringEnumValues(field) {
53
+ const anyOf = field.anyOf;
54
+ if (!Array.isArray(anyOf) || anyOf.length === 0)
55
+ return null;
56
+ const values = [];
57
+ for (const el of anyOf) {
58
+ if (el.type === "string" && typeof el.const === "string") {
59
+ values.push(el.const);
60
+ continue;
61
+ }
62
+ if (Array.isArray(el.enum)) {
63
+ const strings = el.enum.filter((e) => typeof e === "string");
64
+ if (strings.length === el.enum.length && strings.length > 0) {
65
+ values.push(...strings);
66
+ continue;
67
+ }
68
+ }
69
+ return null;
70
+ }
71
+ return values.length > 0 ? values : null;
72
+ }
73
+ /** The typebox Type.Object value carried at runtime on op.parameters. */
74
+ function objectSchema(op) {
75
+ return op.parameters ?? {};
76
+ }
77
+ /**
78
+ * Map a typebox field schema to a CLI field type. Scalars carry an explicit
79
+ * `type`; Type.Unknown() has no `type`; Type.Record/Type.Object report
80
+ * `type:"object"`; arrays `type:"array"` — all of which are JSON-arg fields.
81
+ */
82
+ export function fieldType(field) {
83
+ // String-enum unions (Type.Union of string literals) coerce as verbatim
84
+ // strings — identical to a plain string field — not as JSON.
85
+ if (stringEnumValues(field) !== null)
86
+ return "string";
87
+ switch (field.type) {
88
+ case "string":
89
+ return "string";
90
+ case "number":
91
+ case "integer":
92
+ return "number";
93
+ case "boolean":
94
+ return "boolean";
95
+ default:
96
+ // object | array | undefined (Type.Unknown) → JSON argument
97
+ return "json";
98
+ }
99
+ }
100
+ /** Look up a surfaced op by name. Returns undefined for unknown/non-use ops. */
101
+ export function resolveOp(name) {
102
+ return useOps.find((o) => o.name === name);
103
+ }
104
+ /** True when `name` is a real op but not surfaced via the CLI (surface!=="use"). */
105
+ export function isProcessOnlyOp(name) {
106
+ return ops.some((o) => o.name === name) && !useOps.some((o) => o.name === name);
107
+ }
108
+ /**
109
+ * Resolve the operator identity for schema-driven writer injection. Cascade
110
+ * (replicated from pi-agent-dispatch getVerifiedOperatorIdentity, which is not
111
+ * importable without dragging the dispatch tree):
112
+ * (1) `git config user.email`, trimmed, if non-empty
113
+ * (2) process.env.USER, if non-empty
114
+ * (3) null
115
+ * Dependencies are injectable for unit testing.
116
+ */
117
+ export function resolveIdentity(deps) {
118
+ const gitEmail = deps?.gitEmail ??
119
+ (() => {
120
+ try {
121
+ return execSync("git config user.email", {
122
+ encoding: "utf8",
123
+ stdio: ["ignore", "pipe", "ignore"],
124
+ }).trim();
125
+ }
126
+ catch {
127
+ return null;
128
+ }
129
+ });
130
+ const envUser = deps && "envUser" in deps ? deps.envUser : process.env.USER;
131
+ const email = gitEmail();
132
+ if (email && email.length > 0)
133
+ return email;
134
+ if (envUser && envUser.length > 0)
135
+ return envUser;
136
+ return null;
137
+ }
138
+ export class UsageError extends Error {
139
+ }
140
+ /**
141
+ * Parse the argv tail (everything after the op name) against the op's schema.
142
+ * Throws UsageError on unknown flags, missing required fields, or malformed
143
+ * values. Does NOT inject the writer or evaluate the auth gate — callers do
144
+ * that after parsing so those concerns stay independently testable.
145
+ */
146
+ export function parseOpArgs(op, argv, cwdBase = process.cwd()) {
147
+ const schema = objectSchema(op);
148
+ const props = schema.properties ?? {};
149
+ const out = {
150
+ cwd: cwdBase,
151
+ json: false,
152
+ yes: false,
153
+ help: false,
154
+ params: {},
155
+ };
156
+ for (let i = 0; i < argv.length; i++) {
157
+ const tok = argv[i];
158
+ if (tok === "--help" || tok === "-h") {
159
+ out.help = true;
160
+ continue;
161
+ }
162
+ if (tok === "--json") {
163
+ out.json = true;
164
+ continue;
165
+ }
166
+ if (tok === "--yes" || tok === "--force") {
167
+ out.yes = true;
168
+ continue;
169
+ }
170
+ if (tok === "--cwd") {
171
+ const v = argv[++i];
172
+ if (v === undefined)
173
+ throw new UsageError("--cwd requires a directory argument");
174
+ out.cwd = path.isAbsolute(v) ? v : path.resolve(cwdBase, v);
175
+ continue;
176
+ }
177
+ if (tok === "--writer") {
178
+ const v = argv[++i];
179
+ if (v === undefined)
180
+ throw new UsageError("--writer requires a JSON argument");
181
+ try {
182
+ out.explicitWriter = v.startsWith("@") ? JSON.parse(readFileSync(v.slice(1), "utf8")) : JSON.parse(v);
183
+ }
184
+ catch (err) {
185
+ throw new UsageError(`--writer: ${err instanceof Error ? err.message : String(err)}`);
186
+ }
187
+ continue;
188
+ }
189
+ if (!tok.startsWith("--")) {
190
+ throw new UsageError(`unexpected argument: ${tok}`);
191
+ }
192
+ const field = tok.slice(2);
193
+ const fschema = props[field];
194
+ if (fschema === undefined) {
195
+ throw new UsageError(`unknown flag: ${tok}`);
196
+ }
197
+ const kind = fieldType(fschema);
198
+ if (kind === "boolean") {
199
+ // Presence flag; accept an optional explicit true|false next token.
200
+ const next = argv[i + 1];
201
+ if (next === "true" || next === "false") {
202
+ out.params[field] = next === "true";
203
+ i++;
204
+ }
205
+ else {
206
+ out.params[field] = true;
207
+ }
208
+ continue;
209
+ }
210
+ const value = argv[++i];
211
+ if (value === undefined)
212
+ throw new UsageError(`--${field} requires a value`);
213
+ if (kind === "number") {
214
+ const n = Number(value);
215
+ if (Number.isNaN(n))
216
+ throw new UsageError(`--${field} expects a number, got '${value}'`);
217
+ out.params[field] = n;
218
+ }
219
+ else if (kind === "string") {
220
+ const vals = stringEnumValues(fschema);
221
+ if (vals !== null && !vals.includes(value)) {
222
+ throw new UsageError(`--${field} expects one of: ${vals.join(", ")}; got '${value}'`);
223
+ }
224
+ out.params[field] = value;
225
+ }
226
+ else {
227
+ // json: inline JSON or @file
228
+ try {
229
+ out.params[field] = value.startsWith("@")
230
+ ? JSON.parse(readFileSync(value.slice(1), "utf8"))
231
+ : JSON.parse(value);
232
+ }
233
+ catch (err) {
234
+ throw new UsageError(`--${field}: ${err instanceof Error ? err.message : String(err)}`);
235
+ }
236
+ }
237
+ }
238
+ if (out.explicitWriter !== undefined) {
239
+ out.params.writer = out.explicitWriter;
240
+ }
241
+ // Required-field check — `writer` is exempt (schema-driven auto-injected
242
+ // after parse when the op declares it and none was passed).
243
+ if (!out.help) {
244
+ const required = (schema.required ?? []).filter((r) => r !== "writer");
245
+ const missing = required.filter((r) => !(r in out.params));
246
+ if (missing.length > 0) {
247
+ throw new UsageError(`missing required: ${missing.map((m) => `--${m}`).join(", ")}`);
248
+ }
249
+ }
250
+ return out;
251
+ }
252
+ /**
253
+ * Schema-driven writer injection: when the op declares a `writer` field and the
254
+ * caller did not pass `--writer`, fill params.writer from the resolved operator
255
+ * identity (falling back to "operator"). Mutates and returns `params`.
256
+ */
257
+ export function injectWriter(op, params, identity) {
258
+ const props = objectSchema(op).properties ?? {};
259
+ if (props.writer !== undefined && params.writer === undefined) {
260
+ params.writer = { kind: "human", user: identity ?? "operator" };
261
+ }
262
+ return params;
263
+ }
264
+ /**
265
+ * Pure auth-gate decision (no I/O). Mirrors the pi-agent-dispatch gate:
266
+ * - not gated → allow
267
+ * - --yes/--force → allow
268
+ * - interactive TTY → defer to a prompt (needsPrompt)
269
+ * - non-interactive without --yes → refuse
270
+ */
271
+ export function authDecision(op, opts) {
272
+ if (op.authGated !== true)
273
+ return { allow: true };
274
+ if (opts.yes)
275
+ return { allow: true };
276
+ if (opts.interactive)
277
+ return { allow: false, needsPrompt: true, reason: "interactive confirmation required" };
278
+ return {
279
+ allow: false,
280
+ needsPrompt: false,
281
+ reason: `${op.name} requires authorization; re-run with --yes in a non-interactive context`,
282
+ };
283
+ }
284
+ /** Per-op help text: description + one line per declared field. */
285
+ export function deriveHelp(op) {
286
+ const schema = objectSchema(op);
287
+ const props = schema.properties ?? {};
288
+ const required = new Set(schema.required ?? []);
289
+ const lines = [`${op.name} — ${op.description}`, ""];
290
+ const entries = Object.entries(props);
291
+ if (entries.length === 0) {
292
+ lines.push(" (no parameters)");
293
+ }
294
+ else {
295
+ lines.push("Flags:");
296
+ for (const [field, fschema] of entries) {
297
+ const vals = stringEnumValues(fschema);
298
+ const t = vals ? vals.join("|") : fieldType(fschema);
299
+ const req = required.has(field) ? "required" : "optional";
300
+ const desc = fschema.description ? ` — ${fschema.description}` : "";
301
+ lines.push(` --${field} <${t}> (${req})${desc}`);
302
+ }
303
+ }
304
+ lines.push("", "Global flags: --cwd <dir> --json --yes --writer <json> --help");
305
+ return lines.join("\n");
306
+ }
307
+ /** Top-level help: one line per surfaced op + global flag notes. */
308
+ export function deriveTopHelp() {
309
+ const lines = ["pi-context <op> [flags]", "", "Commands:"];
310
+ const width = Math.max(...useOps.map((o) => o.name.length));
311
+ for (const op of useOps) {
312
+ lines.push(` ${op.name.padEnd(width)} — ${op.description.split("\n")[0]}`);
313
+ }
314
+ lines.push("", "Global flags:", " --cwd <dir> substrate root (default: cwd)", " --json emit { ok, op, output } envelope", " --yes, --force pre-authorize gated ops in non-interactive contexts", " --writer <json> override the auto-resolved writer identity", " --help, -h this help, or per-op help after an op name");
315
+ return lines.join("\n");
316
+ }
317
+ /** Prompt the operator on an interactive TTY. Resolves true on y/yes. */
318
+ function promptConfirm(opName) {
319
+ const rl = createInterface({ input: process.stdin, output: process.stdout });
320
+ return new Promise((resolve) => {
321
+ rl.question(`Authorize ${opName}? [y/N] `, (answer) => {
322
+ rl.close();
323
+ const a = answer.trim().toLowerCase();
324
+ resolve(a === "y" || a === "yes");
325
+ });
326
+ });
327
+ }
328
+ export async function main(argv) {
329
+ const first = argv[0];
330
+ if (first === undefined || first === "--help" || first === "-h") {
331
+ process.stdout.write(`${deriveTopHelp()}\n`);
332
+ return 0;
333
+ }
334
+ const op = resolveOp(first);
335
+ if (op === undefined) {
336
+ if (isProcessOnlyOp(first)) {
337
+ process.stderr.write(`${first} is not available via the CLI (process-only op)\n`);
338
+ }
339
+ else {
340
+ process.stderr.write(`unknown command: ${first}\n\n${deriveTopHelp()}\n`);
341
+ }
342
+ return 2;
343
+ }
344
+ let parsed;
345
+ try {
346
+ parsed = parseOpArgs(op, argv.slice(1));
347
+ }
348
+ catch (err) {
349
+ if (err instanceof UsageError) {
350
+ process.stderr.write(`error: ${err.message}\n\n${deriveHelp(op)}\n`);
351
+ return 2;
352
+ }
353
+ throw err;
354
+ }
355
+ if (parsed.help) {
356
+ process.stdout.write(`${deriveHelp(op)}\n`);
357
+ return 0;
358
+ }
359
+ injectWriter(op, parsed.params, resolveIdentity());
360
+ const decision = authDecision(op, {
361
+ yes: parsed.yes,
362
+ interactive: Boolean(process.stdin.isTTY && process.stdout.isTTY),
363
+ });
364
+ if (decision.allow === false) {
365
+ if (decision.needsPrompt) {
366
+ const ok = await promptConfirm(op.name);
367
+ if (!ok) {
368
+ process.stderr.write(`declined: ${op.name} not authorized\n`);
369
+ return 1;
370
+ }
371
+ }
372
+ else {
373
+ process.stderr.write(`${decision.reason}\n`);
374
+ return 1;
375
+ }
376
+ }
377
+ try {
378
+ const text = await op.run(parsed.cwd, parsed.params);
379
+ if (parsed.json) {
380
+ process.stdout.write(`${JSON.stringify({ ok: true, op: op.name, output: text })}\n`);
381
+ }
382
+ else {
383
+ process.stdout.write(`${text}\n`);
384
+ }
385
+ return 0;
386
+ }
387
+ catch (err) {
388
+ const message = err instanceof Error ? err.message : String(err);
389
+ if (parsed.json) {
390
+ process.stdout.write(`${JSON.stringify({ ok: false, op: op.name, error: message })}\n`);
391
+ }
392
+ else {
393
+ process.stderr.write(`error: ${message}\n`);
394
+ }
395
+ return 1;
396
+ }
397
+ }
398
+ /**
399
+ * True when this module is the process entrypoint (invoked as `pi-context …`),
400
+ * false when it is merely imported (e.g. by the unit tests). Guards the
401
+ * auto-run so importing the module to test its pure helpers does not execute
402
+ * main() against the test runner's argv.
403
+ */
404
+ function isEntrypoint() {
405
+ const invoked = process.argv[1];
406
+ if (invoked === undefined)
407
+ return false;
408
+ try {
409
+ return fileURLToPath(import.meta.url) === path.resolve(invoked);
410
+ }
411
+ catch {
412
+ return false;
413
+ }
414
+ }
415
+ // Module entrypoint: run main() and map its resolved exit code. A thrown
416
+ // (non-UsageError) error maps to exit 1.
417
+ if (isEntrypoint()) {
418
+ main(process.argv.slice(2))
419
+ .then((code) => {
420
+ process.exitCode = code;
421
+ })
422
+ .catch((err) => {
423
+ process.stderr.write(`error: ${err instanceof Error ? err.message : String(err)}\n`);
424
+ process.exitCode = 1;
425
+ });
426
+ }
427
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
package/package.json ADDED
@@ -0,0 +1,42 @@
1
+ {
2
+ "name": "@davidorex/pi-context-cli",
3
+ "version": "0.28.0",
4
+ "publishConfig": {
5
+ "access": "public"
6
+ },
7
+ "description": "Auto-tracking command-line interface over the pi-context op-registry — every substrate op surfaces as a CLI command by reflection, no hardcoded command list",
8
+ "license": "MIT",
9
+ "author": "David Ryan",
10
+ "type": "module",
11
+ "keywords": [
12
+ "pi-context",
13
+ "cli"
14
+ ],
15
+ "repository": {
16
+ "type": "git",
17
+ "url": "git+https://github.com/davidorex/pi-project-workflows.git",
18
+ "directory": "packages/pi-context-cli"
19
+ },
20
+ "homepage": "https://github.com/davidorex/pi-project-workflows/tree/main/packages/pi-context-cli",
21
+ "main": "./dist/cli.js",
22
+ "bin": {
23
+ "pi-context": "./dist/cli.js"
24
+ },
25
+ "files": [
26
+ "dist/",
27
+ "*.md"
28
+ ],
29
+ "scripts": {
30
+ "clean": "rm -rf dist",
31
+ "build": "rm -rf dist && tsc -p tsconfig.build.json",
32
+ "prepublishOnly": "npm run clean && npm run build",
33
+ "test": "tsx --test src/*.test.ts"
34
+ },
35
+ "dependencies": {
36
+ "@davidorex/pi-context": "^0.28.0",
37
+ "typebox": "^1.1.24"
38
+ },
39
+ "engines": {
40
+ "node": ">=22.19.0"
41
+ }
42
+ }