open-research-protocol 0.4.34 → 0.4.35
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 +26 -0
- package/cli/__pycache__/orp.cpython-311.pyc +0 -0
- package/docs/ORP_HOSTED_WORKSPACE_CONTRACT.md +39 -0
- package/package.json +1 -1
- package/packages/orp-workspace-launcher/src/core-plan.js +32 -0
- package/packages/orp-workspace-launcher/src/hosted-state.js +41 -9
- package/packages/orp-workspace-launcher/src/index.js +6 -0
- package/packages/orp-workspace-launcher/src/local-inventory.js +681 -0
- package/packages/orp-workspace-launcher/src/orp.js +23 -0
- package/packages/orp-workspace-launcher/src/registry.js +24 -11
- package/packages/orp-workspace-launcher/src/sync.js +229 -12
- package/packages/orp-workspace-launcher/test/hosted-state.test.js +53 -0
- package/packages/orp-workspace-launcher/test/local-inventory.test.js +126 -0
- package/packages/orp-workspace-launcher/test/orp.test.js +19 -0
- package/scripts/__pycache__/orp-kernel-agent-pilot.cpython-311.pyc +0 -0
- package/scripts/__pycache__/orp-kernel-agent-replication.cpython-311.pyc +0 -0
- package/scripts/__pycache__/orp-kernel-benchmark.cpython-311.pyc +0 -0
- package/scripts/__pycache__/orp-kernel-canonical-continuation.cpython-311.pyc +0 -0
- package/scripts/__pycache__/orp-kernel-continuation-pilot.cpython-311.pyc +0 -0
package/CHANGELOG.md
CHANGED
|
@@ -6,6 +6,32 @@ There was no prior in-repo changelog file, so the first formal entry starts
|
|
|
6
6
|
with the currently shipped `v0.4.4` release and summarizes the full release
|
|
7
7
|
delta reflected in this repo.
|
|
8
8
|
|
|
9
|
+
## v0.4.35 - 2026-04-30
|
|
10
|
+
|
|
11
|
+
This release makes the hosted workspace sync contract canonical from the ORP
|
|
12
|
+
CLI side, so hosted ORP can render the same projects, resume sessions, plans,
|
|
13
|
+
and tasks that local workspace tooling sees.
|
|
14
|
+
|
|
15
|
+
### Added
|
|
16
|
+
|
|
17
|
+
- Added local workspace inventory reconciliation for `orp workspace sync`,
|
|
18
|
+
starting from the selected workspace ledger and refreshing known projects
|
|
19
|
+
from ORP startup state, Clawdad state, and recent Codex session metadata.
|
|
20
|
+
- Added hosted workspace state push support that carries per-project sync
|
|
21
|
+
metadata, linked ORP idea/feature ids, plan summaries, and task lists.
|
|
22
|
+
- Added a hosted workspace sync contract document covering the canonical
|
|
23
|
+
source order and required hosted payload fields.
|
|
24
|
+
|
|
25
|
+
### Changed
|
|
26
|
+
|
|
27
|
+
- `orp workspace sync main` now bridges a local managed workspace file to the
|
|
28
|
+
matching hosted workspace by durable `workspaceId` before pushing state.
|
|
29
|
+
- Hosted workspace sync skips the idea-note compatibility mirror when the
|
|
30
|
+
hosted workspace state can be written directly, avoiding stale or truncated
|
|
31
|
+
plan/task payloads.
|
|
32
|
+
- Workspace manifests now round-trip activity timestamps, sync timestamps,
|
|
33
|
+
sync source labels, plan data, tasks, and linked ORP project references.
|
|
34
|
+
|
|
9
35
|
## v0.4.34 - 2026-04-30
|
|
10
36
|
|
|
11
37
|
This release connects ORP frontier plans to hosted ORP ideas/features and lets
|
|
Binary file
|
|
@@ -27,6 +27,45 @@ The canonical hosted source of truth should be one hosted workspace record:
|
|
|
27
27
|
|
|
28
28
|
Idea notes are a compatibility bridge only after this contract lands.
|
|
29
29
|
|
|
30
|
+
## CLI Sync Contract
|
|
31
|
+
|
|
32
|
+
`orp workspace sync <selector>` is the canonical local-to-hosted sync path.
|
|
33
|
+
The web app should render the hosted workspace state produced by this command,
|
|
34
|
+
not reconstruct a competing workspace model.
|
|
35
|
+
|
|
36
|
+
The local canonical input is a reconciled workspace snapshot:
|
|
37
|
+
|
|
38
|
+
1. Start with the selected ORP workspace ledger, usually
|
|
39
|
+
`orp workspace tabs main`.
|
|
40
|
+
2. If that selector resolves to a local workspace file, match a hosted
|
|
41
|
+
workspace by the same `workspaceId` before writing hosted state.
|
|
42
|
+
3. Reconcile known local projects from ORP project startup state
|
|
43
|
+
(`orp/state.json`, including historical startup result manifests).
|
|
44
|
+
4. Use Clawdad state only to refresh projects already known from the ledger or
|
|
45
|
+
ORP startup manifests, unless a caller explicitly opts into Clawdad-only
|
|
46
|
+
projects.
|
|
47
|
+
5. Use recent Codex session metadata to refresh known project paths with the
|
|
48
|
+
newest local `codex resume ...` session. Codex-only paths are not added by
|
|
49
|
+
default.
|
|
50
|
+
|
|
51
|
+
The pushed hosted state must include, for every project/tab where available:
|
|
52
|
+
|
|
53
|
+
- `title`
|
|
54
|
+
- `project_root` / local `path`
|
|
55
|
+
- resume command plus structured `resume_tool` and `resume_session_id`
|
|
56
|
+
- `last_activity_at_utc`
|
|
57
|
+
- `last_synced_at_utc`
|
|
58
|
+
- `linked_idea_id`
|
|
59
|
+
- `linked_feature_id`
|
|
60
|
+
- `plan`
|
|
61
|
+
- `tasks`
|
|
62
|
+
|
|
63
|
+
Idea notes are only a compatibility mirror. When sync can write the matched
|
|
64
|
+
hosted workspace state directly, the hosted workspace `state` is authoritative
|
|
65
|
+
and the idea-note mirror may be skipped to avoid truncating or conflicting with
|
|
66
|
+
the full payload. If no hosted workspace target exists, sync may still write a
|
|
67
|
+
compact ` ```orp-workspace ` block to the linked idea.
|
|
68
|
+
|
|
30
69
|
## Resource Model
|
|
31
70
|
|
|
32
71
|
### Hosted Workspace
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "open-research-protocol",
|
|
3
|
-
"version": "0.4.
|
|
3
|
+
"version": "0.4.35",
|
|
4
4
|
"description": "ORP CLI (Open Research Protocol): workspace ledgers, secrets, scheduling, governed execution, and agent-friendly research workflows.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"author": "Fractal Research Group <cody@frg.earth>",
|
|
@@ -267,6 +267,12 @@ function normalizeStructuredTab(rawTab, index) {
|
|
|
267
267
|
const tmuxSessionName = normalizeOptionalString(rawTab.tmuxSessionName);
|
|
268
268
|
const plan = rawTab.plan && typeof rawTab.plan === "object" && !Array.isArray(rawTab.plan) ? rawTab.plan : null;
|
|
269
269
|
const tasks = Array.isArray(rawTab.tasks) ? rawTab.tasks : [];
|
|
270
|
+
const lastActivityAt = normalizeOptionalString(
|
|
271
|
+
rawTab.lastActivityAt ?? rawTab.last_activity_at_utc ?? rawTab.lastActivityAtUtc,
|
|
272
|
+
);
|
|
273
|
+
const lastSyncedAt = normalizeOptionalString(
|
|
274
|
+
rawTab.lastSyncedAt ?? rawTab.last_synced_at_utc ?? rawTab.lastSyncedAtUtc,
|
|
275
|
+
);
|
|
270
276
|
|
|
271
277
|
return {
|
|
272
278
|
lineNumber: index + 1,
|
|
@@ -285,6 +291,9 @@ function normalizeStructuredTab(rawTab, index) {
|
|
|
285
291
|
linkedFeatureId: normalizeOptionalString(rawTab.linkedFeatureId ?? rawTab.linked_feature_id),
|
|
286
292
|
plan,
|
|
287
293
|
tasks,
|
|
294
|
+
lastActivityAt,
|
|
295
|
+
lastSyncedAt,
|
|
296
|
+
syncSource: normalizeOptionalString(rawTab.syncSource ?? rawTab.sync_source),
|
|
288
297
|
};
|
|
289
298
|
}
|
|
290
299
|
|
|
@@ -321,6 +330,21 @@ function normalizeStructuredProject(rawProject, projectIndex) {
|
|
|
321
330
|
rawProject.linked_feature_id,
|
|
322
331
|
plan: rawSession.plan ?? rawProject.plan,
|
|
323
332
|
tasks: rawSession.tasks ?? rawProject.tasks,
|
|
333
|
+
lastActivityAt:
|
|
334
|
+
rawSession.lastActivityAt ??
|
|
335
|
+
rawSession.last_activity_at_utc ??
|
|
336
|
+
rawSession.lastActivityAtUtc ??
|
|
337
|
+
rawProject.lastActivityAt ??
|
|
338
|
+
rawProject.last_activity_at_utc ??
|
|
339
|
+
rawProject.lastActivityAtUtc,
|
|
340
|
+
lastSyncedAt:
|
|
341
|
+
rawSession.lastSyncedAt ??
|
|
342
|
+
rawSession.last_synced_at_utc ??
|
|
343
|
+
rawSession.lastSyncedAtUtc ??
|
|
344
|
+
rawProject.lastSyncedAt ??
|
|
345
|
+
rawProject.last_synced_at_utc ??
|
|
346
|
+
rawProject.lastSyncedAtUtc,
|
|
347
|
+
syncSource: rawSession.syncSource ?? rawSession.sync_source ?? rawProject.syncSource ?? rawProject.sync_source,
|
|
324
348
|
},
|
|
325
349
|
sessionIndex,
|
|
326
350
|
);
|
|
@@ -399,6 +423,8 @@ export function buildWorkspaceProjectGroups(entries = []) {
|
|
|
399
423
|
linkedFeatureId: normalizeOptionalString(entry.linkedFeatureId),
|
|
400
424
|
plan: entry.plan && typeof entry.plan === "object" && !Array.isArray(entry.plan) ? entry.plan : null,
|
|
401
425
|
tasks: Array.isArray(entry.tasks) && entry.tasks.length > 0 ? entry.tasks : [],
|
|
426
|
+
lastActivityAt: normalizeOptionalString(entry.lastActivityAt ?? entry.last_activity_at_utc),
|
|
427
|
+
lastSyncedAt: normalizeOptionalString(entry.lastSyncedAt ?? entry.last_synced_at_utc),
|
|
402
428
|
sessions: [],
|
|
403
429
|
});
|
|
404
430
|
}
|
|
@@ -412,6 +438,8 @@ export function buildWorkspaceProjectGroups(entries = []) {
|
|
|
412
438
|
project.plan =
|
|
413
439
|
project.plan ||
|
|
414
440
|
(entry.plan && typeof entry.plan === "object" && !Array.isArray(entry.plan) ? entry.plan : null);
|
|
441
|
+
project.lastActivityAt = project.lastActivityAt || normalizeOptionalString(entry.lastActivityAt ?? entry.last_activity_at_utc);
|
|
442
|
+
project.lastSyncedAt = project.lastSyncedAt || normalizeOptionalString(entry.lastSyncedAt ?? entry.last_synced_at_utc);
|
|
415
443
|
if ((!Array.isArray(project.tasks) || project.tasks.length === 0) && Array.isArray(entry.tasks) && entry.tasks.length > 0) {
|
|
416
444
|
project.tasks = entry.tasks;
|
|
417
445
|
}
|
|
@@ -426,6 +454,8 @@ export function buildWorkspaceProjectGroups(entries = []) {
|
|
|
426
454
|
resumeSessionId: resume.resumeSessionId || undefined,
|
|
427
455
|
codexSessionId: resume.resumeTool === "codex" ? resume.resumeSessionId || undefined : undefined,
|
|
428
456
|
claudeSessionId: resume.resumeTool === "claude" ? resume.resumeSessionId || undefined : undefined,
|
|
457
|
+
lastActivityAt: normalizeOptionalString(entry.lastActivityAt ?? entry.last_activity_at_utc) || undefined,
|
|
458
|
+
lastSyncedAt: normalizeOptionalString(entry.lastSyncedAt ?? entry.last_synced_at_utc) || undefined,
|
|
429
459
|
}).filter(([, value]) => value !== undefined),
|
|
430
460
|
),
|
|
431
461
|
);
|
|
@@ -443,6 +473,8 @@ export function buildWorkspaceProjectGroups(entries = []) {
|
|
|
443
473
|
linkedFeatureId: project.linkedFeatureId || undefined,
|
|
444
474
|
plan: project.plan || undefined,
|
|
445
475
|
tasks: Array.isArray(project.tasks) && project.tasks.length > 0 ? project.tasks : undefined,
|
|
476
|
+
lastActivityAt: project.lastActivityAt || undefined,
|
|
477
|
+
lastSyncedAt: project.lastSyncedAt || undefined,
|
|
446
478
|
sessionCount: project.sessions.length,
|
|
447
479
|
sessions: project.sessions,
|
|
448
480
|
}).filter(([, value]) => value !== undefined),
|
|
@@ -72,6 +72,7 @@ function normalizePreviousHostedTabs(workspace) {
|
|
|
72
72
|
focusSummary: normalizeOptionalString(tab.focus_summary ?? tab.focusSummary),
|
|
73
73
|
trajectorySummary: normalizeOptionalString(tab.trajectory_summary ?? tab.trajectorySummary),
|
|
74
74
|
lastActivityAt: normalizeOptionalString(tab.last_activity_at_utc ?? tab.lastActivityAtUtc),
|
|
75
|
+
lastSyncedAt: normalizeOptionalString(tab.last_synced_at_utc ?? tab.lastSyncedAtUtc),
|
|
75
76
|
linkedIdeaId: normalizeOptionalString(tab.linked_idea_id ?? tab.linkedIdeaId),
|
|
76
77
|
linkedFeatureId: normalizeOptionalString(tab.linked_feature_id ?? tab.linkedFeatureId),
|
|
77
78
|
plan: tab.plan && typeof tab.plan === "object" && !Array.isArray(tab.plan) ? tab.plan : null,
|
|
@@ -116,6 +117,8 @@ function buildHostedProjectGroups(tabs) {
|
|
|
116
117
|
bootstrap_command: normalizeOptionalString(tab.bootstrap_command),
|
|
117
118
|
linked_idea_id: normalizeOptionalString(tab.linked_idea_id),
|
|
118
119
|
linked_feature_id: normalizeOptionalString(tab.linked_feature_id),
|
|
120
|
+
last_activity_at_utc: normalizeOptionalString(tab.last_activity_at_utc),
|
|
121
|
+
last_synced_at_utc: normalizeOptionalString(tab.last_synced_at_utc),
|
|
119
122
|
plan: tab.plan && typeof tab.plan === "object" && !Array.isArray(tab.plan) ? tab.plan : undefined,
|
|
120
123
|
tasks: Array.isArray(tab.tasks) ? tab.tasks : undefined,
|
|
121
124
|
sessions: [],
|
|
@@ -127,6 +130,8 @@ function buildHostedProjectGroups(tabs) {
|
|
|
127
130
|
project.bootstrap_command = project.bootstrap_command || normalizeOptionalString(tab.bootstrap_command);
|
|
128
131
|
project.linked_idea_id = project.linked_idea_id || normalizeOptionalString(tab.linked_idea_id);
|
|
129
132
|
project.linked_feature_id = project.linked_feature_id || normalizeOptionalString(tab.linked_feature_id);
|
|
133
|
+
project.last_activity_at_utc = project.last_activity_at_utc || normalizeOptionalString(tab.last_activity_at_utc);
|
|
134
|
+
project.last_synced_at_utc = project.last_synced_at_utc || normalizeOptionalString(tab.last_synced_at_utc);
|
|
130
135
|
project.plan = project.plan || (tab.plan && typeof tab.plan === "object" && !Array.isArray(tab.plan) ? tab.plan : undefined);
|
|
131
136
|
if ((!Array.isArray(project.tasks) || project.tasks.length === 0) && Array.isArray(tab.tasks) && tab.tasks.length > 0) {
|
|
132
137
|
project.tasks = tab.tasks;
|
|
@@ -143,6 +148,8 @@ function buildHostedProjectGroups(tabs) {
|
|
|
143
148
|
claude_session_id: normalizeOptionalString(tab.claude_session_id),
|
|
144
149
|
status: normalizeOptionalString(tab.status),
|
|
145
150
|
current_task: normalizeOptionalString(tab.current_task),
|
|
151
|
+
last_activity_at_utc: normalizeOptionalString(tab.last_activity_at_utc),
|
|
152
|
+
last_synced_at_utc: normalizeOptionalString(tab.last_synced_at_utc),
|
|
146
153
|
}).filter(([, value]) => value !== undefined && value !== null),
|
|
147
154
|
),
|
|
148
155
|
);
|
|
@@ -158,6 +165,8 @@ function buildHostedProjectGroups(tabs) {
|
|
|
158
165
|
bootstrap_command: project.bootstrap_command || undefined,
|
|
159
166
|
linked_idea_id: project.linked_idea_id || undefined,
|
|
160
167
|
linked_feature_id: project.linked_feature_id || undefined,
|
|
168
|
+
last_activity_at_utc: project.last_activity_at_utc || undefined,
|
|
169
|
+
last_synced_at_utc: project.last_synced_at_utc || undefined,
|
|
161
170
|
plan: project.plan || undefined,
|
|
162
171
|
tasks: Array.isArray(project.tasks) && project.tasks.length > 0 ? project.tasks : undefined,
|
|
163
172
|
session_count: project.sessions.length,
|
|
@@ -448,7 +457,7 @@ export function buildHostedWorkspaceState(manifest, options = {}) {
|
|
|
448
457
|
const title = normalizeOptionalString(tab.title) || previous?.title || null;
|
|
449
458
|
const projectRoot = normalizeOptionalString(tab.path);
|
|
450
459
|
const projectContext = readProjectFrontierContext(projectRoot, projectContextCache);
|
|
451
|
-
const repoLabel = previous?.repoLabel || path.basename(String(projectRoot).replace(/\/+$/, "")) || projectRoot;
|
|
460
|
+
const repoLabel = title || previous?.repoLabel || path.basename(String(projectRoot).replace(/\/+$/, "")) || projectRoot;
|
|
452
461
|
const terminalTitle = previous?.terminalTitle || title || repoLabel;
|
|
453
462
|
const resume = resolveResumeMetadata({
|
|
454
463
|
resumeCommand: tab.resumeCommand,
|
|
@@ -475,6 +484,27 @@ export function buildHostedWorkspaceState(manifest, options = {}) {
|
|
|
475
484
|
title,
|
|
476
485
|
orderIndex: index,
|
|
477
486
|
});
|
|
487
|
+
const plan =
|
|
488
|
+
tab.plan && typeof tab.plan === "object" && !Array.isArray(tab.plan)
|
|
489
|
+
? tab.plan
|
|
490
|
+
: projectContext?.plan || previous?.plan || undefined;
|
|
491
|
+
const tasks =
|
|
492
|
+
Array.isArray(tab.tasks) && tab.tasks.length > 0
|
|
493
|
+
? tab.tasks
|
|
494
|
+
: Array.isArray(projectContext?.tasks) && projectContext.tasks.length > 0
|
|
495
|
+
? projectContext.tasks
|
|
496
|
+
: Array.isArray(previous?.tasks) && previous.tasks.length > 0
|
|
497
|
+
? previous.tasks
|
|
498
|
+
: undefined;
|
|
499
|
+
const lastActivityAt =
|
|
500
|
+
normalizeOptionalString(tab.lastActivityAt ?? tab.last_activity_at_utc ?? tab.lastActivityAtUtc) ||
|
|
501
|
+
previous?.lastActivityAt ||
|
|
502
|
+
undefined;
|
|
503
|
+
const lastSyncedAt =
|
|
504
|
+
normalizeOptionalString(tab.lastSyncedAt ?? tab.last_synced_at_utc ?? tab.lastSyncedAtUtc) ||
|
|
505
|
+
previous?.lastSyncedAt ||
|
|
506
|
+
updatedAt ||
|
|
507
|
+
undefined;
|
|
478
508
|
|
|
479
509
|
return Object.fromEntries(
|
|
480
510
|
Object.entries({
|
|
@@ -496,7 +526,9 @@ export function buildHostedWorkspaceState(manifest, options = {}) {
|
|
|
496
526
|
current_task: previous?.currentTask || undefined,
|
|
497
527
|
focus_summary: previous?.focusSummary || undefined,
|
|
498
528
|
trajectory_summary: previous?.trajectorySummary || undefined,
|
|
499
|
-
last_activity_at_utc:
|
|
529
|
+
last_activity_at_utc: lastActivityAt,
|
|
530
|
+
last_synced_at_utc: lastSyncedAt,
|
|
531
|
+
sync_source: normalizeOptionalString(tab.syncSource ?? tab.sync_source) || undefined,
|
|
500
532
|
linked_feature_id:
|
|
501
533
|
normalizeOptionalString(tab.linkedFeatureId ?? tab.linked_feature_id) ||
|
|
502
534
|
projectContext?.link?.activeFeatureId ||
|
|
@@ -507,13 +539,8 @@ export function buildHostedWorkspaceState(manifest, options = {}) {
|
|
|
507
539
|
projectContext?.link?.ideaId ||
|
|
508
540
|
previous?.linkedIdeaId ||
|
|
509
541
|
undefined,
|
|
510
|
-
plan
|
|
511
|
-
tasks
|
|
512
|
-
Array.isArray(projectContext?.tasks) && projectContext.tasks.length > 0
|
|
513
|
-
? projectContext.tasks
|
|
514
|
-
: Array.isArray(previous?.tasks) && previous.tasks.length > 0
|
|
515
|
-
? previous.tasks
|
|
516
|
-
: undefined,
|
|
542
|
+
plan,
|
|
543
|
+
tasks,
|
|
517
544
|
}).filter(([, value]) => value !== undefined && value !== null),
|
|
518
545
|
);
|
|
519
546
|
});
|
|
@@ -531,6 +558,10 @@ export function buildHostedWorkspaceState(manifest, options = {}) {
|
|
|
531
558
|
durable_backend: options.durableBackend || "manual-ledger",
|
|
532
559
|
}).filter(([, value]) => value !== undefined && value !== null),
|
|
533
560
|
);
|
|
561
|
+
const sourceContract =
|
|
562
|
+
options.localInventory?.contract && typeof options.localInventory.contract === "object" && !Array.isArray(options.localInventory.contract)
|
|
563
|
+
? options.localInventory.contract
|
|
564
|
+
: undefined;
|
|
534
565
|
|
|
535
566
|
const stateVersion = Math.max(1, (getHostedIntegerValue(previousState, "state_version", "stateVersion") || 0) + 1);
|
|
536
567
|
const snapshotSeed = JSON.stringify({
|
|
@@ -558,6 +589,7 @@ export function buildHostedWorkspaceState(manifest, options = {}) {
|
|
|
558
589
|
tab_count: tabs.length,
|
|
559
590
|
project_count: projects.length,
|
|
560
591
|
capture_context: Object.keys(captureContext).length > 0 ? captureContext : undefined,
|
|
592
|
+
source_contract: sourceContract,
|
|
561
593
|
projects,
|
|
562
594
|
tabs,
|
|
563
595
|
}).filter(([, value]) => value !== undefined && value !== null),
|
|
@@ -63,6 +63,7 @@ export {
|
|
|
63
63
|
fetchIdeaPayload,
|
|
64
64
|
fetchIdeasPayload,
|
|
65
65
|
fetchHostedWorkspacesPayload,
|
|
66
|
+
findHostedWorkspaceByWorkspaceId,
|
|
66
67
|
findHostedWorkspaceByLinkedIdea,
|
|
67
68
|
findHostedWorkspaceLinkedToIdea,
|
|
68
69
|
loadWorkspaceSource,
|
|
@@ -72,6 +73,11 @@ export {
|
|
|
72
73
|
resolveWorkspaceSelectorFromCollections,
|
|
73
74
|
updateIdeaPayload,
|
|
74
75
|
} from "./orp.js";
|
|
76
|
+
export {
|
|
77
|
+
buildLocalProjectInventory,
|
|
78
|
+
inferLocalProjectRoots,
|
|
79
|
+
mergeLocalProjectInventoryIntoManifest,
|
|
80
|
+
} from "./local-inventory.js";
|
|
75
81
|
export {
|
|
76
82
|
cacheManagedWorkspaceManifest,
|
|
77
83
|
clearWorkspaceSlot,
|