@north-light/crouter-api 0.3.280 → 0.3.282

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.
@@ -0,0 +1,208 @@
1
+ /** How prominently a node surfaces in ancestor `-h` listings. Default 'normal'. */
2
+ export type ManifestTier = 'normal' | 'common' | 'important';
3
+ /** Root-entry prose for a top-level branch — what every agent reads before it
4
+ * has engaged the command at all. Required on a plugin's top-level branch. */
5
+ export interface ManifestRootEntry {
6
+ concept: string;
7
+ description: string;
8
+ whenToUse: string;
9
+ }
10
+ /** One declared output field of a leaf's result. */
11
+ export interface ManifestField {
12
+ name: string;
13
+ type: string;
14
+ required: boolean;
15
+ /** Inline semantic constraint — bounds, enum, token caps. */
16
+ constraint: string;
17
+ }
18
+ /** How a local file named by a `path` param is encoded into the request: 'text'
19
+ * as UTF-8, 'base64' as the base64 of its raw bytes. The path string itself
20
+ * never crosses the wire. */
21
+ export type ManifestFileEncoding = 'text' | 'base64';
22
+ export interface ManifestPositionalParam {
23
+ kind: 'positional';
24
+ name: string;
25
+ /** Display hint only; always parsed as string. */
26
+ type?: 'string' | 'path';
27
+ required: boolean;
28
+ constraint: string;
29
+ /** Collect every remaining positional token into an array, in argv order.
30
+ * Only an `in: 'body'` REST mapping can carry an array. */
31
+ repeatable?: boolean;
32
+ /** Valid only on a `path` param. */
33
+ encoding?: ManifestFileEncoding;
34
+ /** See {@link ManifestFlagParam.defaultFromEnv}. */
35
+ defaultFromEnv?: string;
36
+ }
37
+ export interface ManifestFlagParam {
38
+ kind: 'flag';
39
+ name: string;
40
+ /** 'bool' flags take no value — presence is true. */
41
+ type: 'string' | 'int' | 'bool' | 'path' | 'enum';
42
+ /** Required, and only valid, when type is 'enum'. */
43
+ choices?: string[];
44
+ required: boolean;
45
+ constraint: string;
46
+ default?: string | number | boolean;
47
+ /** Repeat the flag to accumulate an array value. Valid only on string/int/enum,
48
+ * only with an `in: 'body'` REST mapping, and never alongside `default`. */
49
+ repeatable?: boolean;
50
+ /** Valid only on a `path` flag. */
51
+ encoding?: ManifestFileEncoding;
52
+ /** UPPER_SNAKE_CASE environment variable on the CALLING machine whose value
53
+ * fills this param when the caller omits it. An env-sourced value counts as
54
+ * SUPPLIED — it satisfies `required` and ships on the wire — unlike a static
55
+ * `default`, which does neither. Valid only on string/path params, never
56
+ * alongside `default` or `repeatable`. */
57
+ defaultFromEnv?: string;
58
+ }
59
+ /** Raw stdin content blob — piped text, not parsed as JSON. */
60
+ export interface ManifestStdinParam {
61
+ kind: 'stdin';
62
+ name: string;
63
+ required: boolean;
64
+ constraint: string;
65
+ }
66
+ /** `--context-file PATH`: reads and JSON-parses the file at PATH. */
67
+ export interface ManifestContextFileParam {
68
+ kind: 'context-file';
69
+ name: string;
70
+ required: boolean;
71
+ constraint: string;
72
+ /** Description of the expected JSON shape. */
73
+ shape?: string;
74
+ }
75
+ export type ManifestInputParam = ManifestPositionalParam | ManifestFlagParam | ManifestStdinParam | ManifestContextFileParam;
76
+ export type RestMethod = 'GET' | 'POST' | 'PUT' | 'PATCH' | 'DELETE';
77
+ export type RestParamPlacement = 'path' | 'query' | 'body' | 'header';
78
+ export interface RestParamMapping {
79
+ in: RestParamPlacement;
80
+ /** Rename for query/body; required for header; forbidden for path. */
81
+ as?: string;
82
+ }
83
+ export interface RestMapping {
84
+ method: RestMethod;
85
+ /** Absolute path template; each `{param}` placeholder names an `in: 'path'` param. */
86
+ path: string;
87
+ /** Default false. true means the response is an NDJSON stream relayed verbatim. */
88
+ streaming?: boolean;
89
+ /** Constant body fields merged into the request body verbatim (e.g. the `op`
90
+ * discriminator on a single-endpoint invoke surface) — never sourced from a
91
+ * declared param, and forbidden on GET. */
92
+ body?: Record<string, string | number | boolean>;
93
+ /** When set, every `in: 'body'` param value nests under this key instead of
94
+ * sitting top-level (`bodyRoot: 'args'` → `{ args: { name, url } }`);
95
+ * `body` constants stay top-level regardless. Forbidden on GET. */
96
+ bodyRoot?: string;
97
+ /** Keyed by declared param name; every declared param appears exactly once. */
98
+ params: Record<string, RestParamMapping>;
99
+ }
100
+ export interface ManifestTimeouts {
101
+ connectMs?: number;
102
+ requestMs?: number;
103
+ streamIdleMs?: number;
104
+ }
105
+ /** Exec transport only: forward every argv token after this branch to an
106
+ * external binary instead of parsing children. A passthrough branch is
107
+ * childless by construction; an HTTP manifest rejects it, because an HTTP
108
+ * transport must not name a local binary to execute. */
109
+ export interface ManifestPassthrough {
110
+ bin: string;
111
+ installHint: string;
112
+ }
113
+ export interface ManifestLeafBase {
114
+ kind: 'leaf';
115
+ name: string;
116
+ description: string;
117
+ whenToUse: string;
118
+ tier?: ManifestTier;
119
+ summary: string;
120
+ params: ManifestInputParam[];
121
+ output: ManifestField[];
122
+ /** Non-empty; `["None. Read-only."]` for a read-only leaf. Read-only, so a
123
+ * server assembling a manifest may hand over a frozen or `as const` list. */
124
+ effects: readonly string[];
125
+ }
126
+ /** Exec-transport leaf. */
127
+ export interface ManifestExecLeaf extends ManifestLeafBase {
128
+ outputKind: 'object';
129
+ }
130
+ /** HTTP-transport leaf; `outputKind` derives from `rest.streaming`. */
131
+ export interface ManifestHttpLeaf extends ManifestLeafBase {
132
+ rest: RestMapping;
133
+ }
134
+ export type ManifestLeaf = ManifestExecLeaf | ManifestHttpLeaf;
135
+ export interface ManifestBranch<L extends ManifestLeafBase = ManifestLeaf> {
136
+ kind: 'branch';
137
+ name: string;
138
+ description: string;
139
+ whenToUse: string;
140
+ tier?: ManifestTier;
141
+ /** Required on a top-level branch, forbidden on a nested one. */
142
+ rootEntry?: ManifestRootEntry;
143
+ /** Allows the nearest repository fragment to contribute children below this
144
+ * top-level branch. */
145
+ extensible?: true;
146
+ summary: string;
147
+ model?: string;
148
+ /** Exec dialect only, and the type says so rather than leaving it to the
149
+ * runtime validator: an HTTP-transport manifest naming a local binary to run
150
+ * is the one shape a served manifest must never be able to express. `never`
151
+ * on the HTTP leaf dialect makes `passthrough: {...}` a compile error in a
152
+ * `ManifestBranch<ManifestHttpLeaf>`, and the conditional distributes over
153
+ * the default union so a plain `ManifestBranch` still accepts it. */
154
+ passthrough?: L extends ManifestExecLeaf ? ManifestPassthrough : never;
155
+ children: ManifestNode<L>[];
156
+ }
157
+ /** A branch or a leaf. The parameter fixes which leaf dialect the whole subtree
158
+ * may use, so an HTTP manifest cannot smuggle an exec leaf into a child slot. */
159
+ export type ManifestNode<L extends ManifestLeafBase = ManifestLeaf> = ManifestBranch<L> | L;
160
+ /** One mount point in the manifest's self-contained forest. */
161
+ export interface ManifestMount<L extends ManifestLeafBase = ManifestLeaf> {
162
+ /** `[]` mounts `node` as a new top-level command; a non-empty path names a
163
+ * branch this SAME manifest already contributes. */
164
+ parent: string[];
165
+ node: ManifestNode<L>;
166
+ }
167
+ /**
168
+ * A whole `commands.json` for an HTTP-transport plugin whose endpoint and auth
169
+ * live in the bundle's `bundle.json` rather than the manifest.
170
+ */
171
+ export interface HttpPluginCommandManifest {
172
+ schemaVersion: 1;
173
+ /** Overrides the registration endpoint as the base for every leaf's REST path. */
174
+ baseUrl?: string;
175
+ timeouts?: ManifestTimeouts;
176
+ mounts: ManifestMount<ManifestHttpLeaf>[];
177
+ /** Core command path (space-joined, e.g. "cron add") → product addendum
178
+ * appended to that command's help, rendered by crtr as an attributed
179
+ * `<plugin-help plugin="...">` block after the core body. Append-only by
180
+ * contract: an addendum adds product meaning beneath substrate help, never
181
+ * replaces it. A key naming no core command path fails validation at guest
182
+ * install. */
183
+ helpAddenda?: Record<string, string>;
184
+ }
185
+ /**
186
+ * The one field a plugin's HTTP backend adds to an error envelope to say the
187
+ * client parsed this call from an out-of-date description of its commands.
188
+ *
189
+ * crtr acts on it by refetching that plugin's bundle and re-running the
190
+ * caller's ORIGINAL argv against the refreshed command tree, exactly once. Two
191
+ * preconditions follow from that, and a server that cannot meet both must not
192
+ * set the field:
193
+ *
194
+ * 1. The manifest the server serves at its bundle endpoint must already
195
+ * describe the operation it is complaining about. A refetch that hands back
196
+ * the same description turns the retry into a second identical failure.
197
+ * 2. The original call must be safe to send again. crtr replays the argv, not
198
+ * the request, but a leaf that already committed a side effect before the
199
+ * backend rejected the op would commit it twice.
200
+ *
201
+ * Declared here, in the format both sides compile against, so the field name
202
+ * has one owner: rename it and every reader and writer fails to build. A type
203
+ * rather than a value — a const would force a CJS consumer to `require()` an
204
+ * ESM module.
205
+ */
206
+ export interface ManifestStaleEnvelope {
207
+ manifest_stale?: true;
208
+ }
@@ -0,0 +1,23 @@
1
+ // The command-plugin manifest wire format — the exact JSON shape crtr's manifest
2
+ // validator accepts in a plugin bundle's `commands.json`.
3
+ //
4
+ // This is the canonical, cross-repo declaration of that format. It is published
5
+ // as `@north-light/crouter-api/plugin-manifest` so a server that SERVES a plugin
6
+ // bundle (Northlight Core serves the `northlight` plugin over an authenticated
7
+ // endpoint) compiles its manifest against the same types crtr validates it with,
8
+ // instead of hand-mirroring them and discovering drift at guest install time.
9
+ //
10
+ // Types only. This file imports nothing — not even Node built-ins — so consuming
11
+ // it costs a dependent nothing at runtime.
12
+ //
13
+ // Relationship to `src/core/help.ts`: these param and output types are the
14
+ // JSON-expressible SUBSET of that module's `InputParam` and `Field`. A validated
15
+ // manifest node's params flow straight into `defineLeaf`'s help descriptor
16
+ // (`src/core/command-plugins/compose.ts`), so that assignment is what keeps the
17
+ // two in step — widen a type here beyond what `help.ts` accepts and the build
18
+ // fails at that site. Fields that cannot survive a JSON round trip (a flag's
19
+ // `focusedHelp`, whose `dynamicState` is a function) are deliberately absent.
20
+ //
21
+ // Validators for this format live in `src/core/command-manifests/`, which imports
22
+ // these types rather than redeclaring them.
23
+ export {};
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@north-light/crouter-api",
3
- "version": "0.3.280",
4
- "description": "Typed crtrd /v1 API contract — DTOs, route builders, the error contract, and the CrtrClient. Zero runtime dependencies.",
3
+ "version": "0.3.282",
4
+ "description": "Typed crtrd /v1 API contract — DTOs, route builders, the error contract, the CrtrClient, and the command-plugin manifest format. Zero runtime dependencies.",
5
5
  "type": "module",
6
6
  "main": "./dist/api/index.js",
7
7
  "types": "./dist/api/index.d.ts",
@@ -12,6 +12,12 @@
12
12
  "require": "./dist/api/index.js",
13
13
  "default": "./dist/api/index.js"
14
14
  },
15
+ "./plugin-manifest": {
16
+ "types": "./dist/api/plugin-manifest-schema.d.ts",
17
+ "import": "./dist/api/plugin-manifest-schema.js",
18
+ "require": "./dist/api/plugin-manifest-schema.js",
19
+ "default": "./dist/api/plugin-manifest-schema.js"
20
+ },
15
21
  "./cards": {
16
22
  "types": "./dist/shared/generated-context.d.ts",
17
23
  "import": "./dist/shared/generated-context.js",