@shardflux/cli 0.14.0 → 0.14.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/CHANGELOG.md CHANGED
@@ -1,7 +1,28 @@
1
1
  # Changelog
2
2
 
3
+ ## 0.14.2
4
+
5
+ - `shard agents open` accepts conversation keys, VM keys and conversation ids, reattaching the existing Claude Code or Codex session in its conversation worktree. The menu bar's Open action uses the same path; legacy agents retain their existing behavior.
6
+ - Start local projects without Git history: initialize a repository on `main` when needed and create one empty initial commit, preserving existing files and staged work. Use a command-local Shardflux identity when Git identity is missing, and report actionable `git_error` failures.
7
+
8
+ ## 0.14.1
9
+
10
+ - `shard ssh-proxy` connects faster: host trust (host key pin and device key) runs alongside the tunnel start, with no guest byte reaching OpenSSH before the host key is pinned, and a reconnect checks its device key with one read.
11
+
3
12
  ## 0.14.0
4
13
 
14
+ - Mirror native conversation transcripts when the guest includes its empty append-lock file.
15
+
16
+ - Ask for device approval before preparing the VM-backed local worktree; report a failed preparation as the request's result and bound preparation to 30 seconds.
17
+ - Keep desktop programs running after a command returns with detached `setsid -f` guidance.
18
+ - Allocate one VM per new ACP conversation, with cached initial model choices and live updates from that same VM.
19
+
20
+ - Populate ACP model choices from the cloud adapters for each session, following the VM's native Claude Code and Codex executables. Refresh choices on attachment and model updates, and remove models the live adapter rejects.
21
+ - Register the bound Shardflux conversation MCP server for cloud ACP sessions, so plain chat can fork, join, move, land and request device actions.
22
+ - Request valid 64 MiB file manifests when mirroring native transcripts; the device helper and native history handoff no longer fail with invalid argument.
23
+ - Carry Git fetch/push through the platform binary transport so native protocol flush packets arrive before stdin EOF.
24
+ - Seed the shared project hub before writing Desktop connections so a new thread can initialize its separate VM.
25
+
5
26
  - Parallel conversation launches preserve both sessions in local history.
6
27
 
7
28
  - Help an agent can set up cloud agents from: `shard --help` has a Cloud agents section (conversations, machine, template, agents) and says how a VM is made (the coding template, then your machine, then the project template), that machine and project templates are saved from an agent's VM, that `shard templates` is for your own app's workspaces (a repository bound to one is refused with `template_not_agent_capable`), and that Claude Code and Codex in the VM have the `shardflux-computer` tools. `shard machine`, `shard template` and `shard templates init|build|draft open` help say the same.
package/README.md CHANGED
@@ -62,12 +62,15 @@ shard ./
62
62
 
63
63
  Choose Claude Code or Codex. Claude asks for one cloud sign-in per Shardflux account; Codex uses your copied login.
64
64
  Each `shard ./` starts its own conversation VM and opens your agent’s native terminal. Later turns stay in that
65
- VM; `shard ./ --resume` selects a saved project conversation. You can open conversations in separate terminals at the same time; each stays in the project's local history. `shard` opens the optional command center. On macOS the menu bar starts automatically the first
65
+ VM; `shard ./ --resume` selects a saved project conversation. Native terminal and ACP sessions receive the conversation tools for their own conversation, so the agent can fork, ask for a review, and report to its parent (0.14.0+). You can open conversations in separate terminals at the same time; each stays in the project's local history. `shard` opens the optional command center. On macOS the menu bar starts automatically the first
66
66
  time `shard` runs, with launch at login enabled; `shard menubar stop` turns it off. See [Cloud agents](https://docs.shardflux.dev/guides/cloud-agents).
67
67
 
68
68
  T3 Code uses one **Shardflux** provider; choose a Claude Code or Codex model to start that agent in the cloud.
69
+ Model choices come from your cloud agent's session and use the same coding tools and settings as its terminal.
69
70
  The provider is registered automatically when T3 Code is installed. Use a T3 build that supports ACP providers.
70
71
 
72
+ Git fetch and push use the coding guest’s platform transport when available, preserving Git’s binary packets (0.14.0+). Older guests retain their existing transport.
73
+
71
74
  To try a conversation on your Mac:
72
75
 
73
76
  ```sh
@@ -76,8 +79,8 @@ shard conversations try <conversation>
76
79
 
77
80
  Your branch opens in `.shard/worktrees/<name>`, syncs both ways, and its dev servers appear at localhost.
78
81
  Ctrl-C stops local sync. Your main checkout stays available for your own work.
79
- Device tools ask Allow once or Always for this project on your Mac. Live transcripts stay in
80
- `~/.config/shardflux/conversations/`; ended sessions enter Claude Code’s or Codex’s native history.
82
+ Device tools ask Allow once or Always for this project on your Mac before preparing the conversation’s local worktree. Live transcripts stay in
83
+ `~/.config/shardflux/conversations/`; ended sessions enter Claude Code’s or Codex’s native history. Transcript files up to 64 MiB are supported (0.14.0+).
81
84
 
82
85
  For application workspace commands, `shard signup` creates an account and saves a project key, or set
83
86
  `SHARDFLUX_API_KEY` to a key from the console and run `shard login`. `shard --help` lists every command.
@@ -1150,6 +1153,9 @@ Set `--reachable 30m` when opening a workspace to choose how long waiting agents
1150
1153
  ## Cloud agents (0.13.2+)
1151
1154
 
1152
1155
  Run `shard ./` in your project to start Claude Code or Codex, usable immediately while setup runs in the background.
1156
+
1157
+ New project folders are ready to use: `shard ./` and `shard agents new` initialize Git on `main` when needed and create an empty initial commit (CLI 0.14.2+). Existing files and staged work stay yours; the initial commit contains no files. Repositories without commits keep their current branch. If Git identity is missing, that one commit uses `Shardflux <noreply@shardflux.dev>` without changing your Git configuration.
1158
+
1153
1159
  Your **machine** carries credentials, tools, dotfiles, logins and agent config; the project's **template** carries
1154
1160
  toolchains, dependencies, services and project secrets. Both are private filesystem templates and include secrets
1155
1161
  as ordinary files. Browser logins and Claude/Codex config belong to the machine. Set up tools and secrets normally inside the VM;
@@ -1184,7 +1190,8 @@ refused with `template_not_agent_capable` (0.14.0+).
1184
1190
 
1185
1191
  Inside the VM, Claude Code and Codex have Shardflux computer use next to their own tools (0.14.0+, `coding` 13+): the
1186
1192
  `shardflux-computer` MCP server's `computer` and `computer_batch` drive the VM's desktop. The agent starts a program
1187
- on it with `DISPLAY=:1`, for example `DISPLAY=:1 chromium http://localhost:3000 &`, then takes a screenshot.
1193
+ on it with `DISPLAY=:1`, detached so it outlives the command, for example
1194
+ `DISPLAY=:1 setsid -f chromium http://localhost:3000`, then takes a screenshot.
1188
1195
 
1189
1196
  Volume lists and details (0.14.0+) show `kind`. Project spaces show their measured storage and a platform-managed quota.
1190
1197
 
@@ -1195,7 +1202,7 @@ From 0.14.0, `shard conversations list|get|send|wait|land|move` manages project
1195
1202
 
1196
1203
  Desktop project connections (0.14.0+): `shard agents open codex-app <project>/<workspace>` and
1197
1204
  `shard agents open claude-desktop <project>/<workspace>` register **Shardflux · <project>** in the app.
1198
- Open that project connection to start conversations and return to their saved threads.
1205
+ Open that project connection to start conversations and return to their saved threads. The project hub supplies the base commit to each new thread’s VM (0.14.0+).
1199
1206
 
1200
1207
  Conversation JSON includes `join_mode` and the worktree used by reviewers and workers.
1201
1208
 
@@ -1,152 +1,7 @@
1
- export declare const ACP_CATALOG: {
2
- claude: {
3
- initialize: {
4
- protocolVersion: number;
5
- agentCapabilities: {
6
- _meta: {
7
- claudeCode: {
8
- promptQueueing: boolean;
9
- };
10
- authStatus: {};
11
- };
12
- promptCapabilities: {
13
- image: boolean;
14
- embeddedContext: boolean;
15
- };
16
- mcpCapabilities: {
17
- http: boolean;
18
- sse: boolean;
19
- };
20
- auth: {
21
- logout: {};
22
- };
23
- providers: {};
24
- loadSession: boolean;
25
- sessionCapabilities: {
26
- additionalDirectories: {};
27
- close: {};
28
- delete: {};
29
- fork: {};
30
- list: {};
31
- resume: {};
32
- subagents: {};
33
- };
34
- };
35
- agentInfo: {
36
- name: string;
37
- title: string;
38
- version: string;
39
- };
40
- authMethods: never[];
41
- _meta: {
42
- steering: {
43
- supported: boolean;
44
- };
45
- };
46
- };
47
- session: {
48
- modes: {
49
- currentModeId: string;
50
- availableModes: {
51
- id: string;
52
- name: string;
53
- description: string;
54
- }[];
55
- };
56
- configOptions: {
57
- id: string;
58
- name: string;
59
- description: string;
60
- category: string;
61
- type: string;
62
- currentValue: string;
63
- options: {
64
- value: string;
65
- name: string;
66
- description: string;
67
- }[];
68
- }[];
69
- };
70
- };
71
- codex: {
72
- initialize: {
73
- protocolVersion: number;
74
- agentInfo: {
75
- name: string;
76
- title: string;
77
- version: string;
78
- };
79
- agentCapabilities: {
80
- auth: {
81
- logout: {};
82
- };
83
- providers: {};
84
- loadSession: boolean;
85
- promptCapabilities: {
86
- embeddedContext: boolean;
87
- image: boolean;
88
- };
89
- sessionCapabilities: {
90
- resume: {};
91
- list: {};
92
- close: {};
93
- delete: {};
94
- fork: {};
95
- additionalDirectories: {};
96
- subagents: {};
97
- };
98
- mcpCapabilities: {
99
- acp: boolean;
100
- http: boolean;
101
- sse: boolean;
102
- };
103
- _meta: {
104
- authStatus: {};
105
- };
106
- };
107
- authMethods: ({
108
- id: string;
109
- name: string;
110
- description: string;
111
- _meta: {
112
- "api-key": {
113
- provider: string;
114
- };
115
- };
116
- } | {
117
- id: string;
118
- name: string;
119
- description: string;
120
- _meta?: undefined;
121
- })[];
122
- _meta: {
123
- steering: {
124
- supported: boolean;
125
- };
126
- };
127
- };
128
- session: {
129
- modes: {
130
- availableModes: {
131
- id: string;
132
- name: string;
133
- description: string;
134
- }[];
135
- currentModeId: string;
136
- };
137
- configOptions: {
138
- id: string;
139
- name: string;
140
- description: string;
141
- category: string;
142
- type: string;
143
- currentValue: string;
144
- options: {
145
- value: string;
146
- name: string;
147
- description: string;
148
- }[];
149
- }[];
150
- };
151
- };
152
- };
1
+ import type { ObjectValue } from './acp-rpc.js';
2
+ export type AcpApp = 'claude' | 'codex';
3
+ export type AcpCatalog = Partial<Record<AcpApp, ObjectValue>>;
4
+ export declare const ACP_PROBE_CATALOG: AcpCatalog;
5
+ export declare function nativeModelOptions(session: ObjectValue): ObjectValue[];
6
+ export declare function nativeCurrentModel(session: ObjectValue): string;
7
+ export declare function withoutNativeModel(session: ObjectValue, id: string): ObjectValue;
@@ -1,287 +1,40 @@
1
- // Captured from the pinned adapters; refreshed when their versions change.
2
- export const ACP_CATALOG = {
3
- "claude": {
4
- "initialize": {
5
- "protocolVersion": 1,
6
- "agentCapabilities": {
7
- "_meta": {
8
- "claudeCode": {
9
- "promptQueueing": true
10
- },
11
- "authStatus": {}
12
- },
13
- "promptCapabilities": {
14
- "image": true,
15
- "embeddedContext": true
16
- },
17
- "mcpCapabilities": {
18
- "http": true,
19
- "sse": true
20
- },
21
- "auth": {
22
- "logout": {}
23
- },
24
- "providers": {},
25
- "loadSession": true,
26
- "sessionCapabilities": {
27
- "additionalDirectories": {},
28
- "close": {},
29
- "delete": {},
30
- "fork": {},
31
- "list": {},
32
- "resume": {},
33
- "subagents": {}
34
- }
35
- },
36
- "agentInfo": {
37
- "name": "@agentclientprotocol/claude-agent-acp",
38
- "title": "Claude Agent",
39
- "version": "0.87.0"
40
- },
41
- "authMethods": [],
42
- "_meta": {
43
- "steering": {
44
- "supported": true
45
- }
46
- }
47
- },
48
- "session": {
49
- "modes": {
50
- "currentModeId": "auto",
51
- "availableModes": [
52
- {
53
- "id": "default",
54
- "name": "Manual",
55
- "description": "Always ask before making changes"
56
- },
57
- {
58
- "id": "acceptEdits",
59
- "name": "Accept edits",
60
- "description": "Automatically accept all file edits"
61
- },
62
- {
63
- "id": "plan",
64
- "name": "Plan",
65
- "description": "Create a plan before making changes"
66
- },
67
- {
68
- "id": "auto",
69
- "name": "Auto",
70
- "description": "Claude handles permission decisions"
71
- },
72
- {
73
- "id": "bypassPermissions",
74
- "name": "Bypass permissions",
75
- "description": "Accepts all permissions"
76
- }
77
- ]
78
- },
79
- "configOptions": [
80
- {
81
- "id": "model",
82
- "name": "Model",
83
- "description": "AI model to use",
84
- "category": "model",
85
- "type": "select",
86
- "currentValue": "opus",
87
- "options": [
88
- {
89
- "value": "default",
90
- "name": "Default (recommended)",
91
- "description": "Opus 5.5"
92
- },
93
- {
94
- "value": "opus",
95
- "name": "Opus 5.5",
96
- "description": "Best for everyday, complex tasks"
97
- },
98
- {
99
- "value": "fable",
100
- "name": "Fable 5.1",
101
- "description": "Most capable for your hardest and longest-running tasks"
102
- },
103
- {
104
- "value": "sonnet",
105
- "name": "Sonnet 5.5",
106
- "description": "Efficient for routine tasks"
107
- },
108
- {
109
- "value": "haiku",
110
- "name": "Haiku 4.5",
111
- "description": "Fastest for quick answers"
112
- },
113
- {
114
- "value": "claude-sonnet-5",
115
- "name": "Sonnet 5",
116
- "description": "Efficient for routine tasks"
117
- },
118
- {
119
- "value": "claude-opus-5",
120
- "name": "Opus 5",
121
- "description": "Best for everyday, complex tasks"
122
- },
123
- {
124
- "value": "claude-fable-5",
125
- "name": "Fable 5",
126
- "description": "Most capable for your hardest and longest-running tasks"
127
- },
128
- {
129
- "value": "claude-opus-4-8",
130
- "name": "Opus 4.8",
131
- "description": "Best for everyday, complex tasks"
132
- },
133
- {
134
- "value": "claude-opus-4-7",
135
- "name": "Opus 4.7",
136
- "description": "Best for everyday, complex tasks"
137
- },
138
- {
139
- "value": "claude-opus-4-6",
140
- "name": "Opus 4.6",
141
- "description": "Best for everyday, complex tasks"
142
- },
143
- {
144
- "value": "claude-sonnet-4-6",
145
- "name": "Sonnet 4.6",
146
- "description": "Efficient for routine tasks"
147
- }
148
- ]
149
- }
150
- ]
151
- }
152
- },
153
- "codex": {
154
- "initialize": {
155
- "protocolVersion": 1,
156
- "agentInfo": {
157
- "name": "@agentclientprotocol/codex-acp",
158
- "title": "Codex",
159
- "version": "2.1.1"
160
- },
161
- "agentCapabilities": {
162
- "auth": {
163
- "logout": {}
164
- },
165
- "providers": {},
166
- "loadSession": true,
167
- "promptCapabilities": {
168
- "embeddedContext": true,
169
- "image": true
170
- },
171
- "sessionCapabilities": {
172
- "resume": {},
173
- "list": {},
174
- "close": {},
175
- "delete": {},
176
- "fork": {},
177
- "additionalDirectories": {},
178
- "subagents": {}
179
- },
180
- "mcpCapabilities": {
181
- "acp": false,
182
- "http": true,
183
- "sse": false
184
- },
185
- "_meta": {
186
- "authStatus": {}
187
- }
188
- },
189
- "authMethods": [
190
- {
191
- "id": "api-key",
192
- "name": "API Key",
193
- "description": "Use an API key to authenticate",
194
- "_meta": {
195
- "api-key": {
196
- "provider": "openai"
197
- }
198
- }
199
- },
200
- {
201
- "id": "chat-gpt",
202
- "name": "ChatGPT",
203
- "description": "Use ChatGPT to authenticate"
204
- }
205
- ],
206
- "_meta": {
207
- "steering": {
208
- "supported": true
209
- }
210
- }
211
- },
212
- "session": {
213
- "modes": {
214
- "availableModes": [
215
- {
216
- "id": "read-only",
217
- "name": "Read-only",
218
- "description": "Requires approval to edit files and access the internet."
219
- },
220
- {
221
- "id": "workspace-write",
222
- "name": "Workspace access",
223
- "description": "Edit workspace files; ask before writing outside the workspace or accessing the network."
224
- },
225
- {
226
- "id": "agent",
227
- "name": "Auto review",
228
- "description": "Only ask for actions detected as potentially unsafe"
229
- },
230
- {
231
- "id": "agent-full-access",
232
- "name": "Full access",
233
- "description": "Unrestricted access to the internet and any file on your computer"
234
- }
235
- ],
236
- "currentModeId": "agent"
237
- },
238
- "configOptions": [
239
- {
240
- "id": "model",
241
- "name": "Model",
242
- "description": "Model Codex uses for the session",
243
- "category": "model",
244
- "type": "select",
245
- "currentValue": "gpt-6-astra",
246
- "options": [
247
- {
248
- "value": "gpt-6.1-sol",
249
- "name": "6.1 Sol",
250
- "description": "Latest workhorse model for coding and everyday work."
251
- },
252
- {
253
- "value": "gpt-6-astra",
254
- "name": "6 Astra",
255
- "description": "Frontier intelligence for the most demanding work."
256
- },
257
- {
258
- "value": "gpt-6-sol",
259
- "name": "6 Sol",
260
- "description": "Previous generation workhorse model."
261
- },
262
- {
263
- "value": "gpt-6-luna",
264
- "name": "6 Luna",
265
- "description": "Fast and affordable model for easier tasks."
266
- },
267
- {
268
- "value": "gpt-5.6-sol",
269
- "name": "5.6 Sol",
270
- "description": "Older generation workhorse model."
271
- },
272
- {
273
- "value": "gpt-5.6-terra",
274
- "name": "5.6 Terra",
275
- "description": "Older balanced model for straightforward work."
276
- },
277
- {
278
- "value": "gpt-5.6-luna",
279
- "name": "5.6 Luna",
280
- "description": "Older fast and efficient model."
281
- }
282
- ]
283
- }
284
- ]
285
- }
286
- }
1
+ import { objectValue } from "./acp-rpc.js";
2
+ // T3's installation probe works offline, without a VM. These are harness
3
+ // labels only. Real sessions always replace them with guest metadata.
4
+ export const ACP_PROBE_CATALOG = {
5
+ claude: { models: { currentModelId: 'default', availableModels: [{ modelId: 'default', name: 'Claude Code' }] } },
6
+ codex: { models: { currentModelId: 'default', availableModels: [{ modelId: 'default', name: 'Codex' }] } },
287
7
  };
8
+ export function nativeModelOptions(session) {
9
+ const configs = Array.isArray(session.configOptions) ? session.configOptions.map(objectValue) : [];
10
+ const model = configs.find(c => c.category === 'model' || c.id === 'model');
11
+ const options = model && Array.isArray(model.options)
12
+ ? model.options.flatMap(raw => {
13
+ const option = objectValue(raw);
14
+ return Array.isArray(option.options) ? option.options.map(objectValue) : [option];
15
+ })
16
+ : (Array.isArray(objectValue(session.models).availableModels) ? objectValue(session.models).availableModels : [])
17
+ .map(raw => { const m = objectValue(raw); return { value: m.modelId, name: m.name, ...(m.description ? { description: m.description } : {}) }; });
18
+ const seen = new Set();
19
+ return options.map(option => {
20
+ if (typeof option.value !== 'string' || !option.value || typeof option.name !== 'string' || !option.name || seen.has(option.value))
21
+ throw new Error('Agent model metadata omitted a unique ID or name');
22
+ seen.add(option.value);
23
+ return option;
24
+ });
25
+ }
26
+ export function nativeCurrentModel(session) {
27
+ const configs = Array.isArray(session.configOptions) ? session.configOptions.map(objectValue) : [];
28
+ const current = configs.find(c => c.category === 'model' || c.id === 'model')?.currentValue ?? objectValue(session.models).currentModelId;
29
+ const options = nativeModelOptions(session);
30
+ if (typeof current === 'string' && options.some(o => o.value === current))
31
+ return current;
32
+ throw new Error('The guest adapter returned no current model among its available models.');
33
+ }
34
+ export function withoutNativeModel(session, id) {
35
+ const options = nativeModelOptions(session).filter(o => o.value !== id);
36
+ const configs = Array.isArray(session.configOptions) ? session.configOptions.map(objectValue) : [];
37
+ const current = configs.find(c => c.category === 'model' || c.id === 'model')?.currentValue ?? objectValue(session.models).currentModelId;
38
+ return { ...session, configOptions: [{ id: 'model', category: 'model', type: 'select', options,
39
+ ...(options.some(o => o.value === current) ? { currentValue: current } : {}) }, ...configs.filter(c => c.category !== 'model' && c.id !== 'model')] };
40
+ }
@@ -0,0 +1,36 @@
1
+ import type { Workspace, WorkspaceView } from '@shardflux/sdk';
2
+ import type { Ctx } from './commands.js';
3
+ import type { Conversation } from './conversations.js';
4
+ import type { AcpCatalog } from './acp-catalog.js';
5
+ /** No prompts, login, logout or credential writes. Every child process group is
6
+ * terminated, including initialization failures and interrupted clients. */
7
+ export declare const ACP_MODELS_SCRIPT: string;
8
+ export interface AcpScope {
9
+ apiUrl: string;
10
+ organizationId: string;
11
+ template: string;
12
+ }
13
+ export declare function acpScope(apiUrl: string, ws: Pick<WorkspaceView, 'organization_id' | 'template'>): AcpScope;
14
+ /** Model payloads are account/harness/template scoped. The credential fingerprint
15
+ * only locates the last verified binding; it is never stored or logged in clear. */
16
+ export declare class AcpModelCache {
17
+ #private;
18
+ constructor(dir: string);
19
+ lookup(ctx: Ctx, folder: string): {
20
+ scope: AcpScope;
21
+ catalog: AcpCatalog;
22
+ } | undefined;
23
+ remember(ctx: Ctx, folder: string, scope: AcpScope): void;
24
+ read(scope: AcpScope): AcpCatalog;
25
+ write(scope: AcpScope, catalog: AcpCatalog): void;
26
+ }
27
+ export declare function discoverAcpCatalog(ctx: Ctx, ws: Workspace, root: string): Promise<AcpCatalog>;
28
+ export interface AcpPreparation {
29
+ allocated(conversation: Conversation, workspace: WorkspaceView): void;
30
+ ready(workspace: Workspace): void;
31
+ prepared(): void;
32
+ }
33
+ export interface AcpLifecycle {
34
+ prepare(ctx: Ctx, folder: string, name: string, callbacks: AcpPreparation): Promise<AcpCatalog>;
35
+ }
36
+ export declare const ACP_LIFECYCLE: AcpLifecycle;