open-research-protocol 0.4.14 → 0.4.15
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 +50 -0
- package/README.md +273 -144
- package/bin/orp.js +14 -1
- package/cli/orp.py +14846 -9925
- package/docs/AGENT_LOOP.md +13 -0
- package/docs/AGENT_MODES.md +79 -0
- package/docs/CANONICAL_CLI_BOUNDARY.md +15 -0
- package/docs/EXCHANGE.md +94 -0
- package/docs/LAUNCH_KIT.md +107 -0
- package/docs/ORP_HOSTED_WORKSPACE_CONTRACT.md +295 -0
- package/docs/ORP_PUBLIC_LAUNCH_CHECKLIST.md +5 -0
- package/docs/START_HERE.md +567 -0
- package/package.json +4 -2
- package/packages/lifeops-orp/README.md +67 -0
- package/packages/lifeops-orp/package.json +48 -0
- package/packages/lifeops-orp/src/index.d.ts +106 -0
- package/packages/lifeops-orp/src/index.js +7 -0
- package/packages/lifeops-orp/src/mapping.js +309 -0
- package/packages/lifeops-orp/src/workspace.js +108 -0
- package/packages/lifeops-orp/test/orp.test.js +187 -0
- package/packages/orp-workspace-launcher/README.md +82 -0
- package/packages/orp-workspace-launcher/package.json +39 -0
- package/packages/orp-workspace-launcher/src/commands.js +77 -0
- package/packages/orp-workspace-launcher/src/core-plan.js +506 -0
- package/packages/orp-workspace-launcher/src/hosted-state.js +208 -0
- package/packages/orp-workspace-launcher/src/index.js +82 -0
- package/packages/orp-workspace-launcher/src/ledger.js +745 -0
- package/packages/orp-workspace-launcher/src/list.js +488 -0
- package/packages/orp-workspace-launcher/src/orp-command.js +126 -0
- package/packages/orp-workspace-launcher/src/orp.js +912 -0
- package/packages/orp-workspace-launcher/src/registry.js +558 -0
- package/packages/orp-workspace-launcher/src/slot.js +188 -0
- package/packages/orp-workspace-launcher/src/sync.js +363 -0
- package/packages/orp-workspace-launcher/src/tabs.js +166 -0
- package/packages/orp-workspace-launcher/test/commands.test.js +164 -0
- package/packages/orp-workspace-launcher/test/core-plan.test.js +253 -0
- package/packages/orp-workspace-launcher/test/fixtures/smoke-notes.txt +2 -0
- package/packages/orp-workspace-launcher/test/fixtures/workspace-manifest.json +17 -0
- package/packages/orp-workspace-launcher/test/ledger.test.js +244 -0
- package/packages/orp-workspace-launcher/test/list.test.js +299 -0
- package/packages/orp-workspace-launcher/test/orp-command.test.js +44 -0
- package/packages/orp-workspace-launcher/test/orp.test.js +224 -0
- package/packages/orp-workspace-launcher/test/tabs.test.js +168 -0
- package/scripts/orp-kernel-agent-pilot.py +10 -1
- package/scripts/orp-kernel-agent-replication.py +10 -1
- package/scripts/orp-kernel-canonical-continuation.py +10 -1
- package/scripts/orp-kernel-continuation-pilot.py +10 -1
- package/scripts/render-terminal-demo.py +416 -0
- package/spec/v1/exchange-report.schema.json +105 -0
- package/spec/v1/hosted-workspace-event.schema.json +102 -0
- package/spec/v1/hosted-workspace.schema.json +332 -0
- package/spec/v1/workspace.schema.json +108 -0
|
@@ -0,0 +1,208 @@
|
|
|
1
|
+
import os from "node:os";
|
|
2
|
+
import path from "node:path";
|
|
3
|
+
import crypto from "node:crypto";
|
|
4
|
+
|
|
5
|
+
import { resolveResumeMetadata } from "./core-plan.js";
|
|
6
|
+
|
|
7
|
+
function normalizeOptionalString(value) {
|
|
8
|
+
if (value == null) {
|
|
9
|
+
return null;
|
|
10
|
+
}
|
|
11
|
+
const trimmed = String(value).trim();
|
|
12
|
+
return trimmed.length > 0 ? trimmed : null;
|
|
13
|
+
}
|
|
14
|
+
|
|
15
|
+
function hashText(value) {
|
|
16
|
+
return crypto.createHash("sha256").update(String(value || ""), "utf8").digest("hex");
|
|
17
|
+
}
|
|
18
|
+
|
|
19
|
+
function getHostedObjectValue(record, ...keys) {
|
|
20
|
+
for (const key of keys) {
|
|
21
|
+
const value = record?.[key];
|
|
22
|
+
if (value && typeof value === "object" && !Array.isArray(value)) {
|
|
23
|
+
return value;
|
|
24
|
+
}
|
|
25
|
+
}
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function getHostedIntegerValue(record, ...keys) {
|
|
30
|
+
for (const key of keys) {
|
|
31
|
+
const value = record?.[key];
|
|
32
|
+
if (Number.isInteger(value)) {
|
|
33
|
+
return value;
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return null;
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function normalizePreviousHostedTabs(workspace) {
|
|
40
|
+
const state = getHostedObjectValue(workspace, "state") || {};
|
|
41
|
+
const tabs = Array.isArray(state.tabs) ? state.tabs : Array.isArray(workspace?.tabs) ? workspace.tabs : [];
|
|
42
|
+
|
|
43
|
+
return tabs.map((tab) => {
|
|
44
|
+
const resume = resolveResumeMetadata({
|
|
45
|
+
resumeCommand: tab.resume_command ?? tab.resumeCommand,
|
|
46
|
+
resumeTool: tab.resume_tool ?? tab.resumeTool,
|
|
47
|
+
resumeSessionId:
|
|
48
|
+
tab.resume_session_id ??
|
|
49
|
+
tab.resumeSessionId ??
|
|
50
|
+
tab.codex_session_id ??
|
|
51
|
+
tab.codexSessionId ??
|
|
52
|
+
tab.claude_session_id ??
|
|
53
|
+
tab.claudeSessionId,
|
|
54
|
+
codexSessionId: tab.codex_session_id ?? tab.codexSessionId,
|
|
55
|
+
claudeSessionId: tab.claude_session_id ?? tab.claudeSessionId,
|
|
56
|
+
});
|
|
57
|
+
|
|
58
|
+
return {
|
|
59
|
+
tabId: normalizeOptionalString(tab.tab_id ?? tab.tabId),
|
|
60
|
+
title: normalizeOptionalString(tab.title),
|
|
61
|
+
path: normalizeOptionalString(tab.project_root ?? tab.projectRoot),
|
|
62
|
+
repoLabel: normalizeOptionalString(tab.repo_label ?? tab.repoLabel),
|
|
63
|
+
terminalTitle: normalizeOptionalString(tab.terminal_title ?? tab.terminalTitle),
|
|
64
|
+
resumeCommand: resume.resumeCommand,
|
|
65
|
+
resumeTool: resume.resumeTool,
|
|
66
|
+
resumeSessionId: resume.resumeSessionId,
|
|
67
|
+
currentTask: normalizeOptionalString(tab.current_task ?? tab.currentTask),
|
|
68
|
+
focusSummary: normalizeOptionalString(tab.focus_summary ?? tab.focusSummary),
|
|
69
|
+
trajectorySummary: normalizeOptionalString(tab.trajectory_summary ?? tab.trajectorySummary),
|
|
70
|
+
lastActivityAt: normalizeOptionalString(tab.last_activity_at_utc ?? tab.lastActivityAtUtc),
|
|
71
|
+
linkedIdeaId: normalizeOptionalString(tab.linked_idea_id ?? tab.linkedIdeaId),
|
|
72
|
+
linkedFeatureId: normalizeOptionalString(tab.linked_feature_id ?? tab.linkedFeatureId),
|
|
73
|
+
used: false,
|
|
74
|
+
};
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
function matchPreviousHostedTab(tab, previousTabs) {
|
|
79
|
+
const normalizedTitle = normalizeOptionalString(tab.title);
|
|
80
|
+
|
|
81
|
+
let match =
|
|
82
|
+
previousTabs.find(
|
|
83
|
+
(candidate) => !candidate.used && candidate.path === tab.path && candidate.title === normalizedTitle,
|
|
84
|
+
) || null;
|
|
85
|
+
|
|
86
|
+
if (!match) {
|
|
87
|
+
match = previousTabs.find((candidate) => !candidate.used && candidate.path === tab.path) || null;
|
|
88
|
+
}
|
|
89
|
+
|
|
90
|
+
if (match) {
|
|
91
|
+
match.used = true;
|
|
92
|
+
}
|
|
93
|
+
|
|
94
|
+
return match;
|
|
95
|
+
}
|
|
96
|
+
|
|
97
|
+
export function buildHostedWorkspaceState(manifest, options = {}) {
|
|
98
|
+
if (!manifest || typeof manifest !== "object" || Array.isArray(manifest)) {
|
|
99
|
+
throw new Error("workspace manifest is required to build a hosted workspace state payload");
|
|
100
|
+
}
|
|
101
|
+
if (!Array.isArray(manifest.tabs) || manifest.tabs.length === 0) {
|
|
102
|
+
throw new Error("workspace manifest must include at least one saved tab");
|
|
103
|
+
}
|
|
104
|
+
|
|
105
|
+
const previousWorkspace =
|
|
106
|
+
options.previousWorkspace && typeof options.previousWorkspace === "object" && !Array.isArray(options.previousWorkspace)
|
|
107
|
+
? options.previousWorkspace
|
|
108
|
+
: null;
|
|
109
|
+
const previousState = getHostedObjectValue(previousWorkspace, "state") || {};
|
|
110
|
+
const capturedAt = normalizeOptionalString(options.capturedAt) || new Date().toISOString();
|
|
111
|
+
const updatedAt = normalizeOptionalString(options.updatedAt) || capturedAt;
|
|
112
|
+
const previousTabs = normalizePreviousHostedTabs(previousWorkspace);
|
|
113
|
+
|
|
114
|
+
const tabs = manifest.tabs.map((tab, index) => {
|
|
115
|
+
const previous = matchPreviousHostedTab(tab, previousTabs);
|
|
116
|
+
const title = normalizeOptionalString(tab.title) || previous?.title || null;
|
|
117
|
+
const projectRoot = normalizeOptionalString(tab.path);
|
|
118
|
+
const repoLabel = previous?.repoLabel || path.basename(String(projectRoot).replace(/\/+$/, "")) || projectRoot;
|
|
119
|
+
const terminalTitle = previous?.terminalTitle || title || repoLabel;
|
|
120
|
+
const resume = resolveResumeMetadata({
|
|
121
|
+
resumeCommand: tab.resumeCommand,
|
|
122
|
+
resumeTool: tab.resumeTool,
|
|
123
|
+
resumeSessionId: tab.resumeSessionId ?? tab.sessionId,
|
|
124
|
+
codexSessionId: tab.codexSessionId,
|
|
125
|
+
claudeSessionId: tab.claudeSessionId,
|
|
126
|
+
});
|
|
127
|
+
const previousResume = resolveResumeMetadata(previous || {});
|
|
128
|
+
const resumeCommand = resume.resumeCommand || previousResume.resumeCommand || undefined;
|
|
129
|
+
const resumeTool = resume.resumeTool || previousResume.resumeTool || undefined;
|
|
130
|
+
const resumeSessionId = resume.resumeSessionId || previousResume.resumeSessionId || undefined;
|
|
131
|
+
const codexSessionId =
|
|
132
|
+
(resumeTool === "codex" ? resumeSessionId : null) ||
|
|
133
|
+
(previousResume.resumeTool === "codex" ? previousResume.resumeSessionId : null) ||
|
|
134
|
+
undefined;
|
|
135
|
+
const claudeSessionId =
|
|
136
|
+
(resumeTool === "claude" ? resumeSessionId : null) ||
|
|
137
|
+
(previousResume.resumeTool === "claude" ? previousResume.resumeSessionId : null) ||
|
|
138
|
+
undefined;
|
|
139
|
+
const tabIdSeed = JSON.stringify({
|
|
140
|
+
workspaceId: manifest.workspaceId || previousWorkspace?.workspace_id || previousWorkspace?.id || "workspace",
|
|
141
|
+
projectRoot,
|
|
142
|
+
title,
|
|
143
|
+
orderIndex: index,
|
|
144
|
+
});
|
|
145
|
+
|
|
146
|
+
return Object.fromEntries(
|
|
147
|
+
Object.entries({
|
|
148
|
+
tab_id: previous?.tabId || `tab-${hashText(tabIdSeed).slice(0, 16)}`,
|
|
149
|
+
order_index: index,
|
|
150
|
+
title: title || undefined,
|
|
151
|
+
project_root: projectRoot,
|
|
152
|
+
repo_label: repoLabel || undefined,
|
|
153
|
+
resume_command: resumeCommand,
|
|
154
|
+
resume_tool: resumeTool,
|
|
155
|
+
resume_session_id: resumeSessionId,
|
|
156
|
+
codex_session_id: codexSessionId,
|
|
157
|
+
claude_session_id: claudeSessionId,
|
|
158
|
+
terminal_title: terminalTitle || undefined,
|
|
159
|
+
status: "active",
|
|
160
|
+
current_task: previous?.currentTask || undefined,
|
|
161
|
+
focus_summary: previous?.focusSummary || undefined,
|
|
162
|
+
trajectory_summary: previous?.trajectorySummary || undefined,
|
|
163
|
+
last_activity_at_utc: previous?.lastActivityAt || undefined,
|
|
164
|
+
linked_idea_id: previous?.linkedIdeaId || undefined,
|
|
165
|
+
linked_feature_id: previous?.linkedFeatureId || undefined,
|
|
166
|
+
}).filter(([, value]) => value !== undefined && value !== null),
|
|
167
|
+
);
|
|
168
|
+
});
|
|
169
|
+
|
|
170
|
+
const captureContext = Object.fromEntries(
|
|
171
|
+
Object.entries({
|
|
172
|
+
source_app: "terminal-ledger",
|
|
173
|
+
mode: "manual",
|
|
174
|
+
host: os.hostname(),
|
|
175
|
+
terminal_frontend: "terminal",
|
|
176
|
+
durable_backend: options.durableBackend || "manual-ledger",
|
|
177
|
+
}).filter(([, value]) => value !== undefined && value !== null),
|
|
178
|
+
);
|
|
179
|
+
|
|
180
|
+
const stateVersion = Math.max(1, (getHostedIntegerValue(previousState, "state_version", "stateVersion") || 0) + 1);
|
|
181
|
+
const snapshotSeed = JSON.stringify({
|
|
182
|
+
workspaceId: manifest.workspaceId || previousWorkspace?.workspace_id || previousWorkspace?.id || "workspace",
|
|
183
|
+
capturedAt,
|
|
184
|
+
tabs: tabs.map((tab) => ({
|
|
185
|
+
order_index: tab.order_index,
|
|
186
|
+
project_root: tab.project_root,
|
|
187
|
+
title: tab.title || null,
|
|
188
|
+
codex_session_id: tab.codex_session_id || null,
|
|
189
|
+
claude_session_id: tab.claude_session_id || null,
|
|
190
|
+
})),
|
|
191
|
+
});
|
|
192
|
+
|
|
193
|
+
return Object.fromEntries(
|
|
194
|
+
Object.entries({
|
|
195
|
+
state_version: stateVersion,
|
|
196
|
+
snapshot_id: `snapshot-${hashText(snapshotSeed).slice(0, 16)}`,
|
|
197
|
+
summary: normalizeOptionalString(previousState.summary),
|
|
198
|
+
current_focus: normalizeOptionalString(previousState.current_focus ?? previousState.currentFocus),
|
|
199
|
+
trajectory: normalizeOptionalString(previousState.trajectory),
|
|
200
|
+
opened_at_utc: normalizeOptionalString(previousState.opened_at_utc ?? previousState.openedAtUtc),
|
|
201
|
+
captured_at_utc: capturedAt,
|
|
202
|
+
updated_at_utc: updatedAt,
|
|
203
|
+
tab_count: tabs.length,
|
|
204
|
+
capture_context: Object.keys(captureContext).length > 0 ? captureContext : undefined,
|
|
205
|
+
tabs,
|
|
206
|
+
}).filter(([, value]) => value !== undefined && value !== null),
|
|
207
|
+
);
|
|
208
|
+
}
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
export {
|
|
2
|
+
buildDirectCommand,
|
|
3
|
+
buildLaunchPlan,
|
|
4
|
+
getResumeCommand,
|
|
5
|
+
deriveBaseTitle,
|
|
6
|
+
deriveWorkspaceId,
|
|
7
|
+
extractStructuredWorkspaceFromNotes,
|
|
8
|
+
normalizeWorkspaceManifest,
|
|
9
|
+
parseCorePlanNotes,
|
|
10
|
+
parseResumeCommandText,
|
|
11
|
+
parseWorkspaceSource,
|
|
12
|
+
resolveResumeMetadata,
|
|
13
|
+
summarizeLaunchPlan,
|
|
14
|
+
WORKSPACE_SCHEMA_VERSION,
|
|
15
|
+
} from "./core-plan.js";
|
|
16
|
+
export {
|
|
17
|
+
buildWorkspaceCommandsReport,
|
|
18
|
+
parseWorkspaceCommandsArgs,
|
|
19
|
+
runWorkspaceCommands,
|
|
20
|
+
summarizeWorkspaceCommands,
|
|
21
|
+
} from "./commands.js";
|
|
22
|
+
export {
|
|
23
|
+
addTabToManifest,
|
|
24
|
+
parseWorkspaceCreateArgs,
|
|
25
|
+
parseWorkspaceAddTabArgs,
|
|
26
|
+
parseWorkspaceRemoveTabArgs,
|
|
27
|
+
removeTabsFromManifest,
|
|
28
|
+
runWorkspaceCreate,
|
|
29
|
+
runWorkspaceAddTab,
|
|
30
|
+
runWorkspaceRemoveTab,
|
|
31
|
+
} from "./ledger.js";
|
|
32
|
+
export { buildHostedWorkspaceState } from "./hosted-state.js";
|
|
33
|
+
export {
|
|
34
|
+
applyWorkspaceSlotsToInventory,
|
|
35
|
+
buildWorkspaceInventory,
|
|
36
|
+
parseWorkspaceListArgs,
|
|
37
|
+
runWorkspaceList,
|
|
38
|
+
summarizeTrackedWorkspaces,
|
|
39
|
+
summarizeWorkspaceInventory,
|
|
40
|
+
} from "./list.js";
|
|
41
|
+
export { runWorkspaceSlot } from "./slot.js";
|
|
42
|
+
export { buildWorkspaceTabsReport, parseWorkspaceTabsArgs, runWorkspaceTabs, summarizeWorkspaceTabs } from "./tabs.js";
|
|
43
|
+
export {
|
|
44
|
+
buildWorkspaceManifestFromHostedWorkspacePayload,
|
|
45
|
+
fetchHostedWorkspacePayload,
|
|
46
|
+
fetchIdeaPayload,
|
|
47
|
+
fetchIdeasPayload,
|
|
48
|
+
fetchHostedWorkspacesPayload,
|
|
49
|
+
loadWorkspaceSource,
|
|
50
|
+
pushHostedWorkspaceState,
|
|
51
|
+
chooseImplicitMainCandidate,
|
|
52
|
+
resolveWorkspaceWatchTargets,
|
|
53
|
+
resolveWorkspaceSelectorFromCollections,
|
|
54
|
+
updateIdeaPayload,
|
|
55
|
+
} from "./orp.js";
|
|
56
|
+
export {
|
|
57
|
+
cacheManagedWorkspaceManifest,
|
|
58
|
+
clearWorkspaceSlot,
|
|
59
|
+
getConfigHome,
|
|
60
|
+
getManagedWorkspaceDir,
|
|
61
|
+
getManagedWorkspaceManifestPath,
|
|
62
|
+
getOrpUserDir,
|
|
63
|
+
getWorkspaceRegistryPath,
|
|
64
|
+
getWorkspaceSlotsPath,
|
|
65
|
+
getWorkspaceStyleBindingsPath,
|
|
66
|
+
getWorkspaceStylesPath,
|
|
67
|
+
isManagedWorkspaceManifestPath,
|
|
68
|
+
listTrackedWorkspaces,
|
|
69
|
+
loadWorkspaceSlots,
|
|
70
|
+
loadWorkspaceRegistry,
|
|
71
|
+
normalizeWorkspaceSlotName,
|
|
72
|
+
registerWorkspaceManifest,
|
|
73
|
+
setWorkspaceSlot,
|
|
74
|
+
summarizeManifestForRegistry,
|
|
75
|
+
} from "./registry.js";
|
|
76
|
+
export {
|
|
77
|
+
buildWorkspaceSyncPreview,
|
|
78
|
+
extractWorkspaceNarrativeNotes,
|
|
79
|
+
resolveWorkspaceSyncTargetIdeaId,
|
|
80
|
+
runWorkspaceSync,
|
|
81
|
+
} from "./sync.js";
|
|
82
|
+
export { runOrpWorkspaceCommand } from "./orp-command.js";
|