@shardflux/cli 0.19.1 → 0.22.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 +278 -1
- package/README.md +225 -73
- package/dist/account-args.js +7 -2
- package/dist/account-commands.js +56 -106
- package/dist/account-pool.d.ts +20 -15
- package/dist/account-pool.js +51 -97
- package/dist/account-scope.d.ts +65 -0
- package/dist/account-scope.js +246 -0
- package/dist/acp-login.d.ts +4 -3
- package/dist/acp-login.js +7 -5
- package/dist/acp-models.js +20 -15
- package/dist/acp.js +66 -13
- package/dist/agent-commands.d.ts +4 -1
- package/dist/agent-commands.js +86 -32
- package/dist/agent-config-files.d.ts +19 -0
- package/dist/agent-config-files.js +70 -1
- package/dist/agent-config-return.d.ts +194 -0
- package/dist/agent-config-return.js +724 -0
- package/dist/agent-config-sync.d.ts +10 -2
- package/dist/agent-config-sync.js +45 -51
- package/dist/agent-credentials.js +7 -3
- package/dist/agent-repository.d.ts +16 -3
- package/dist/agent-repository.js +149 -74
- package/dist/agent-setup.d.ts +14 -3
- package/dist/agent-setup.js +78 -36
- package/dist/agent-target-commands.js +24 -13
- package/dist/args.d.ts +1 -1
- package/dist/args.js +104 -55
- package/dist/bin.js +5 -1
- package/dist/browser.d.ts +13 -2
- package/dist/browser.js +30 -14
- package/dist/claude-cloud-login.d.ts +24 -2
- package/dist/claude-cloud-login.js +151 -11
- package/dist/cli-proxy-forward.d.ts +2 -0
- package/dist/cli-proxy-forward.js +9 -2
- package/dist/cli-proxy-hub.d.ts +69 -25
- package/dist/cli-proxy-hub.js +231 -54
- package/dist/cli-proxy.d.ts +70 -1
- package/dist/cli-proxy.js +298 -32
- package/dist/client-settings.d.ts +39 -0
- package/dist/client-settings.js +91 -0
- package/dist/codex-cloud.d.ts +5 -0
- package/dist/codex-cloud.js +88 -17
- package/dist/command-center-actions.js +5 -1
- package/dist/commands.js +171 -22
- package/dist/conversation-commands.d.ts +5 -0
- package/dist/conversation-commands.js +8 -5
- package/dist/conversation-terminal.d.ts +10 -2
- package/dist/conversation-terminal.js +81 -15
- package/dist/conversations.d.ts +77 -1
- package/dist/conversations.js +257 -23
- package/dist/device-bridge.d.ts +1 -1
- package/dist/device-bridge.js +6 -4
- package/dist/device-helper.js +52 -4
- package/dist/errors.d.ts +34 -1
- package/dist/errors.js +56 -5
- package/dist/filesystem-commands.d.ts +22 -3
- package/dist/filesystem-commands.js +132 -16
- package/dist/format.d.ts +2 -1
- package/dist/format.js +10 -1
- package/dist/handlers.js +4 -1
- package/dist/initial-prompt.d.ts +8 -0
- package/dist/initial-prompt.js +43 -1
- package/dist/large-media.d.ts +14 -0
- package/dist/large-media.js +100 -0
- package/dist/linux-terminal.d.ts +5 -3
- package/dist/linux-terminal.js +6 -20
- package/dist/local-sessions.d.ts +26 -2
- package/dist/local-sessions.js +113 -24
- package/dist/machine-setup.d.ts +190 -0
- package/dist/machine-setup.js +849 -0
- package/dist/machine-status.d.ts +67 -0
- package/dist/machine-status.js +140 -0
- package/dist/main.js +23 -13
- package/dist/move-worktrees-restore.py +144 -0
- package/dist/move-worktrees.d.ts +63 -0
- package/dist/move-worktrees.js +201 -0
- package/dist/move.d.ts +10 -1
- package/dist/move.js +116 -16
- package/dist/onboarding.d.ts +11 -7
- package/dist/onboarding.js +59 -27
- package/dist/prepared-repository.d.ts +202 -0
- package/dist/prepared-repository.js +860 -0
- package/dist/prepared-repository.py +1306 -0
- package/dist/project-preparation.d.ts +48 -0
- package/dist/project-preparation.js +304 -0
- package/dist/project-sync-manifest.d.ts +4 -0
- package/dist/project-sync-manifest.js +5 -1
- package/dist/project-sync-transfer.js +1 -1
- package/dist/project-sync.d.ts +19 -4
- package/dist/project-sync.js +31 -8
- package/dist/project-template-setup.d.ts +33 -1
- package/dist/project-template-setup.js +59 -2
- package/dist/secret-ask.d.ts +72 -0
- package/dist/secret-ask.js +351 -0
- package/dist/seed-phases.d.ts +13 -3
- package/dist/seed-phases.js +21 -3
- package/dist/setup-cache.d.ts +7 -0
- package/dist/setup-cache.js +32 -0
- package/dist/t3-launch.js +1 -4
- package/dist/t3-mode.d.ts +8 -2
- package/dist/t3-mode.js +19 -4
- package/dist/t3-phone.d.ts +4 -2
- package/dist/t3-phone.js +12 -4
- package/dist/terminal-apps.d.ts +157 -0
- package/dist/terminal-apps.js +561 -0
- package/dist/terminal-onboarding.d.ts +2 -0
- package/dist/terminal-onboarding.js +11 -1
- package/dist/this-computer.d.ts +11 -0
- package/dist/this-computer.js +36 -0
- package/dist/thread-on-computer.js +4 -1
- package/dist/update.js +11 -3
- package/dist/worktree-twin.d.ts +10 -2
- package/dist/worktree-twin.js +27 -9
- package/package.json +5 -5
|
@@ -53,14 +53,22 @@ export declare function applyConfigFiles(cell: CellClient, home: string, files:
|
|
|
53
53
|
copied: string[];
|
|
54
54
|
removed: string[];
|
|
55
55
|
}>;
|
|
56
|
-
|
|
56
|
+
/**
|
|
57
|
+
* `memoryOnly` (0.20.0+): just the project memory, for an account whose saved machine carries the rest. A conversation
|
|
58
|
+
* VM gets this computer's memory for its project, under the VM project folder's name (Claude keys memory by path).
|
|
59
|
+
*/
|
|
60
|
+
export declare function syncAgentConfig(ctx: Ctx, ws: Workspace, opts?: {
|
|
61
|
+
memoryOnly?: boolean;
|
|
62
|
+
}): Promise<ConfigSyncResult>;
|
|
57
63
|
/**
|
|
58
64
|
* Copies the laptop's agent config into a new conversation's VM after its agent started (0.19.0+): the first prompt
|
|
59
65
|
* never waits for it. From an installed shard it runs as its own detached process (`shard agents config-sync`, its
|
|
60
66
|
* output in agent-config-sync.log of the config directory), so the command that started the conversation reports the
|
|
61
67
|
* start at once; without a runtime (tests, an embedding) it runs here and the returned promise settles when it ends.
|
|
62
68
|
*/
|
|
63
|
-
export declare function syncAgentConfigAfterStart(ctx: Ctx, ws: Workspace
|
|
69
|
+
export declare function syncAgentConfigAfterStart(ctx: Ctx, ws: Workspace, opts?: {
|
|
70
|
+
memoryOnly?: boolean;
|
|
71
|
+
}): Promise<void> | undefined;
|
|
64
72
|
/** Tunnels are owned by the attachment, and close even if the terminal fails or the user detaches. */
|
|
65
73
|
export declare function startAgentConfigTunnels(ctx: Ctx, ws: Workspace): Promise<{
|
|
66
74
|
stop(): Promise<void>;
|
|
@@ -7,7 +7,8 @@ import { parse, stringify } from 'smol-toml';
|
|
|
7
7
|
import { ShardfluxApiError, tarEnd, tarHeader, tarPadding } from '@shardflux/sdk';
|
|
8
8
|
import { AgentStateStore } from "./agent-state.js";
|
|
9
9
|
import { UsageError } from "./errors.js";
|
|
10
|
-
import { collectPlugins, collectUserFiles, object, readObject, readOptional, rewritePaths } from "./agent-config-files.js";
|
|
10
|
+
import { collectMemory, collectPlugins, collectUserFiles, object, readObject, readOptional, rewritePaths, vmMemoryPath } from "./agent-config-files.js";
|
|
11
|
+
import { localConversations } from "./conversations.js";
|
|
11
12
|
import { digest, prepareMcp } from "./agent-config-mcp.js";
|
|
12
13
|
import { configIssueLines } from "./agent-config-report.js";
|
|
13
14
|
const missing = (e) => e instanceof ShardfluxApiError && e.status === 404;
|
|
@@ -15,7 +16,8 @@ const parseFailure = (e) => e instanceof SyntaxError || (e instanceof Error && /
|
|
|
15
16
|
const markerPath = '.config/shardflux/agent-config.json';
|
|
16
17
|
const safePath = (path) => !path.split('/').some(p => !p || p === '.' || p === '..') &&
|
|
17
18
|
(/^(?:\.claude\/(?:settings\.json|CLAUDE\.md)|\.codex\/(?:config\.toml|AGENTS\.md))$/.test(path) ||
|
|
18
|
-
/^\.claude\/(?:skills|commands|agents|output-styles|plugins)\/.+/.test(path) || /^\.codex\/(?:prompts|skills)\/.+/.test(path)
|
|
19
|
+
/^\.claude\/(?:skills|commands|agents|output-styles|plugins)\/.+/.test(path) || /^\.codex\/(?:prompts|skills)\/.+/.test(path) ||
|
|
20
|
+
/^\.claude\/projects\/[^/]+\/memory\/.+/.test(path));
|
|
19
21
|
const key = (ctx, id) => `${ctx.apiUrl}:${id}`;
|
|
20
22
|
export function configManifests(ctx) {
|
|
21
23
|
const value = object(new AgentStateStore(ctx.store.dir).read().agent_config);
|
|
@@ -285,33 +287,51 @@ async function installPlugins(cell, plan, issues, signal) {
|
|
|
285
287
|
if (line.startsWith('failed '))
|
|
286
288
|
issues.push({ item: `plugin:${line.slice(7)}`, reason: 'could not be installed in the VM' });
|
|
287
289
|
}
|
|
288
|
-
|
|
290
|
+
/**
|
|
291
|
+
* `memoryOnly` (0.20.0+): just the project memory, for an account whose saved machine carries the rest. A conversation
|
|
292
|
+
* VM gets this computer's memory for its project, under the VM project folder's name (Claude keys memory by path).
|
|
293
|
+
*/
|
|
294
|
+
export async function syncAgentConfig(ctx, ws, opts = {}) {
|
|
289
295
|
const home = ctx.io.env.HOME || homedir();
|
|
290
296
|
const store = new AgentStateStore(ctx.store.dir);
|
|
291
297
|
const previous = configManifests(ctx)[key(ctx, ws.id)];
|
|
292
298
|
const issues = [];
|
|
293
|
-
const files = await collectUserFiles(home, issues);
|
|
294
|
-
const codexBytes = await readOptional(join(home, '.codex/config.toml'));
|
|
299
|
+
const files = opts.memoryOnly ? new Map() : await collectUserFiles(home, issues);
|
|
300
|
+
const codexBytes = opts.memoryOnly ? undefined : await readOptional(join(home, '.codex/config.toml'));
|
|
295
301
|
// One file that does not parse is skipped with a reason; it never stops the rest of the sync.
|
|
296
302
|
let claude;
|
|
297
|
-
|
|
298
|
-
|
|
299
|
-
|
|
300
|
-
|
|
301
|
-
|
|
302
|
-
|
|
303
|
-
|
|
303
|
+
if (!opts.memoryOnly) {
|
|
304
|
+
try {
|
|
305
|
+
claude = await readObject(join(home, '.claude.json'));
|
|
306
|
+
}
|
|
307
|
+
catch (error) {
|
|
308
|
+
if (!parseFailure(error))
|
|
309
|
+
throw error;
|
|
310
|
+
issues.push({ item: '.claude.json', reason: 'not valid JSON; its MCP servers were not copied' });
|
|
311
|
+
}
|
|
304
312
|
}
|
|
305
|
-
const plugins = await collectPlugins(home, issues);
|
|
313
|
+
const plugins = opts.memoryOnly ? { marketplaces: [], plugins: [] } : await collectPlugins(home, issues);
|
|
306
314
|
const hasPlugins = plugins.marketplaces.length > 0 || plugins.plugins.length > 0;
|
|
315
|
+
const records = Object.values(localConversations(ctx));
|
|
316
|
+
const conversation = records.find(r => r.conversation.id === ws.labels.shard_conversation) ?? records.find(r => r.conversation.workspace_id === ws.id);
|
|
317
|
+
const memory = conversation ? await collectMemory(home, conversation.folder, issues) : undefined;
|
|
307
318
|
const empty = { workspace_id: ws.id, workspace_key: ws.key, copied: [], removed: [], skipped: issues, mcp: [], synced_at: null };
|
|
308
|
-
if (!files.size && !codexBytes && !hasPlugins && !Object.keys(object(claude?.mcpServers)).length && !previous)
|
|
319
|
+
if (!files.size && !memory?.files.size && !codexBytes && !hasPlugins && !Object.keys(object(claude?.mcpServers)).length && !previous)
|
|
309
320
|
return empty;
|
|
310
321
|
const cell = ws.cell({ agentLabel: ctx.agentLabel, transitionTimeoutMs: ctx.wakeTimeoutMs });
|
|
311
|
-
|
|
312
|
-
const
|
|
322
|
+
// The VM home, and the project folder its Claude keys memory by (the main checkout of the conversation's worktree).
|
|
323
|
+
const run = await cell.exec.run(['sh', '-c', 'printf "%s\\n" "$HOME"; [ -n "$1" ] && git -C "$1" rev-parse --path-format=absolute --git-common-dir 2>/dev/null || true', 'shard-config', conversation?.conversation.worktree_path ?? ''], { signal: ctx.signal, timeoutMs: 5000, maxOutputBytes: 4096 });
|
|
324
|
+
const [remoteHome = '', common = ''] = run.stdout.trim().split('\n').map(line => line.trim());
|
|
313
325
|
if (run.exitCode !== 0 || !/^\/(?:[a-zA-Z0-9._-]+\/)*[a-zA-Z0-9._-]+$/.test(remoteHome) || remoteHome.split('/').some(p => p === '..' || p === '.'))
|
|
314
326
|
throw new Error('agent config could not resolve the VM user home');
|
|
327
|
+
if (memory && conversation) {
|
|
328
|
+
const vmRoot = common.endsWith('/.git') ? common.slice(0, -5) : conversation.conversation.worktree_path;
|
|
329
|
+
for (const [path, file] of memory.files) {
|
|
330
|
+
const dest = vmMemoryPath(path, memory.root, vmRoot);
|
|
331
|
+
if (dest)
|
|
332
|
+
files.set(dest, file);
|
|
333
|
+
}
|
|
334
|
+
}
|
|
315
335
|
// Claude settings stay the user's. sf-agent hooks are in /etc/claude-code/managed-settings.json.
|
|
316
336
|
const secrets = { ...previous?.secrets, ...object(object(store.read().agent_config_secrets)[key(ctx, ws.id)]) };
|
|
317
337
|
const commandCache = new Map();
|
|
@@ -432,8 +452,10 @@ export async function syncAgentConfig(ctx, ws) {
|
|
|
432
452
|
sync_state: 'synced', synced_at, files: applied.files, claude_mcp: Object.keys(claudeMcp), claude_mcp_owned: partial.claude_mcp_owned, secrets, skipped: issues, mcp, tunnels,
|
|
433
453
|
...(pluginsHash ? { plugins_hash: pluginsHash } : {}) };
|
|
434
454
|
manifest.remote_hash = digest(JSON.stringify({ files: applied.files, claude_mcp: claudeMcp, mcp, tunnels }));
|
|
435
|
-
|
|
436
|
-
|
|
455
|
+
// The marker names each file's hash (0.20.0+): the guest tells this copy's writes from the agent's own changes.
|
|
456
|
+
if (marker?.workspace_id !== ws.id || marker.manifest_hash !== manifest.remote_hash || !marker.files)
|
|
457
|
+
await cell.files.write(`${remoteHome}/${markerPath}`, JSON.stringify({ workspace_id: ws.id, manifest_hash: manifest.remote_hash,
|
|
458
|
+
files: Object.fromEntries(Object.entries(applied.files).map(([path, file]) => [path, file.hash])) }) + '\n', { createParents: true, mode: '0600' });
|
|
437
459
|
store.update(doc => { const all = object(doc.agent_config); all[key(ctx, ws.id)] = manifest; doc.agent_config = all; });
|
|
438
460
|
const result = { ...empty, copied: applied.copied, removed: applied.removed, skipped: issues, mcp, synced_at };
|
|
439
461
|
if (!ctx.json) {
|
|
@@ -451,13 +473,13 @@ export async function syncAgentConfig(ctx, ws) {
|
|
|
451
473
|
* output in agent-config-sync.log of the config directory), so the command that started the conversation reports the
|
|
452
474
|
* start at once; without a runtime (tests, an embedding) it runs here and the returned promise settles when it ends.
|
|
453
475
|
*/
|
|
454
|
-
export function syncAgentConfigAfterStart(ctx, ws) {
|
|
476
|
+
export function syncAgentConfigAfterStart(ctx, ws, opts = {}) {
|
|
455
477
|
if (ctx.runtime?.script) {
|
|
456
478
|
try {
|
|
457
479
|
mkdirSync(ctx.store.dir, { recursive: true, mode: 0o700 });
|
|
458
480
|
const log = openSync(join(ctx.store.dir, 'agent-config-sync.log'), 'a', 0o600);
|
|
459
481
|
try {
|
|
460
|
-
const child = spawn(ctx.runtime.node, [ctx.runtime.script, 'agents', 'config-sync', ws.id], {
|
|
482
|
+
const child = spawn(ctx.runtime.node, [ctx.runtime.script, 'agents', 'config-sync', ws.id, ...(opts.memoryOnly ? ['--memory-only'] : [])], {
|
|
461
483
|
detached: true, stdio: ['ignore', log, log],
|
|
462
484
|
env: { ...process.env, ...ctx.io.env, SHARDFLUX_CONFIG_DIR: ctx.store.dir, SHARDFLUX_API_URL: ctx.apiUrl, SHARDFLUX_NO_UPDATE_CHECK: '1' }
|
|
463
485
|
});
|
|
@@ -471,7 +493,7 @@ export function syncAgentConfigAfterStart(ctx, ws) {
|
|
|
471
493
|
}
|
|
472
494
|
catch { /* runs in this process below */ }
|
|
473
495
|
}
|
|
474
|
-
return syncAgentConfig(ctx, ws).then(() => undefined, (error) => {
|
|
496
|
+
return syncAgentConfig(ctx, ws, opts).then(() => undefined, (error) => {
|
|
475
497
|
ctx.io.stderr.write(`Agent config not copied to ${ws.key}: ${error instanceof Error ? error.message : String(error)}\n`);
|
|
476
498
|
});
|
|
477
499
|
}
|
|
@@ -501,41 +523,13 @@ export async function startAgentConfigTunnels(ctx, ws) {
|
|
|
501
523
|
}
|
|
502
524
|
export const AGENT_CONFIG_HANDLERS = {
|
|
503
525
|
/** The detached copy syncAgentConfigAfterStart starts; one line per run in agent-config-sync.log. */
|
|
504
|
-
async 'agents config-sync'(ctx,
|
|
526
|
+
async 'agents config-sync'(ctx, values, [id]) {
|
|
505
527
|
const ws = await ctx.cloud().workspaces.get(id);
|
|
506
528
|
const started = Date.now();
|
|
507
|
-
const result = await syncAgentConfig({ ...ctx, json: true }, ws);
|
|
529
|
+
const result = await syncAgentConfig({ ...ctx, json: true }, ws, { memoryOnly: values['memory-only'] === true });
|
|
508
530
|
ctx.io.stderr.write(`${new Date().toISOString()} ${ws.key}: ${result.copied.length} copied, ${result.removed.length} removed, ${result.skipped.length} skipped in ${Date.now() - started} ms\n`);
|
|
509
531
|
for (const line of configIssueLines(result.skipped))
|
|
510
532
|
ctx.io.stderr.write(` ${line}\n`);
|
|
511
533
|
return 0;
|
|
512
534
|
},
|
|
513
|
-
'agents config status'(ctx, values) {
|
|
514
|
-
const workspace = typeof values.workspace === 'string' ? values.workspace : undefined;
|
|
515
|
-
const manifests = Object.values(configManifests(ctx)).filter(m => m.api_url === ctx.apiUrl && (!workspace || m.workspace_id === workspace || m.workspace_key === workspace));
|
|
516
|
-
const report = { observation: 'last sync on this machine', workspaces: manifests };
|
|
517
|
-
ctx.io.stdout.write(ctx.json ? JSON.stringify(report, null, 2) + '\n' : manifests.length ? manifests.map(m => `${m.workspace_key}: ${Object.keys(m.files).length} files; ${m.sync_state === 'synced' ? `last sync ${m.synced_at}` : 'sync interrupted; run config sync again'}\n` +
|
|
518
|
-
m.skipped.map(s => ` skipped ${s.item}: ${s.reason}\n`).join('') +
|
|
519
|
-
m.mcp.map(s => ` MCP ${s.app}/${s.name}: ${s.status}${s.reason ? ` (${s.reason})` : ''}\n`).join('')).join('') : 'No agent config has been synced on this machine.\n');
|
|
520
|
-
return Promise.resolve(0);
|
|
521
|
-
},
|
|
522
|
-
async 'agents config sync'(ctx, values) {
|
|
523
|
-
const workspace = typeof values.workspace === 'string' ? values.workspace : undefined;
|
|
524
|
-
const cloud = ctx.cloud();
|
|
525
|
-
const targets = [];
|
|
526
|
-
if (workspace) {
|
|
527
|
-
const ws = await cloud.workspaces.findByKey(workspace, { includeDeleted: false, signal: ctx.signal });
|
|
528
|
-
targets.push(ws ?? await cloud.workspaces.get(workspace));
|
|
529
|
-
}
|
|
530
|
-
else
|
|
531
|
-
for await (const ws of cloud.workspaces.listAll()) {
|
|
532
|
-
if (ws.labels.shard_project && ws.mode === 'processful')
|
|
533
|
-
targets.push(ws);
|
|
534
|
-
}
|
|
535
|
-
const results = [];
|
|
536
|
-
for (const ws of targets)
|
|
537
|
-
results.push(await syncAgentConfig(ctx, ws));
|
|
538
|
-
ctx.io.stdout.write(ctx.json ? JSON.stringify({ workspaces: results }, null, 2) + '\n' : results.length ? results.map(r => r.synced_at === null ? `${r.workspace_key}: no local agent config found\n` : `${r.workspace_key}: ${r.copied.length} files copied, ${r.removed.length} removed\n`).join('') : 'No agent workspaces found.\n');
|
|
539
|
-
return 0;
|
|
540
|
-
},
|
|
541
535
|
};
|
|
@@ -3,7 +3,8 @@ import { homedir } from 'node:os';
|
|
|
3
3
|
import { join } from 'node:path';
|
|
4
4
|
import { json } from "./format.js";
|
|
5
5
|
import { UsageError } from "./errors.js";
|
|
6
|
-
import {
|
|
6
|
+
import { claudeTerminal, cloudClaudeLogin, loginClaudeInWorkspace } from "./claude-cloud-login.js";
|
|
7
|
+
import { askTimeout } from "./secret-ask.js";
|
|
7
8
|
import { resolveWorkspace } from "./commands.js";
|
|
8
9
|
import { projectIdentity, projectLabels } from "./project-identity.js";
|
|
9
10
|
async function optionalFile(file) {
|
|
@@ -74,7 +75,10 @@ export const AGENT_CREDENTIAL_HANDLERS = {
|
|
|
74
75
|
output(ctx, existing);
|
|
75
76
|
return 0;
|
|
76
77
|
}
|
|
77
|
-
|
|
78
|
+
// In a coding agent's shell, with --json, without a terminal or with --ask (0.20.1+): the claude.ai sign-in and a
|
|
79
|
+
// page for its code open in the browser. On a terminal the sign-in attaches to it.
|
|
80
|
+
const headless = values.ask === true || !claudeTerminal(ctx);
|
|
81
|
+
const timeoutMs = askTimeout(values);
|
|
78
82
|
const project = projectIdentity('./');
|
|
79
83
|
let ws;
|
|
80
84
|
if (typeof values.workspace === 'string')
|
|
@@ -85,7 +89,7 @@ export const AGENT_CREDENTIAL_HANDLERS = {
|
|
|
85
89
|
const current = await cloud.workspaces.findByKey(key, { includeDeleted: false, signal: ctx.signal });
|
|
86
90
|
ws = await cloud.workspaces.open({ key, template: 'coding', labels: { ...current?.labels, ...projectLabels(project, 'main', 'claude') }, wait: { signal: ctx.signal, timeoutMs: ctx.wakeTimeoutMs } });
|
|
87
91
|
}
|
|
88
|
-
output(ctx, await loginClaudeInWorkspace(ctx, ws));
|
|
92
|
+
output(ctx, await loginClaudeInWorkspace(ctx, ws, headless ? { headless: { timeoutMs } } : {}));
|
|
89
93
|
return 0;
|
|
90
94
|
},
|
|
91
95
|
'agents credentials sync': async (ctx) => { output(ctx, await syncAgentCredentials(ctx.cloud(), { home: ctx.io.env.HOME ?? ctx.io.env.USERPROFILE, redact: (value) => ctx.addSecret(value) })); return 0; },
|
|
@@ -22,12 +22,21 @@ export declare function seedAgentRepository(ctx: Ctx, ws: Workspace, folder: str
|
|
|
22
22
|
populate?: boolean;
|
|
23
23
|
initialFiles?: readonly string[];
|
|
24
24
|
onInitialFiles?: () => void;
|
|
25
|
+
changes?: Promise<LocalChanges>;
|
|
26
|
+
background?: (started: Promise<unknown>) => void;
|
|
27
|
+
beforeHistory?: Promise<unknown>;
|
|
25
28
|
}): Promise<void>;
|
|
26
29
|
/**
|
|
27
30
|
* Above this (an estimate: the repository's packed and loose objects) the workspace fetches the history from origin as a
|
|
28
31
|
* blobless partial clone, and receives only the commits origin lacks (0.19.0+). Below it, one small bundle is faster.
|
|
29
32
|
*/
|
|
30
33
|
export declare const ORIGIN_FIRST_BYTES: number;
|
|
34
|
+
/**
|
|
35
|
+
* A Git step of the seed that writes the workspace repository's index, refs or config: run again, for up to ~5 s,
|
|
36
|
+
* while another Git process in the VM holds the lock (a conversation's agent starts as soon as its repository appears,
|
|
37
|
+
* and its own `git status` takes the index lock). Every step passed here is safe to repeat.
|
|
38
|
+
*/
|
|
39
|
+
export declare function runGitStep(cell: Pick<SyncCell, 'exec'>, argv: string[], options: Parameters<SyncCell['exec']['run']>[1] & object, attempts?: number): Promise<Awaited<ReturnType<SyncCell['exec']['run']>>>;
|
|
31
40
|
/** The repository's object store size, an upper bound of any one branch's history bundle. Reads sizes only. */
|
|
32
41
|
export declare function historyEstimate(folder: string, signal?: AbortSignal): Promise<number>;
|
|
33
42
|
export declare const FETCH_ORIGIN: string;
|
|
@@ -39,7 +48,10 @@ export declare const CHECKOUT_HEAD: string;
|
|
|
39
48
|
* from origin as a blobless partial clone (the workspace's own Git credentials), plus a bundle of the commits origin
|
|
40
49
|
* lacks. Without a reachable origin the whole bundle is streamed in chunks: no history size refuses (0.19.0+).
|
|
41
50
|
*/
|
|
42
|
-
export declare function importProjectHistory(cell: SyncCell, folder: string, root: string, head: string, branch: string, origin: string | null, signal?: AbortSignal, originFirst?: number, report?: (message: string) => void
|
|
51
|
+
export declare function importProjectHistory(cell: SyncCell, folder: string, root: string, head: string, branch: string, origin: string | null, signal?: AbortSignal, originFirst?: number, report?: (message: string) => void, configure?: {
|
|
52
|
+
settings: string[];
|
|
53
|
+
excludes: string;
|
|
54
|
+
}): Promise<{
|
|
43
55
|
partial: string | null;
|
|
44
56
|
}>;
|
|
45
57
|
/**
|
|
@@ -47,11 +59,12 @@ export declare function importProjectHistory(cell: SyncCell, folder: string, roo
|
|
|
47
59
|
* untracked files Git does not ignore, the .env files we always carry, Git LFS files (their content lives outside Git),
|
|
48
60
|
* and deletions. Ignored files, nested repositories and submodule contents stay out.
|
|
49
61
|
*/
|
|
50
|
-
export
|
|
62
|
+
export type LocalChanges = {
|
|
51
63
|
copy: string[];
|
|
52
64
|
remove: string[];
|
|
53
65
|
skipped: {
|
|
54
66
|
path: string;
|
|
55
67
|
reason: string;
|
|
56
68
|
}[];
|
|
57
|
-
}
|
|
69
|
+
};
|
|
70
|
+
export declare function localChanges(folder: string, signal?: AbortSignal): Promise<LocalChanges>;
|