@byokit/herdr 0.3.0 → 0.4.0
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/CHANGELOG.md +9 -0
- package/README.md +34 -4
- package/dist/accounts.d.ts +3 -2
- package/dist/accounts.js +72 -20
- package/dist/index.d.ts +1 -1
- package/dist/kit.d.ts +4 -2
- package/dist/kit.js +2 -1
- package/dist/types.d.ts +17 -1
- package/package.json +2 -2
package/CHANGELOG.md
CHANGED
|
@@ -2,6 +2,14 @@
|
|
|
2
2
|
|
|
3
3
|
## Unreleased
|
|
4
4
|
|
|
5
|
+
## 0.4.0 (2026-10-01)
|
|
6
|
+
|
|
7
|
+
- Dependency update: pins @byokit/reach 0.6.0.
|
|
8
|
+
|
|
9
|
+
- Add `move` with caller resume args, credential shedding, staging/replacement hooks and `MoveResult.paneId`.
|
|
10
|
+
- Add per-call `cli` env overlays for managed folder hook installation.
|
|
11
|
+
- Report surviving replacement panes when environment verification rollback fails; refuse folder moves for agents that ignore the folder variables.
|
|
12
|
+
|
|
5
13
|
## 0.3.0 (2026-10-01)
|
|
6
14
|
|
|
7
15
|
- Dependency update: pins @byokit/reach 0.5.0.
|
|
@@ -24,6 +32,7 @@
|
|
|
24
32
|
launcher such as a mise shim: shimmed or absent reads `installs-on-first-start`, sharing the
|
|
25
33
|
one probe path with `installedAgentKinds` (`resolveAgentBinary`, `isAutoInstallShim`).
|
|
26
34
|
|
|
35
|
+
|
|
27
36
|
## 0.2.0 (2026-09-30)
|
|
28
37
|
|
|
29
38
|
- `HerdrKit.agentStatus(kinds)` (B5): per-kind onboarding readiness — installed plus CLI
|
package/README.md
CHANGED
|
@@ -149,7 +149,7 @@ persistent grant store, and the phone page above.
|
|
|
149
149
|
|
|
150
150
|
| Export | What it does |
|
|
151
151
|
|---|---|
|
|
152
|
-
| `HerdrKit` (`@byokit/herdr`) | The host-side kit, in `adopt` or `own` mode: `start`/`stop`, `state`, `snapshot`/`onChange`, `startAgent`, `openSignInTab`, `moveToAccount`, `onStartAgent`, `prompt`, `sendKeys`, `wait`, `read`, `blocked`/`onBlocked`/`answer`, `closePane`/`closeTab`/`closeWorkspace`, `agentKinds`, `installedAgentKinds`, `agentStatus`, `agentInstallState`, `terminal`, `onEvent`, `statusWatchReady`, and the pass-throughs `call`, `subscribe` and `cli` |
|
|
152
|
+
| `HerdrKit` (`@byokit/herdr`) | The host-side kit, in `adopt` or `own` mode: `start`/`stop`, `state`, `snapshot`/`onChange`, `startAgent`, `openSignInTab`, `move`, `moveToAccount`, `onStartAgent`, `prompt`, `sendKeys`, `wait`, `read`, `blocked`/`onBlocked`/`answer`, `closePane`/`closeTab`/`closeWorkspace`, `agentKinds`, `installedAgentKinds`, `agentStatus`, `agentInstallState`, `terminal`, `onEvent`, `statusWatchReady`, and the pass-throughs `call`, `subscribe` and `cli` |
|
|
153
153
|
| `agentStatus`, `agentInstallState`, `agentProbePath`, `extraPathDirs`, `runStatusCommand`, `isAutoInstallShim`, `resolveAgentBinary` (`@byokit/herdr`) | Onboarding readiness: per-kind install + CLI sign-in without a Herdr connection (see below) |
|
|
154
154
|
| `HERDR_VERSION`, `HERDR_PROTOCOL` | The pinned Herdr release (`0.9.1`) and the protocol the kit speaks (`22`) |
|
|
155
155
|
| `words`, `agentWords`, `stateWords`, `WORDS` | Plain sentences for agent statuses and kit states |
|
|
@@ -176,9 +176,10 @@ The host supplies account folders and shares conversation history as needed. The
|
|
|
176
176
|
credentials. To connect an account, open its CLI in a new tab and let the person complete the CLI's own login:
|
|
177
177
|
|
|
178
178
|
```ts
|
|
179
|
-
import
|
|
179
|
+
import { HerdrKit } from '@byokit/herdr';
|
|
180
|
+
const kit = new HerdrKit({ mode: 'adopt', bin: '/app/bin/herdr', socketPath: '/app/herdr.sock' });
|
|
181
|
+
await kit.start();
|
|
180
182
|
|
|
181
|
-
declare const kit: HerdrKit; // the host's started kit
|
|
182
183
|
const signIn = await kit.openSignInTab({
|
|
183
184
|
workspaceId: 'w1', kind: 'codex', cwd: '/home/me/project', env: { CODEX_HOME: '/app/accounts/work' },
|
|
184
185
|
});
|
|
@@ -189,13 +190,42 @@ const moved = await kit.moveToAccount({ paneId: 'w1:p2' }, {
|
|
|
189
190
|
if (moved.ok) console.log(moved.session); // new pane to follow
|
|
190
191
|
```
|
|
191
192
|
|
|
192
|
-
A move accepts Claude
|
|
193
|
+
A move accepts Claude for Claude folders and Codex for Codex folders. Pi ignores these folder variables and is refused. It verifies the new shell's effective
|
|
193
194
|
account folder, resumes the conversation there, waits for a ready session, then closes the old pane. A failed
|
|
194
195
|
start preserves the original; a failed source close rolls back the new pane. Failures return a plain `message`
|
|
195
196
|
and a `live` pane id for recovery, including when cleanup fails. Wait until a conversation is idle or done before
|
|
196
197
|
moving it. `StartAgent.env` applies to newly created placements; existing shells cannot receive a new env.
|
|
197
198
|
Tokens stay on the device and are never logged. Each provider's own terms apply to how you use your plan.
|
|
198
199
|
|
|
200
|
+
For managed-folder stores that supply resume arguments and credential shedding, use `move`:
|
|
201
|
+
|
|
202
|
+
```ts
|
|
203
|
+
import { HerdrKit } from '@byokit/herdr';
|
|
204
|
+
const kit = new HerdrKit({ mode: 'adopt', bin: '/app/bin/herdr', socketPath: '/app/herdr.sock' });
|
|
205
|
+
await kit.start();
|
|
206
|
+
|
|
207
|
+
const conversationId = 'published-conversation-id';
|
|
208
|
+
const staged = new Set<string>();
|
|
209
|
+
let activePane = 'w1:p2';
|
|
210
|
+
const moved = await kit.move({
|
|
211
|
+
paneId: 'w1:p2', kind: 'codex', args: ['resume', conversationId],
|
|
212
|
+
set: { CODEX_HOME: '/app/accounts/work' }, unset: ['OPENAI_API_KEY', 'CODEX_API_KEY'],
|
|
213
|
+
onStaged(paneId) { staged.add(paneId); },
|
|
214
|
+
onReplaced(paneId) { staged.delete(paneId); activePane = paneId; },
|
|
215
|
+
});
|
|
216
|
+
if (moved.ok) console.log(moved.paneId);
|
|
217
|
+
await kit.cli(['integration', 'install', 'codex'], { env: { CODEX_HOME: '/app/accounts/work' } });
|
|
218
|
+
```
|
|
219
|
+
|
|
220
|
+
`MoveResult` names the new pane as `paneId`; `moveToAccount` retains its `session` result as
|
|
221
|
+
`MoveToAccountResult`. Both share the same per-source lock. Staging runs before verification/start; a staging
|
|
222
|
+
exception rolls back. Replacement notification runs after closing the source and cannot undo the move.
|
|
223
|
+
`move` clears `unset` in the new shell, verifies the account folder and unset names' absence, and requires an interactive
|
|
224
|
+
agent publishing a conversation before closing the source. The pinned start API has no command-prefix/env
|
|
225
|
+
field, so this uses shell `unset` rather than `env -u`; shells that cannot clear a variable fail closed.
|
|
226
|
+
Only folder paths belong in `set`, never tokens. `cli` env overlays the kit's explicit env for one call;
|
|
227
|
+
it inherits no process variables. The default move step timeout is 60 seconds.
|
|
228
|
+
|
|
199
229
|
## Two ways in
|
|
200
230
|
|
|
201
231
|
- `adopt` talks to the socket path the app passes: the person's own Herdr, nothing spawned, nothing written.
|
package/dist/accounts.d.ts
CHANGED
|
@@ -1,9 +1,10 @@
|
|
|
1
1
|
import type { Call } from './agents.ts';
|
|
2
|
-
import type { AgentRef, MoveResult, MoveToAccount, OpenSignInTab, StartAgent } from './types.ts';
|
|
2
|
+
import type { AgentRef, Move, MoveResult, MoveToAccount, MoveToAccountResult, OpenSignInTab, StartAgent } from './types.ts';
|
|
3
3
|
export declare function createAccountPanes(ctx: {
|
|
4
4
|
call: Call;
|
|
5
5
|
startAgent(o: StartAgent): Promise<AgentRef>;
|
|
6
6
|
}): {
|
|
7
7
|
openSignInTab: (o: OpenSignInTab) => Promise<AgentRef>;
|
|
8
|
-
|
|
8
|
+
move: (o: Move) => Promise<MoveResult>;
|
|
9
|
+
moveToAccount: (target: AgentRef, o: MoveToAccount) => Promise<MoveToAccountResult>;
|
|
9
10
|
};
|
package/dist/accounts.js
CHANGED
|
@@ -17,11 +17,12 @@ export function createAccountPanes(ctx) {
|
|
|
17
17
|
}
|
|
18
18
|
// A shell rc can override placement env. Verify what the shell actually resolves, rather
|
|
19
19
|
// than pane.get's launch env. The variable name is fixed by the provider, never caller text.
|
|
20
|
-
async function checkEnv(paneId, variable, folder, timeout) {
|
|
20
|
+
async function checkEnv(paneId, variable, folder, timeout, absent = false) {
|
|
21
21
|
const marker = `BYOKIT_ACCOUNT_${randomBytes(8).toString('hex')}`;
|
|
22
22
|
const deadline = Date.now() + timeout;
|
|
23
|
+
const expansion = absent ? '${' + variable + '+x}' : '$' + variable;
|
|
23
24
|
try {
|
|
24
|
-
await call('pane.send_text', { pane_id: paneId, text: `echo ${marker}="
|
|
25
|
+
await call('pane.send_text', { pane_id: paneId, text: `echo ${marker}="${expansion}"\n` }, timeout);
|
|
25
26
|
for (;;) {
|
|
26
27
|
const result = await call('pane.read', { pane_id: paneId, source: 'recent_unwrapped', lines: 40,
|
|
27
28
|
format: 'text', strip_ansi: true }, Math.max(1, deadline - Date.now()));
|
|
@@ -38,6 +39,28 @@ export function createAccountPanes(ctx) {
|
|
|
38
39
|
return false;
|
|
39
40
|
}
|
|
40
41
|
}
|
|
42
|
+
// agent.start has no env/unset/command field in the pinned protocol. Clear credentials in
|
|
43
|
+
// the shell that launches it, then verify absence (never echo credential values).
|
|
44
|
+
async function prepareEnv(paneId, set, unset, variable, timeout) {
|
|
45
|
+
const entries = Object.entries(set);
|
|
46
|
+
if ([...entries.map(([key]) => key), ...unset].some((key) => !/^[A-Za-z_][A-Za-z0-9_]*$/.test(key))
|
|
47
|
+
|| entries.some(([, value]) => typeof value !== 'string' || /[\r\n\0]/.test(value))
|
|
48
|
+
|| unset.some((key) => key in set))
|
|
49
|
+
return false;
|
|
50
|
+
try {
|
|
51
|
+
if (unset.length > 0)
|
|
52
|
+
await call('pane.send_text', { pane_id: paneId, text: `unset ${unset.join(' ')}\n` }, timeout);
|
|
53
|
+
if (!await checkEnv(paneId, variable, set[variable], timeout))
|
|
54
|
+
return false;
|
|
55
|
+
for (const key of unset)
|
|
56
|
+
if (!await checkEnv(paneId, key, '', timeout, true))
|
|
57
|
+
return false;
|
|
58
|
+
return true;
|
|
59
|
+
}
|
|
60
|
+
catch {
|
|
61
|
+
return false;
|
|
62
|
+
}
|
|
63
|
+
}
|
|
41
64
|
async function openSignInTab(o) {
|
|
42
65
|
const { workspaceId, label, ...start } = o;
|
|
43
66
|
try {
|
|
@@ -49,7 +72,7 @@ export function createAccountPanes(ctx) {
|
|
|
49
72
|
throw Object.assign(new Error(words('agent.notReady')), { code: 'sign_in_failed' });
|
|
50
73
|
}
|
|
51
74
|
}
|
|
52
|
-
async function
|
|
75
|
+
async function perform(target, o, request) {
|
|
53
76
|
const failed = (code, live = target.paneId) => ({ ok: false, code, message: words(`move.${code}`), live });
|
|
54
77
|
if (moving.has(target.paneId))
|
|
55
78
|
return failed('busy');
|
|
@@ -69,17 +92,17 @@ export function createAccountPanes(ctx) {
|
|
|
69
92
|
if (!['idle', 'done'].includes(agent.agent_status))
|
|
70
93
|
return failed('busy');
|
|
71
94
|
const kind = agent.agent;
|
|
72
|
-
if (!['claude', 'codex'].includes(o.provider) ||
|
|
73
|
-
||
|
|
95
|
+
if (!['claude', 'codex'].includes(o.provider) || kind !== o.provider
|
|
96
|
+
|| (request !== undefined && request.kind !== kind)
|
|
97
|
+
|| session.agent !== kind || session.kind !== 'id')
|
|
74
98
|
return failed('unsupported');
|
|
75
|
-
const args = kind === '
|
|
76
|
-
: kind === '
|
|
77
|
-
|
|
78
|
-
if (args === undefined)
|
|
99
|
+
const args = request?.args ?? (kind === 'claude' && session.kind === 'id' ? ['--resume', session.value]
|
|
100
|
+
: kind === 'codex' && session.kind === 'id' ? ['resume', session.value] : undefined);
|
|
101
|
+
if (args === undefined || !Array.isArray(args) || args.length === 0 || args.some((a) => typeof a !== 'string' || /[\r\n\0]/.test(a)))
|
|
79
102
|
return failed('unsupported');
|
|
80
103
|
if (!o.folder || /[\r\n\0]/.test(o.folder))
|
|
81
104
|
return failed('env_mismatch');
|
|
82
|
-
const timeout = o.timeoutMs ??
|
|
105
|
+
const timeout = o.timeoutMs ?? 60_000;
|
|
83
106
|
if (!Number.isFinite(timeout) || timeout <= 0)
|
|
84
107
|
return failed('start_failed');
|
|
85
108
|
const variable = o.provider === 'claude' ? 'CLAUDE_CONFIG_DIR' : 'CODEX_HOME';
|
|
@@ -96,21 +119,37 @@ export function createAccountPanes(ctx) {
|
|
|
96
119
|
catch {
|
|
97
120
|
return failed('start_failed');
|
|
98
121
|
}
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
122
|
+
const rollback = async (code) => failed(code, await close(paneId) ? target.paneId : paneId);
|
|
123
|
+
try {
|
|
124
|
+
request?.onStaged?.(paneId);
|
|
125
|
+
}
|
|
126
|
+
catch {
|
|
127
|
+
return rollback('start_failed');
|
|
128
|
+
}
|
|
129
|
+
if (request !== undefined && !await prepareEnv(paneId, request.set, request.unset ?? [], variable, timeout)) {
|
|
130
|
+
return rollback('env_mismatch');
|
|
131
|
+
}
|
|
132
|
+
if (request === undefined && !await checkEnv(paneId, variable, o.folder, timeout)) {
|
|
133
|
+
return rollback('env_mismatch');
|
|
102
134
|
}
|
|
103
135
|
try {
|
|
104
136
|
// Unique names avoid colliding with the still-live source agent.
|
|
105
137
|
await ctx.startAgent({ kind, cwd: agent.foreground_cwd ?? agent.cwd ?? '.',
|
|
106
138
|
name: `move-${randomBytes(8).toString('hex')}`, place: { pane: paneId }, args, timeoutMs: timeout });
|
|
107
139
|
await call('agent.wait', { target: paneId, until: ['idle', 'done'], timeout_ms: timeout }, timeout + 5000);
|
|
108
|
-
const
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
140
|
+
const deadline = Date.now() + timeout;
|
|
141
|
+
for (;;) {
|
|
142
|
+
const ready = (await call('agent.get', { target: paneId }, Math.max(1, deadline - Date.now())))?.agent;
|
|
143
|
+
if (ready && ready.launch_pending !== true && ['idle', 'done'].includes(ready.agent_status)
|
|
144
|
+
&& (request === undefined || ready.interactive_ready === true)
|
|
145
|
+
&& ready.agent === kind && ready.agent_session?.agent === kind
|
|
146
|
+
&& ready.agent_session?.kind === session.kind && typeof ready.agent_session?.value === 'string'
|
|
147
|
+
&& ready.agent_session.value.length > 0)
|
|
148
|
+
break;
|
|
149
|
+
if (Date.now() >= deadline)
|
|
150
|
+
throw new Error('not ready');
|
|
151
|
+
await sleep(Math.min(100, Math.max(1, deadline - Date.now())));
|
|
152
|
+
}
|
|
114
153
|
}
|
|
115
154
|
catch {
|
|
116
155
|
const cleaned = await close(paneId);
|
|
@@ -120,11 +159,24 @@ export function createAccountPanes(ctx) {
|
|
|
120
159
|
const cleaned = await close(paneId);
|
|
121
160
|
return failed('close_failed', cleaned ? target.paneId : paneId);
|
|
122
161
|
}
|
|
162
|
+
// The source is closed: a notification failure cannot undo a successful move.
|
|
163
|
+
try {
|
|
164
|
+
request?.onReplaced?.(paneId);
|
|
165
|
+
}
|
|
166
|
+
catch { /* notification only */ }
|
|
123
167
|
return { ok: true, session: paneId };
|
|
124
168
|
}
|
|
125
169
|
finally {
|
|
126
170
|
moving.delete(target.paneId);
|
|
127
171
|
}
|
|
128
172
|
}
|
|
129
|
-
|
|
173
|
+
async function move(o) {
|
|
174
|
+
const variable = o.kind === 'claude' ? 'CLAUDE_CONFIG_DIR' : 'CODEX_HOME';
|
|
175
|
+
const result = await perform({ paneId: o.paneId }, {
|
|
176
|
+
provider: o.kind === 'claude' ? 'claude' : 'codex', folder: o.set[variable] ?? '',
|
|
177
|
+
env: o.set, timeoutMs: o.timeoutMs,
|
|
178
|
+
}, o);
|
|
179
|
+
return result.ok ? { ok: true, paneId: result.session } : result;
|
|
180
|
+
}
|
|
181
|
+
return { openSignInTab, move, moveToAccount: (target, o) => perform(target, o) };
|
|
130
182
|
}
|
package/dist/index.d.ts
CHANGED
|
@@ -2,4 +2,4 @@ export { HERDR_VERSION, HERDR_PROTOCOL } from './constants.ts';
|
|
|
2
2
|
export { HerdrKit } from './kit.ts';
|
|
3
3
|
export { agentWords, stateWords, words, WORDS, type WordKey } from './words.ts';
|
|
4
4
|
export { agentProbePath, extraPathDirs, runStatusCommand, agentInstallState, isAutoInstallShim, resolveAgentBinary, classifyStartFailure } from './agents.ts';
|
|
5
|
-
export type { AgentCliSignIn, AgentInstallProbe, AgentInstallState, AgentLaunchFailureReason, AgentReadiness, AgentStartEvent, AgentStatusOptions, AgentStatusRunner, AgentRef, AgentStatus, BlockedAgent, HerdrEvent, HerdrEventName, HerdrEventOf, HerdrKitOptions, HerdrMethod, HerdrMethods, HerdrParams, HerdrProtocolRange, HerdrResult, HerdrSnapshot, HerdrState, HerdrSubscription, HerdrSubscribeStop, HerdrTransport, MoveToAccount, MoveResult, OpenSignInTab, PromptReceipt, StartAgent, TerminalSession, } from './types.ts';
|
|
5
|
+
export type { AgentCliSignIn, AgentInstallProbe, AgentInstallState, AgentLaunchFailureReason, AgentReadiness, AgentStartEvent, AgentStatusOptions, AgentStatusRunner, AgentRef, AgentStatus, BlockedAgent, HerdrEvent, HerdrEventName, HerdrEventOf, HerdrKitOptions, HerdrMethod, HerdrMethods, HerdrParams, HerdrProtocolRange, HerdrResult, HerdrSnapshot, HerdrState, HerdrSubscription, HerdrSubscribeStop, HerdrTransport, Move, MoveToAccount, MoveToAccountResult, MoveResult, OpenSignInTab, PromptReceipt, StartAgent, TerminalSession, } from './types.ts';
|
package/dist/kit.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { AgentReadiness, AgentStartEvent, AgentStatusOptions, AgentRef, AgentStatus, BlockedAgent, HerdrEvent, HerdrEventName, HerdrEventOf, HerdrKitOptions, HerdrMethod, HerdrParams, HerdrResult, HerdrSnapshot, HerdrState, HerdrSubscription, HerdrSubscribeStop, PromptReceipt, StartAgent, TerminalSession, MoveToAccount, MoveResult, OpenSignInTab } from './types.ts';
|
|
1
|
+
import type { AgentReadiness, AgentStartEvent, AgentStatusOptions, AgentRef, AgentStatus, BlockedAgent, HerdrEvent, HerdrEventName, HerdrEventOf, HerdrKitOptions, HerdrMethod, HerdrParams, HerdrResult, HerdrSnapshot, HerdrState, HerdrSubscription, HerdrSubscribeStop, PromptReceipt, StartAgent, TerminalSession, Move, MoveToAccount, MoveToAccountResult, MoveResult, OpenSignInTab } from './types.ts';
|
|
2
2
|
export declare class HerdrKit {
|
|
3
3
|
private readonly supervisor;
|
|
4
4
|
private transport?;
|
|
@@ -39,6 +39,7 @@ export declare class HerdrKit {
|
|
|
39
39
|
subscribe<E extends HerdrEventName>(subs: HerdrSubscription<E>[], on: (e: HerdrEventOf<E>) => void, onError?: (code: string, message: string) => void): HerdrSubscribeStop;
|
|
40
40
|
cli(args: string[], o?: {
|
|
41
41
|
timeoutMs?: number;
|
|
42
|
+
env?: Record<string, string>;
|
|
42
43
|
}): Promise<{
|
|
43
44
|
stdout: string;
|
|
44
45
|
stderr: string;
|
|
@@ -68,7 +69,8 @@ export declare class HerdrKit {
|
|
|
68
69
|
*/
|
|
69
70
|
statusWatchReady(): Promise<void>;
|
|
70
71
|
openSignInTab(o: OpenSignInTab): Promise<AgentRef>;
|
|
71
|
-
|
|
72
|
+
move(o: Move): Promise<MoveResult>;
|
|
73
|
+
moveToAccount(target: AgentRef, o: MoveToAccount): Promise<MoveToAccountResult>;
|
|
72
74
|
startAgent(o: StartAgent): Promise<AgentRef>;
|
|
73
75
|
onStartAgent(fn: (e: AgentStartEvent) => void): () => void;
|
|
74
76
|
prompt(target: AgentRef, text: string, o?: {
|
package/dist/kit.js
CHANGED
|
@@ -427,7 +427,7 @@ export class HerdrKit {
|
|
|
427
427
|
throw new Error('herdr: not connected');
|
|
428
428
|
return this.transport.subscribe(subs, on, onError ?? (() => { }));
|
|
429
429
|
}
|
|
430
|
-
cli(args, o) { return runCli(this.o.bin, this.supervisor.env(), args, o?.timeoutMs); }
|
|
430
|
+
cli(args, o) { return runCli(this.o.bin, { ...this.supervisor.env(), ...o?.env }, args, o?.timeoutMs); }
|
|
431
431
|
terminal(paneId, o) { return openTerminal(this.o.bin, this.supervisor.env(), paneId, o); }
|
|
432
432
|
snapshot() { return structuredClone(this.tree); }
|
|
433
433
|
onChange(fn) { this.listeners.add(fn); return () => { this.listeners.delete(fn); }; }
|
|
@@ -447,6 +447,7 @@ export class HerdrKit {
|
|
|
447
447
|
*/
|
|
448
448
|
statusWatchReady() { return this.statusReadyPromise; }
|
|
449
449
|
openSignInTab(o) { return this.accountPanes.openSignInTab(o); }
|
|
450
|
+
move(o) { return this.accountPanes.move(o); }
|
|
450
451
|
moveToAccount(target, o) { return this.accountPanes.moveToAccount(target, o); }
|
|
451
452
|
startAgent(o) { return this.agents.startAgent(o); }
|
|
452
453
|
// App-wide start lifecycle without polling: every startAgent's installing/ready/launchFailed
|
package/dist/types.d.ts
CHANGED
|
@@ -132,7 +132,7 @@ export type MoveToAccount = {
|
|
|
132
132
|
direction?: 'right' | 'down';
|
|
133
133
|
timeoutMs?: number;
|
|
134
134
|
};
|
|
135
|
-
export type
|
|
135
|
+
export type MoveToAccountResult = {
|
|
136
136
|
ok: true;
|
|
137
137
|
session: string;
|
|
138
138
|
} | {
|
|
@@ -141,6 +141,22 @@ export type MoveResult = {
|
|
|
141
141
|
message: string;
|
|
142
142
|
live?: string;
|
|
143
143
|
};
|
|
144
|
+
export type Move = {
|
|
145
|
+
paneId: string;
|
|
146
|
+
kind: string;
|
|
147
|
+
args: string[];
|
|
148
|
+
set: Record<string, string>;
|
|
149
|
+
unset?: string[];
|
|
150
|
+
onStaged?(newPaneId: string): void;
|
|
151
|
+
onReplaced?(newPaneId: string): void;
|
|
152
|
+
timeoutMs?: number;
|
|
153
|
+
};
|
|
154
|
+
export type MoveResult = {
|
|
155
|
+
ok: true;
|
|
156
|
+
paneId: string;
|
|
157
|
+
} | Extract<MoveToAccountResult, {
|
|
158
|
+
ok: false;
|
|
159
|
+
}>;
|
|
144
160
|
export type PromptReceipt = {
|
|
145
161
|
paneId: string;
|
|
146
162
|
terminalId: string;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@byokit/herdr",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.4.0",
|
|
4
4
|
"description": "Drive the Herdr on this computer — workspaces, tabs, panes, agents and blocked-approval answers — from an app, or hand it to a phone over @byokit/link.",
|
|
5
5
|
"license": "Apache-2.0",
|
|
6
6
|
"type": "module",
|
|
@@ -54,7 +54,7 @@
|
|
|
54
54
|
"dependencies": {
|
|
55
55
|
"@byokit/link": "0.7.0",
|
|
56
56
|
"@byokit/relay": "0.5.0",
|
|
57
|
-
"@byokit/reach": "0.
|
|
57
|
+
"@byokit/reach": "0.6.0",
|
|
58
58
|
"@byokit/seal": "0.2.0",
|
|
59
59
|
"ws": "8.21.3"
|
|
60
60
|
},
|