open-research-protocol 0.4.19 → 0.4.21
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/AGENT_INTEGRATION.md +8 -0
- package/README.md +204 -16
- package/cli/orp.py +14969 -10304
- package/docs/AGENT_LOOP.md +39 -0
- package/docs/ORP_AUTONOMY_PROJECT_COMPILATION_MODEL.md +252 -0
- package/docs/START_HERE.md +241 -9
- package/package.json +1 -1
- package/packages/orp-workspace-launcher/README.md +19 -1
- package/packages/orp-workspace-launcher/src/core-plan.js +72 -2
- package/packages/orp-workspace-launcher/src/hosted-state.js +9 -0
- package/packages/orp-workspace-launcher/src/index.js +2 -0
- package/packages/orp-workspace-launcher/src/ledger.js +74 -2
- package/packages/orp-workspace-launcher/src/list.js +18 -0
- package/packages/orp-workspace-launcher/src/orp-command.js +8 -4
- package/packages/orp-workspace-launcher/src/orp.js +13 -0
- package/packages/orp-workspace-launcher/src/registry.js +10 -0
- package/packages/orp-workspace-launcher/src/sync.js +12 -0
- package/packages/orp-workspace-launcher/src/tabs.js +39 -2
- package/packages/orp-workspace-launcher/test/core-plan.test.js +13 -0
- package/packages/orp-workspace-launcher/test/ledger.test.js +50 -0
- package/packages/orp-workspace-launcher/test/list.test.js +19 -0
- package/packages/orp-workspace-launcher/test/tabs.test.js +51 -6
- package/spec/v1/workspace.schema.json +36 -2
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# orp-workspace-launcher
|
|
2
2
|
|
|
3
|
-
Manage a durable ORP workspace ledger of project paths plus saved `codex resume ...` or `claude --resume ...` commands.
|
|
3
|
+
Manage a durable ORP workspace ledger of project paths plus saved `codex resume ...` or `claude --resume ...` commands, optional remote git URLs, bootstrap commands, and per-machine workspace identity.
|
|
4
4
|
|
|
5
5
|
The package no longer automates iTerm or Terminal.app. The workspace ledger is the source of truth, and you use Terminal however you want.
|
|
6
6
|
|
|
@@ -11,6 +11,7 @@ Create a local workspace ledger with no hosted account required:
|
|
|
11
11
|
```bash
|
|
12
12
|
orp workspace create main-cody-1
|
|
13
13
|
orp workspace create research-lab --path /absolute/path/to/research-lab --resume-tool claude --resume-session-id 469d99b2-2997-42bf-a8f5-3812c808ef29
|
|
14
|
+
orp workspace create mac-main --machine-label "Mac Studio" --path /absolute/path/to/orp --remote-url git@github.com:SproutSeeds/orp.git --bootstrap-command "npm install"
|
|
14
15
|
```
|
|
15
16
|
|
|
16
17
|
Inspect the saved ledger:
|
|
@@ -32,6 +33,7 @@ Add a new saved tab manually:
|
|
|
32
33
|
```bash
|
|
33
34
|
orp workspace ledger add main --path /absolute/path/to/frg-site --resume-command "codex resume 019d348d-5031-78e1-9840-a66deaac33ae"
|
|
34
35
|
orp workspace add-tab main --path /absolute/path/to/anthropic-lab --resume-tool claude --resume-session-id claude-456
|
|
36
|
+
orp workspace add-tab main --path /absolute/path/to/orp-web-app --remote-url git@github.com:SproutSeeds/orp-web-app.git --bootstrap-command "pnpm install"
|
|
35
37
|
```
|
|
36
38
|
|
|
37
39
|
Remove a saved tab manually:
|
|
@@ -75,8 +77,24 @@ orp workspace slot set offhand research-lab
|
|
|
75
77
|
- `--orp-command <path-or-command>`: override the ORP CLI binary used to fetch hosted idea JSON
|
|
76
78
|
- `--path <absolute-path>`: add or match a saved project path
|
|
77
79
|
- `--title <text>`: set or match a saved tab title
|
|
80
|
+
- `--remote-url <git-url>`: remember where to clone the repo on another machine
|
|
81
|
+
- `--remote-branch <branch>`: remember the branch to clone by default
|
|
82
|
+
- `--bootstrap-command <text>`: remember the setup command for another machine, like `npm install`, `pnpm install`, or `uv sync`
|
|
78
83
|
- `--resume-command <text>`: save or match an exact `codex resume ...` or `claude --resume ...` command
|
|
79
84
|
- `--resume-tool <codex|claude>`: build or narrow the resume command by tool
|
|
80
85
|
- `--resume-session-id <id>`: build or match a specific session id
|
|
81
86
|
- `--index <n>`: remove a saved tab by 1-based index
|
|
82
87
|
- `--all`: remove every matching saved tab
|
|
88
|
+
|
|
89
|
+
## Cross-machine idea
|
|
90
|
+
|
|
91
|
+
The local `path` is still the machine-specific working directory. The optional `remoteUrl`, `remoteBranch`, and `bootstrapCommand` fields are the portable part that an agent or user can carry to another rig.
|
|
92
|
+
|
|
93
|
+
That means one workspace can remember:
|
|
94
|
+
|
|
95
|
+
- where the repo lives on this machine
|
|
96
|
+
- which git remote should be cloned on the next machine
|
|
97
|
+
- which setup command should be run after clone
|
|
98
|
+
- which `codex resume ...` or `claude --resume ...` line is valid on this machine
|
|
99
|
+
|
|
100
|
+
Resume session ids are still machine-local/runtime-local. The remote and bootstrap metadata are what make the ledger portable.
|
|
@@ -64,6 +64,41 @@ function normalizeOptionalString(value) {
|
|
|
64
64
|
return trimmed.length > 0 ? trimmed : null;
|
|
65
65
|
}
|
|
66
66
|
|
|
67
|
+
function normalizeOptionalCommand(value) {
|
|
68
|
+
return normalizeOptionalString(value);
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
function normalizeOptionalUrl(value, label) {
|
|
72
|
+
const normalized = normalizeOptionalString(value);
|
|
73
|
+
if (!normalized) {
|
|
74
|
+
return null;
|
|
75
|
+
}
|
|
76
|
+
if (/^[a-z][a-z0-9+.-]*:\/\//i.test(normalized) || /^[^@\s]+@[^:\s]+:[^\s]+$/i.test(normalized)) {
|
|
77
|
+
return normalized;
|
|
78
|
+
}
|
|
79
|
+
throw new Error(`${label} must look like a git remote URL`);
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function normalizeMachineMetadata(rawMachine) {
|
|
83
|
+
if (rawMachine == null) {
|
|
84
|
+
return null;
|
|
85
|
+
}
|
|
86
|
+
if (!rawMachine || typeof rawMachine !== "object" || Array.isArray(rawMachine)) {
|
|
87
|
+
throw new Error("workspace manifest machine metadata must be an object");
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
const machine = Object.fromEntries(
|
|
91
|
+
Object.entries({
|
|
92
|
+
machineId: normalizeOptionalString(rawMachine.machineId),
|
|
93
|
+
machineLabel: normalizeOptionalString(rawMachine.machineLabel),
|
|
94
|
+
platform: normalizeOptionalString(rawMachine.platform),
|
|
95
|
+
host: normalizeOptionalString(rawMachine.host),
|
|
96
|
+
}).filter(([, value]) => value != null),
|
|
97
|
+
);
|
|
98
|
+
|
|
99
|
+
return Object.keys(machine).length > 0 ? machine : null;
|
|
100
|
+
}
|
|
101
|
+
|
|
67
102
|
function normalizeResumeTool(value) {
|
|
68
103
|
const trimmed = normalizeOptionalString(value)?.toLowerCase() || null;
|
|
69
104
|
return trimmed && SUPPORTED_RESUME_TOOLS.has(trimmed) ? trimmed : null;
|
|
@@ -241,6 +276,9 @@ function normalizeStructuredTab(rawTab, index) {
|
|
|
241
276
|
resumeTool: resume.resumeTool,
|
|
242
277
|
title,
|
|
243
278
|
tmuxSessionName,
|
|
279
|
+
remoteUrl: normalizeOptionalUrl(rawTab.remoteUrl, `workspace tab ${index + 1} remoteUrl`),
|
|
280
|
+
remoteBranch: normalizeOptionalString(rawTab.remoteBranch),
|
|
281
|
+
bootstrapCommand: normalizeOptionalCommand(rawTab.bootstrapCommand),
|
|
244
282
|
};
|
|
245
283
|
}
|
|
246
284
|
|
|
@@ -254,8 +292,8 @@ export function normalizeWorkspaceManifest(rawManifest) {
|
|
|
254
292
|
throw new Error(`unsupported workspace manifest version: ${version}`);
|
|
255
293
|
}
|
|
256
294
|
|
|
257
|
-
if (!Array.isArray(rawManifest.tabs)
|
|
258
|
-
throw new Error("workspace manifest must include a
|
|
295
|
+
if (!Array.isArray(rawManifest.tabs)) {
|
|
296
|
+
throw new Error("workspace manifest must include a tabs array");
|
|
259
297
|
}
|
|
260
298
|
|
|
261
299
|
const tabs = rawManifest.tabs.map((tab, index) => normalizeStructuredTab(tab, index));
|
|
@@ -264,6 +302,7 @@ export function normalizeWorkspaceManifest(rawManifest) {
|
|
|
264
302
|
workspaceId: normalizeOptionalString(rawManifest.workspaceId),
|
|
265
303
|
title: normalizeOptionalString(rawManifest.title),
|
|
266
304
|
tmuxPrefix: normalizeOptionalString(rawManifest.tmuxPrefix),
|
|
305
|
+
machine: normalizeMachineMetadata(rawManifest.machine),
|
|
267
306
|
capture: normalizeCaptureMetadata(rawManifest.capture),
|
|
268
307
|
tabs,
|
|
269
308
|
};
|
|
@@ -401,6 +440,37 @@ export function buildDirectCommand(entry, options = {}) {
|
|
|
401
440
|
return commands.join(" && ");
|
|
402
441
|
}
|
|
403
442
|
|
|
443
|
+
export function buildCloneCommand(entry, options = {}) {
|
|
444
|
+
const remoteUrl = normalizeOptionalUrl(entry?.remoteUrl, "workspace tab remoteUrl");
|
|
445
|
+
if (!remoteUrl) {
|
|
446
|
+
return null;
|
|
447
|
+
}
|
|
448
|
+
const repoDir = options.repoDir || path.basename(normalizeDisplayPath(entry.path));
|
|
449
|
+
const branch = normalizeOptionalString(entry?.remoteBranch);
|
|
450
|
+
const parts = ["git", "clone"];
|
|
451
|
+
if (branch) {
|
|
452
|
+
parts.push("--branch", shellQuote(branch));
|
|
453
|
+
}
|
|
454
|
+
parts.push(shellQuote(remoteUrl));
|
|
455
|
+
if (repoDir) {
|
|
456
|
+
parts.push(shellQuote(repoDir));
|
|
457
|
+
}
|
|
458
|
+
return parts.join(" ");
|
|
459
|
+
}
|
|
460
|
+
|
|
461
|
+
export function buildSetupCommand(entry, options = {}) {
|
|
462
|
+
const cloneCommand = buildCloneCommand(entry, options);
|
|
463
|
+
const bootstrapCommand = normalizeOptionalCommand(entry?.bootstrapCommand);
|
|
464
|
+
if (!cloneCommand && !bootstrapCommand) {
|
|
465
|
+
return null;
|
|
466
|
+
}
|
|
467
|
+
if (cloneCommand && bootstrapCommand) {
|
|
468
|
+
const repoDir = options.repoDir || path.basename(normalizeDisplayPath(entry.path));
|
|
469
|
+
return `${cloneCommand} && cd ${shellQuote(repoDir)} && ${bootstrapCommand}`;
|
|
470
|
+
}
|
|
471
|
+
return cloneCommand || bootstrapCommand;
|
|
472
|
+
}
|
|
473
|
+
|
|
404
474
|
export function buildTmuxPresentationCommands(entry, options = {}) {
|
|
405
475
|
const sessionName = options.sessionName || deriveTmuxSessionName(entry, options);
|
|
406
476
|
const quotedSession = shellQuote(sessionName);
|
|
@@ -59,6 +59,9 @@ function normalizePreviousHostedTabs(workspace) {
|
|
|
59
59
|
tabId: normalizeOptionalString(tab.tab_id ?? tab.tabId),
|
|
60
60
|
title: normalizeOptionalString(tab.title),
|
|
61
61
|
path: normalizeOptionalString(tab.project_root ?? tab.projectRoot),
|
|
62
|
+
remoteUrl: normalizeOptionalString(tab.remote_url ?? tab.remoteUrl),
|
|
63
|
+
remoteBranch: normalizeOptionalString(tab.remote_branch ?? tab.remoteBranch),
|
|
64
|
+
bootstrapCommand: normalizeOptionalString(tab.bootstrap_command ?? tab.bootstrapCommand),
|
|
62
65
|
repoLabel: normalizeOptionalString(tab.repo_label ?? tab.repoLabel),
|
|
63
66
|
terminalTitle: normalizeOptionalString(tab.terminal_title ?? tab.terminalTitle),
|
|
64
67
|
resumeCommand: resume.resumeCommand,
|
|
@@ -149,6 +152,9 @@ export function buildHostedWorkspaceState(manifest, options = {}) {
|
|
|
149
152
|
order_index: index,
|
|
150
153
|
title: title || undefined,
|
|
151
154
|
project_root: projectRoot,
|
|
155
|
+
remote_url: normalizeOptionalString(tab.remoteUrl) || previous?.remoteUrl || undefined,
|
|
156
|
+
remote_branch: normalizeOptionalString(tab.remoteBranch) || previous?.remoteBranch || undefined,
|
|
157
|
+
bootstrap_command: normalizeOptionalString(tab.bootstrapCommand) || previous?.bootstrapCommand || undefined,
|
|
152
158
|
repo_label: repoLabel || undefined,
|
|
153
159
|
resume_command: resumeCommand,
|
|
154
160
|
resume_tool: resumeTool,
|
|
@@ -172,6 +178,9 @@ export function buildHostedWorkspaceState(manifest, options = {}) {
|
|
|
172
178
|
source_app: "terminal-ledger",
|
|
173
179
|
mode: "manual",
|
|
174
180
|
host: os.hostname(),
|
|
181
|
+
machine_id: normalizeOptionalString(manifest.machine?.machineId) || undefined,
|
|
182
|
+
machine_label: normalizeOptionalString(manifest.machine?.machineLabel) || undefined,
|
|
183
|
+
platform: normalizeOptionalString(manifest.machine?.platform) || process.platform,
|
|
175
184
|
terminal_frontend: "terminal",
|
|
176
185
|
durable_backend: options.durableBackend || "manual-ledger",
|
|
177
186
|
}).filter(([, value]) => value !== undefined && value !== null),
|
|
@@ -1,4 +1,5 @@
|
|
|
1
1
|
import fs from "node:fs/promises";
|
|
2
|
+
import os from "node:os";
|
|
2
3
|
import path from "node:path";
|
|
3
4
|
import process from "node:process";
|
|
4
5
|
|
|
@@ -36,6 +37,16 @@ function normalizeOptionalString(value) {
|
|
|
36
37
|
return trimmed.length > 0 ? trimmed : null;
|
|
37
38
|
}
|
|
38
39
|
|
|
40
|
+
function buildCurrentMachineMetadata(options = {}) {
|
|
41
|
+
const machineId = normalizeOptionalString(options.machineId) || `${os.hostname().trim() || "machine"}:${process.platform}`;
|
|
42
|
+
return {
|
|
43
|
+
machineId,
|
|
44
|
+
machineLabel: normalizeOptionalString(options.machineLabel) || os.hostname().trim() || "This Machine",
|
|
45
|
+
platform: normalizeOptionalString(options.platform) || process.platform,
|
|
46
|
+
host: os.hostname().trim() || undefined,
|
|
47
|
+
};
|
|
48
|
+
}
|
|
49
|
+
|
|
39
50
|
function validateAbsolutePath(value, label) {
|
|
40
51
|
const normalized = normalizeOptionalString(value);
|
|
41
52
|
if (!normalized || !normalized.startsWith("/")) {
|
|
@@ -65,6 +76,9 @@ function materializeWorkspaceTab(tab) {
|
|
|
65
76
|
Object.entries({
|
|
66
77
|
title: normalizeOptionalString(tab.title) || undefined,
|
|
67
78
|
path: tab.path,
|
|
79
|
+
remoteUrl: normalizeOptionalString(tab.remoteUrl) || undefined,
|
|
80
|
+
remoteBranch: normalizeOptionalString(tab.remoteBranch) || undefined,
|
|
81
|
+
bootstrapCommand: normalizeOptionalString(tab.bootstrapCommand) || undefined,
|
|
68
82
|
resumeCommand: resume.resumeCommand || undefined,
|
|
69
83
|
resumeTool: resume.resumeTool || undefined,
|
|
70
84
|
resumeSessionId: resume.resumeSessionId || undefined,
|
|
@@ -101,6 +115,7 @@ function materializeWorkspaceManifest(manifest) {
|
|
|
101
115
|
version: normalized.version,
|
|
102
116
|
workspaceId: normalized.workspaceId || undefined,
|
|
103
117
|
title: normalized.title || undefined,
|
|
118
|
+
machine: normalized.machine || undefined,
|
|
104
119
|
capture: normalized.capture || undefined,
|
|
105
120
|
tabs: normalized.tabs.map((tab) => materializeWorkspaceTab(tab)),
|
|
106
121
|
}).filter(([, value]) => value !== undefined),
|
|
@@ -113,6 +128,7 @@ function normalizeEditableManifest(source, parsed) {
|
|
|
113
128
|
version: parsed.manifest.version,
|
|
114
129
|
workspaceId: parsed.manifest.workspaceId,
|
|
115
130
|
title: parsed.manifest.title,
|
|
131
|
+
machine: parsed.manifest.machine,
|
|
116
132
|
capture: parsed.manifest.capture,
|
|
117
133
|
tabs: parsed.manifest.tabs.map((entry) => {
|
|
118
134
|
const resume = resolveResumeMetadata(entry);
|
|
@@ -120,6 +136,9 @@ function normalizeEditableManifest(source, parsed) {
|
|
|
120
136
|
Object.entries({
|
|
121
137
|
title: normalizeOptionalString(entry.title) || undefined,
|
|
122
138
|
path: entry.path,
|
|
139
|
+
remoteUrl: normalizeOptionalString(entry.remoteUrl) || undefined,
|
|
140
|
+
remoteBranch: normalizeOptionalString(entry.remoteBranch) || undefined,
|
|
141
|
+
bootstrapCommand: normalizeOptionalString(entry.bootstrapCommand) || undefined,
|
|
123
142
|
resumeCommand: resume.resumeCommand || undefined,
|
|
124
143
|
resumeTool: resume.resumeTool || undefined,
|
|
125
144
|
resumeSessionId: resume.resumeSessionId || undefined,
|
|
@@ -133,6 +152,7 @@ function normalizeEditableManifest(source, parsed) {
|
|
|
133
152
|
version: "1",
|
|
134
153
|
workspaceId: source.workspaceManifest?.workspaceId || source.title || "workspace",
|
|
135
154
|
title: source.workspaceManifest?.title || source.title || null,
|
|
155
|
+
machine: source.workspaceManifest?.machine || null,
|
|
136
156
|
capture: source.workspaceManifest?.capture || null,
|
|
137
157
|
tabs: parsed.entries.map((entry) => {
|
|
138
158
|
const resume = resolveResumeMetadata(entry);
|
|
@@ -140,6 +160,9 @@ function normalizeEditableManifest(source, parsed) {
|
|
|
140
160
|
Object.entries({
|
|
141
161
|
title: normalizeOptionalString(entry.title) || deriveBaseTitle(entry),
|
|
142
162
|
path: entry.path,
|
|
163
|
+
remoteUrl: normalizeOptionalString(entry.remoteUrl) || undefined,
|
|
164
|
+
remoteBranch: normalizeOptionalString(entry.remoteBranch) || undefined,
|
|
165
|
+
bootstrapCommand: normalizeOptionalString(entry.bootstrapCommand) || undefined,
|
|
143
166
|
resumeCommand: resume.resumeCommand || undefined,
|
|
144
167
|
resumeTool: resume.resumeTool || undefined,
|
|
145
168
|
resumeSessionId: resume.resumeSessionId || undefined,
|
|
@@ -216,6 +239,12 @@ function parseLedgerSelectorArgs(
|
|
|
216
239
|
options.resumeTool = next;
|
|
217
240
|
} else if (arg === "--resume-session-id") {
|
|
218
241
|
options.resumeSessionId = next;
|
|
242
|
+
} else if (arg === "--remote-url") {
|
|
243
|
+
options.remoteUrl = next;
|
|
244
|
+
} else if (arg === "--remote-branch") {
|
|
245
|
+
options.remoteBranch = next;
|
|
246
|
+
} else if (arg === "--bootstrap-command") {
|
|
247
|
+
options.bootstrapCommand = next;
|
|
219
248
|
} else if (arg === "--index") {
|
|
220
249
|
options.index = next;
|
|
221
250
|
} else {
|
|
@@ -312,6 +341,18 @@ export function parseWorkspaceCreateArgs(argv = []) {
|
|
|
312
341
|
options.resumeTool = next;
|
|
313
342
|
} else if (arg === "--resume-session-id") {
|
|
314
343
|
options.resumeSessionId = next;
|
|
344
|
+
} else if (arg === "--remote-url") {
|
|
345
|
+
options.remoteUrl = next;
|
|
346
|
+
} else if (arg === "--remote-branch") {
|
|
347
|
+
options.remoteBranch = next;
|
|
348
|
+
} else if (arg === "--bootstrap-command") {
|
|
349
|
+
options.bootstrapCommand = next;
|
|
350
|
+
} else if (arg === "--machine-id") {
|
|
351
|
+
options.machineId = next;
|
|
352
|
+
} else if (arg === "--machine-label") {
|
|
353
|
+
options.machineLabel = next;
|
|
354
|
+
} else if (arg === "--platform") {
|
|
355
|
+
options.platform = next;
|
|
315
356
|
} else {
|
|
316
357
|
throw new Error(`unknown option: ${arg}`);
|
|
317
358
|
}
|
|
@@ -392,6 +433,13 @@ export function addTabToManifest(manifest, options = {}) {
|
|
|
392
433
|
Object.entries({
|
|
393
434
|
title: normalizedTitle || normalizeOptionalString(existingTab?.title) || undefined,
|
|
394
435
|
path: normalizedPath,
|
|
436
|
+
remoteUrl: normalizeOptionalString(options.remoteUrl) || normalizeOptionalString(existingTab?.remoteUrl) || undefined,
|
|
437
|
+
remoteBranch:
|
|
438
|
+
normalizeOptionalString(options.remoteBranch) || normalizeOptionalString(existingTab?.remoteBranch) || undefined,
|
|
439
|
+
bootstrapCommand:
|
|
440
|
+
normalizeOptionalString(options.bootstrapCommand) ||
|
|
441
|
+
normalizeOptionalString(existingTab?.bootstrapCommand) ||
|
|
442
|
+
undefined,
|
|
395
443
|
resumeCommand: chosenResume.resumeCommand || undefined,
|
|
396
444
|
resumeTool: chosenResume.resumeTool || undefined,
|
|
397
445
|
resumeSessionId: chosenResume.resumeSessionId || undefined,
|
|
@@ -607,7 +655,7 @@ function printWorkspaceAddTabHelp() {
|
|
|
607
655
|
console.log(`ORP workspace add-tab
|
|
608
656
|
|
|
609
657
|
Usage:
|
|
610
|
-
orp workspace add-tab <name-or-id> (--path <absolute-path> | --here) [--title <title>] [--resume-command <text> | --resume-tool <codex|claude> --resume-session-id <id> | --current-codex] [--append] [--json]
|
|
658
|
+
orp workspace add-tab <name-or-id> (--path <absolute-path> | --here) [--title <title>] [--remote-url <git-url>] [--remote-branch <branch>] [--bootstrap-command <text>] [--resume-command <text> | --resume-tool <codex|claude> --resume-session-id <id> | --current-codex] [--append] [--json]
|
|
611
659
|
orp workspace add-tab --hosted-workspace-id <workspace-id> (--path <absolute-path> | --here) [--json]
|
|
612
660
|
orp workspace add-tab --workspace-file <path> (--path <absolute-path> | --here) [--json]
|
|
613
661
|
|
|
@@ -615,6 +663,9 @@ Options:
|
|
|
615
663
|
--path <absolute-path> Add this local project path to the saved workspace
|
|
616
664
|
--here Use the current working directory as the saved path
|
|
617
665
|
--title <title> Optional saved tab title
|
|
666
|
+
--remote-url <git-url> Optional git remote URL for cross-machine setup
|
|
667
|
+
--remote-branch <branch> Optional default branch to clone on another machine
|
|
668
|
+
--bootstrap-command <text> Optional setup command like \`npm install\` or \`uv sync\`
|
|
618
669
|
--resume-command <text> Exact saved resume command, like \`codex resume ...\` or \`claude --resume ...\`
|
|
619
670
|
--resume-tool <tool> Build the resume command from \`codex\` or \`claude\`
|
|
620
671
|
--resume-session-id <id> Resume session id to save with the tab
|
|
@@ -630,6 +681,7 @@ Examples:
|
|
|
630
681
|
orp workspace add-tab main --here --current-codex
|
|
631
682
|
orp workspace add-tab main --path /absolute/path/to/new-project --resume-command "codex resume 019d..."
|
|
632
683
|
orp workspace add-tab main --path /absolute/path/to/new-project --resume-tool claude --resume-session-id claude-456
|
|
684
|
+
orp workspace add-tab main --path /absolute/path/to/new-project --remote-url git@github.com:org/new-project.git --bootstrap-command "npm install"
|
|
633
685
|
`);
|
|
634
686
|
}
|
|
635
687
|
|
|
@@ -637,13 +689,19 @@ function printWorkspaceCreateHelp() {
|
|
|
637
689
|
console.log(`ORP workspace create
|
|
638
690
|
|
|
639
691
|
Usage:
|
|
640
|
-
orp workspace create <title-slug> [--workspace-file <path>] [--slot <main|offhand>] [--path <absolute-path>] [--resume-command <text> | --resume-tool <codex|claude> --resume-session-id <id>] [--json]
|
|
692
|
+
orp workspace create <title-slug> [--workspace-file <path>] [--slot <main|offhand>] [--machine-id <id>] [--machine-label <label>] [--platform <platform>] [--path <absolute-path>] [--remote-url <git-url>] [--remote-branch <branch>] [--bootstrap-command <text>] [--resume-command <text> | --resume-tool <codex|claude> --resume-session-id <id>] [--json]
|
|
641
693
|
|
|
642
694
|
Options:
|
|
643
695
|
<title-slug> Required local workspace title using lowercase letters, numbers, and dashes only
|
|
644
696
|
--workspace-file <path> Create the workspace manifest at an explicit local path instead of the managed ORP workspace directory
|
|
645
697
|
--slot <main|offhand> Optionally assign the created workspace to a named slot
|
|
698
|
+
--machine-id <id> Optional stable machine id for this workspace ledger (defaults to this machine)
|
|
699
|
+
--machine-label <label> Optional human label for the current machine
|
|
700
|
+
--platform <platform> Optional platform label like darwin, linux, or win32
|
|
646
701
|
--path <absolute-path> Optionally seed the workspace with one saved path immediately
|
|
702
|
+
--remote-url <git-url> Optional git remote URL for the first saved tab
|
|
703
|
+
--remote-branch <branch> Optional default branch to clone on another machine
|
|
704
|
+
--bootstrap-command <text> Optional setup command like \`npm install\` or \`uv sync\`
|
|
647
705
|
--resume-command <text> Exact saved resume command, like \`codex resume ...\` or \`claude --resume ...\`
|
|
648
706
|
--resume-tool <tool> Build the resume command from \`codex\` or \`claude\`
|
|
649
707
|
--resume-session-id <id> Resume session id to save with the first tab
|
|
@@ -655,6 +713,7 @@ Examples:
|
|
|
655
713
|
orp workspace create main-cody-1 --slot main
|
|
656
714
|
orp workspace create research-lab --path /absolute/path/to/research-lab
|
|
657
715
|
orp workspace create research-lab --path /absolute/path/to/research-lab --resume-tool claude --resume-session-id 469d99b2-2997-42bf-a8f5-3812c808ef29
|
|
716
|
+
orp workspace create mac-main --machine-label "Mac Studio" --path /absolute/path/to/research-lab --remote-url git@github.com:org/research-lab.git --bootstrap-command "npm install"
|
|
658
717
|
`);
|
|
659
718
|
}
|
|
660
719
|
|
|
@@ -697,6 +756,12 @@ function summarizeWorkspaceLedgerMutation(result) {
|
|
|
697
756
|
if (result.action === "add-tab") {
|
|
698
757
|
lines.push(`Tab: ${result.tab?.title || path.basename(result.tab?.path || "") || result.tab?.path}`);
|
|
699
758
|
lines.push(`Path: ${result.tab?.path}`);
|
|
759
|
+
if (result.tab?.remoteUrl) {
|
|
760
|
+
lines.push(`Remote: ${result.tab.remoteUrl}`);
|
|
761
|
+
}
|
|
762
|
+
if (result.tab?.bootstrapCommand) {
|
|
763
|
+
lines.push(`Bootstrap: ${result.tab.bootstrapCommand}`);
|
|
764
|
+
}
|
|
700
765
|
if (result.tab?.resumeCommand && result.tab?.restartCommand) {
|
|
701
766
|
lines.push(`Resume: ${result.tab.restartCommand}`);
|
|
702
767
|
}
|
|
@@ -792,6 +857,9 @@ export async function runWorkspaceCreate(argv = process.argv.slice(2)) {
|
|
|
792
857
|
Object.entries({
|
|
793
858
|
title: deriveBaseTitle({ path: options.path }),
|
|
794
859
|
path: options.path,
|
|
860
|
+
remoteUrl: normalizeOptionalString(options.remoteUrl) || undefined,
|
|
861
|
+
remoteBranch: normalizeOptionalString(options.remoteBranch) || undefined,
|
|
862
|
+
bootstrapCommand: normalizeOptionalString(options.bootstrapCommand) || undefined,
|
|
795
863
|
resumeCommand: resume.resumeCommand || undefined,
|
|
796
864
|
resumeTool: resume.resumeTool || undefined,
|
|
797
865
|
resumeSessionId: resume.resumeSessionId || undefined,
|
|
@@ -806,6 +874,7 @@ export async function runWorkspaceCreate(argv = process.argv.slice(2)) {
|
|
|
806
874
|
version: "1",
|
|
807
875
|
workspaceId: options.title,
|
|
808
876
|
title: options.title,
|
|
877
|
+
machine: buildCurrentMachineMetadata(options),
|
|
809
878
|
tabs,
|
|
810
879
|
});
|
|
811
880
|
|
|
@@ -869,6 +938,9 @@ export async function runWorkspaceCreate(argv = process.argv.slice(2)) {
|
|
|
869
938
|
`Saved tabs: ${result.tabCount}`,
|
|
870
939
|
`Saved file: ${result.manifestPath}`,
|
|
871
940
|
];
|
|
941
|
+
if (result.manifest?.machine?.machineLabel) {
|
|
942
|
+
lines.push(`Machine: ${result.manifest.machine.machineLabel}${result.manifest.machine.platform ? ` (${result.manifest.machine.platform})` : ""}`);
|
|
943
|
+
}
|
|
872
944
|
if (result.slot?.slot) {
|
|
873
945
|
lines.push(`Slot: ${result.slot.slot}`);
|
|
874
946
|
}
|
|
@@ -52,6 +52,10 @@ function buildHostedWorkspaceSummary(workspace) {
|
|
|
52
52
|
return {
|
|
53
53
|
workspaceId: normalizeOptionalString(workspace?.workspace_id ?? workspace?.id),
|
|
54
54
|
title: normalizeOptionalString(workspace?.title),
|
|
55
|
+
machineId: normalizeOptionalString(workspace?.state?.capture_context?.machine_id ?? workspace?.state?.captureContext?.machineId),
|
|
56
|
+
machineLabel:
|
|
57
|
+
normalizeOptionalString(workspace?.state?.capture_context?.machine_label ?? workspace?.state?.captureContext?.machineLabel),
|
|
58
|
+
platform: normalizeOptionalString(workspace?.state?.capture_context?.platform ?? workspace?.state?.captureContext?.platform),
|
|
55
59
|
visibility: normalizeOptionalString(workspace?.visibility),
|
|
56
60
|
ideaId: normalizeOptionalString(linkedIdea.idea_id ?? linkedIdea.ideaId),
|
|
57
61
|
tabCount:
|
|
@@ -66,6 +70,9 @@ function buildLocalWorkspaceSummary(workspace) {
|
|
|
66
70
|
return {
|
|
67
71
|
workspaceId: normalizeOptionalString(workspace?.workspaceId),
|
|
68
72
|
title: normalizeOptionalString(workspace?.title),
|
|
73
|
+
machineId: normalizeOptionalString(workspace?.machineId),
|
|
74
|
+
machineLabel: normalizeOptionalString(workspace?.machineLabel),
|
|
75
|
+
platform: normalizeOptionalString(workspace?.platform),
|
|
69
76
|
status: normalizeOptionalString(workspace?.status) || "ok",
|
|
70
77
|
manifestPath: normalizeOptionalString(workspace?.manifestPath),
|
|
71
78
|
tabCount: Number.isInteger(workspace?.tabCount) ? workspace.tabCount : 0,
|
|
@@ -244,6 +251,9 @@ export function buildWorkspaceInventory({ localResult, hostedResult, hostedError
|
|
|
244
251
|
availability:
|
|
245
252
|
entry.hosted && entry.local ? "hosted+local" : entry.hosted ? "hosted" : "local",
|
|
246
253
|
syncStatus: inferSyncStatus(entry),
|
|
254
|
+
machineId: entry.local?.machineId || entry.hosted?.machineId || null,
|
|
255
|
+
machineLabel: entry.local?.machineLabel || entry.hosted?.machineLabel || null,
|
|
256
|
+
platform: entry.local?.platform || entry.hosted?.platform || null,
|
|
247
257
|
sources: entry.sources,
|
|
248
258
|
hosted: entry.hosted || null,
|
|
249
259
|
local: entry.local || null,
|
|
@@ -308,6 +318,11 @@ export function summarizeWorkspaceInventory(result) {
|
|
|
308
318
|
`Slots: ${workspace.slots.join(", ")}${workspace.implicitMain ? " (main inferred because this is the only workspace)" : ""}`,
|
|
309
319
|
);
|
|
310
320
|
}
|
|
321
|
+
if (workspace.machineLabel || workspace.machineId) {
|
|
322
|
+
lines.push(
|
|
323
|
+
`Machine: ${workspace.machineLabel || workspace.machineId}${workspace.platform ? ` (${workspace.platform})` : ""}`,
|
|
324
|
+
);
|
|
325
|
+
}
|
|
311
326
|
lines.push(`Availability: ${workspace.availability}`);
|
|
312
327
|
lines.push(`Sync: ${workspace.syncStatus}`);
|
|
313
328
|
if (workspace.hosted) {
|
|
@@ -400,6 +415,9 @@ export function summarizeTrackedWorkspaces(result) {
|
|
|
400
415
|
lines.push(`Status: ${workspace.status}`);
|
|
401
416
|
lines.push(`File: ${workspace.manifestPath}`);
|
|
402
417
|
lines.push(`Saved tabs: ${workspace.tabCount || 0}`);
|
|
418
|
+
if (workspace.machineLabel || workspace.machineId) {
|
|
419
|
+
lines.push(`Machine: ${workspace.machineLabel || workspace.machineId}${workspace.platform ? ` (${workspace.platform})` : ""}`);
|
|
420
|
+
}
|
|
403
421
|
|
|
404
422
|
if (workspace.captureMode) {
|
|
405
423
|
lines.push(`Capture mode: ${workspace.captureMode}`);
|
|
@@ -8,18 +8,18 @@ function printWorkspaceHelp() {
|
|
|
8
8
|
console.log(`ORP workspace
|
|
9
9
|
|
|
10
10
|
Usage:
|
|
11
|
-
orp workspace create <title-slug> [--workspace-file <path>] [--slot <main|offhand>] [--path <absolute-path>] [--resume-command <text> | --resume-tool <codex|claude> --resume-session-id <id>] [--json]
|
|
11
|
+
orp workspace create <title-slug> [--workspace-file <path>] [--slot <main|offhand>] [--machine-id <id>] [--machine-label <label>] [--platform <platform>] [--path <absolute-path>] [--remote-url <git-url>] [--remote-branch <branch>] [--bootstrap-command <text>] [--resume-command <text> | --resume-tool <codex|claude> --resume-session-id <id>] [--json]
|
|
12
12
|
orp workspace list [--json]
|
|
13
13
|
orp workspace tabs <name-or-id> [--json]
|
|
14
14
|
orp workspace tabs --hosted-workspace-id <workspace-id> [--json]
|
|
15
15
|
orp workspace tabs --notes-file <path> [--json]
|
|
16
16
|
orp workspace tabs --workspace-file <path> [--json]
|
|
17
|
-
orp workspace add-tab <name-or-id> (--path <absolute-path> | --here) [--title <title>] [--resume-command <text> | --resume-tool <codex|claude> --resume-session-id <id> | --current-codex] [--append] [--json]
|
|
17
|
+
orp workspace add-tab <name-or-id> (--path <absolute-path> | --here) [--title <title>] [--remote-url <git-url>] [--remote-branch <branch>] [--bootstrap-command <text>] [--resume-command <text> | --resume-tool <codex|claude> --resume-session-id <id> | --current-codex] [--append] [--json]
|
|
18
18
|
orp workspace remove-tab <name-or-id> (--index <n> | --path <absolute-path> | --title <title> | --resume-session-id <id> | --resume-command <text>) [--all] [--json]
|
|
19
19
|
orp workspace slot <list|set|clear> ...
|
|
20
20
|
orp workspace sync <name-or-id> [--workspace-file <path> | --notes-file <path>] [--dry-run] [--json]
|
|
21
21
|
orp workspace ledger <name-or-id> [--json]
|
|
22
|
-
orp workspace ledger add <name-or-id> (--path <absolute-path> | --here) [--title <title>] [--resume-command <text> | --resume-tool <codex|claude> --resume-session-id <id> | --current-codex] [--append] [--json]
|
|
22
|
+
orp workspace ledger add <name-or-id> (--path <absolute-path> | --here) [--title <title>] [--remote-url <git-url>] [--remote-branch <branch>] [--bootstrap-command <text>] [--resume-command <text> | --resume-tool <codex|claude> --resume-session-id <id> | --current-codex] [--append] [--json]
|
|
23
23
|
orp workspace ledger remove <name-or-id> (--index <n> | --path <absolute-path> | --title <title> | --resume-session-id <id> | --resume-command <text>) [--all] [--json]
|
|
24
24
|
orp workspace -h
|
|
25
25
|
|
|
@@ -36,7 +36,9 @@ Commands:
|
|
|
36
36
|
Notes:
|
|
37
37
|
- Local-only usage works: create a workspace with \`orp workspace create <title-slug>\`, then use \`orp workspace tabs ...\`, \`orp workspace add-tab ...\`, and \`orp workspace remove-tab ...\` without authenticating.
|
|
38
38
|
- Use \`orp workspace list\` for the combined hosted + local workspace inventory.
|
|
39
|
-
- Use \`orp workspace tabs <workspace>\` when you want saved paths plus copyable \`cd ... && codex resume ...\` / \`claude --resume ...\` recovery lines.
|
|
39
|
+
- Use \`orp workspace tabs <workspace>\` when you want saved paths plus copyable \`cd ... && codex resume ...\` / \`claude --resume ...\` recovery lines, along with optional remote repo and bootstrap metadata for another machine.
|
|
40
|
+
- Use \`orp workspace create ... --machine-label ...\` when you want the workspace ledger to stay clearly tied to one rig.
|
|
41
|
+
- Use \`orp workspace add-tab ... --remote-url ... --bootstrap-command ...\` when you want ORP to remember how to recreate the repo on another machine.
|
|
40
42
|
- Use \`orp workspace add-tab ...\` and \`orp workspace remove-tab ...\` when you want to edit the saved workspace ledger explicitly from Terminal.app or any other shell.
|
|
41
43
|
- If you prefer the older ledger-prefixed wording, \`orp workspace ledger\`, \`orp workspace ledger add\`, and \`orp workspace ledger remove\` stay available as aliases.
|
|
42
44
|
- \`main\` and \`offhand\` are reserved slot selectors; use \`orp workspace slot set ...\` to assign them.
|
|
@@ -46,10 +48,12 @@ Notes:
|
|
|
46
48
|
Examples:
|
|
47
49
|
orp workspace create main-cody-1
|
|
48
50
|
orp workspace create main-cody-1 --slot main
|
|
51
|
+
orp workspace create mac-main --machine-label "Mac Studio" --path /absolute/path/to/orp --remote-url git@github.com:SproutSeeds/orp.git --bootstrap-command "npm install"
|
|
49
52
|
orp workspace list
|
|
50
53
|
orp workspace tabs main-cody-1
|
|
51
54
|
orp workspace add-tab main --here --current-codex
|
|
52
55
|
orp workspace add-tab main --path /absolute/path/to/new-project --resume-command "codex resume 019d..."
|
|
56
|
+
orp workspace add-tab main --path /absolute/path/to/new-project --remote-url git@github.com:org/new-project.git --bootstrap-command "npm install"
|
|
53
57
|
orp workspace remove-tab main --path /absolute/path/to/frg-site --resume-session-id 019d348d-5031-78e1-9840-a66deaac33ae
|
|
54
58
|
orp workspace slot set main main-cody-1
|
|
55
59
|
orp workspace slot set offhand research-lab
|
|
@@ -627,6 +627,16 @@ export function buildWorkspaceManifestFromHostedWorkspacePayload(payload) {
|
|
|
627
627
|
version: "1",
|
|
628
628
|
workspaceId: getTextValue(workspace, "workspace_id", "id"),
|
|
629
629
|
title: getTextValue(workspace, "title"),
|
|
630
|
+
machine: captureContext
|
|
631
|
+
? Object.fromEntries(
|
|
632
|
+
Object.entries({
|
|
633
|
+
machineId: getTextValue(captureContext, "machine_id", "machineId"),
|
|
634
|
+
machineLabel: getTextValue(captureContext, "machine_label", "machineLabel"),
|
|
635
|
+
platform: getTextValue(captureContext, "platform"),
|
|
636
|
+
host: getTextValue(captureContext, "host"),
|
|
637
|
+
}).filter(([, value]) => value !== undefined && value !== null),
|
|
638
|
+
)
|
|
639
|
+
: undefined,
|
|
630
640
|
capture: captureContext
|
|
631
641
|
? Object.fromEntries(
|
|
632
642
|
Object.entries({
|
|
@@ -671,6 +681,9 @@ export function buildWorkspaceManifestFromHostedWorkspacePayload(payload) {
|
|
|
671
681
|
path.basename(String(getTextValue(tab, "project_root", "projectRoot") || "").replace(/\/+$/, "")) ||
|
|
672
682
|
undefined,
|
|
673
683
|
path: getTextValue(tab, "project_root", "projectRoot"),
|
|
684
|
+
remoteUrl: getTextValue(tab, "remote_url", "remoteUrl"),
|
|
685
|
+
remoteBranch: getTextValue(tab, "remote_branch", "remoteBranch"),
|
|
686
|
+
bootstrapCommand: getTextValue(tab, "bootstrap_command", "bootstrapCommand"),
|
|
674
687
|
resumeCommand: getTextValue(tab, "resume_command", "resumeCommand"),
|
|
675
688
|
resumeTool: getTextValue(tab, "resume_tool", "resumeTool"),
|
|
676
689
|
resumeSessionId: getTextValue(tab, "resume_session_id", "resumeSessionId"),
|
|
@@ -78,6 +78,9 @@ function normalizeRegistryEntry(rawEntry) {
|
|
|
78
78
|
manifestPath,
|
|
79
79
|
workspaceId: normalizeOptionalString(rawEntry.workspaceId) ?? undefined,
|
|
80
80
|
title: normalizeOptionalString(rawEntry.title) ?? undefined,
|
|
81
|
+
machineId: normalizeOptionalString(rawEntry.machineId) ?? undefined,
|
|
82
|
+
machineLabel: normalizeOptionalString(rawEntry.machineLabel) ?? undefined,
|
|
83
|
+
platform: normalizeOptionalString(rawEntry.platform) ?? undefined,
|
|
81
84
|
host: normalizeOptionalString(rawEntry.host) ?? undefined,
|
|
82
85
|
captureMode: normalizeOptionalString(rawEntry.captureMode) ?? undefined,
|
|
83
86
|
capturedAt: normalizeOptionalString(rawEntry.capturedAt) ?? undefined,
|
|
@@ -312,6 +315,9 @@ export function summarizeManifestForRegistry(manifestPath, manifest) {
|
|
|
312
315
|
manifestPath: normalizedPath,
|
|
313
316
|
workspaceId: normalizeOptionalString(manifest.workspaceId) ?? undefined,
|
|
314
317
|
title: normalizeOptionalString(manifest.title) ?? undefined,
|
|
318
|
+
machineId: normalizeOptionalString(manifest.machine?.machineId) ?? undefined,
|
|
319
|
+
machineLabel: normalizeOptionalString(manifest.machine?.machineLabel) ?? undefined,
|
|
320
|
+
platform: normalizeOptionalString(manifest.machine?.platform) ?? undefined,
|
|
315
321
|
host: normalizeOptionalString(manifest.capture?.host) ?? undefined,
|
|
316
322
|
captureMode: normalizeOptionalString(manifest.capture?.mode) ?? undefined,
|
|
317
323
|
capturedAt: normalizeOptionalString(manifest.capture?.capturedAt) ?? undefined,
|
|
@@ -337,6 +343,9 @@ function serializeManagedWorkspaceManifest(manifest) {
|
|
|
337
343
|
Object.entries({
|
|
338
344
|
title: normalizeOptionalString(tab.title) ?? undefined,
|
|
339
345
|
path: normalizeOptionalString(tab.path) ?? undefined,
|
|
346
|
+
remoteUrl: normalizeOptionalString(tab.remoteUrl) ?? undefined,
|
|
347
|
+
remoteBranch: normalizeOptionalString(tab.remoteBranch) ?? undefined,
|
|
348
|
+
bootstrapCommand: normalizeOptionalString(tab.bootstrapCommand) ?? undefined,
|
|
340
349
|
resumeCommand: resumeCommand ?? undefined,
|
|
341
350
|
resumeTool: resumeTool ?? undefined,
|
|
342
351
|
resumeSessionId: resumeSessionId ?? undefined,
|
|
@@ -353,6 +362,7 @@ function serializeManagedWorkspaceManifest(manifest) {
|
|
|
353
362
|
version: normalized.version,
|
|
354
363
|
workspaceId: normalizeOptionalString(normalized.workspaceId) ?? undefined,
|
|
355
364
|
title: normalizeOptionalString(normalized.title) ?? undefined,
|
|
365
|
+
machine: normalized.machine || undefined,
|
|
356
366
|
capture: normalized.capture || undefined,
|
|
357
367
|
tabs,
|
|
358
368
|
}).filter(([, value]) => value !== undefined),
|
|
@@ -191,6 +191,9 @@ function serializeWorkspaceManifest(manifest) {
|
|
|
191
191
|
Object.entries({
|
|
192
192
|
title: normalizeOptionalString(entry.title) ?? undefined,
|
|
193
193
|
path: String(entry.path).trim(),
|
|
194
|
+
remoteUrl: normalizeOptionalString(entry.remoteUrl) ?? undefined,
|
|
195
|
+
remoteBranch: normalizeOptionalString(entry.remoteBranch) ?? undefined,
|
|
196
|
+
bootstrapCommand: normalizeOptionalString(entry.bootstrapCommand) ?? undefined,
|
|
194
197
|
resumeCommand: normalizeOptionalString(entry.resumeCommand) ?? undefined,
|
|
195
198
|
resumeTool: normalizeOptionalString(entry.resumeTool) ?? undefined,
|
|
196
199
|
resumeSessionId: normalizeOptionalString(entry.resumeSessionId ?? entry.sessionId) ?? undefined,
|
|
@@ -211,6 +214,7 @@ function serializeWorkspaceManifest(manifest) {
|
|
|
211
214
|
version: WORKSPACE_SCHEMA_VERSION,
|
|
212
215
|
workspaceId: normalizeOptionalString(manifest.workspaceId) ?? undefined,
|
|
213
216
|
title: normalizeOptionalString(manifest.title) ?? undefined,
|
|
217
|
+
machine: manifest.machine ?? undefined,
|
|
214
218
|
tabs,
|
|
215
219
|
}).filter(([, value]) => value !== undefined),
|
|
216
220
|
);
|
|
@@ -231,9 +235,13 @@ export function buildWorkspaceSyncPreview({ source, parsed, targetIdea, workspac
|
|
|
231
235
|
version: parsed.manifest.version || WORKSPACE_SCHEMA_VERSION,
|
|
232
236
|
workspaceId: parsed.manifest.workspaceId || workspaceTitle || deriveWorkspaceId(source, parsed),
|
|
233
237
|
title: workspaceTitle || parsed.manifest.title || null,
|
|
238
|
+
machine: parsed.manifest.machine || null,
|
|
234
239
|
tabs: parsed.manifest.tabs.map((entry) => ({
|
|
235
240
|
title: entry.title || deriveBaseTitle(entry),
|
|
236
241
|
path: entry.path,
|
|
242
|
+
remoteUrl: entry.remoteUrl || null,
|
|
243
|
+
remoteBranch: entry.remoteBranch || null,
|
|
244
|
+
bootstrapCommand: entry.bootstrapCommand || null,
|
|
237
245
|
resumeCommand: entry.resumeCommand || null,
|
|
238
246
|
resumeTool: entry.resumeTool || null,
|
|
239
247
|
resumeSessionId: entry.sessionId || null,
|
|
@@ -245,9 +253,13 @@ export function buildWorkspaceSyncPreview({ source, parsed, targetIdea, workspac
|
|
|
245
253
|
version: WORKSPACE_SCHEMA_VERSION,
|
|
246
254
|
workspaceId: workspaceTitle || deriveWorkspaceId(source, parsed),
|
|
247
255
|
title: workspaceTitle || null,
|
|
256
|
+
machine: null,
|
|
248
257
|
tabs: parsed.entries.map((entry) => ({
|
|
249
258
|
title: deriveBaseTitle(entry),
|
|
250
259
|
path: entry.path,
|
|
260
|
+
remoteUrl: entry.remoteUrl || null,
|
|
261
|
+
remoteBranch: entry.remoteBranch || null,
|
|
262
|
+
bootstrapCommand: entry.bootstrapCommand || null,
|
|
251
263
|
resumeCommand: getResumeCommand(entry),
|
|
252
264
|
resumeTool: resolveResumeMetadata(entry).resumeTool,
|
|
253
265
|
resumeSessionId: resolveResumeMetadata(entry).resumeSessionId,
|