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.
Files changed (52) hide show
  1. package/AGENT_INTEGRATION.md +50 -0
  2. package/README.md +273 -144
  3. package/bin/orp.js +14 -1
  4. package/cli/orp.py +14846 -9925
  5. package/docs/AGENT_LOOP.md +13 -0
  6. package/docs/AGENT_MODES.md +79 -0
  7. package/docs/CANONICAL_CLI_BOUNDARY.md +15 -0
  8. package/docs/EXCHANGE.md +94 -0
  9. package/docs/LAUNCH_KIT.md +107 -0
  10. package/docs/ORP_HOSTED_WORKSPACE_CONTRACT.md +295 -0
  11. package/docs/ORP_PUBLIC_LAUNCH_CHECKLIST.md +5 -0
  12. package/docs/START_HERE.md +567 -0
  13. package/package.json +4 -2
  14. package/packages/lifeops-orp/README.md +67 -0
  15. package/packages/lifeops-orp/package.json +48 -0
  16. package/packages/lifeops-orp/src/index.d.ts +106 -0
  17. package/packages/lifeops-orp/src/index.js +7 -0
  18. package/packages/lifeops-orp/src/mapping.js +309 -0
  19. package/packages/lifeops-orp/src/workspace.js +108 -0
  20. package/packages/lifeops-orp/test/orp.test.js +187 -0
  21. package/packages/orp-workspace-launcher/README.md +82 -0
  22. package/packages/orp-workspace-launcher/package.json +39 -0
  23. package/packages/orp-workspace-launcher/src/commands.js +77 -0
  24. package/packages/orp-workspace-launcher/src/core-plan.js +506 -0
  25. package/packages/orp-workspace-launcher/src/hosted-state.js +208 -0
  26. package/packages/orp-workspace-launcher/src/index.js +82 -0
  27. package/packages/orp-workspace-launcher/src/ledger.js +745 -0
  28. package/packages/orp-workspace-launcher/src/list.js +488 -0
  29. package/packages/orp-workspace-launcher/src/orp-command.js +126 -0
  30. package/packages/orp-workspace-launcher/src/orp.js +912 -0
  31. package/packages/orp-workspace-launcher/src/registry.js +558 -0
  32. package/packages/orp-workspace-launcher/src/slot.js +188 -0
  33. package/packages/orp-workspace-launcher/src/sync.js +363 -0
  34. package/packages/orp-workspace-launcher/src/tabs.js +166 -0
  35. package/packages/orp-workspace-launcher/test/commands.test.js +164 -0
  36. package/packages/orp-workspace-launcher/test/core-plan.test.js +253 -0
  37. package/packages/orp-workspace-launcher/test/fixtures/smoke-notes.txt +2 -0
  38. package/packages/orp-workspace-launcher/test/fixtures/workspace-manifest.json +17 -0
  39. package/packages/orp-workspace-launcher/test/ledger.test.js +244 -0
  40. package/packages/orp-workspace-launcher/test/list.test.js +299 -0
  41. package/packages/orp-workspace-launcher/test/orp-command.test.js +44 -0
  42. package/packages/orp-workspace-launcher/test/orp.test.js +224 -0
  43. package/packages/orp-workspace-launcher/test/tabs.test.js +168 -0
  44. package/scripts/orp-kernel-agent-pilot.py +10 -1
  45. package/scripts/orp-kernel-agent-replication.py +10 -1
  46. package/scripts/orp-kernel-canonical-continuation.py +10 -1
  47. package/scripts/orp-kernel-continuation-pilot.py +10 -1
  48. package/scripts/render-terminal-demo.py +416 -0
  49. package/spec/v1/exchange-report.schema.json +105 -0
  50. package/spec/v1/hosted-workspace-event.schema.json +102 -0
  51. package/spec/v1/hosted-workspace.schema.json +332 -0
  52. 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";