@jini-ai/cli 0.1.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.
Files changed (62) hide show
  1. package/LICENSE +201 -0
  2. package/dist/command-registry.d.ts +82 -0
  3. package/dist/command-registry.d.ts.map +1 -0
  4. package/dist/command-registry.js +88 -0
  5. package/dist/command-registry.js.map +1 -0
  6. package/dist/daemon-command.d.ts +42 -0
  7. package/dist/daemon-command.d.ts.map +1 -0
  8. package/dist/daemon-command.js +103 -0
  9. package/dist/daemon-command.js.map +1 -0
  10. package/dist/daemon-url.d.ts +68 -0
  11. package/dist/daemon-url.d.ts.map +1 -0
  12. package/dist/daemon-url.js +99 -0
  13. package/dist/daemon-url.js.map +1 -0
  14. package/dist/errors.d.ts +82 -0
  15. package/dist/errors.d.ts.map +1 -0
  16. package/dist/errors.js +103 -0
  17. package/dist/errors.js.map +1 -0
  18. package/dist/flags.d.ts +61 -0
  19. package/dist/flags.d.ts.map +1 -0
  20. package/dist/flags.js +111 -0
  21. package/dist/flags.js.map +1 -0
  22. package/dist/http.d.ts +63 -0
  23. package/dist/http.d.ts.map +1 -0
  24. package/dist/http.js +226 -0
  25. package/dist/http.js.map +1 -0
  26. package/dist/index.d.ts +24 -0
  27. package/dist/index.d.ts.map +1 -0
  28. package/dist/index.js +30 -0
  29. package/dist/index.js.map +1 -0
  30. package/dist/local-daemon-discovery.d.ts +31 -0
  31. package/dist/local-daemon-discovery.d.ts.map +1 -0
  32. package/dist/local-daemon-discovery.js +53 -0
  33. package/dist/local-daemon-discovery.js.map +1 -0
  34. package/dist/main.d.ts +21 -0
  35. package/dist/main.d.ts.map +1 -0
  36. package/dist/main.js +231 -0
  37. package/dist/main.js.map +1 -0
  38. package/dist/prompt.d.ts +83 -0
  39. package/dist/prompt.d.ts.map +1 -0
  40. package/dist/prompt.js +198 -0
  41. package/dist/prompt.js.map +1 -0
  42. package/dist/redact.d.ts +48 -0
  43. package/dist/redact.d.ts.map +1 -0
  44. package/dist/redact.js +134 -0
  45. package/dist/redact.js.map +1 -0
  46. package/dist/run-command.d.ts +39 -0
  47. package/dist/run-command.d.ts.map +1 -0
  48. package/dist/run-command.js +291 -0
  49. package/dist/run-command.js.map +1 -0
  50. package/dist/tokens.d.ts +3 -0
  51. package/dist/tokens.d.ts.map +1 -0
  52. package/dist/tokens.js +12 -0
  53. package/dist/tokens.js.map +1 -0
  54. package/dist/usage.d.ts +24 -0
  55. package/dist/usage.d.ts.map +1 -0
  56. package/dist/usage.js +25 -0
  57. package/dist/usage.js.map +1 -0
  58. package/dist/version-command.d.ts +38 -0
  59. package/dist/version-command.d.ts.map +1 -0
  60. package/dist/version-command.js +78 -0
  61. package/dist/version-command.js.map +1 -0
  62. package/package.json +48 -0
package/dist/http.js ADDED
@@ -0,0 +1,226 @@
1
+ /**
2
+ * @module http
3
+ *
4
+ * HTTP-client-mode transport plumbing, ported from OD's
5
+ * `apps/daemon/src/cli.ts` `surfaceFetchError`/`postJsonToDaemon` (see
6
+ * `source-map.md`). This is the "HTTP-client mode default" half of
7
+ * extraction-plan §3's `@jini-ai/cli` spec: fetch a daemon route, translate a
8
+ * network failure or a daemon error envelope into the structured exit-code
9
+ * contract from `errors.ts`.
10
+ */
11
+ import { DEFAULT_CLI_EXIT_CODES, exitWithStructuredError, structuredErrorData } from './errors.js';
12
+ import { sanitizeDaemonUrlForDisplay } from './daemon-url.js';
13
+ import { sanitizeUntrustedText } from './redact.js';
14
+ /**
15
+ * Format a `fetch()` rejection (network-unreachable, sandbox-denied) into a
16
+ * human-readable stderr line, with a hint when the underlying cause looks
17
+ * like a sandboxed-environment outbound-connect denial. Per CR-004/SEC-RB-009,
18
+ * `daemonUrl` and the failure detail are both sanitized before they reach
19
+ * stderr — a `daemonUrl` with embedded userinfo, or a cause message that
20
+ * embeds terminal control sequences or a leaked credential, must not be
21
+ * printed verbatim.
22
+ */
23
+ export function surfaceFetchError(err, daemonUrl, options = {}) {
24
+ const write = options.write ?? ((text) => { process.stderr.write(text); });
25
+ const cause = err !== null && typeof err === 'object' ? err.cause : null;
26
+ const code = cause !== null && typeof cause === 'object' && typeof cause.code === 'string'
27
+ ? cause.code
28
+ : null;
29
+ const causeMessage = cause !== null && typeof cause === 'object' && typeof cause.message === 'string'
30
+ ? cause.message
31
+ : '';
32
+ let detail = err instanceof Error ? err.message : String(err);
33
+ if (code !== null)
34
+ detail = `${code}${causeMessage.length > 0 ? ` — ${causeMessage}` : ''}`;
35
+ else if (causeMessage.length > 0)
36
+ detail = causeMessage;
37
+ write(`failed to reach daemon at ${sanitizeDaemonUrlForDisplay(daemonUrl)}: ${sanitizeUntrustedText(detail)}\n`);
38
+ if (code === 'EPERM' || code === 'ENETUNREACH') {
39
+ write('hint: outbound connect was denied, likely by a sandbox policy. ' +
40
+ 'If this command ran inside an agent sandbox, check its network policy — ' +
41
+ 'the daemon itself is unaffected and can be reached from a regular shell.\n');
42
+ }
43
+ }
44
+ /** Default request deadline. Generous enough for a slow agent run kickoff, short enough that a stalled daemon doesn't hang a CLI invocation forever. */
45
+ const DEFAULT_TIMEOUT_MS = 15_000;
46
+ /** Default cap on a daemon response body. Comfortably larger than any real status/error envelope, small enough to bound worst-case memory from a hostile/broken daemon. */
47
+ const DEFAULT_MAX_RESPONSE_BYTES = 10 * 1024 * 1024;
48
+ /** Thrown internally by {@link readJsonWithLimit} when a response exceeds its byte cap; never escapes {@link postJsonToDaemon}. */
49
+ class ResponseTooLargeError extends Error {
50
+ limitBytes;
51
+ constructor(limitBytes) {
52
+ super(`response exceeded the ${limitBytes}-byte limit`);
53
+ this.limitBytes = limitBytes;
54
+ this.name = 'ResponseTooLargeError';
55
+ }
56
+ }
57
+ /**
58
+ * Read `resp`'s body as JSON without ever buffering past `maxBytes`. Prefers streaming via
59
+ * `resp.body`'s reader (what a real `fetch()` `Response` provides) so a huge response is
60
+ * rejected mid-stream instead of first being buffered whole; falls back to `resp.text()` (still
61
+ * byte-checked before parsing) and finally to `resp.json()` for response-like objects that
62
+ * implement neither — the shape test doubles in this package's own suite use. A body that isn't
63
+ * valid JSON resolves to `{}`, matching this module's previous behavior.
64
+ */
65
+ async function readJsonWithLimit(resp, maxBytes) {
66
+ const contentLength = resp.headers?.get?.('content-length');
67
+ if (contentLength !== null && contentLength !== undefined) {
68
+ const declared = Number(contentLength);
69
+ if (Number.isFinite(declared) && declared > maxBytes)
70
+ throw new ResponseTooLargeError(maxBytes);
71
+ }
72
+ const body = resp.body;
73
+ if (body != null && typeof body.getReader === 'function') {
74
+ const reader = body.getReader();
75
+ const decoder = new TextDecoder();
76
+ let text = '';
77
+ let total = 0;
78
+ try {
79
+ for (;;) {
80
+ const { done, value } = await reader.read();
81
+ if (done === true)
82
+ break;
83
+ if (value !== undefined) {
84
+ total += value.byteLength;
85
+ if (total > maxBytes)
86
+ throw new ResponseTooLargeError(maxBytes);
87
+ text += decoder.decode(value, { stream: true });
88
+ }
89
+ }
90
+ text += decoder.decode();
91
+ }
92
+ finally {
93
+ reader.releaseLock();
94
+ }
95
+ try {
96
+ return text.length > 0 ? JSON.parse(text) : {};
97
+ }
98
+ catch {
99
+ return {};
100
+ }
101
+ }
102
+ if (typeof resp.text === 'function') {
103
+ const text = await resp.text();
104
+ if (Buffer.byteLength(text, 'utf8') > maxBytes)
105
+ throw new ResponseTooLargeError(maxBytes);
106
+ try {
107
+ return text.length > 0 ? JSON.parse(text) : {};
108
+ }
109
+ catch {
110
+ return {};
111
+ }
112
+ }
113
+ return await resp.json().catch(() => ({}));
114
+ }
115
+ /**
116
+ * Shared transport core behind {@link postJsonToDaemon} and {@link getJsonFromDaemon}: fetch
117
+ * `<base><route>` with a bounded timeout and response-size cap, and map a network failure or a
118
+ * non-2xx daemon response through the structured error contract (`errors.ts`) instead of
119
+ * returning — this function either resolves with the parsed body or never returns. Per
120
+ * CR-004/SEC-RB-009, daemon-supplied error detail is redacted before it reaches stderr rather than
121
+ * dumped verbatim. Both public wrappers exist only to fix `init.method`/`init.body` at their own
122
+ * call site — nothing method-specific lives here beyond that.
123
+ */
124
+ async function requestJsonFromDaemon(base, route, init, options = {}) {
125
+ const fetchImpl = options.fetchImpl ?? fetch;
126
+ const write = options.write ?? ((text) => { process.stderr.write(text); });
127
+ const exit = options.exit ?? ((exitCode) => process.exit(exitCode));
128
+ const timeoutMs = options.timeoutMs ?? DEFAULT_TIMEOUT_MS;
129
+ const maxResponseBytes = options.maxResponseBytes ?? DEFAULT_MAX_RESPONSE_BYTES;
130
+ const structuredOptions = {
131
+ write,
132
+ exit,
133
+ ...(options.exitCodes !== undefined ? { exitCodes: options.exitCodes } : {}),
134
+ };
135
+ const timeoutController = new AbortController();
136
+ const timeoutHandle = setTimeout(() => {
137
+ timeoutController.abort(new Error(`request to ${route} timed out after ${timeoutMs}ms`));
138
+ }, timeoutMs);
139
+ // A short-lived CLI invocation shouldn't be kept alive purely by this timer.
140
+ timeoutHandle.unref?.();
141
+ const signal = options.signal !== undefined ? AbortSignal.any([options.signal, timeoutController.signal]) : timeoutController.signal;
142
+ // The timeout signal stays live through both the initial fetch *and* the body read below — a
143
+ // daemon that returns headers promptly but then drips its body slowly should still be bounded
144
+ // by the same deadline, not just the connection phase.
145
+ let resp;
146
+ let data;
147
+ try {
148
+ try {
149
+ resp = await fetchImpl(`${base}${route}`, {
150
+ method: init.method,
151
+ headers: init.method === 'POST' ? { 'content-type': 'application/json', ...options.headers } : { ...options.headers },
152
+ ...(init.method === 'POST' ? { body: JSON.stringify(init.body) } : {}),
153
+ signal,
154
+ });
155
+ }
156
+ catch (err) {
157
+ surfaceFetchError(err, base, { write });
158
+ return exitWithStructuredError({ code: 'daemon-not-running', message: `Cannot reach daemon at ${sanitizeDaemonUrlForDisplay(base)}` }, structuredOptions);
159
+ }
160
+ try {
161
+ data = await readJsonWithLimit(resp, maxResponseBytes);
162
+ }
163
+ catch (err) {
164
+ if (err instanceof ResponseTooLargeError) {
165
+ write(`response from ${sanitizeDaemonUrlForDisplay(base)}${route} exceeded the ${err.limitBytes}-byte limit; aborting.\n`);
166
+ return exit(1);
167
+ }
168
+ throw err;
169
+ }
170
+ }
171
+ finally {
172
+ clearTimeout(timeoutHandle);
173
+ }
174
+ if (!resp.ok) {
175
+ const errorObj = data.error;
176
+ const exitCodes = { ...DEFAULT_CLI_EXIT_CODES, ...options.exitCodes };
177
+ const code = typeof errorObj?.code === 'string' && errorObj.code in exitCodes ? errorObj.code : null;
178
+ if (code !== null) {
179
+ const rawMessage = typeof errorObj?.message === 'string' ? errorObj.message : `HTTP ${resp.status}`;
180
+ const message = sanitizeUntrustedText(rawMessage);
181
+ const errorData = structuredErrorData(errorObj);
182
+ return exitWithStructuredError({ code, message, ...(errorData !== undefined ? { data: errorData } : {}) }, structuredOptions);
183
+ }
184
+ const rawExcerpt = describeUnrecognizedDaemonPayload(data);
185
+ write(`${init.method} ${route} failed: ${resp.status}${rawExcerpt}\n`);
186
+ return exit(1);
187
+ }
188
+ return data;
189
+ }
190
+ /**
191
+ * `POST` a JSON body to `<base><route>` and return the parsed JSON response.
192
+ * A network failure or a non-2xx daemon response both exit via the
193
+ * structured error contract (`errors.ts`) instead of returning — this
194
+ * function either resolves with the parsed body or never returns.
195
+ *
196
+ * Per CR-004/SEC-RB-009, this now enforces a request deadline (combined with
197
+ * an optional caller `signal`) and a maximum response size, and redacts
198
+ * daemon-supplied error detail before it reaches stderr instead of dumping
199
+ * it verbatim.
200
+ */
201
+ export async function postJsonToDaemon(base, route, body, options = {}) {
202
+ return requestJsonFromDaemon(base, route, { method: 'POST', body }, options);
203
+ }
204
+ /**
205
+ * `GET` `<base><route>` and return the parsed JSON response. Same transport contract as
206
+ * {@link postJsonToDaemon} (timeout, response-size cap, structured-error mapping, redaction) with
207
+ * no request body — for read-only daemon routes such as `@jini-ai/http`'s `GET /api/runs` and
208
+ * `GET /api/runs/:runId`.
209
+ */
210
+ export async function getJsonFromDaemon(base, route, options = {}) {
211
+ return requestJsonFromDaemon(base, route, { method: 'GET' }, options);
212
+ }
213
+ /** A bounded, redacted excerpt of an unrecognized daemon error payload — never the full raw body. */
214
+ function describeUnrecognizedDaemonPayload(data) {
215
+ let raw;
216
+ try {
217
+ raw = JSON.stringify(data) ?? '';
218
+ }
219
+ catch {
220
+ raw = String(data);
221
+ }
222
+ if (raw.length === 0)
223
+ return '';
224
+ return ` (daemon response, redacted/truncated): ${sanitizeUntrustedText(raw)}`;
225
+ }
226
+ //# sourceMappingURL=http.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"http.js","sourceRoot":"","sources":["../src/http.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ /**
2
+ * @module @jini-ai/cli
3
+ *
4
+ * CLI transport-shell: HTTP-client-mode generic transport/infra ported from
5
+ * OD's `apps/daemon/src/cli.ts` (extraction-plan §3 / §8 task 9). See
6
+ * `source-map.md` for the full classification of what was and wasn't
7
+ * ported. This is a first generic slice, not the full `@jini-ai/cli` package —
8
+ * no pack has registered against `CommandRegistry` yet because no HTTP-
9
+ * client-mode pack exists in this repo to call.
10
+ */
11
+ export * from './flags.js';
12
+ export * from './daemon-url.js';
13
+ export * from './errors.js';
14
+ export * from './http.js';
15
+ export * from './prompt.js';
16
+ export * from './redact.js';
17
+ export * from './usage.js';
18
+ export * from './command-registry.js';
19
+ export * from './run-command.js';
20
+ export * from './daemon-command.js';
21
+ export * from './version-command.js';
22
+ export * from './local-daemon-discovery.js';
23
+ export * from './tokens.js';
24
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,aAAa,CAAC"}
package/dist/index.js ADDED
@@ -0,0 +1,30 @@
1
+ /**
2
+ * @module @jini-ai/cli
3
+ *
4
+ * CLI transport-shell: HTTP-client-mode generic transport/infra ported from
5
+ * OD's `apps/daemon/src/cli.ts` (extraction-plan §3 / §8 task 9). See
6
+ * `source-map.md` for the full classification of what was and wasn't
7
+ * ported. This is a first generic slice, not the full `@jini-ai/cli` package —
8
+ * no pack has registered against `CommandRegistry` yet because no HTTP-
9
+ * client-mode pack exists in this repo to call.
10
+ */
11
+ export * from './flags.js';
12
+ export * from './daemon-url.js';
13
+ export * from './errors.js';
14
+ export * from './http.js';
15
+ export * from './prompt.js';
16
+ export * from './redact.js';
17
+ export * from './usage.js';
18
+ export * from './command-registry.js';
19
+ export * from './run-command.js';
20
+ export * from './daemon-command.js';
21
+ export * from './version-command.js';
22
+ export * from './local-daemon-discovery.js';
23
+ export * from './tokens.js';
24
+ // NOTE: `main.ts` (the bootable `jini` binary, wired via `package.json`'s `"bin"` field) is
25
+ // deliberately NOT re-exported here. This barrel is imported as a plain library dependency;
26
+ // `main.ts` parses `process.argv` and may call `process.exit` as a side effect of being
27
+ // imported for real (guarded so that merely importing its named `main` export does not trigger
28
+ // that side effect — see `main.ts`'s own module doc) — bundling it into this barrel would mean
29
+ // `import '@jini-ai/cli'` could start behaving like a CLI invocation.
30
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,cAAc,YAAY,CAAC;AAC3B,cAAc,iBAAiB,CAAC;AAChC,cAAc,aAAa,CAAC;AAC5B,cAAc,WAAW,CAAC;AAC1B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,uBAAuB,CAAC;AACtC,cAAc,kBAAkB,CAAC;AACjC,cAAc,qBAAqB,CAAC;AACpC,cAAc,sBAAsB,CAAC;AACrC,cAAc,6BAA6B,CAAC;AAC5C,cAAc,aAAa,CAAC;AAC5B,4FAA4F;AAC5F,4FAA4F;AAC5F,wFAAwF;AACxF,+FAA+F;AAC/F,+FAA+F;AAC/F,sEAAsE"}
@@ -0,0 +1,31 @@
1
+ import type { ResolveDaemonUrlOptions } from './daemon-url.js';
2
+ export interface LocalDaemonDiscoveryOptions {
3
+ /**
4
+ * The same `dataDir` the target `createLocalNodeDaemon({ dataDir, ... })` call was given. The
5
+ * registry path is derived from it via `@jini-ai/sidecar`'s `resolveDaemonRegistryPath` — the
6
+ * identical derivation `@jini-ai/node-host` uses for its own `discoveryFile` default. Ignored when
7
+ * `registryPath` is also given.
8
+ */
9
+ dataDir?: string;
10
+ /**
11
+ * The exact registry file path, for when the host overrode `createLocalNodeDaemon`'s
12
+ * `discoveryFile` away from its `dataDir`-derived default. Takes precedence over `dataDir`.
13
+ */
14
+ registryPath?: string;
15
+ }
16
+ /**
17
+ * Build a `resolveDaemonUrl({ discover })`-compatible probe backed by a local, on-disk daemon
18
+ * registry record: reads the record at the resolved registry path, confirms the recording
19
+ * process's pid is still alive (a stale record left behind by a daemon that crashed rather than
20
+ * shut down cleanly is never trusted — see `readLiveDaemonRegistryRecord`), and returns its
21
+ * `url`. Resolves to `null` (never rejects) when no live record is found, so `resolveDaemonUrl`
22
+ * falls through to its own `defaultUrl`/error exactly as if no `discover` had been supplied at
23
+ * all — a missing or stale local daemon is an ordinary, expected outcome here, not a failure.
24
+ *
25
+ * @throws Synchronously, at build time (not when the returned probe is later called), when
26
+ * neither `dataDir` nor `registryPath` is given — there is nothing to resolve a path from, and a
27
+ * probe that silently always discovers nothing would hide a caller's config mistake instead of
28
+ * surfacing it immediately.
29
+ */
30
+ export declare function createLocalDaemonDiscovery(options: LocalDaemonDiscoveryOptions): NonNullable<ResolveDaemonUrlOptions['discover']>;
31
+ //# sourceMappingURL=local-daemon-discovery.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-daemon-discovery.d.ts","sourceRoot":"","sources":["../src/local-daemon-discovery.ts"],"names":[],"mappings":"AAqBA,OAAO,KAAK,EAAE,uBAAuB,EAAE,MAAM,iBAAiB,CAAC;AAE/D,MAAM,WAAW,2BAA2B;IAC1C;;;;;OAKG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;OAGG;IACH,YAAY,CAAC,EAAE,MAAM,CAAC;CACvB;AAYD;;;;;;;;;;;;;GAaG;AACH,wBAAgB,0BAA0B,CACxC,OAAO,EAAE,2BAA2B,GACnC,WAAW,CAAC,uBAAuB,CAAC,UAAU,CAAC,CAAC,CAMlD"}
@@ -0,0 +1,53 @@
1
+ /**
2
+ * @module local-daemon-discovery
3
+ *
4
+ * The real `discover` callback `resolveDaemonUrl` (`daemon-url.ts`) has always accepted but this
5
+ * package never implemented — see `source-map.md`'s "Deferred" item 1 and its own 2026-07-21
6
+ * investigation, which found `@jini-ai/node-host`'s `createLocalNodeDaemon` wrote nothing anywhere a
7
+ * separate CLI process could read. That daemon side is now built (`@jini-ai/node-host`'s
8
+ * `discoveryFile` config, backed by `@jini-ai/sidecar`'s `daemon-registry.ts`); this module is the
9
+ * matching CLI-side reader: `createLocalDaemonDiscovery(...)` builds a probe over that same
10
+ * on-disk record, verified live (not just present — see `readLiveDaemonRegistryRecord`'s own
11
+ * doc), that plugs directly into `resolveDaemonUrl({ discover })`.
12
+ *
13
+ * Deliberately not wired to a hardcoded default `dataDir`: exactly like `resolveDaemonUrl` itself
14
+ * has no baked-in env var name or default URL, this package has no opinion on where a given
15
+ * product's daemon keeps its data — the caller (whatever wires a `@jini-ai/node-host` daemon and a
16
+ * `@jini-ai/cli`-transport pack together for one product) supplies the same `dataDir` (or an
17
+ * explicit `registryPath`, when `createLocalNodeDaemon`'s own `discoveryFile` was overridden away
18
+ * from its default) to both sides.
19
+ */
20
+ import { readLiveDaemonRegistryRecord, resolveDaemonRegistryPath } from '@jini-ai/sidecar';
21
+ /**
22
+ * @internal Resolve the registry path this discovery probe should read, from whichever of
23
+ * `registryPath`/`dataDir` was supplied.
24
+ */
25
+ function resolveRegistryPathFromOptions(options) {
26
+ if (options.registryPath !== undefined)
27
+ return options.registryPath;
28
+ if (options.dataDir !== undefined)
29
+ return resolveDaemonRegistryPath(options.dataDir);
30
+ throw new Error('createLocalDaemonDiscovery requires either dataDir or registryPath');
31
+ }
32
+ /**
33
+ * Build a `resolveDaemonUrl({ discover })`-compatible probe backed by a local, on-disk daemon
34
+ * registry record: reads the record at the resolved registry path, confirms the recording
35
+ * process's pid is still alive (a stale record left behind by a daemon that crashed rather than
36
+ * shut down cleanly is never trusted — see `readLiveDaemonRegistryRecord`), and returns its
37
+ * `url`. Resolves to `null` (never rejects) when no live record is found, so `resolveDaemonUrl`
38
+ * falls through to its own `defaultUrl`/error exactly as if no `discover` had been supplied at
39
+ * all — a missing or stale local daemon is an ordinary, expected outcome here, not a failure.
40
+ *
41
+ * @throws Synchronously, at build time (not when the returned probe is later called), when
42
+ * neither `dataDir` nor `registryPath` is given — there is nothing to resolve a path from, and a
43
+ * probe that silently always discovers nothing would hide a caller's config mistake instead of
44
+ * surfacing it immediately.
45
+ */
46
+ export function createLocalDaemonDiscovery(options) {
47
+ const registryPath = resolveRegistryPathFromOptions(options);
48
+ return async () => {
49
+ const record = await readLiveDaemonRegistryRecord(registryPath);
50
+ return record?.url ?? null;
51
+ };
52
+ }
53
+ //# sourceMappingURL=local-daemon-discovery.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"local-daemon-discovery.js","sourceRoot":"","sources":["../src/local-daemon-discovery.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;GAkBG;AACH,OAAO,EAAE,4BAA4B,EAAE,yBAAyB,EAAE,MAAM,kBAAkB,CAAC;AAmB3F;;;GAGG;AACH,SAAS,8BAA8B,CAAC,OAAoC;IAC1E,IAAI,OAAO,CAAC,YAAY,KAAK,SAAS;QAAE,OAAO,OAAO,CAAC,YAAY,CAAC;IACpE,IAAI,OAAO,CAAC,OAAO,KAAK,SAAS;QAAE,OAAO,yBAAyB,CAAC,OAAO,CAAC,OAAO,CAAC,CAAC;IACrF,MAAM,IAAI,KAAK,CAAC,oEAAoE,CAAC,CAAC;AACxF,CAAC;AAED;;;;;;;;;;;;;GAaG;AACH,MAAM,UAAU,0BAA0B,CACxC,OAAoC;IAEpC,MAAM,YAAY,GAAG,8BAA8B,CAAC,OAAO,CAAC,CAAC;IAC7D,OAAO,KAAK,IAAI,EAAE;QAChB,MAAM,MAAM,GAAG,MAAM,4BAA4B,CAAC,YAAY,CAAC,CAAC;QAChE,OAAO,MAAM,EAAE,GAAG,IAAI,IAAI,CAAC;IAC7B,CAAC,CAAC;AACJ,CAAC"}
package/dist/main.d.ts ADDED
@@ -0,0 +1,21 @@
1
+ #!/usr/bin/env node
2
+ export interface MainDeps {
3
+ /** Defaults to `process.stdout.write`; inject for tests. */
4
+ write?: (text: string) => void;
5
+ /** Defaults to `process.stderr.write`; inject for tests. */
6
+ writeErr?: (text: string) => void;
7
+ /** Defaults to `process.exit`; inject for tests (must not return). */
8
+ exit?: (code: number) => never;
9
+ /** Defaults to the global `fetch`; inject for tests. */
10
+ fetchImpl?: typeof fetch;
11
+ /** Defaults to `process.env`; inject for tests. */
12
+ env?: NodeJS.ProcessEnv;
13
+ }
14
+ /**
15
+ * Parse `argv` (already stripped of `node`/script-path, i.e. `process.argv.slice(2)`) and
16
+ * dispatch to the registered `run`/`daemon`/`version` commands. Never throws a raw error to its
17
+ * caller under normal use — usage errors and daemon failures both exit through this package's
18
+ * structured-error contract (`errors.ts`), via the injected (or default, real) `exit`.
19
+ */
20
+ export declare function main(argv: readonly string[], deps?: MainDeps): Promise<void>;
21
+ //# sourceMappingURL=main.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"main.d.ts","sourceRoot":"","sources":["../src/main.ts"],"names":[],"mappings":";AAsFA,MAAM,WAAW,QAAQ;IACvB,4DAA4D;IAC5D,KAAK,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAC/B,4DAA4D;IAC5D,QAAQ,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,IAAI,CAAC;IAClC,sEAAsE;IACtE,IAAI,CAAC,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK,KAAK,CAAC;IAC/B,wDAAwD;IACxD,SAAS,CAAC,EAAE,OAAO,KAAK,CAAC;IACzB,mDAAmD;IACnD,GAAG,CAAC,EAAE,MAAM,CAAC,UAAU,CAAC;CACzB;AA+FD;;;;;GAKG;AACH,wBAAsB,IAAI,CAAC,IAAI,EAAE,SAAS,MAAM,EAAE,EAAE,IAAI,GAAE,QAAa,GAAG,OAAO,CAAC,IAAI,CAAC,CA2DtF"}