starbridge 0.1.3 → 0.1.4-rc.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.
Files changed (2) hide show
  1. package/dist/starbridge.js +55 -25
  2. package/package.json +1 -1
@@ -10203,6 +10203,7 @@ var PermissionAnswer = object({
10203
10203
  if (a.behavior === "allow" && a.message !== undefined)
10204
10204
  ctx.addIssue({ code: "custom", message: "message is for a deny" });
10205
10205
  });
10206
+ var SETTLED_REASON_MAX = 120;
10206
10207
  var Settled = object({
10207
10208
  v: literal(1),
10208
10209
  id: Id,
@@ -10214,7 +10215,8 @@ var Settled = object({
10214
10215
  choice: string2().max(100).optional(),
10215
10216
  text: string2().max(4000).optional(),
10216
10217
  dir: DirectoryHead.optional(),
10217
- behavior: _enum(["allow", "deny"]).optional()
10218
+ behavior: _enum(["allow", "deny"]).optional(),
10219
+ reason: string2().min(1).max(SETTLED_REASON_MAX).regex(/^[^\r\n]*$/, "one line").optional()
10218
10220
  }).refine((s) => s.device !== undefined || s.choice === undefined && s.text === undefined, {
10219
10221
  message: "choice and text come only with a device's outcome"
10220
10222
  }).refine((s) => s.choice === undefined || s.text === undefined, {
@@ -14368,6 +14370,7 @@ function checkJoined(dir, me) {
14368
14370
  if (!entry?.active || entry.member.role !== me.role || entry.member.boxPk !== me.boxPk || entry.member.signPk !== me.signPk)
14369
14371
  throw new ProtocolError("unknown-member", "the directory does not hold my keys");
14370
14372
  }
14373
+ var CHECK_CONFIRM_MS = 10 * 60000;
14371
14374
  function checkInput(entries, id) {
14372
14375
  const nul = new Uint8Array([0]);
14373
14376
  for (const e of entries) {
@@ -14426,7 +14429,10 @@ function publicKeys(keys) {
14426
14429
  // ../packages/protocol/src/notifications.ts
14427
14430
  var NotifyState = _enum(["on", "off", "blocked"]);
14428
14431
  var DeviceNotifications = object({ state: NotifyState });
14429
- var NotificationStates = object({ devices: record(string2(), NotifyState) });
14432
+ var NotificationStates = object({
14433
+ devices: record(string2(), NotifyState),
14434
+ clients: record(string2(), string2()).optional()
14435
+ });
14430
14436
  var AppSignedIn = object({ signedIn: boolean2() });
14431
14437
  // ../packages/protocol/src/pace.ts
14432
14438
  var MIN_ELAPSED_FRACTION = 0.05;
@@ -14649,7 +14655,7 @@ function processAlive(pid) {
14649
14655
  // package.json
14650
14656
  var package_default = {
14651
14657
  name: "starbridge",
14652
- version: "0.1.3",
14658
+ version: "0.1.4-rc.2",
14653
14659
  description: "Post decisions to your Starbridge devices and upload quota windows from CodexBar",
14654
14660
  license: "MIT",
14655
14661
  repository: {
@@ -16731,16 +16737,33 @@ async function settle2(ctx, opts) {
16731
16737
  if (opts.outcome !== undefined && opts.outcome !== "elsewhere" && opts.outcome !== "withdrawn")
16732
16738
  throw new UsageError("--outcome is elsewhere or withdrawn");
16733
16739
  const outcome = opts.outcome;
16740
+ const { reason } = opts;
16741
+ if (reason !== undefined)
16742
+ checkReason(reason);
16734
16743
  if (id) {
16735
16744
  const asked = ctx.store.state().asked[id];
16736
16745
  if (!asked)
16737
16746
  throw new UsageError(`${id} is not a decision this machine asked`);
16747
+ const withdrawn = (outcome ?? (asked.answerIn ? "elsewhere" : "withdrawn")) === "withdrawn";
16748
+ if (withdrawn && reason === undefined)
16749
+ throw new UsageError(`say why you withdraw it, in one short line: --reason 'Fixed it myself after rereading the logs'`);
16750
+ if (!withdrawn && reason !== undefined)
16751
+ throw new UsageError("--reason is for --outcome withdrawn");
16738
16752
  const s = session(ctx);
16739
- await settleOne(ctx, s, await refreshDirectory(ctx, s), id, outcome);
16753
+ await settleOne(ctx, s, await refreshDirectory(ctx, s), id, outcome, false, reason);
16740
16754
  return 0;
16741
16755
  }
16756
+ if (reason !== undefined && outcome !== "withdrawn")
16757
+ throw new UsageError("--reason is for --outcome withdrawn");
16742
16758
  return settleMany(ctx, opts, outcome);
16743
16759
  }
16760
+ function pickerReason(outcome) {
16761
+ return outcome === "withdrawn" ? { reason: "Its answer could no longer reach the agent" } : {};
16762
+ }
16763
+ function checkReason(reason) {
16764
+ if (!reason.trim() || /[\r\n]/.test(reason) || reason.length > SETTLED_REASON_MAX)
16765
+ throw new UsageError(`--reason is one line of at most ${SETTLED_REASON_MAX} characters`);
16766
+ }
16744
16767
  async function settleMany(ctx, opts, outcome) {
16745
16768
  const st = ctx.store.state();
16746
16769
  const open = Object.entries(st.asked).filter(([id, a]) => (!a.settled || a.unposted) && !a.revoked && !st.answers[id]).filter(([, a]) => opts.all || a.session === opts.session).map(([id]) => id);
@@ -16761,7 +16784,7 @@ async function settleMany(ctx, opts, outcome) {
16761
16784
  return 130;
16762
16785
  }
16763
16786
  try {
16764
- if (await settleOne(ctx, s, dir, id, outcome, true))
16787
+ if (await settleOne(ctx, s, dir, id, outcome, true, opts.reason))
16765
16788
  done++;
16766
16789
  break;
16767
16790
  } catch (e) {
@@ -16778,7 +16801,7 @@ async function settleMany(ctx, opts, outcome) {
16778
16801
  ctx.out(`Settled ${done} decision${done === 1 ? "" : "s"}.`);
16779
16802
  return 0;
16780
16803
  }
16781
- async function settleOne(ctx, s, dir, id, outcomeOpt, bulk = false) {
16804
+ async function settleOne(ctx, s, dir, id, outcomeOpt, bulk = false, reason) {
16782
16805
  const asked = ctx.store.state().asked[id];
16783
16806
  if (!asked || asked.revoked)
16784
16807
  return false;
@@ -16803,6 +16826,7 @@ async function settleOne(ctx, s, dir, id, outcomeOpt, bulk = false) {
16803
16826
  to: to.map((d) => d.id),
16804
16827
  at: iso2(ctx.now()),
16805
16828
  outcome,
16829
+ ...reason !== undefined && outcome === "withdrawn" ? { reason } : {},
16806
16830
  dir: signedHead(dir)
16807
16831
  };
16808
16832
  try {
@@ -17636,7 +17660,7 @@ import { existsSync as existsSync6, mkdirSync as mkdirSync7, readFileSync as rea
17636
17660
  import { dirname as dirname5, join as join11 } from "node:path";
17637
17661
 
17638
17662
  // ../plugin/hooks/rule.md
17639
- var rule_default = "I am often away from this terminal and may not read your final message for hours. Reach me through the `starbridge` skill, not here, when you need a decision that is mine, and before you end a turn on work that waits on me, such as a PR to review or merge, or a failure only I can fix. In Claude Code, a quick question may use AskUserQuestion instead, since it reaches my devices too. Decide everything else yourself and keep working. Ask here only when `starbridge` fails. Write each card to be read in seconds on a phone, as the skill says.\n\nRun a command that blocks me (takes over the screen, keyboard or session, or holds a device I use), or that my instructions ask you to report, whole through `starbridge run`.\n";
17663
+ var rule_default = "I am often away from this terminal and may not read your final message for hours. Reach me through the `starbridge` skill, not here, when you need a decision that is mine, and before you end a turn on work that waits on me, such as a PR to review or merge, or a failure only I can fix. In Claude Code, a quick question may use AskUserQuestion instead, since it reaches my devices too. Decide everything else yourself and keep working. Ask here only when `starbridge` fails. Write each card to be read in seconds on a phone, as the skill says. When I answer one of your open cards here instead, withdraw it, saying why in a few words: `starbridge settle <id> --outcome withdrawn --reason 'You answered in the terminal'`.\n\nRun a command that blocks me (takes over the screen, keyboard or session, or holds a device I use), or that my instructions ask you to report, whole through `starbridge run`.\n";
17640
17664
 
17641
17665
  // ../plugin/skills/starbridge/SKILL.md
17642
17666
  var SKILL_default = `---
@@ -17751,6 +17775,13 @@ if it leaves the choice open. Act on the answer at once. Post again only when
17751
17775
  the outcome changes what they would do (the merge failed); otherwise say it
17752
17776
  in your final message.
17753
17777
 
17778
+ A card still open that no longer needs an answer (the owner answered in the
17779
+ terminal, or you found it yourself) stays in their inbox until you take it
17780
+ back, before you act: \`starbridge settle <id> --outcome withdrawn --reason
17781
+ '…'\`. The reason shows in their History: one short line, 120 characters at
17782
+ most, such as \`'You answered in the terminal'\` or \`'Fixed it myself after
17783
+ rereading the logs'\`.
17784
+
17754
17785
  ## Answers in an artifact
17755
17786
 
17756
17787
  When you built a claude.ai artifact whose buttons send the pick to this
@@ -17759,8 +17790,6 @@ arrives, run \`starbridge settle <id>\`, then act; a card answered in Starbridge
17759
17790
  needs no settle. When the owner taps Done on the card instead, you get
17760
17791
  \`Answer to <id> (…): answered on its page; read the answer there\`: the card is
17761
17792
  closed, so read the pick on the page and act, with no settle. An artifact only to look at goes in \`--link\`, with options.
17762
- \`starbridge settle <id> --outcome withdrawn\` takes back a card you no longer
17763
- need.
17764
17793
 
17765
17794
  ## Report a run
17766
17795
 
@@ -18550,7 +18579,7 @@ function pickerOpen(st, session) {
18550
18579
  return Object.entries(st.asked).filter(([id, a]) => a.picker === session && !a.settled && !st.answers[id]).map(([id]) => id);
18551
18580
  }
18552
18581
  async function settlePicker(ctx, session, outcome) {
18553
- await Promise.all(pickerOpen(ctx.store.state(), session).map((id) => settle2({ ...ctx, signal: undefined }, { id, outcome }).catch((e) => ctx.err(`starbridge: could not settle ${id}: ${e.message}`))));
18582
+ await Promise.all(pickerOpen(ctx.store.state(), session).map((id) => settle2({ ...ctx, signal: undefined }, { id, outcome, ...pickerReason(outcome) }).catch((e) => ctx.err(`starbridge: could not settle ${id}: ${e.message}`))));
18554
18583
  }
18555
18584
  async function racePicker(ctx, outer, hook, waitText) {
18556
18585
  const questions = pickerQuestions(hook.tool_input);
@@ -18686,7 +18715,7 @@ async function hookQuestion(outer, stdin, opts) {
18686
18715
  return 0;
18687
18716
  }
18688
18717
  const outcome = outer.signal?.aborted ? "elsewhere" : "withdrawn";
18689
- await Promise.all(ids.map((id) => id ? settle2({ ...ctx, signal: undefined }, { id, outcome }).catch((e) => ctx.err(`starbridge: could not settle ${id}: ${e.message}`)) : undefined));
18718
+ await Promise.all(ids.map((id) => id ? settle2({ ...ctx, signal: undefined }, { id, outcome, ...pickerReason(outcome) }).catch((e) => ctx.err(`starbridge: could not settle ${id}: ${e.message}`)) : undefined));
18690
18719
  } catch (e) {
18691
18720
  ctx.err(`starbridge: question not sent: ${e.message}`);
18692
18721
  } finally {
@@ -19036,7 +19065,7 @@ import { configDir } from "./poller.ts";
19036
19065
 
19037
19066
  /** The agent API revision this mod speaks, sent in the \`starbridge-api\` header. */
19038
19067
  export const API = 1;
19039
- export const VERSION = "0.1.3";
19068
+ export const VERSION = "0.1.4-rc.2";
19040
19069
  const CLIENT = \`starbridge-mod/\${VERSION}\`;
19041
19070
 
19042
19071
  /** Event types this mod submits; others are skipped and left unconfirmed, as the API asks. */
@@ -23041,7 +23070,7 @@ async function ask2(ctx, hook, questions, signal) {
23041
23070
  if (picked.every((p) => p !== undefined) && !stop.aborted)
23042
23071
  return picked;
23043
23072
  const outcome = signal.aborted ? "elsewhere" : "withdrawn";
23044
- await Promise.all(ids.map((id) => id ? settle2({ ...ctx, signal: undefined }, { id, outcome }).catch((e) => ctx.err(`starbridge: could not settle ${id}: ${e.message}`)) : undefined));
23073
+ await Promise.all(ids.map((id) => id ? settle2({ ...ctx, signal: undefined }, { id, outcome, ...pickerReason(outcome) }).catch((e) => ctx.err(`starbridge: could not settle ${id}: ${e.message}`)) : undefined));
23045
23074
  return;
23046
23075
  }
23047
23076
 
@@ -23897,7 +23926,6 @@ function addedAt(entries, id) {
23897
23926
  }
23898
23927
  }
23899
23928
  }
23900
- var CONFIRM_MS = 10 * 60000;
23901
23929
  var waitingFile = (ctx) => join14(ctx.store.dir, "pair-waiting");
23902
23930
  var answerFile = (ctx, code) => join14(ctx.store.dir, `pair-answer.${code}`);
23903
23931
  function writeWhole(path, text) {
@@ -23935,7 +23963,7 @@ async function confirmCheck(ctx, code, name) {
23935
23963
  typed.push(l);
23936
23964
  }) : undefined;
23937
23965
  try {
23938
- const until = ctx.now().getTime() + CONFIRM_MS;
23966
+ const until = ctx.now().getTime() + CHECK_CONFIRM_MS;
23939
23967
  for (;; ) {
23940
23968
  if (ctx.signal?.aborted || ctx.now().getTime() > until)
23941
23969
  return;
@@ -24548,14 +24576,14 @@ import {
24548
24576
  import { dirname as dirname8, join as join16 } from "node:path";
24549
24577
  // src/setup/codexbar-pin.json
24550
24578
  var codexbar_pin_default = {
24551
- version: "0.73.0",
24579
+ version: "0.74.0",
24552
24580
  sha256: {
24553
- "macos-arm64": "cd8f853779f8faec003f53d5fc2a1614aef577ec9f603cbd58a9559b54e159b9",
24554
- "macos-x86_64": "19e7059de688e62be98790bc10198257f5d326e4a3f4191183c23106eb91780a",
24555
- "linux-aarch64": "ae6f9be046b09dc9d17210b661c25e2ee8a0150edb047b917d9eb17c295c7094",
24556
- "linux-x86_64": "a84f556c7ecebc8e606e0a34ee0d121626f72d7afc1e3adf5746410bc10f9611",
24557
- "linux-musl-aarch64": "a4007dfa6577a436eaeb6b46601982c69548c6e20730b3eb9133d4266d5ea92b",
24558
- "linux-musl-x86_64": "75fd9cfc00784eef8badd6e76f4f74cbdf7c13db0b7f9ca6e105ddb793e6e8f8"
24581
+ "macos-arm64": "9aab1b9229f5d1d77de21b99aa887a60a47921bfd9b66e4b941a0e8a9d6e38e8",
24582
+ "macos-x86_64": "4d239b7412683f1eb529d55b851fe922bb462527850b767d6c9b89ba14be3fdb",
24583
+ "linux-aarch64": "46dc3b259b1df48b3fd6f337c754dd60dbece6772d7840cdc9514ab4977a0007",
24584
+ "linux-x86_64": "fac8b2c474e4e37a2b067224437cb182693411ebf639441cd0facbb57bf086b1",
24585
+ "linux-musl-aarch64": "9dab39f1197d9ccc501d1f678234cf15f94e8b84aa7349ba87103a5866dd793b",
24586
+ "linux-musl-x86_64": "e7b0bdc6d6931a4e6fd5ce4037e1125a073ec6cf38cd72f1b3bd8aeecfde51f5"
24559
24587
  }
24560
24588
  };
24561
24589
 
@@ -25809,7 +25837,7 @@ async function testDecision(ctx, name) {
25809
25837
  if (code !== EXIT_INTERRUPTED || !id)
25810
25838
  return;
25811
25839
  try {
25812
- await settle2(ctx, { id, outcome: "withdrawn" });
25840
+ await settle2(ctx, { id, outcome: "withdrawn", reason: "Skipped in starbridge setup" });
25813
25841
  ctx.out("– Skipped");
25814
25842
  } catch (e) {
25815
25843
  ctx.out(`– Skipped, but the card stays open on your devices: ${e.message}`);
@@ -26254,11 +26282,12 @@ var HELP = `starbridge: post decisions to your devices, report runs, upload quot
26254
26282
  Show the owner that you are now blocked on the decision ("Waiting for you", which
26255
26283
  notifies them once more), or back to working on other things.
26256
26284
 
26257
- starbridge settle <decision id> [--outcome elsewhere|withdrawn]
26285
+ starbridge settle <decision id> [--outcome elsewhere|withdrawn] [--reason <text>]
26258
26286
  starbridge settle --session <id> | --all [--yes] [--outcome elsewhere|withdrawn]
26259
26287
  Close a decision without a Starbridge answer: answered on its --answer-in page
26260
26288
  (elsewhere, the default for those) or no longer needed (withdrawn). Devices move it
26261
- out of the inbox. --session closes every open decision that session asked, --all every
26289
+ out of the inbox. A withdrawal says why in --reason, one short line of at most 120
26290
+ characters that History shows: --reason 'Fixed it myself after rereading the logs'. --session closes every open decision that session asked, --all every
26262
26291
  one this machine asked, after asking (--yes skips the question), at the pace the
26263
26292
  server allows: a looping agent's thousands take over an hour.
26264
26293
 
@@ -26490,6 +26519,7 @@ async function run2(argv, ctx) {
26490
26519
  allowPositionals: true,
26491
26520
  options: {
26492
26521
  outcome: { type: "string" },
26522
+ reason: { type: "string" },
26493
26523
  session: { type: "string" },
26494
26524
  all: { type: "boolean" },
26495
26525
  yes: { type: "boolean", short: "y" }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "starbridge",
3
- "version": "0.1.3",
3
+ "version": "0.1.4-rc.2",
4
4
  "description": "Post decisions to your Starbridge devices and upload quota windows from CodexBar",
5
5
  "license": "MIT",
6
6
  "repository": {