@mycompbox/compbox-cli 1.13.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/.tsbuildinfo +1 -0
- package/commands/configure.d.ts +24 -0
- package/commands/configure.d.ts.map +1 -0
- package/commands/configure.js +170 -0
- package/commands/configure.js.map +1 -0
- package/commands/doctor.d.ts +136 -0
- package/commands/doctor.d.ts.map +1 -0
- package/commands/doctor.js +606 -0
- package/commands/doctor.js.map +1 -0
- package/commands/install.d.ts +3 -0
- package/commands/install.d.ts.map +1 -0
- package/commands/install.js +88 -0
- package/commands/install.js.map +1 -0
- package/commands/list.d.ts +3 -0
- package/commands/list.d.ts.map +1 -0
- package/commands/list.js +141 -0
- package/commands/list.js.map +1 -0
- package/commands/login.d.ts +15 -0
- package/commands/login.d.ts.map +1 -0
- package/commands/login.js +102 -0
- package/commands/login.js.map +1 -0
- package/commands/publish.d.ts +3 -0
- package/commands/publish.d.ts.map +1 -0
- package/commands/publish.js +102 -0
- package/commands/publish.js.map +1 -0
- package/commands/run.d.ts +76 -0
- package/commands/run.d.ts.map +1 -0
- package/commands/run.js +417 -0
- package/commands/run.js.map +1 -0
- package/commands/service.d.ts +29 -0
- package/commands/service.d.ts.map +1 -0
- package/commands/service.js +142 -0
- package/commands/service.js.map +1 -0
- package/commands/update.d.ts +3 -0
- package/commands/update.d.ts.map +1 -0
- package/commands/update.js +141 -0
- package/commands/update.js.map +1 -0
- package/index.d.ts +3 -0
- package/index.d.ts.map +1 -0
- package/index.js +8508 -0
- package/index.js.map +1 -0
- package/package.json +30 -0
- package/utils/agent-invoker.d.ts +393 -0
- package/utils/agent-invoker.d.ts.map +1 -0
- package/utils/agent-invoker.js +1632 -0
- package/utils/agent-invoker.js.map +1 -0
- package/utils/api-client.d.ts +54 -0
- package/utils/api-client.d.ts.map +1 -0
- package/utils/api-client.js +214 -0
- package/utils/api-client.js.map +1 -0
- package/utils/auth-client.d.ts +61 -0
- package/utils/auth-client.d.ts.map +1 -0
- package/utils/auth-client.js +135 -0
- package/utils/auth-client.js.map +1 -0
- package/utils/claude-runtime.d.ts +116 -0
- package/utils/claude-runtime.d.ts.map +1 -0
- package/utils/claude-runtime.js +291 -0
- package/utils/claude-runtime.js.map +1 -0
- package/utils/config-store.d.ts +128 -0
- package/utils/config-store.d.ts.map +1 -0
- package/utils/config-store.js +137 -0
- package/utils/config-store.js.map +1 -0
- package/utils/file-manager.d.ts +32 -0
- package/utils/file-manager.d.ts.map +1 -0
- package/utils/file-manager.js +208 -0
- package/utils/file-manager.js.map +1 -0
- package/utils/keychain.d.ts +46 -0
- package/utils/keychain.d.ts.map +1 -0
- package/utils/keychain.js +167 -0
- package/utils/keychain.js.map +1 -0
- package/utils/loopback.d.ts +45 -0
- package/utils/loopback.d.ts.map +1 -0
- package/utils/loopback.js +95 -0
- package/utils/loopback.js.map +1 -0
- package/utils/mailbox-client.d.ts +98 -0
- package/utils/mailbox-client.d.ts.map +1 -0
- package/utils/mailbox-client.js +178 -0
- package/utils/mailbox-client.js.map +1 -0
- package/utils/mcp-config-writer.d.ts +133 -0
- package/utils/mcp-config-writer.d.ts.map +1 -0
- package/utils/mcp-config-writer.js +184 -0
- package/utils/mcp-config-writer.js.map +1 -0
- package/utils/pack-bundler.d.ts +30 -0
- package/utils/pack-bundler.d.ts.map +1 -0
- package/utils/pack-bundler.js +141 -0
- package/utils/pack-bundler.js.map +1 -0
- package/utils/prompt.d.ts +31 -0
- package/utils/prompt.d.ts.map +1 -0
- package/utils/prompt.js +86 -0
- package/utils/prompt.js.map +1 -0
- package/utils/table-formatter.d.ts +42 -0
- package/utils/table-formatter.d.ts.map +1 -0
- package/utils/table-formatter.js +125 -0
- package/utils/table-formatter.js.map +1 -0
- package/utils/version-resolver.d.ts +31 -0
- package/utils/version-resolver.d.ts.map +1 -0
- package/utils/version-resolver.js +75 -0
- package/utils/version-resolver.js.map +1 -0
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loopback / local-endpoint detection for central-target guardrails (ENG-130).
|
|
3
|
+
*
|
|
4
|
+
* A central API URL that resolves to the local machine (localhost, 127.0.0.0/8,
|
|
5
|
+
* ::1, 0.0.0.0, *.localhost) means the CompBox MCP writes to a LOCAL dev
|
|
6
|
+
* database — valid in development, but work done against it will NOT reach the
|
|
7
|
+
* cloud central (mycompbox.web.app). `doctor`, `configure`, and `login` share
|
|
8
|
+
* this detector so the warning is worded identically everywhere and the check
|
|
9
|
+
* lives in exactly one place.
|
|
10
|
+
*
|
|
11
|
+
* This is WARN-level only: localhost is a legitimate dev target, so callers
|
|
12
|
+
* surface a notice — they never block.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Shared impact sentence for loopback warnings. `doctor`'s "Central target"
|
|
16
|
+
* check and LOOPBACK_NOTICE both build on this fragment so the core wording
|
|
17
|
+
* ("work will NOT reach the cloud (mycompbox.web.app)") cannot diverge.
|
|
18
|
+
*/
|
|
19
|
+
export declare const LOOPBACK_IMPACT = "your work will NOT reach the cloud (mycompbox.web.app)";
|
|
20
|
+
/**
|
|
21
|
+
* Shared, non-blocking notice shown by `configure` and `login` when the central
|
|
22
|
+
* URL is a local dev endpoint. Wording is kept consistent with the `doctor`
|
|
23
|
+
* "Central target" check (both derive from LOOPBACK_IMPACT) so users see the
|
|
24
|
+
* same message everywhere.
|
|
25
|
+
*/
|
|
26
|
+
export declare const LOOPBACK_NOTICE: string;
|
|
27
|
+
/**
|
|
28
|
+
* True if `hostname` (already stripped of scheme/port) refers to the local
|
|
29
|
+
* machine. Handles IPv4 loopback (127.0.0.0/8), IPv6 loopback (::1, with or
|
|
30
|
+
* without brackets), IPv4-mapped IPv6 loopback in dotted form
|
|
31
|
+
* (`::ffff:127.0.0.1`), the unspecified 0.0.0.0 bind address, `localhost`,
|
|
32
|
+
* and RFC-6761 `*.localhost` names. Case-insensitive.
|
|
33
|
+
*
|
|
34
|
+
* Known limitation (accepted): the hex form of IPv4-mapped IPv6 loopback
|
|
35
|
+
* (`::ffff:7f00:1`) is NOT detected — it is vanishingly rare in
|
|
36
|
+
* user-supplied central URLs and this check is WARN-level only.
|
|
37
|
+
*/
|
|
38
|
+
export declare function isLoopbackHostname(hostname: string): boolean;
|
|
39
|
+
/**
|
|
40
|
+
* True if `rawUrl` points at a local dev endpoint. Accepts a full URL
|
|
41
|
+
* (`http://localhost:3000`) or a bare host[:port] (`localhost:3000`). Returns
|
|
42
|
+
* false for empty/undefined input and for non-loopback cloud URLs.
|
|
43
|
+
*/
|
|
44
|
+
export declare function isLoopbackUrl(rawUrl: string | undefined): boolean;
|
|
45
|
+
//# sourceMappingURL=loopback.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loopback.d.ts","sourceRoot":"","sources":["../../src/utils/loopback.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH;;;;GAIG;AACH,eAAO,MAAM,eAAe,2DAC8B,CAAC;AAE3D;;;;;GAKG;AACH,eAAO,MAAM,eAAe,QAE6B,CAAC;AAE1D;;;;;;;;;;GAUG;AACH,wBAAgB,kBAAkB,CAAC,QAAQ,EAAE,MAAM,GAAG,OAAO,CAwB5D;AAED;;;;GAIG;AACH,wBAAgB,aAAa,CAAC,MAAM,EAAE,MAAM,GAAG,SAAS,GAAG,OAAO,CAmBjE"}
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Loopback / local-endpoint detection for central-target guardrails (ENG-130).
|
|
3
|
+
*
|
|
4
|
+
* A central API URL that resolves to the local machine (localhost, 127.0.0.0/8,
|
|
5
|
+
* ::1, 0.0.0.0, *.localhost) means the CompBox MCP writes to a LOCAL dev
|
|
6
|
+
* database — valid in development, but work done against it will NOT reach the
|
|
7
|
+
* cloud central (mycompbox.web.app). `doctor`, `configure`, and `login` share
|
|
8
|
+
* this detector so the warning is worded identically everywhere and the check
|
|
9
|
+
* lives in exactly one place.
|
|
10
|
+
*
|
|
11
|
+
* This is WARN-level only: localhost is a legitimate dev target, so callers
|
|
12
|
+
* surface a notice — they never block.
|
|
13
|
+
*/
|
|
14
|
+
/**
|
|
15
|
+
* Shared impact sentence for loopback warnings. `doctor`'s "Central target"
|
|
16
|
+
* check and LOOPBACK_NOTICE both build on this fragment so the core wording
|
|
17
|
+
* ("work will NOT reach the cloud (mycompbox.web.app)") cannot diverge.
|
|
18
|
+
*/
|
|
19
|
+
export const LOOPBACK_IMPACT = 'your work will NOT reach the cloud (mycompbox.web.app)';
|
|
20
|
+
/**
|
|
21
|
+
* Shared, non-blocking notice shown by `configure` and `login` when the central
|
|
22
|
+
* URL is a local dev endpoint. Wording is kept consistent with the `doctor`
|
|
23
|
+
* "Central target" check (both derive from LOOPBACK_IMPACT) so users see the
|
|
24
|
+
* same message everywhere.
|
|
25
|
+
*/
|
|
26
|
+
export const LOOPBACK_NOTICE = `This is a LOCAL dev endpoint — ${LOOPBACK_IMPACT}. ` +
|
|
27
|
+
'Use `compbox login --url <cloud-url>` for production.';
|
|
28
|
+
/**
|
|
29
|
+
* True if `hostname` (already stripped of scheme/port) refers to the local
|
|
30
|
+
* machine. Handles IPv4 loopback (127.0.0.0/8), IPv6 loopback (::1, with or
|
|
31
|
+
* without brackets), IPv4-mapped IPv6 loopback in dotted form
|
|
32
|
+
* (`::ffff:127.0.0.1`), the unspecified 0.0.0.0 bind address, `localhost`,
|
|
33
|
+
* and RFC-6761 `*.localhost` names. Case-insensitive.
|
|
34
|
+
*
|
|
35
|
+
* Known limitation (accepted): the hex form of IPv4-mapped IPv6 loopback
|
|
36
|
+
* (`::ffff:7f00:1`) is NOT detected — it is vanishingly rare in
|
|
37
|
+
* user-supplied central URLs and this check is WARN-level only.
|
|
38
|
+
*/
|
|
39
|
+
export function isLoopbackHostname(hostname) {
|
|
40
|
+
let host = hostname.trim().toLowerCase();
|
|
41
|
+
if (host.length === 0)
|
|
42
|
+
return false;
|
|
43
|
+
// Strip surrounding brackets from IPv6 literals (e.g. "[::1]").
|
|
44
|
+
if (host.startsWith('[') && host.endsWith(']')) {
|
|
45
|
+
host = host.slice(1, -1);
|
|
46
|
+
}
|
|
47
|
+
if (host === 'localhost' || host.endsWith('.localhost'))
|
|
48
|
+
return true;
|
|
49
|
+
if (host === '::1')
|
|
50
|
+
return true;
|
|
51
|
+
if (host === '0.0.0.0')
|
|
52
|
+
return true;
|
|
53
|
+
// IPv4-mapped IPv6 in dotted form, e.g. "::ffff:127.0.0.1" — unwrap and
|
|
54
|
+
// fall through to the IPv4 loopback-range check below.
|
|
55
|
+
if (host.startsWith('::ffff:')) {
|
|
56
|
+
host = host.slice('::ffff:'.length);
|
|
57
|
+
}
|
|
58
|
+
// IPv4 loopback range 127.0.0.0/8 (covers 127.0.0.1 and any 127.x.x.x).
|
|
59
|
+
const m = /^(\d{1,3})\.(\d{1,3})\.(\d{1,3})\.(\d{1,3})$/.exec(host);
|
|
60
|
+
if (m) {
|
|
61
|
+
const octets = m.slice(1).map(Number);
|
|
62
|
+
if (octets.every((o) => o >= 0 && o <= 255) && octets[0] === 127) {
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
return false;
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* True if `rawUrl` points at a local dev endpoint. Accepts a full URL
|
|
70
|
+
* (`http://localhost:3000`) or a bare host[:port] (`localhost:3000`). Returns
|
|
71
|
+
* false for empty/undefined input and for non-loopback cloud URLs.
|
|
72
|
+
*/
|
|
73
|
+
export function isLoopbackUrl(rawUrl) {
|
|
74
|
+
if (!rawUrl)
|
|
75
|
+
return false;
|
|
76
|
+
const trimmed = rawUrl.trim();
|
|
77
|
+
if (trimmed.length === 0)
|
|
78
|
+
return false;
|
|
79
|
+
// Try to parse as-is; if that yields no host (e.g. a bare "localhost:3000",
|
|
80
|
+
// where "localhost:" is read as a scheme), retry with an added scheme so the
|
|
81
|
+
// URL parser extracts the hostname consistently.
|
|
82
|
+
for (const candidate of [trimmed, `http://${trimmed}`]) {
|
|
83
|
+
try {
|
|
84
|
+
const { hostname } = new URL(candidate);
|
|
85
|
+
if (hostname.length > 0) {
|
|
86
|
+
return isLoopbackHostname(hostname);
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
catch {
|
|
90
|
+
// Not parseable with this candidate — try the next form.
|
|
91
|
+
}
|
|
92
|
+
}
|
|
93
|
+
return false;
|
|
94
|
+
}
|
|
95
|
+
//# sourceMappingURL=loopback.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"loopback.js","sourceRoot":"","sources":["../../src/utils/loopback.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAEH;;;;GAIG;AACH,MAAM,CAAC,MAAM,eAAe,GAC1B,wDAAwD,CAAC;AAE3D;;;;;GAKG;AACH,MAAM,CAAC,MAAM,eAAe,GAC1B,kCAAkC,eAAe,IAAI;IACrD,uDAAuD,CAAC;AAE1D;;;;;;;;;;GAUG;AACH,MAAM,UAAU,kBAAkB,CAAC,QAAgB;IACjD,IAAI,IAAI,GAAG,QAAQ,CAAC,IAAI,EAAE,CAAC,WAAW,EAAE,CAAC;IACzC,IAAI,IAAI,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IACpC,gEAAgE;IAChE,IAAI,IAAI,CAAC,UAAU,CAAC,GAAG,CAAC,IAAI,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,EAAE,CAAC;QAC/C,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,CAAC;IAC3B,CAAC;IACD,IAAI,IAAI,KAAK,WAAW,IAAI,IAAI,CAAC,QAAQ,CAAC,YAAY,CAAC;QAAE,OAAO,IAAI,CAAC;IACrE,IAAI,IAAI,KAAK,KAAK;QAAE,OAAO,IAAI,CAAC;IAChC,IAAI,IAAI,KAAK,SAAS;QAAE,OAAO,IAAI,CAAC;IACpC,wEAAwE;IACxE,uDAAuD;IACvD,IAAI,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QAC/B,IAAI,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IACtC,CAAC;IACD,wEAAwE;IACxE,MAAM,CAAC,GAAG,8CAA8C,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACpE,IAAI,CAAC,EAAE,CAAC;QACN,MAAM,MAAM,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC;QACtC,IAAI,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,GAAG,CAAC,IAAI,MAAM,CAAC,CAAC,CAAC,KAAK,GAAG,EAAE,CAAC;YACjE,OAAO,IAAI,CAAC;QACd,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED;;;;GAIG;AACH,MAAM,UAAU,aAAa,CAAC,MAA0B;IACtD,IAAI,CAAC,MAAM;QAAE,OAAO,KAAK,CAAC;IAC1B,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,EAAE,CAAC;IAC9B,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,KAAK,CAAC;IAEvC,4EAA4E;IAC5E,6EAA6E;IAC7E,iDAAiD;IACjD,KAAK,MAAM,SAAS,IAAI,CAAC,OAAO,EAAE,UAAU,OAAO,EAAE,CAAC,EAAE,CAAC;QACvD,IAAI,CAAC;YACH,MAAM,EAAE,QAAQ,EAAE,GAAG,IAAI,GAAG,CAAC,SAAS,CAAC,CAAC;YACxC,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACxB,OAAO,kBAAkB,CAAC,QAAQ,CAAC,CAAC;YACtC,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,yDAAyD;QAC3D,CAAC;IACH,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC"}
|
|
@@ -0,0 +1,98 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP client for the mailbox seam (ENG-E23 / ENG-122) — the daemon's view of
|
|
3
|
+
* the pull-based job queue.
|
|
4
|
+
*
|
|
5
|
+
* Two auth contexts, mirrored here as two sets of methods:
|
|
6
|
+
* - User-auth (the `st_...` token from `compbox login`): pairMachine — a
|
|
7
|
+
* one-time step that registers this device and mints its machine token.
|
|
8
|
+
* - Machine-auth (the `mk_...` token minted by pairMachine): nextJob,
|
|
9
|
+
* heartbeat, postTurn, completeJob — the daemon's own long-poll loop.
|
|
10
|
+
*
|
|
11
|
+
* Kept separate from `auth-client.ts` (user identity/pairing) and
|
|
12
|
+
* `api-client.ts` (skill-pack registry) for the same reason those are
|
|
13
|
+
* separate: distinct concerns, distinct auth contexts.
|
|
14
|
+
*/
|
|
15
|
+
import type { AgentRuntimeProbe } from './claude-runtime.js';
|
|
16
|
+
/** A paired machine, as returned by pairMachine (token included, once). */
|
|
17
|
+
export interface PairedMachine {
|
|
18
|
+
id: string;
|
|
19
|
+
name: string;
|
|
20
|
+
status: string;
|
|
21
|
+
lastSeenAt: string | null;
|
|
22
|
+
createdAt: string;
|
|
23
|
+
updatedAt: string;
|
|
24
|
+
/** Plaintext machine token (`mk_...`) — returned ONLY at pairing time. */
|
|
25
|
+
token: string;
|
|
26
|
+
}
|
|
27
|
+
/**
|
|
28
|
+
* An image (or other file) attached to a turn (ENG-151 read-contract). The
|
|
29
|
+
* machine `next-job` path attaches `attachments: []` (never undefined) to every
|
|
30
|
+
* turn; each entry carries a short-TTL `signedUrl` to the private bucket that
|
|
31
|
+
* the daemon fetches directly (no download endpoint, no extra auth).
|
|
32
|
+
*/
|
|
33
|
+
export interface MailboxAttachment {
|
|
34
|
+
id: string;
|
|
35
|
+
mimeType: string;
|
|
36
|
+
sizeBytes: number;
|
|
37
|
+
signedUrl: string;
|
|
38
|
+
}
|
|
39
|
+
/** A single turn in a job's conversation log. */
|
|
40
|
+
export interface MailboxJobTurn {
|
|
41
|
+
id: string;
|
|
42
|
+
role: 'agent' | 'user';
|
|
43
|
+
content: string;
|
|
44
|
+
createdAt: string;
|
|
45
|
+
/**
|
|
46
|
+
* Image/file attachments on this turn (ENG-151). Present on every turn from
|
|
47
|
+
* the machine next-job path (`[]` when none); optional here so older payloads
|
|
48
|
+
* and hand-built test turns without the field still type-check.
|
|
49
|
+
*/
|
|
50
|
+
attachments?: MailboxAttachment[];
|
|
51
|
+
}
|
|
52
|
+
/** A job as returned by next-job / post-turn / complete-job. */
|
|
53
|
+
export interface MailboxJob {
|
|
54
|
+
id: string;
|
|
55
|
+
machineId: string;
|
|
56
|
+
organizationId: string;
|
|
57
|
+
/** 'epic_request' | 'start_execution' today; kept as `string` — matches the API's own Job.type typing. */
|
|
58
|
+
type: string;
|
|
59
|
+
status: 'pending' | 'claimed' | 'running' | 'awaiting_input' | 'done' | 'failed';
|
|
60
|
+
payload: unknown;
|
|
61
|
+
result: unknown;
|
|
62
|
+
createdAt: string;
|
|
63
|
+
updatedAt: string;
|
|
64
|
+
turns: MailboxJobTurn[];
|
|
65
|
+
}
|
|
66
|
+
/** Normalized error for mailbox request failures with a stable HTTP-ish status. */
|
|
67
|
+
export declare class MailboxClientError extends Error {
|
|
68
|
+
/** HTTP status when the server responded; 0 for network-level failures. */
|
|
69
|
+
readonly status: number;
|
|
70
|
+
constructor(message: string, status: number);
|
|
71
|
+
}
|
|
72
|
+
export declare class MailboxClient {
|
|
73
|
+
private readonly http;
|
|
74
|
+
readonly baseUrl: string;
|
|
75
|
+
constructor(baseUrl: string);
|
|
76
|
+
/** Register this device with central using the user's API token, returning its machine token (once). */
|
|
77
|
+
pairMachine(userToken: string, name: string): Promise<PairedMachine>;
|
|
78
|
+
/**
|
|
79
|
+
* Long-polls for the next job assigned to this machine, waiting up to
|
|
80
|
+
* `waitMs` (server clamps to its own max, currently ~25s). Returns `null`
|
|
81
|
+
* on a 204 (nothing to do — the caller should loop and poll again).
|
|
82
|
+
*/
|
|
83
|
+
nextJob(machineToken: string, waitMs?: number): Promise<MailboxJob | null>;
|
|
84
|
+
/**
|
|
85
|
+
* Explicit heartbeat ping (idle-period keepalive; next-job itself also
|
|
86
|
+
* heartbeats). Optionally reports the local agent runtime status (ENG-136):
|
|
87
|
+
* when `runtime` is supplied, the POST body carries
|
|
88
|
+
* `{ agentRuntime: { status, detail, checkedAt } }` — the SOLE ingestion
|
|
89
|
+
* channel for runtime status (next-job is a GET and cannot carry it). Calling
|
|
90
|
+
* `heartbeat(token)` with no runtime is backward-compatible and sends `{}`.
|
|
91
|
+
*/
|
|
92
|
+
heartbeat(machineToken: string, runtime?: AgentRuntimeProbe): Promise<void>;
|
|
93
|
+
/** Posts an agent turn (a question/status update) to a job's interview log. */
|
|
94
|
+
postTurn(machineToken: string, jobId: string, content: string): Promise<MailboxJob>;
|
|
95
|
+
/** Marks a claimed job done or failed, with an optional structured result. */
|
|
96
|
+
completeJob(machineToken: string, jobId: string, status: 'done' | 'failed', result?: Record<string, unknown>): Promise<MailboxJob>;
|
|
97
|
+
}
|
|
98
|
+
//# sourceMappingURL=mailbox-client.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mailbox-client.d.ts","sourceRoot":"","sources":["../../src/utils/mailbox-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAGH,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,qBAAqB,CAAC;AAE7D,2EAA2E;AAC3E,MAAM,WAAW,aAAa;IAC5B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,GAAG,IAAI,CAAC;IAC1B,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,0EAA0E;IAC1E,KAAK,EAAE,MAAM,CAAC;CACf;AAED;;;;;GAKG;AACH,MAAM,WAAW,iBAAiB;IAChC,EAAE,EAAE,MAAM,CAAC;IACX,QAAQ,EAAE,MAAM,CAAC;IACjB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,iDAAiD;AACjD,MAAM,WAAW,cAAc;IAC7B,EAAE,EAAE,MAAM,CAAC;IACX,IAAI,EAAE,OAAO,GAAG,MAAM,CAAC;IACvB,OAAO,EAAE,MAAM,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB;;;;OAIG;IACH,WAAW,CAAC,EAAE,iBAAiB,EAAE,CAAC;CACnC;AAED,gEAAgE;AAChE,MAAM,WAAW,UAAU;IACzB,EAAE,EAAE,MAAM,CAAC;IACX,SAAS,EAAE,MAAM,CAAC;IAClB,cAAc,EAAE,MAAM,CAAC;IACvB,0GAA0G;IAC1G,IAAI,EAAE,MAAM,CAAC;IACb,MAAM,EACF,SAAS,GACT,SAAS,GACT,SAAS,GACT,gBAAgB,GAChB,MAAM,GACN,QAAQ,CAAC;IACb,OAAO,EAAE,OAAO,CAAC;IACjB,MAAM,EAAE,OAAO,CAAC;IAChB,SAAS,EAAE,MAAM,CAAC;IAClB,SAAS,EAAE,MAAM,CAAC;IAClB,KAAK,EAAE,cAAc,EAAE,CAAC;CACzB;AAED,mFAAmF;AACnF,qBAAa,kBAAmB,SAAQ,KAAK;IAC3C,2EAA2E;IAC3E,SAAgB,MAAM,EAAE,MAAM,CAAC;gBAEnB,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM;CAK5C;AAoCD,qBAAa,aAAa;IACxB,OAAO,CAAC,QAAQ,CAAC,IAAI,CAAgB;IACrC,SAAgB,OAAO,EAAE,MAAM,CAAC;gBAEpB,OAAO,EAAE,MAAM;IAoB3B,wGAAwG;IAClG,WAAW,CAAC,SAAS,EAAE,MAAM,EAAE,IAAI,EAAE,MAAM,GAAG,OAAO,CAAC,aAAa,CAAC;IAsB1E;;;;OAIG;IACG,OAAO,CAAC,YAAY,EAAE,MAAM,EAAE,MAAM,SAAS,GAAG,OAAO,CAAC,UAAU,GAAG,IAAI,CAAC;IAoBhF;;;;;;;OAOG;IACG,SAAS,CACb,YAAY,EAAE,MAAM,EACpB,OAAO,CAAC,EAAE,iBAAiB,GAC1B,OAAO,CAAC,IAAI,CAAC;IAwBhB,+EAA+E;IACzE,QAAQ,CACZ,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,EACb,OAAO,EAAE,MAAM,GACd,OAAO,CAAC,UAAU,CAAC;IAkBtB,8EAA8E;IACxE,WAAW,CACf,YAAY,EAAE,MAAM,EACpB,KAAK,EAAE,MAAM,EACb,MAAM,EAAE,MAAM,GAAG,QAAQ,EACzB,MAAM,CAAC,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,GAC/B,OAAO,CAAC,UAAU,CAAC;CAiBvB"}
|
|
@@ -0,0 +1,178 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* HTTP client for the mailbox seam (ENG-E23 / ENG-122) — the daemon's view of
|
|
3
|
+
* the pull-based job queue.
|
|
4
|
+
*
|
|
5
|
+
* Two auth contexts, mirrored here as two sets of methods:
|
|
6
|
+
* - User-auth (the `st_...` token from `compbox login`): pairMachine — a
|
|
7
|
+
* one-time step that registers this device and mints its machine token.
|
|
8
|
+
* - Machine-auth (the `mk_...` token minted by pairMachine): nextJob,
|
|
9
|
+
* heartbeat, postTurn, completeJob — the daemon's own long-poll loop.
|
|
10
|
+
*
|
|
11
|
+
* Kept separate from `auth-client.ts` (user identity/pairing) and
|
|
12
|
+
* `api-client.ts` (skill-pack registry) for the same reason those are
|
|
13
|
+
* separate: distinct concerns, distinct auth contexts.
|
|
14
|
+
*/
|
|
15
|
+
import axios, { isAxiosError } from 'axios';
|
|
16
|
+
/** Normalized error for mailbox request failures with a stable HTTP-ish status. */
|
|
17
|
+
export class MailboxClientError extends Error {
|
|
18
|
+
/** HTTP status when the server responded; 0 for network-level failures. */
|
|
19
|
+
status;
|
|
20
|
+
constructor(message, status) {
|
|
21
|
+
super(message);
|
|
22
|
+
this.name = 'MailboxClientError';
|
|
23
|
+
this.status = status;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
/** Extracts a server-provided error message from a JSON error body, if present. */
|
|
27
|
+
function extractServerMessage(data) {
|
|
28
|
+
if (typeof data !== 'object' || data === null)
|
|
29
|
+
return undefined;
|
|
30
|
+
const shaped = data;
|
|
31
|
+
return shaped.error?.message ?? shaped.message;
|
|
32
|
+
}
|
|
33
|
+
/** Normalizes a thrown error (network failure, DNS, timeout, etc.) from axios. */
|
|
34
|
+
function toMailboxError(error, fallback) {
|
|
35
|
+
if (isAxiosError(error)) {
|
|
36
|
+
const status = error.response?.status ?? 0;
|
|
37
|
+
const message = extractServerMessage(error.response?.data) ?? error.message;
|
|
38
|
+
return new MailboxClientError(message, status);
|
|
39
|
+
}
|
|
40
|
+
if (error instanceof Error) {
|
|
41
|
+
return new MailboxClientError(error.message, 0);
|
|
42
|
+
}
|
|
43
|
+
return new MailboxClientError(fallback, 0);
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Normalizes a RESOLVED non-2xx response (the client is configured with
|
|
47
|
+
* `validateStatus: () => true`, so non-2xx never throws — it resolves like
|
|
48
|
+
* any other response). Distinct from {@link toMailboxError}, which handles
|
|
49
|
+
* actually-thrown errors (network failure, DNS, timeout).
|
|
50
|
+
*/
|
|
51
|
+
function errorFromResponse(res, fallback) {
|
|
52
|
+
const message = extractServerMessage(res.data) ?? fallback;
|
|
53
|
+
return new MailboxClientError(message, res.status);
|
|
54
|
+
}
|
|
55
|
+
export class MailboxClient {
|
|
56
|
+
http;
|
|
57
|
+
baseUrl;
|
|
58
|
+
constructor(baseUrl) {
|
|
59
|
+
this.baseUrl = baseUrl.replace(/\/+$/, '');
|
|
60
|
+
this.http = axios.create({
|
|
61
|
+
baseURL: this.baseUrl,
|
|
62
|
+
// Generously longer than the requested long-poll window (POLL_WAIT_MS,
|
|
63
|
+
// ~15s) so a slow-but-alive next-job response is never mistaken for a
|
|
64
|
+
// network failure. Widened from 35s: on Cloud Run the overhead on a held
|
|
65
|
+
// connection occasionally pushed a 25s poll past a 35s timeout, so every
|
|
66
|
+
// idle poll errored and backed off. The margin here (client 45s vs ~15s
|
|
67
|
+
// poll) absorbs that overhead.
|
|
68
|
+
timeout: 45_000,
|
|
69
|
+
headers: { 'Content-Type': 'application/json' },
|
|
70
|
+
validateStatus: () => true,
|
|
71
|
+
});
|
|
72
|
+
}
|
|
73
|
+
// ---------------------------------------------------------------------
|
|
74
|
+
// User-auth: one-time machine pairing (called by `compbox configure`)
|
|
75
|
+
// ---------------------------------------------------------------------
|
|
76
|
+
/** Register this device with central using the user's API token, returning its machine token (once). */
|
|
77
|
+
async pairMachine(userToken, name) {
|
|
78
|
+
let res;
|
|
79
|
+
try {
|
|
80
|
+
res = await this.http.post('/api/v1/machines', { name }, { headers: { Authorization: `Bearer ${userToken}` } });
|
|
81
|
+
}
|
|
82
|
+
catch (error) {
|
|
83
|
+
throw toMailboxError(error, 'Machine pairing request failed');
|
|
84
|
+
}
|
|
85
|
+
if (res.status < 200 || res.status >= 300) {
|
|
86
|
+
throw errorFromResponse(res, 'Machine pairing failed');
|
|
87
|
+
}
|
|
88
|
+
const data = res.data;
|
|
89
|
+
return data.data;
|
|
90
|
+
}
|
|
91
|
+
// ---------------------------------------------------------------------
|
|
92
|
+
// Machine-auth: the daemon's own calls
|
|
93
|
+
// ---------------------------------------------------------------------
|
|
94
|
+
/**
|
|
95
|
+
* Long-polls for the next job assigned to this machine, waiting up to
|
|
96
|
+
* `waitMs` (server clamps to its own max, currently ~25s). Returns `null`
|
|
97
|
+
* on a 204 (nothing to do — the caller should loop and poll again).
|
|
98
|
+
*/
|
|
99
|
+
async nextJob(machineToken, waitMs = 25_000) {
|
|
100
|
+
let res;
|
|
101
|
+
try {
|
|
102
|
+
res = await this.http.get('/api/v1/machines/next-job', {
|
|
103
|
+
headers: { Authorization: `Bearer ${machineToken}` },
|
|
104
|
+
params: { waitMs },
|
|
105
|
+
});
|
|
106
|
+
}
|
|
107
|
+
catch (error) {
|
|
108
|
+
throw toMailboxError(error, 'next-job request failed');
|
|
109
|
+
}
|
|
110
|
+
if (res.status === 204) {
|
|
111
|
+
return null;
|
|
112
|
+
}
|
|
113
|
+
if (res.status < 200 || res.status >= 300) {
|
|
114
|
+
throw errorFromResponse(res, 'next-job failed');
|
|
115
|
+
}
|
|
116
|
+
const data = res.data;
|
|
117
|
+
return data.data;
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Explicit heartbeat ping (idle-period keepalive; next-job itself also
|
|
121
|
+
* heartbeats). Optionally reports the local agent runtime status (ENG-136):
|
|
122
|
+
* when `runtime` is supplied, the POST body carries
|
|
123
|
+
* `{ agentRuntime: { status, detail, checkedAt } }` — the SOLE ingestion
|
|
124
|
+
* channel for runtime status (next-job is a GET and cannot carry it). Calling
|
|
125
|
+
* `heartbeat(token)` with no runtime is backward-compatible and sends `{}`.
|
|
126
|
+
*/
|
|
127
|
+
async heartbeat(machineToken, runtime) {
|
|
128
|
+
let res;
|
|
129
|
+
try {
|
|
130
|
+
res = await this.http.post('/api/v1/machines/heartbeat', runtime
|
|
131
|
+
? {
|
|
132
|
+
agentRuntime: {
|
|
133
|
+
status: runtime.status,
|
|
134
|
+
detail: runtime.detail,
|
|
135
|
+
checkedAt: runtime.checkedAt,
|
|
136
|
+
},
|
|
137
|
+
}
|
|
138
|
+
: {}, { headers: { Authorization: `Bearer ${machineToken}` } });
|
|
139
|
+
}
|
|
140
|
+
catch (error) {
|
|
141
|
+
throw toMailboxError(error, 'Heartbeat request failed');
|
|
142
|
+
}
|
|
143
|
+
if (res.status < 200 || res.status >= 300) {
|
|
144
|
+
throw errorFromResponse(res, 'Heartbeat failed');
|
|
145
|
+
}
|
|
146
|
+
}
|
|
147
|
+
/** Posts an agent turn (a question/status update) to a job's interview log. */
|
|
148
|
+
async postTurn(machineToken, jobId, content) {
|
|
149
|
+
let res;
|
|
150
|
+
try {
|
|
151
|
+
res = await this.http.post(`/api/v1/jobs/${jobId}/turns`, { content }, { headers: { Authorization: `Bearer ${machineToken}` } });
|
|
152
|
+
}
|
|
153
|
+
catch (error) {
|
|
154
|
+
throw toMailboxError(error, 'post-turn request failed');
|
|
155
|
+
}
|
|
156
|
+
if (res.status < 200 || res.status >= 300) {
|
|
157
|
+
throw errorFromResponse(res, 'post-turn failed');
|
|
158
|
+
}
|
|
159
|
+
const data = res.data;
|
|
160
|
+
return data.data;
|
|
161
|
+
}
|
|
162
|
+
/** Marks a claimed job done or failed, with an optional structured result. */
|
|
163
|
+
async completeJob(machineToken, jobId, status, result) {
|
|
164
|
+
let res;
|
|
165
|
+
try {
|
|
166
|
+
res = await this.http.post(`/api/v1/jobs/${jobId}/complete`, { status, ...(result !== undefined && { result }) }, { headers: { Authorization: `Bearer ${machineToken}` } });
|
|
167
|
+
}
|
|
168
|
+
catch (error) {
|
|
169
|
+
throw toMailboxError(error, 'complete-job request failed');
|
|
170
|
+
}
|
|
171
|
+
if (res.status < 200 || res.status >= 300) {
|
|
172
|
+
throw errorFromResponse(res, 'complete-job failed');
|
|
173
|
+
}
|
|
174
|
+
const data = res.data;
|
|
175
|
+
return data.data;
|
|
176
|
+
}
|
|
177
|
+
}
|
|
178
|
+
//# sourceMappingURL=mailbox-client.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mailbox-client.js","sourceRoot":"","sources":["../../src/utils/mailbox-client.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;GAaG;AAEH,OAAO,KAAK,EAAE,EAAsB,YAAY,EAAE,MAAM,OAAO,CAAC;AA+DhE,mFAAmF;AACnF,MAAM,OAAO,kBAAmB,SAAQ,KAAK;IAC3C,2EAA2E;IAC3D,MAAM,CAAS;IAE/B,YAAY,OAAe,EAAE,MAAc;QACzC,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,oBAAoB,CAAC;QACjC,IAAI,CAAC,MAAM,GAAG,MAAM,CAAC;IACvB,CAAC;CACF;AAED,mFAAmF;AACnF,SAAS,oBAAoB,CAAC,IAAa;IACzC,IAAI,OAAO,IAAI,KAAK,QAAQ,IAAI,IAAI,KAAK,IAAI;QAAE,OAAO,SAAS,CAAC;IAChE,MAAM,MAAM,GAAG,IAA0D,CAAC;IAC1E,OAAO,MAAM,CAAC,KAAK,EAAE,OAAO,IAAI,MAAM,CAAC,OAAO,CAAC;AACjD,CAAC;AAED,kFAAkF;AAClF,SAAS,cAAc,CAAC,KAAc,EAAE,QAAgB;IACtD,IAAI,YAAY,CAAC,KAAK,CAAC,EAAE,CAAC;QACxB,MAAM,MAAM,GAAG,KAAK,CAAC,QAAQ,EAAE,MAAM,IAAI,CAAC,CAAC;QAC3C,MAAM,OAAO,GAAG,oBAAoB,CAAC,KAAK,CAAC,QAAQ,EAAE,IAAI,CAAC,IAAI,KAAK,CAAC,OAAO,CAAC;QAC5E,OAAO,IAAI,kBAAkB,CAAC,OAAO,EAAE,MAAM,CAAC,CAAC;IACjD,CAAC;IACD,IAAI,KAAK,YAAY,KAAK,EAAE,CAAC;QAC3B,OAAO,IAAI,kBAAkB,CAAC,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC,CAAC;IAClD,CAAC;IACD,OAAO,IAAI,kBAAkB,CAAC,QAAQ,EAAE,CAAC,CAAC,CAAC;AAC7C,CAAC;AAED;;;;;GAKG;AACH,SAAS,iBAAiB,CACxB,GAAsC,EACtC,QAAgB;IAEhB,MAAM,OAAO,GAAG,oBAAoB,CAAC,GAAG,CAAC,IAAI,CAAC,IAAI,QAAQ,CAAC;IAC3D,OAAO,IAAI,kBAAkB,CAAC,OAAO,EAAE,GAAG,CAAC,MAAM,CAAC,CAAC;AACrD,CAAC;AAED,MAAM,OAAO,aAAa;IACP,IAAI,CAAgB;IACrB,OAAO,CAAS;IAEhC,YAAY,OAAe;QACzB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;QAC3C,IAAI,CAAC,IAAI,GAAG,KAAK,CAAC,MAAM,CAAC;YACvB,OAAO,EAAE,IAAI,CAAC,OAAO;YACrB,uEAAuE;YACvE,sEAAsE;YACtE,yEAAyE;YACzE,yEAAyE;YACzE,wEAAwE;YACxE,+BAA+B;YAC/B,OAAO,EAAE,MAAM;YACf,OAAO,EAAE,EAAE,cAAc,EAAE,kBAAkB,EAAE;YAC/C,cAAc,EAAE,GAAG,EAAE,CAAC,IAAI;SAC3B,CAAC,CAAC;IACL,CAAC;IAED,wEAAwE;IACxE,sEAAsE;IACtE,wEAAwE;IAExE,wGAAwG;IACxG,KAAK,CAAC,WAAW,CAAC,SAAiB,EAAE,IAAY;QAC/C,IAAI,GAAG,CAAC;QACR,IAAI,CAAC;YACH,GAAG,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CACxB,kBAAkB,EAClB,EAAE,IAAI,EAAE,EACR,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,SAAS,EAAE,EAAE,EAAE,CACtD,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,cAAc,CAAC,KAAK,EAAE,gCAAgC,CAAC,CAAC;QAChE,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC;YAC1C,MAAM,iBAAiB,CAAC,GAAG,EAAE,wBAAwB,CAAC,CAAC;QACzD,CAAC;QACD,MAAM,IAAI,GAAG,GAAG,CAAC,IAA+B,CAAC;QACjD,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,wEAAwE;IACxE,uCAAuC;IACvC,wEAAwE;IAExE;;;;OAIG;IACH,KAAK,CAAC,OAAO,CAAC,YAAoB,EAAE,MAAM,GAAG,MAAM;QACjD,IAAI,GAAG,CAAC;QACR,IAAI,CAAC;YACH,GAAG,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC,2BAA2B,EAAE;gBACrD,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,YAAY,EAAE,EAAE;gBACpD,MAAM,EAAE,EAAE,MAAM,EAAE;aACnB,CAAC,CAAC;QACL,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,cAAc,CAAC,KAAK,EAAE,yBAAyB,CAAC,CAAC;QACzD,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,KAAK,GAAG,EAAE,CAAC;YACvB,OAAO,IAAI,CAAC;QACd,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC;YAC1C,MAAM,iBAAiB,CAAC,GAAG,EAAE,iBAAiB,CAAC,CAAC;QAClD,CAAC;QACD,MAAM,IAAI,GAAG,GAAG,CAAC,IAA4B,CAAC;QAC9C,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED;;;;;;;OAOG;IACH,KAAK,CAAC,SAAS,CACb,YAAoB,EACpB,OAA2B;QAE3B,IAAI,GAAG,CAAC;QACR,IAAI,CAAC;YACH,GAAG,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CACxB,4BAA4B,EAC5B,OAAO;gBACL,CAAC,CAAC;oBACE,YAAY,EAAE;wBACZ,MAAM,EAAE,OAAO,CAAC,MAAM;wBACtB,MAAM,EAAE,OAAO,CAAC,MAAM;wBACtB,SAAS,EAAE,OAAO,CAAC,SAAS;qBAC7B;iBACF;gBACH,CAAC,CAAC,EAAE,EACN,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,YAAY,EAAE,EAAE,EAAE,CACzD,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,cAAc,CAAC,KAAK,EAAE,0BAA0B,CAAC,CAAC;QAC1D,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC;YAC1C,MAAM,iBAAiB,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAC;QACnD,CAAC;IACH,CAAC;IAED,+EAA+E;IAC/E,KAAK,CAAC,QAAQ,CACZ,YAAoB,EACpB,KAAa,EACb,OAAe;QAEf,IAAI,GAAG,CAAC;QACR,IAAI,CAAC;YACH,GAAG,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CACxB,gBAAgB,KAAK,QAAQ,EAC7B,EAAE,OAAO,EAAE,EACX,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,YAAY,EAAE,EAAE,EAAE,CACzD,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,cAAc,CAAC,KAAK,EAAE,0BAA0B,CAAC,CAAC;QAC1D,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC;YAC1C,MAAM,iBAAiB,CAAC,GAAG,EAAE,kBAAkB,CAAC,CAAC;QACnD,CAAC;QACD,MAAM,IAAI,GAAG,GAAG,CAAC,IAA4B,CAAC;QAC9C,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;IAED,8EAA8E;IAC9E,KAAK,CAAC,WAAW,CACf,YAAoB,EACpB,KAAa,EACb,MAAyB,EACzB,MAAgC;QAEhC,IAAI,GAAG,CAAC;QACR,IAAI,CAAC;YACH,GAAG,GAAG,MAAM,IAAI,CAAC,IAAI,CAAC,IAAI,CACxB,gBAAgB,KAAK,WAAW,EAChC,EAAE,MAAM,EAAE,GAAG,CAAC,MAAM,KAAK,SAAS,IAAI,EAAE,MAAM,EAAE,CAAC,EAAE,EACnD,EAAE,OAAO,EAAE,EAAE,aAAa,EAAE,UAAU,YAAY,EAAE,EAAE,EAAE,CACzD,CAAC;QACJ,CAAC;QAAC,OAAO,KAAK,EAAE,CAAC;YACf,MAAM,cAAc,CAAC,KAAK,EAAE,6BAA6B,CAAC,CAAC;QAC7D,CAAC;QACD,IAAI,GAAG,CAAC,MAAM,GAAG,GAAG,IAAI,GAAG,CAAC,MAAM,IAAI,GAAG,EAAE,CAAC;YAC1C,MAAM,iBAAiB,CAAC,GAAG,EAAE,qBAAqB,CAAC,CAAC;QACtD,CAAC;QACD,MAAM,IAAI,GAAG,GAAG,CAAC,IAA4B,CAAC;QAC9C,OAAO,IAAI,CAAC,IAAI,CAAC;IACnB,CAAC;CACF"}
|
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Generate / patch a local MCP config so Claude Code points at central CompBox.
|
|
3
|
+
*
|
|
4
|
+
* Claude Code (and compatible MCP hosts) read a JSON file with an `mcpServers`
|
|
5
|
+
* map: `{ "mcpServers": { "<name>": { command, args, env } } }`. This writer
|
|
6
|
+
* inserts/updates ONLY the CompBox server entry, preserving every other server
|
|
7
|
+
* entry and every unrelated top-level key. Existing configuration for other
|
|
8
|
+
* tools is never clobbered.
|
|
9
|
+
*
|
|
10
|
+
* The CompBox entry prefers the brew-installed MCP server bundle when present
|
|
11
|
+
* (`node <prefix>/opt/compbox/libexec/compbox-mcp.cjs`, installed by the
|
|
12
|
+
* Homebrew formula — see deploy/homebrew-tap/compbox.rb), and falls back to
|
|
13
|
+
* launching the published package via `npx` on first use. Either way the
|
|
14
|
+
* per-employee token and central base URL are supplied through its `env`.
|
|
15
|
+
*/
|
|
16
|
+
/** Default Claude Code project-level MCP config file name. */
|
|
17
|
+
export declare const DEFAULT_MCP_CONFIG_FILENAME = ".mcp.json";
|
|
18
|
+
/** Default server key used for the CompBox MCP entry. */
|
|
19
|
+
export declare const DEFAULT_SERVER_KEY = "compbox";
|
|
20
|
+
/** The published MCP server package launched by the generated entry. */
|
|
21
|
+
export declare const MCP_SERVER_PACKAGE = "@mycompbox/compbox-mcp";
|
|
22
|
+
/**
|
|
23
|
+
* Locate the brew-installed MCP server bundle, if any.
|
|
24
|
+
*
|
|
25
|
+
* Candidate prefixes, in order: an explicit `opts.prefix` (e.g. from
|
|
26
|
+
* `brew --prefix`), `$HOMEBREW_PREFIX`, `/opt/homebrew` (Apple Silicon
|
|
27
|
+
* default), `/usr/local` (Intel default). Each is checked for the formula's
|
|
28
|
+
* keg-relative bundle path `opt/compbox/libexec/compbox-mcp.cjs`.
|
|
29
|
+
*
|
|
30
|
+
* `opts.exists` is injectable so tests never need a real brew install.
|
|
31
|
+
*/
|
|
32
|
+
export declare function resolveInstalledMcpBundle(opts?: {
|
|
33
|
+
prefix?: string;
|
|
34
|
+
exists?: (p: string) => boolean;
|
|
35
|
+
}): string | undefined;
|
|
36
|
+
/** A single MCP server definition. */
|
|
37
|
+
export interface McpServerEntry {
|
|
38
|
+
command: string;
|
|
39
|
+
args: string[];
|
|
40
|
+
env: Record<string, string>;
|
|
41
|
+
}
|
|
42
|
+
/** Parameters describing the CompBox MCP server entry to write. */
|
|
43
|
+
export interface McpServerSpec {
|
|
44
|
+
/** Central CompBox API base URL. */
|
|
45
|
+
apiBaseUrl: string;
|
|
46
|
+
/** Per-employee CompBox API token (`st_...`). */
|
|
47
|
+
apiToken: string;
|
|
48
|
+
/** Key under `mcpServers` to write. Defaults to `compbox`. */
|
|
49
|
+
serverKey?: string;
|
|
50
|
+
/** Override the launch command (default: auto-detected, see below). */
|
|
51
|
+
command?: string;
|
|
52
|
+
/** Override the launch args (default: auto-detected, see below). */
|
|
53
|
+
args?: string[];
|
|
54
|
+
/**
|
|
55
|
+
* Injectable installed-bundle resolver (defaults to
|
|
56
|
+
* {@link resolveInstalledMcpBundle}). Lets tests and `configure` control
|
|
57
|
+
* launch-mode detection without touching the real filesystem.
|
|
58
|
+
*/
|
|
59
|
+
resolveInstalledBundle?: () => string | undefined;
|
|
60
|
+
}
|
|
61
|
+
/** Outcome of a patch operation. */
|
|
62
|
+
export interface PatchResult {
|
|
63
|
+
/** True if the config file did not previously exist. */
|
|
64
|
+
fileCreated: boolean;
|
|
65
|
+
/** True if the CompBox server entry was newly added (vs. updated). */
|
|
66
|
+
entryCreated: boolean;
|
|
67
|
+
/** Keys of other MCP servers left untouched. */
|
|
68
|
+
preservedServers: string[];
|
|
69
|
+
/** Absolute path written. */
|
|
70
|
+
configPath: string;
|
|
71
|
+
/**
|
|
72
|
+
* The exact CompBox server entry that was written — lets callers (e.g.
|
|
73
|
+
* `configure`) report which launch mode was chosen (`node <bundle>` vs
|
|
74
|
+
* `npx -y <package>`) without re-running detection.
|
|
75
|
+
*/
|
|
76
|
+
entry: McpServerEntry;
|
|
77
|
+
}
|
|
78
|
+
/** Default absolute path to the project MCP config in the given directory. */
|
|
79
|
+
export declare function defaultMcpConfigPath(projectRoot?: string): string;
|
|
80
|
+
/**
|
|
81
|
+
* Build the CompBox MCP server entry from a spec. Exposed for testing and reuse.
|
|
82
|
+
*
|
|
83
|
+
* Launch-target selection (when neither `command` nor `args` is explicitly
|
|
84
|
+
* overridden): prefer `node <installed bundle>` when the brew-installed
|
|
85
|
+
* compbox-mcp.cjs resolves, else fall back to `npx -y ${MCP_SERVER_PACKAGE}`
|
|
86
|
+
* (fetched from the public npm registry on first use). An explicit `command`
|
|
87
|
+
* or `args` override always wins and disables detection.
|
|
88
|
+
*/
|
|
89
|
+
export declare function buildCompboxServerEntry(spec: McpServerSpec): McpServerEntry;
|
|
90
|
+
/** Read-only status of the CompBox MCP entry in a config file. */
|
|
91
|
+
export interface McpConfigStatus {
|
|
92
|
+
/** Absolute path inspected. */
|
|
93
|
+
configPath: string;
|
|
94
|
+
/** True if the config file exists on disk. */
|
|
95
|
+
fileExists: boolean;
|
|
96
|
+
/** True if the CompBox server entry is present under `mcpServers`. */
|
|
97
|
+
entryPresent: boolean;
|
|
98
|
+
/**
|
|
99
|
+
* The central API base URL the CompBox entry is configured to write to
|
|
100
|
+
* (its `env.API_BASE_URL`), or `undefined` when the entry is absent or has no
|
|
101
|
+
* such value. Read-only; used by `doctor` to surface which central the MCP
|
|
102
|
+
* targets (ENG-130). The API token is deliberately NOT surfaced here.
|
|
103
|
+
*/
|
|
104
|
+
apiBaseUrl?: string;
|
|
105
|
+
/**
|
|
106
|
+
* The entry's configured launch command (e.g. `node` or `npx`), or
|
|
107
|
+
* `undefined` when the entry is absent or malformed. Read-only; used by
|
|
108
|
+
* `doctor` to verify the launch target (ENG-141).
|
|
109
|
+
*/
|
|
110
|
+
command?: string;
|
|
111
|
+
/**
|
|
112
|
+
* The entry's configured launch args (e.g. the installed bundle path for
|
|
113
|
+
* `node`, or `['-y', '@mycompbox/compbox-mcp']` for `npx`), or `undefined`
|
|
114
|
+
* when absent/malformed. Read-only; used by `doctor` (ENG-141).
|
|
115
|
+
*/
|
|
116
|
+
args?: string[];
|
|
117
|
+
}
|
|
118
|
+
/**
|
|
119
|
+
* Inspect a config file for the CompBox MCP server entry WITHOUT modifying it.
|
|
120
|
+
*
|
|
121
|
+
* Used by `compbox doctor` to verify that `configure` already wrote the entry
|
|
122
|
+
* to the expected path. This verifies the WRITTEN config file and surfaces the
|
|
123
|
+
* configured launch target (command + args) read-only, so doctor can further
|
|
124
|
+
* check that a `node <bundle>` target actually exists on disk (the entry may
|
|
125
|
+
* instead be `npx`, which fetches the published package on first use).
|
|
126
|
+
*/
|
|
127
|
+
export declare function inspectMcpConfig(configPath: string, serverKey?: string): McpConfigStatus;
|
|
128
|
+
/**
|
|
129
|
+
* Patch (or create) the MCP config at `configPath`, writing the CompBox server
|
|
130
|
+
* entry while preserving all other content.
|
|
131
|
+
*/
|
|
132
|
+
export declare function patchMcpConfig(configPath: string, spec: McpServerSpec): PatchResult;
|
|
133
|
+
//# sourceMappingURL=mcp-config-writer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"mcp-config-writer.d.ts","sourceRoot":"","sources":["../../src/utils/mcp-config-writer.ts"],"names":[],"mappings":"AACA;;;;;;;;;;;;;;GAcG;AAKH,8DAA8D;AAC9D,eAAO,MAAM,2BAA2B,cAAc,CAAC;AAEvD,yDAAyD;AACzD,eAAO,MAAM,kBAAkB,YAAY,CAAC;AAE5C,wEAAwE;AACxE,eAAO,MAAM,kBAAkB,2BAA2B,CAAC;AAE3D;;;;;;;;;GASG;AACH,wBAAgB,yBAAyB,CAAC,IAAI,CAAC,EAAE;IAC/C,MAAM,CAAC,EAAE,MAAM,CAAC;IAChB,MAAM,CAAC,EAAE,CAAC,CAAC,EAAE,MAAM,KAAK,OAAO,CAAC;CACjC,GAAG,MAAM,GAAG,SAAS,CAerB;AAED,sCAAsC;AACtC,MAAM,WAAW,cAAc;IAC7B,OAAO,EAAE,MAAM,CAAC;IAChB,IAAI,EAAE,MAAM,EAAE,CAAC;IACf,GAAG,EAAE,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAAC;CAC7B;AAED,mEAAmE;AACnE,MAAM,WAAW,aAAa;IAC5B,oCAAoC;IACpC,UAAU,EAAE,MAAM,CAAC;IACnB,iDAAiD;IACjD,QAAQ,EAAE,MAAM,CAAC;IACjB,8DAA8D;IAC9D,SAAS,CAAC,EAAE,MAAM,CAAC;IACnB,uEAAuE;IACvE,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,oEAAoE;IACpE,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;IAChB;;;;OAIG;IACH,sBAAsB,CAAC,EAAE,MAAM,MAAM,GAAG,SAAS,CAAC;CACnD;AAED,oCAAoC;AACpC,MAAM,WAAW,WAAW;IAC1B,wDAAwD;IACxD,WAAW,EAAE,OAAO,CAAC;IACrB,sEAAsE;IACtE,YAAY,EAAE,OAAO,CAAC;IACtB,gDAAgD;IAChD,gBAAgB,EAAE,MAAM,EAAE,CAAC;IAC3B,6BAA6B;IAC7B,UAAU,EAAE,MAAM,CAAC;IACnB;;;;OAIG;IACH,KAAK,EAAE,cAAc,CAAC;CACvB;AAED,8EAA8E;AAC9E,wBAAgB,oBAAoB,CAAC,WAAW,GAAE,MAAsB,GAAG,MAAM,CAEhF;AAED;;;;;;;;GAQG;AACH,wBAAgB,uBAAuB,CAAC,IAAI,EAAE,aAAa,GAAG,cAAc,CAmB3E;AAuBD,kEAAkE;AAClE,MAAM,WAAW,eAAe;IAC9B,+BAA+B;IAC/B,UAAU,EAAE,MAAM,CAAC;IACnB,8CAA8C;IAC9C,UAAU,EAAE,OAAO,CAAC;IACpB,sEAAsE;IACtE,YAAY,EAAE,OAAO,CAAC;IACtB;;;;;OAKG;IACH,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB;;;;OAIG;IACH,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB;;;;OAIG;IACH,IAAI,CAAC,EAAE,MAAM,EAAE,CAAC;CACjB;AAED;;;;;;;;GAQG;AACH,wBAAgB,gBAAgB,CAC9B,UAAU,EAAE,MAAM,EAClB,SAAS,GAAE,MAA2B,GACrC,eAAe,CA8CjB;AAED;;;GAGG;AACH,wBAAgB,cAAc,CAC5B,UAAU,EAAE,MAAM,EAClB,IAAI,EAAE,aAAa,GAClB,WAAW,CAkCb"}
|