@cabane/companion 0.6.0 → 0.6.2

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.
@@ -10,7 +10,7 @@ import {
10
10
  } from "fs";
11
11
  import { homedir, userInfo } from "os";
12
12
  import { dirname, join } from "path";
13
- import { z as z3 } from "zod";
13
+ import { z as z2 } from "zod";
14
14
 
15
15
  // src/errors.ts
16
16
  var CompanionError = class extends Error {
@@ -37,9 +37,6 @@ var ConfigError = class extends CompanionError {
37
37
  };
38
38
 
39
39
  // src/pairing.ts
40
- import { z } from "zod";
41
- var PAIRING_VERSION = 1;
42
- var DEVICE_TOKEN_PREFIX = "cabdev_";
43
40
  function isAllowedBaseUrl(raw) {
44
41
  let url;
45
42
  try {
@@ -54,45 +51,24 @@ function isAllowedBaseUrl(raw) {
54
51
  }
55
52
  return false;
56
53
  }
57
- var pairingSchema = z.object({
58
- // Bumped if the wire shape changes incompatibly. We only accept v1.
59
- v: z.literal(PAIRING_VERSION),
60
- baseUrl: z.string().url().refine(isAllowedBaseUrl, {
61
- message: "baseUrl must be https (loopback http is allowed for local dev only)"
62
- }),
63
- // The `cabdev_` device token plaintext — the companion's one durable credential.
64
- deviceToken: z.string().min(1).startsWith(DEVICE_TOKEN_PREFIX, {
65
- message: 'deviceToken must be a cabane device token (starts with "cabdev_")'
66
- }),
67
- // Optional identity hints the app may include for nicer local display. The
68
- // companion also learns these from the first assignments pull, so they're not
69
- // required.
70
- deviceId: z.string().min(1).optional(),
71
- deviceLabel: z.string().min(1).optional()
72
- });
73
54
 
74
55
  // src/prepare-hook.ts
75
56
  import { spawn } from "child_process";
76
- import { z as z2 } from "zod";
77
- var prepareHookSchema = z2.object({
78
- command: z2.string().min(1),
79
- args: z2.array(z2.string()).optional(),
57
+ import { z } from "zod";
58
+ var prepareHookSchema = z.object({
59
+ command: z.string().min(1),
60
+ args: z.array(z.string()).optional(),
80
61
  // Extra env handed to the hook process itself (merged over process.env).
81
- env: z2.record(z2.string(), z2.string()).optional(),
62
+ env: z.record(z.string(), z.string()).optional(),
82
63
  // Wall-clock cap for the hook. Provisioning is slow (minutes), so the
83
64
  // default is generous; a hook that hangs past this is killed and the turn
84
65
  // fails with a clear timeout message rather than pinning the companion.
85
- timeoutMs: z2.number().int().positive().optional()
66
+ timeoutMs: z.number().int().positive().optional()
86
67
  }).strict();
87
68
  var DEFAULT_TIMEOUT_MS = 10 * 6e4;
88
- var prepareResultSchema = z2.object({
89
- cwd: z2.string().min(1),
90
- env: z2.record(z2.string(), z2.string()).optional(),
91
- nativeWorkAssignment: z2.object({
92
- itemId: z2.string(),
93
- executionId: z2.string(),
94
- activationEpoch: z2.number().int().nonnegative()
95
- }).strict().optional()
69
+ var prepareResultSchema = z.object({
70
+ cwd: z.string().min(1),
71
+ env: z.record(z.string(), z.string()).optional()
96
72
  });
97
73
 
98
74
  // src/config.ts
@@ -122,8 +98,8 @@ function cabaneDir() {
122
98
  function configPath() {
123
99
  return join(cabaneDir(), "config.json");
124
100
  }
125
- var localAgentConfigSchema = z3.object({
126
- cwd: z3.string().optional(),
101
+ var localAgentConfigSchema = z2.object({
102
+ cwd: z2.string().optional(),
127
103
  prepareHook: prepareHookSchema.optional(),
128
104
  // CT289: the Claude Code auto-memory escape hatch. Auto-memory is forced OFF
129
105
  // by default on every companion (memory belongs in the Cabane workspace, and a
@@ -132,13 +108,13 @@ var localAgentConfigSchema = z3.object({
132
108
  // auto-memory back to your own `~/.claude/settings.json` — Cabane then stops
133
109
  // injecting the off switch and your normal Claude Code memory workflow applies
134
110
  // (in coding mode, where the checkout's project settings are read).
135
- claudeCode: z3.object({ autoMemory: z3.boolean().optional() }).strict().optional()
111
+ claudeCode: z2.object({ autoMemory: z2.boolean().optional() }).strict().optional()
136
112
  }).strict();
137
- var companionConfigSchema = z3.object({
113
+ var companionConfigSchema = z2.object({
138
114
  // The cabane instance this device is paired with. SJ515: https-enforced
139
115
  // (loopback exempt) so a hand-edited config can't smuggle a plaintext-http
140
116
  // base URL onto the MITM-able channel the device token + prompt ride.
141
- baseUrl: z3.string().url().refine(isAllowedBaseUrl, {
117
+ baseUrl: z2.string().url().refine(isAllowedBaseUrl, {
142
118
  message: "baseUrl must be https (loopback http is allowed for local dev only)"
143
119
  }),
144
120
  // The `cabdev_` device token plaintext — the companion's one durable credential,
@@ -146,22 +122,22 @@ var companionConfigSchema = z3.object({
146
122
  // heartbeat endpoints. Optional so `cabane-companion logout` can strip it (a
147
123
  // "paired but logged out" state the supervisor refuses to run) while keeping
148
124
  // the rest of the config; `pair` always writes one.
149
- deviceToken: z3.string().optional(),
150
- // Identity hints, learned from the pairing string and refreshed on the first
125
+ deviceToken: z2.string().optional(),
126
+ // Identity hints, learned from the device flow and refreshed on the first
151
127
  // assignments pull. Cosmetic — used for `status`/dashboard display only.
152
- deviceId: z3.string().optional(),
153
- deviceLabel: z3.string().optional(),
128
+ deviceId: z2.string().optional(),
129
+ deviceLabel: z2.string().optional(),
154
130
  // Optional per-agent machine-local overrides (cwd / prepareHook), keyed by
155
131
  // agentId / username / `slug/username`. Hand-added by the operator; the companion
156
132
  // never writes this (it only persists credentials + the device, elsewhere).
157
- agents: z3.record(z3.string(), localAgentConfigSchema).optional(),
133
+ agents: z2.record(z2.string(), localAgentConfigSchema).optional(),
158
134
  // Dashboard settings (all optional). dashboardPort: preferred bind port (next
159
135
  // free one if taken); autoOpen: whether `start` opens the browser (the
160
136
  // `--no-open` flag / `COMPANION_NO_OPEN=1` override per-run); logLevel: pino
161
137
  // level, live-editable from the dashboard settings panel.
162
- dashboardPort: z3.number().int().min(1).max(65535).optional(),
163
- autoOpen: z3.boolean().optional(),
164
- logLevel: z3.enum(["warn", "info", "debug"]).optional(),
138
+ dashboardPort: z2.number().int().min(1).max(65535).optional(),
139
+ autoOpen: z2.boolean().optional(),
140
+ logLevel: z2.enum(["warn", "info", "debug"]).optional(),
165
141
  // CT270: the opencode runtime, when the operator runs one on this machine. The
166
142
  // operator installs opencode, starts `opencode serve` (auth via opencode's own
167
143
  // `/connect` — Cabane never sees provider keys), and points the companion at it
@@ -169,8 +145,8 @@ var companionConfigSchema = z3.object({
169
145
  // heartbeat manifest (so the server offers DeepSeek/opencode models here and
170
146
  // routes those turns to this device) AND registers the opencode adapter in the
171
147
  // dispatcher. Absent → the device is claude-code-only, exactly as before.
172
- opencode: z3.object({
173
- serverUrl: z3.string().url()
148
+ opencode: z2.object({
149
+ serverUrl: z2.string().url()
174
150
  }).strict().optional(),
175
151
  // CT481: the codex runtime, when the operator runs Codex on this machine. Unlike
176
152
  // opencode (a long-lived `opencode serve` addressed by URL), Codex is a local CLI
@@ -181,8 +157,8 @@ var companionConfigSchema = z3.object({
181
157
  // keeps the block but turns it off). Enabling makes the device advertise the
182
158
  // `codex` runtime on its heartbeat manifest AND registers the codex adapter in
183
159
  // the dispatcher. Absent → the device doesn't offer codex, exactly as before.
184
- codex: z3.object({
185
- enabled: z3.boolean().optional()
160
+ codex: z2.object({
161
+ enabled: z2.boolean().optional()
186
162
  }).strict().optional()
187
163
  });
188
164
  function loadConfig() {
@@ -251,7 +227,7 @@ function loadConfigTolerant() {
251
227
  }
252
228
  const obj = parsed && typeof parsed === "object" ? parsed : {};
253
229
  const local = {};
254
- const agents = z3.record(z3.string(), localAgentConfigSchema).safeParse(obj.agents);
230
+ const agents = z2.record(z2.string(), localAgentConfigSchema).safeParse(obj.agents);
255
231
  if (agents.success) local.agents = agents.data;
256
232
  if (typeof obj.dashboardPort === "number") local.dashboardPort = obj.dashboardPort;
257
233
  if (typeof obj.autoOpen === "boolean") local.autoOpen = obj.autoOpen;
@@ -316,7 +292,7 @@ async function postJson(baseUrl, path, body) {
316
292
  if (res.status >= 400) {
317
293
  if (res.status === 404 && path.endsWith("/code")) {
318
294
  throw new CompanionError(
319
- `this cabane server (${baseUrl}) doesn't support device-flow pairing yet. Update the server, or use \`cabane-companion pair --legacy\` with a pairing string from the app.`
295
+ `this cabane server (${baseUrl}) doesn't support device-flow pairing yet. Update the server to a version that supports \`cabane-companion pair\`.`
320
296
  );
321
297
  }
322
298
  const msg = parsed && typeof parsed === "object" && "error" in parsed ? String(parsed.error) : `${res.status}`;