spur-board 0.4.0 → 0.4.1

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/dist/cli.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { F as configSchema, I as SLACK_BOT_SCOPES, s as OPERATIONS } from "./src-Cf78bzK5.mjs";
2
- import { a as renderCliError, i as errorExitCode, n as requestTokenEnrollment, o as escapeTerminalControls, r as CliError, t as requestOperation } from "./client-sGJ4fzQ4.mjs";
3
- import { n as loadEnrollmentConfig, t as loadClientConfig } from "./config-DPXFxZQy.mjs";
1
+ import { I as configSchema, L as SLACK_BOT_SCOPES, s as OPERATIONS } from "./src-BEo3mvRC.mjs";
2
+ import { a as renderCliError, i as errorExitCode, n as requestTokenEnrollment, o as escapeTerminalControls, r as CliError, t as requestOperation } from "./client-CHohYNxa.mjs";
3
+ import { i as resolveDaemonAddress, n as loadClientConfig, r as loadEnrollmentConfig, t as configFile } from "./config-BuxxS_er.mjs";
4
4
  import { createHash, randomBytes, randomUUID } from "node:crypto";
5
5
  import { chmodSync, closeSync, constants, existsSync, lstatSync, mkdirSync, openSync, readFileSync, readdirSync, readlinkSync, realpathSync, statSync, unlinkSync, writeFileSync } from "node:fs";
6
6
  import { homedir, hostname, userInfo } from "node:os";
@@ -140,12 +140,6 @@ function warning(id, fix) {
140
140
  fix
141
141
  };
142
142
  }
143
- function configFile(env, home) {
144
- const boardHome = env["BOARD_HOME"];
145
- if (boardHome) return join(resolve(boardHome), "config.yaml");
146
- const xdg = env["XDG_CONFIG_HOME"];
147
- return join(xdg && isAbsolute(xdg) ? xdg : join(home, ".config"), "spur-board", "config.yaml");
148
- }
149
143
  function unitFile(env, home) {
150
144
  const xdg = env["XDG_CONFIG_HOME"];
151
145
  return join(xdg && isAbsolute(xdg) ? xdg : join(home, ".config"), "systemd", "user", "spur-board.service");
@@ -334,8 +328,8 @@ async function runDoctor(options = {}) {
334
328
  checks.push(stale.length > 0 || unknownStarts ? warning("sessions.stale", `Restart sessions started before the last skill install${staleIds.length ? `: ${staleIds.join(", ")}` : ""}; verify sessions whose start time is unavailable.`) : result("sessions.stale", true, "Restart older sessions."));
335
329
  let remote = null;
336
330
  try {
337
- const base = env["BOARD_DAEMON_URL"] || `http://127.0.0.1:${String(config.http.port)}`;
338
- const response = await ports.fetcher(new URL("/v1/doctor", base), { signal: AbortSignal.timeout(8e3) });
331
+ const address = resolveDaemonAddress(env, home, config.http.port);
332
+ const response = await ports.fetcher(new URL("/v1/doctor", address), { signal: AbortSignal.timeout(8e3) });
339
333
  if (response.ok) remote = remoteChecks(await response.json());
340
334
  } catch {}
341
335
  checks.push(result("daemon.available", remote !== null, "Start or restart the user service."));
@@ -1032,7 +1026,7 @@ function createProgram(options = {}) {
1032
1026
  const key = op.kind === "mutation" ? keyOption || randomUUID() : void 0;
1033
1027
  if (key) io.stderr(`key: ${escapeTerminalControls(key)}\n`);
1034
1028
  try {
1035
- const result = await requestOperation(op, input, key, config);
1029
+ const result = await (options.sendOperation ?? requestOperation)(op, input, key, config);
1036
1030
  io.stdout(`${json || !io.isTTY ? JSON.stringify(result) : formatHuman(result)}\n`);
1037
1031
  } catch (error) {
1038
1032
  if (error instanceof CliError) {
@@ -1,4 +1,4 @@
1
- import { M as errorContextSchema, N as errorEnvelopeSchema, P as successEnvelopeSchema, j as ERRORS, l as renderJsonError } from "./src-Cf78bzK5.mjs";
1
+ import { M as errorContextSchema, N as errorEnvelopeSchema, P as successEnvelopeSchema, j as ERRORS, l as renderJsonError } from "./src-BEo3mvRC.mjs";
2
2
  import { randomUUID } from "node:crypto";
3
3
  import { z } from "zod";
4
4
  import { request } from "node:http";
package/dist/client.mjs CHANGED
@@ -1,2 +1,2 @@
1
- import { n as requestTokenEnrollment, t as requestOperation } from "./client-sGJ4fzQ4.mjs";
1
+ import { n as requestTokenEnrollment, t as requestOperation } from "./client-CHohYNxa.mjs";
2
2
  export { requestOperation, requestTokenEnrollment };
@@ -1,13 +1,32 @@
1
- import { r as CliError } from "./client-sGJ4fzQ4.mjs";
1
+ import { I as configSchema } from "./src-BEo3mvRC.mjs";
2
+ import { r as CliError } from "./client-CHohYNxa.mjs";
2
3
  import { closeSync, constants, fstatSync, lstatSync, openSync, readFileSync, realpathSync, statSync } from "node:fs";
3
4
  import { homedir } from "node:os";
4
- import { dirname, isAbsolute, join, relative, sep } from "node:path";
5
+ import { dirname, isAbsolute, join, relative, resolve, sep } from "node:path";
6
+ import YAML from "yaml";
5
7
  //#region src/config.ts
6
8
  const CONNECT_TIMEOUT_MS = 2e3;
7
9
  const RESPONSE_TIMEOUT_MS = 3e4;
8
- function daemonAddress(env) {
10
+ function configFile(env, home) {
11
+ const boardHome = env["BOARD_HOME"];
12
+ if (boardHome) return join(resolve(boardHome), "config.yaml");
13
+ const xdg = env["XDG_CONFIG_HOME"];
14
+ return join(xdg && isAbsolute(xdg) ? xdg : join(home, ".config"), "spur-board", "config.yaml");
15
+ }
16
+ function resolveDaemonAddress(env = process.env, home = homedir(), configuredPort) {
9
17
  const rawAddress = env["BOARD_DAEMON_URL"];
10
- if (!rawAddress) throw new CliError("config", { environmentVariable: "BOARD_DAEMON_URL" });
18
+ if (rawAddress === void 0) {
19
+ let port = configuredPort ?? 4311;
20
+ if (configuredPort === void 0) try {
21
+ const parsed = YAML.parseDocument(readFileSync(configFile(env, home), "utf8"));
22
+ if (parsed.errors.length === 0) {
23
+ const config = configSchema.safeParse(parsed.toJS());
24
+ if (config.success) port = config.data.http.port;
25
+ }
26
+ } catch {}
27
+ if (port === 0) throw new CliError("config", void 0, void 0, "http.port: 0 assigns a runtime port that clients cannot discover. Set BOARD_DAEMON_URL to the daemon listening address.");
28
+ return new URL(`http://127.0.0.1:${String(port)}`);
29
+ }
11
30
  let address;
12
31
  try {
13
32
  address = new URL(rawAddress);
@@ -66,7 +85,7 @@ function loadClientConfig(env = process.env, paths = {
66
85
  cwd: process.cwd(),
67
86
  home: homedir()
68
87
  }) {
69
- const address = daemonAddress(env);
88
+ const address = resolveDaemonAddress(env, paths.home);
70
89
  const session = env["SPUR_SESSION"] || void 0;
71
90
  const token = session ? void 0 : env["BOARD_TOKEN"] === void 0 ? findTokenFile(paths.cwd, paths.home) : env["BOARD_TOKEN"];
72
91
  if (!session && !token) throw new CliError("config", { environmentVariable: "BOARD_TOKEN" });
@@ -81,7 +100,7 @@ function loadClientConfig(env = process.env, paths = {
81
100
  /** Enrollment sends only a hash and works before any operator credential exists. */
82
101
  function loadEnrollmentConfig(env = process.env) {
83
102
  return {
84
- address: daemonAddress(env),
103
+ address: resolveDaemonAddress(env),
85
104
  session: void 0,
86
105
  token: void 0,
87
106
  connectTimeoutMs: CONNECT_TIMEOUT_MS,
@@ -89,4 +108,4 @@ function loadEnrollmentConfig(env = process.env) {
89
108
  };
90
109
  }
91
110
  //#endregion
92
- export { loadEnrollmentConfig as n, loadClientConfig as t };
111
+ export { resolveDaemonAddress as i, loadClientConfig as n, loadEnrollmentConfig as r, configFile as t };
package/dist/daemon.mjs CHANGED
@@ -1,4 +1,4 @@
1
- import { A as taskKeySchema, C as sessionFactsSchema, D as errorCodeOf, E as encodeActorId, F as configSchema, I as SLACK_BOT_SCOPES, O as parseActorId, P as successEnvelopeSchema, S as prRefSchema, T as actorIdSchema, _ as EVENT_KINDS, a as buildCatalogSnapshot, b as SESSION_STATUSES, c as renderHttpProblem, d as SPACE_IDS, f as conversationRefSchema, g as userIdSchema, h as messageRefSchema, i as sourceCursorSchema, j as ERRORS, k as parseRef$1, m as interactionRefSchema, n as batchSchema, o as roleCanUseOperation, p as inboundEventSchema, r as entityRefSchema, s as OPERATIONS, t as AdapterError, v as eventPayloadSchemas, w as ticketFactsSchema, x as prFactsSchema, y as SESSION_HEALTH_STATES } from "./src-Cf78bzK5.mjs";
1
+ import { A as taskKeySchema, C as sessionFactsSchema, D as errorCodeOf, E as encodeActorId, I as configSchema, L as SLACK_BOT_SCOPES, O as parseActorId, P as successEnvelopeSchema, S as prRefSchema, T as actorIdSchema, _ as EVENT_KINDS, a as buildCatalogSnapshot, b as SESSION_STATUSES, c as renderHttpProblem, d as SPACE_IDS, f as conversationRefSchema, g as userIdSchema, h as messageRefSchema, i as sourceCursorSchema, j as ERRORS, k as parseRef$1, m as interactionRefSchema, n as batchSchema, o as roleCanUseOperation, p as inboundEventSchema, r as entityRefSchema, s as OPERATIONS, t as AdapterError, v as eventPayloadSchemas, w as ticketFactsSchema, x as prFactsSchema, y as SESSION_HEALTH_STATES } from "./src-BEo3mvRC.mjs";
2
2
  import { createRequire } from "node:module";
3
3
  import { createHash, randomUUID } from "node:crypto";
4
4
  import { closeSync, existsSync, fstatSync, ftruncateSync, mkdirSync, openSync, readFileSync, readdirSync, writeSync } from "node:fs";
package/dist/mcp.mjs CHANGED
@@ -1,6 +1,6 @@
1
- import { j as ERRORS, s as OPERATIONS, u as renderMcpError } from "./src-Cf78bzK5.mjs";
2
- import { r as CliError, t as requestOperation } from "./client-sGJ4fzQ4.mjs";
3
- import { t as loadClientConfig } from "./config-DPXFxZQy.mjs";
1
+ import { j as ERRORS, s as OPERATIONS, u as renderMcpError } from "./src-BEo3mvRC.mjs";
2
+ import { r as CliError, t as requestOperation } from "./client-CHohYNxa.mjs";
3
+ import { n as loadClientConfig } from "./config-BuxxS_er.mjs";
4
4
  import { randomUUID } from "node:crypto";
5
5
  import { readFileSync } from "node:fs";
6
6
  import { z } from "zod";
@@ -110,6 +110,7 @@ const SLACK_BOT_SCOPES = [
110
110
  ];
111
111
  //#endregion
112
112
  //#region ../contracts/src/config.ts
113
+ const DEFAULT_HTTP_PORT = 4311;
113
114
  const WEEKDAYS = [
114
115
  "monday",
115
116
  "tuesday",
@@ -276,7 +277,7 @@ const configSchema = z.strictObject({
276
277
  message: "Final unanswered pause must exceed the second retry pause"
277
278
  });
278
279
  }).prefault({}),
279
- http: z.strictObject({ port: z.int().min(0).max(65535).default(4311).describe("Local HTTP API port (0 assigns a free port).") }).prefault({}),
280
+ http: z.strictObject({ port: z.int().min(0).max(65535).default(DEFAULT_HTTP_PORT).describe("Local HTTP API port (0 assigns a free port).") }).prefault({}),
280
281
  adapters: z.strictObject({
281
282
  spur: spurAdapterSection,
282
283
  github: adapterSection(6e4),
@@ -2630,4 +2631,4 @@ var AdapterError = class extends Error {
2630
2631
  }
2631
2632
  };
2632
2633
  //#endregion
2633
- export { taskKeySchema as A, sessionFactsSchema as C, errorCodeOf as D, encodeActorId as E, configSchema as F, SLACK_BOT_SCOPES as I, errorContextSchema as M, errorEnvelopeSchema as N, parseActorId as O, successEnvelopeSchema as P, prRefSchema as S, actorIdSchema as T, EVENT_KINDS as _, buildCatalogSnapshot as a, SESSION_STATUSES as b, renderHttpProblem as c, SPACE_IDS as d, conversationRefSchema as f, userIdSchema as g, messageRefSchema as h, sourceCursorSchema as i, ERRORS as j, parseRef as k, renderJsonError as l, interactionRefSchema as m, batchSchema as n, roleCanUseOperation as o, inboundEventSchema as p, entityRefSchema as r, OPERATIONS as s, AdapterError as t, renderMcpError as u, eventPayloadSchemas as v, ticketFactsSchema as w, prFactsSchema as x, SESSION_HEALTH_STATES as y };
2634
+ export { taskKeySchema as A, sessionFactsSchema as C, errorCodeOf as D, encodeActorId as E, DEFAULT_HTTP_PORT as F, configSchema as I, SLACK_BOT_SCOPES as L, errorContextSchema as M, errorEnvelopeSchema as N, parseActorId as O, successEnvelopeSchema as P, prRefSchema as S, actorIdSchema as T, EVENT_KINDS as _, buildCatalogSnapshot as a, SESSION_STATUSES as b, renderHttpProblem as c, SPACE_IDS as d, conversationRefSchema as f, userIdSchema as g, messageRefSchema as h, sourceCursorSchema as i, ERRORS as j, parseRef as k, renderJsonError as l, interactionRefSchema as m, batchSchema as n, roleCanUseOperation as o, inboundEventSchema as p, entityRefSchema as r, OPERATIONS as s, AdapterError as t, renderMcpError as u, eventPayloadSchemas as v, ticketFactsSchema as w, prFactsSchema as x, SESSION_HEALTH_STATES as y };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "spur-board",
3
- "version": "0.4.0",
3
+ "version": "0.4.1",
4
4
  "license": "MIT",
5
5
  "engines": {
6
6
  "node": "^24.12.0 || ^26.0.0"