sideby 0.9.2 → 0.9.3
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/build.json +1 -1
- package/dist/src/core/handoff-chain.d.ts +2 -0
- package/dist/src/core/handoff-run.js +7 -0
- package/dist/src/families/claude/handoff.js +1 -0
- package/dist/src/handoff/hook.js +12 -4
- package/dist/src/handoff/messages.d.ts +2 -0
- package/dist/src/handoff/messages.js +4 -0
- package/dist/src/types.d.ts +1 -1
- package/package.json +1 -1
- package/skills/sideby/SKILL.md +3 -3
package/dist/build.json
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"id":"
|
|
1
|
+
{"id":"20261015T124638-3ce884"}
|
|
@@ -18,6 +18,8 @@ export interface PlanFile {
|
|
|
18
18
|
threshold: number;
|
|
19
19
|
/** False when the session cannot write its Brief: no preparing step, and the threshold only ends the turn. */
|
|
20
20
|
agentBrief?: boolean;
|
|
21
|
+
/** The parent reads `to` from a manual request; a parent from before 0.9.3 does not write it and ignores `to`. */
|
|
22
|
+
acceptsTo?: true;
|
|
21
23
|
}
|
|
22
24
|
/** What the hook already did in one run. */
|
|
23
25
|
export interface RunState {
|
|
@@ -8,6 +8,7 @@ import { join } from 'node:path';
|
|
|
8
8
|
import { HOOK_FAMILIES } from '../handoff/hook.js';
|
|
9
9
|
import { firstPrompt } from '../handoff/messages.js';
|
|
10
10
|
import { aliasArgs } from './config.js';
|
|
11
|
+
import { UserError } from './errors.js';
|
|
11
12
|
import { finishBrief } from './handoff-brief.js';
|
|
12
13
|
import { briefPath, chainDir, ensureChainDir, FILES, HANDOFF_ENV, newId, readJsonFile, writeJsonFile, } from './handoff-chain.js';
|
|
13
14
|
import { runHost, sidebyBinProblem, spawnHost } from './launch.js';
|
|
@@ -232,6 +233,7 @@ opts = {}) {
|
|
|
232
233
|
prepareAt: settings.prepareAt,
|
|
233
234
|
threshold: settings.threshold,
|
|
234
235
|
...(elig.agentBrief === false ? { agentBrief: false } : {}),
|
|
236
|
+
acceptsTo: true,
|
|
235
237
|
};
|
|
236
238
|
await writeJsonFile(join(dir, FILES.plan), plan);
|
|
237
239
|
}
|
|
@@ -347,6 +349,11 @@ export async function readyDecision(rt, env, to) {
|
|
|
347
349
|
const ref = env.SIDEBY_ACCOUNT;
|
|
348
350
|
if (!env[HANDOFF_ENV.run] || !dir || !ref)
|
|
349
351
|
return null;
|
|
352
|
+
if (to !== undefined) {
|
|
353
|
+
const plan = await readJsonFile(join(dir, FILES.plan));
|
|
354
|
+
if (plan && plan.runId === env[HANDOFF_ENV.run] && !plan.acceptsTo)
|
|
355
|
+
throw new UserError(`this session was started by an older sideby, which cannot hand over to a named account; exit it and start ${to} yourself (\`sideby run ${to}\`), or run \`sideby handoff ready\` without --to`, { code: 'parent-too-old' });
|
|
356
|
+
}
|
|
350
357
|
const account = await rt.resolve(ref);
|
|
351
358
|
const chain = await readJsonFile(join(dir, FILES.chain));
|
|
352
359
|
return decide(rt, account, chain?.hops.map((h) => h.ref) ?? [account.ref], to);
|
package/dist/src/handoff/hook.js
CHANGED
|
@@ -7,7 +7,7 @@ import { FILES, HANDOFF_ENV, readJsonFile, writeJsonFile, } from '../core/handof
|
|
|
7
7
|
import { claudeHookReader } from '../families/claude/handoff-hook.js';
|
|
8
8
|
import { codexHookReader } from '../families/codex/handoff-hook.js';
|
|
9
9
|
import { grokHookReader } from '../families/grok/handoff-hook.js';
|
|
10
|
-
import { endTurnMessage, prepareMessage, stopMessage, thresholdMessage } from './messages.js';
|
|
10
|
+
import { endTurnMessage, prepareMessage, sessionStartMessage, stopMessage, thresholdMessage, } from './messages.js';
|
|
11
11
|
import { field } from './reader.js';
|
|
12
12
|
export const HOOK_COMMAND = 'sideby handoff-hook';
|
|
13
13
|
const READERS = {
|
|
@@ -17,7 +17,7 @@ const READERS = {
|
|
|
17
17
|
};
|
|
18
18
|
/** Families whose hooks this entry understands; only they can start a Handoff. */
|
|
19
19
|
export const HOOK_FAMILIES = Object.keys(READERS);
|
|
20
|
-
const EVENTS = new Set(['PostToolUse', 'Stop', 'StopFailure']);
|
|
20
|
+
const EVENTS = new Set(['SessionStart', 'PostToolUse', 'Stop', 'StopFailure']);
|
|
21
21
|
async function readAll(stream) {
|
|
22
22
|
const chunks = [];
|
|
23
23
|
try {
|
|
@@ -29,8 +29,8 @@ async function readAll(stream) {
|
|
|
29
29
|
}
|
|
30
30
|
return Buffer.concat(chunks).toString('utf8');
|
|
31
31
|
}
|
|
32
|
-
const contextOutput = (text) => ({
|
|
33
|
-
hookSpecificOutput: { hookEventName
|
|
32
|
+
const contextOutput = (text, hookEventName = 'PostToolUse') => ({
|
|
33
|
+
hookSpecificOutput: { hookEventName, additionalContext: text },
|
|
34
34
|
});
|
|
35
35
|
const blockOutput = (reason) => ({ decision: 'block', reason });
|
|
36
36
|
async function mtimeMs(path) {
|
|
@@ -67,6 +67,14 @@ export async function decide(opts) {
|
|
|
67
67
|
return;
|
|
68
68
|
await writeJsonFile(readyFile, { runId, at: now.toISOString(), ...session, ...r });
|
|
69
69
|
};
|
|
70
|
+
// The session learns it may move the task on when the user asks; without this it tells the user to start the
|
|
71
|
+
// other account by hand.
|
|
72
|
+
if (event === 'SessionStart') {
|
|
73
|
+
const ref = env.SIDEBY_ACCOUNT;
|
|
74
|
+
return ref && usable
|
|
75
|
+
? { output: contextOutput(sessionStartMessage(ref, usable.brief), 'SessionStart') }
|
|
76
|
+
: {};
|
|
77
|
+
}
|
|
70
78
|
const threshold = usable?.threshold ?? 95;
|
|
71
79
|
const pressure = reader.pressure ? await reader.pressure(input, env, now) : null;
|
|
72
80
|
if (event === 'StopFailure') {
|
|
@@ -3,6 +3,8 @@ export declare function thresholdMessage(brief: string, pressure: number): strin
|
|
|
3
3
|
/** At the threshold when the session cannot write a Brief: sideby puts one together from its records. */
|
|
4
4
|
export declare function endTurnMessage(pressure: number): string;
|
|
5
5
|
export declare function stopMessage(brief: string): string;
|
|
6
|
+
/** At session start (Claude): this session may hand its task to another account when the user asks. */
|
|
7
|
+
export declare function sessionStartMessage(ref: string, brief: string): string;
|
|
6
8
|
declare const WHY: {
|
|
7
9
|
readonly threshold: 'its quota ran low';
|
|
8
10
|
readonly limit: 'its quota ran out';
|
|
@@ -21,6 +21,10 @@ export function endTurnMessage(pressure) {
|
|
|
21
21
|
export function stopMessage(brief) {
|
|
22
22
|
return `sideby: before you stop, update the handoff brief at ${brief} (${TEMPLATE}; ${RULES}), then end your turn.`;
|
|
23
23
|
}
|
|
24
|
+
/** At session start (Claude): this session may hand its task to another account when the user asks. */
|
|
25
|
+
export function sessionStartMessage(ref, brief) {
|
|
26
|
+
return `sideby: this session runs in ${ref} under sideby with Auto Handoff. If the user wants this task to go on in another account ("continue in cc008", "hand it back to cc008"), do not ask them to start that account: write a handoff brief to ${brief} (${TEMPLATE}; ${RULES}), run \`sideby handoff ready --to <account>\` (an account or short command), tell the user the account it prints, and end your turn. sideby then ends this session and starts that account in this terminal.`;
|
|
27
|
+
}
|
|
24
28
|
const WHY = {
|
|
25
29
|
threshold: 'its quota ran low',
|
|
26
30
|
limit: 'its quota ran out',
|
package/dist/src/types.d.ts
CHANGED
|
@@ -112,7 +112,7 @@ export interface FamilyDef {
|
|
|
112
112
|
handoff?: FamilyHandoff;
|
|
113
113
|
}
|
|
114
114
|
/** A Host hook event sideby's handoff hook listens to. */
|
|
115
|
-
export type HandoffHookEvent = 'PostToolUse' | 'Stop' | 'StopFailure';
|
|
115
|
+
export type HandoffHookEvent = 'SessionStart' | 'PostToolUse' | 'Stop' | 'StopFailure';
|
|
116
116
|
/** Whether one run may start a Handoff, or start as the next Account of one, and why not. */
|
|
117
117
|
export interface HandoffEligibility {
|
|
118
118
|
start: boolean;
|
package/package.json
CHANGED
package/skills/sideby/SKILL.md
CHANGED
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
---
|
|
2
2
|
name: sideby
|
|
3
|
-
description: Use when the user runs, or wants to run, several AI coding accounts (Claude Code, Codex, Grok Build, pi) side by side. Covers installing sideby and setting up a new account ("install sideby", "set up another Claude account", "add cc008", "配置一个 cc00x", "再加一个 Codex 账号"), explaining what accounts share and what stays separate ("what do my accounts share?", "这些账号共享了什么"), showing which account a session is ("show [cc001] in the status line", "加上账号标识"), seeing accounts, quota and usage, moving on when one hits its 5-hour or weekly limit, adding a short command (alias), and repairing drifted account directories (skills, hooks, rules or settings not shared, wrong symlinks, credential file permissions). Drives the `sideby` CLI with `--json`; the agent does every step except browser sign-in, filling in secrets and starting interactive sessions, which it hands to the user as one command.
|
|
3
|
+
description: Use when the user runs, or wants to run, several AI coding accounts (Claude Code, Codex, Grok Build, pi) side by side. Covers installing sideby and setting up a new account ("install sideby", "set up another Claude account", "add cc008", "配置一个 cc00x", "再加一个 Codex 账号"), explaining what accounts share and what stays separate ("what do my accounts share?", "这些账号共享了什么"), showing which account a session is ("show [cc001] in the status line", "加上账号标识"), seeing accounts, quota and usage, moving on when one hits its 5-hour or weekly limit, moving the current task to another account ("用 cc008 继续", "交回 cc008"), adding a short command (alias), and repairing drifted account directories (skills, hooks, rules or settings not shared, wrong symlinks, credential file permissions). Drives the `sideby` CLI with `--json`; the agent does every step except browser sign-in, filling in secrets and starting interactive sessions, which it hands to the user as one command (inside an Auto Handoff session, `sideby handoff ready --to` moves the task itself).
|
|
4
4
|
metadata:
|
|
5
|
-
version: "0.9.
|
|
5
|
+
version: "0.9.3"
|
|
6
6
|
requires:
|
|
7
7
|
bins: [sideby, node]
|
|
8
8
|
cliHelp: sideby --help
|
|
@@ -20,7 +20,7 @@ Do every step you can yourself. Only browser sign-in, secrets and interactive se
|
|
|
20
20
|
- **Never sign in for the user.** Give them `sideby login <ref>` as one line to run in their own terminal (Claude Code: `! sideby login <ref>`). OAuth needs their browser and their decision.
|
|
21
21
|
- **Never put a secret on the command line or in chat.** For API accounts, the user edits `proxy.env` themselves.
|
|
22
22
|
- **Never start a Host session from your shell.** `sideby run`, `sideby next` (without `--dry-run`) and `sideby login` open an interactive session; give the user the command instead.
|
|
23
|
-
- **Never switch, rotate or proxy accounts yourself.** Do not work around sideby by editing config, copying session files or moving credentials. `sideby next` only recommends. Moving a running task on its own is Auto Handoff, which the user turns on: use `sideby handoff enable` (exit 10, then their yes), never hand-edit `config.json`. Inside such a session
|
|
23
|
+
- **Never switch, rotate or proxy accounts yourself.** Do not work around sideby by editing config, copying session files or moving credentials. `sideby next` only recommends. Moving a running task on its own is Auto Handoff, which the user turns on: use `sideby handoff enable` (exit 10, then their yes), never hand-edit `config.json`. Inside such a session (the environment has `SIDEBY_HANDOFF_RUN`), when the user wants the task to go on in another account ("用 cc008 继续", "交回 cc008"), do not hand them a command to start it: update the brief, run `sideby handoff ready --to <account>`, tell them the account it prints, and end your turn; sideby starts that account in the same terminal.
|
|
24
24
|
- **Say what you change.** Read-only commands first. What the user asked for (the account they asked to create, its short command, the shell line that makes it work) you do, saying what you do. Changes they did not ask for (`doctor --fix` on other accounts, `quota setup`, `app install`) wait until they have seen the change and agreed.
|
|
25
25
|
- Do not edit Host config files (`settings.json`, `config.toml`, symlinks in account directories) by hand when a `sideby` command does the job.
|
|
26
26
|
|