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.
- package/dist/starbridge.js +55 -25
- package/package.json +1 -1
package/dist/starbridge.js
CHANGED
|
@@ -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({
|
|
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.
|
|
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
|
|
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.
|
|
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() +
|
|
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.
|
|
24579
|
+
version: "0.74.0",
|
|
24552
24580
|
sha256: {
|
|
24553
|
-
"macos-arm64": "
|
|
24554
|
-
"macos-x86_64": "
|
|
24555
|
-
"linux-aarch64": "
|
|
24556
|
-
"linux-x86_64": "
|
|
24557
|
-
"linux-musl-aarch64": "
|
|
24558
|
-
"linux-musl-x86_64": "
|
|
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.
|
|
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" }
|