open-research-protocol 0.4.2 → 0.4.4

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/package.json CHANGED
@@ -1,11 +1,11 @@
1
1
  {
2
2
  "name": "open-research-protocol",
3
- "version": "0.4.2",
3
+ "version": "0.4.4",
4
4
  "description": "ORP CLI (Open Research Protocol): agent-friendly research workflows, runtime, reports, and pack tooling.",
5
5
  "license": "MIT",
6
6
  "repository": {
7
7
  "type": "git",
8
- "url": "https://github.com/SproutSeeds/orp.git"
8
+ "url": "git+https://github.com/SproutSeeds/orp.git"
9
9
  },
10
10
  "homepage": "https://github.com/SproutSeeds/orp#readme",
11
11
  "bugs": {
@@ -37,6 +37,7 @@
37
37
  },
38
38
  "scripts": {
39
39
  "postinstall": "node scripts/npm-postinstall-check.js",
40
+ "prepublishOnly": "node scripts/npm-prepublish-guard.js",
40
41
  "test": "python3 -m unittest discover -s tests -v"
41
42
  },
42
43
  "keywords": [
@@ -0,0 +1,55 @@
1
+ #!/usr/bin/env node
2
+
3
+ const { spawnSync } = require("child_process");
4
+
5
+ function git(args) {
6
+ return spawnSync("git", args, { encoding: "utf8" });
7
+ }
8
+
9
+ function fail(message, details = "") {
10
+ console.error(`[orp] prepublish blocked: ${message}`);
11
+ if (details.trim()) {
12
+ console.error(details.trim());
13
+ }
14
+ process.exit(1);
15
+ }
16
+
17
+ const inside = git(["rev-parse", "--is-inside-work-tree"]);
18
+ if (inside.error || inside.status !== 0 || inside.stdout.trim() !== "true") {
19
+ fail("npm publish must run from inside a git worktree.");
20
+ }
21
+
22
+ const status = git(["status", "--short"]);
23
+ if (status.error || status.status !== 0) {
24
+ fail("unable to inspect git working tree state.", status.stderr || status.stdout);
25
+ }
26
+
27
+ if (status.stdout.trim()) {
28
+ const preview = status.stdout
29
+ .trim()
30
+ .split("\n")
31
+ .slice(0, 10)
32
+ .join("\n");
33
+ fail(
34
+ "working tree is not clean. Commit, stash, or remove local-only files before publishing so npm and GitHub stay aligned.",
35
+ preview,
36
+ );
37
+ }
38
+
39
+ if (process.env.GITHUB_ACTIONS === "true") {
40
+ process.exit(0);
41
+ }
42
+
43
+ const remoteContains = git(["branch", "-r", "--contains", "HEAD"]);
44
+ if (remoteContains.error || remoteContains.status !== 0) {
45
+ fail("unable to confirm that HEAD exists on a remote branch.", remoteContains.stderr || remoteContains.stdout);
46
+ }
47
+
48
+ const remoteBranches = remoteContains.stdout
49
+ .split("\n")
50
+ .map((line) => line.trim())
51
+ .filter(Boolean);
52
+
53
+ if (remoteBranches.length === 0) {
54
+ fail("current HEAD is not present on any remote branch. Push the release commit to GitHub before publishing.");
55
+ }
@@ -0,0 +1,234 @@
1
+ #!/usr/bin/env bash
2
+ set -euo pipefail
3
+
4
+ ROOT_DIR="$(cd "$(dirname "$0")/.." && pwd)"
5
+ RUN_HOSTED=0
6
+ RUN_WORKER=0
7
+ RUN_TESTS=1
8
+ KEEP_TEMP=0
9
+ CODEX_SESSION_ID="${CODEX_THREAD_ID:-}"
10
+ IDEA_ID=""
11
+ TMP_ROOT=""
12
+ ORP_BIN=""
13
+
14
+ usage() {
15
+ cat <<'EOF'
16
+ Usage: scripts/orp-release-smoke.sh [options]
17
+
18
+ Local release smoke:
19
+ - runs unit tests
20
+ - verifies npm pack / publish dry runs
21
+ - installs the packed tarball into a clean temp prefix
22
+ - exercises init/status/branch/checkpoint/gate/ready on a fresh repo
23
+
24
+ Optional hosted smoke:
25
+ --hosted run hosted whoami/ideas/add/show/world/checkpoint smoke
26
+ --worker after --hosted, run `orp agent work --once`
27
+ --codex-session-id Codex session id used for hosted world binding
28
+
29
+ Other options:
30
+ --skip-tests skip the unit test pass
31
+ --keep-temp keep temp install/repo directories for inspection
32
+ -h, --help show this help
33
+ EOF
34
+ }
35
+
36
+ note() {
37
+ printf '\n[%s] %s\n' "$(date '+%H:%M:%S')" "$*"
38
+ }
39
+
40
+ json_field() {
41
+ python3 - "$1" "$2" <<'PY'
42
+ import json
43
+ import sys
44
+
45
+ path = sys.argv[1]
46
+ field = sys.argv[2]
47
+ value = json.loads(open(path, encoding="utf-8").read())
48
+ for part in field.split("."):
49
+ if isinstance(value, dict):
50
+ value = value.get(part)
51
+ elif isinstance(value, list) and part.isdigit():
52
+ idx = int(part)
53
+ value = value[idx] if 0 <= idx < len(value) else None
54
+ else:
55
+ value = None
56
+ break
57
+ if value is None:
58
+ print("")
59
+ elif isinstance(value, bool):
60
+ print("true" if value else "false")
61
+ else:
62
+ print(value)
63
+ PY
64
+ }
65
+
66
+ cleanup() {
67
+ local exit_code=$?
68
+ if [[ -n "${IDEA_ID}" && -n "${ORP_BIN}" ]]; then
69
+ note "Cleaning up hosted smoke idea ${IDEA_ID}"
70
+ "${ORP_BIN}" idea remove "${IDEA_ID}" --purge --json >/dev/null 2>&1 || true
71
+ fi
72
+ if [[ "${KEEP_TEMP}" != "1" && -n "${TMP_ROOT}" && -d "${TMP_ROOT}" ]]; then
73
+ rm -rf "${TMP_ROOT}" >/dev/null 2>&1 || true
74
+ fi
75
+ exit "${exit_code}"
76
+ }
77
+
78
+ while [[ $# -gt 0 ]]; do
79
+ case "$1" in
80
+ --hosted)
81
+ RUN_HOSTED=1
82
+ shift
83
+ ;;
84
+ --worker)
85
+ RUN_HOSTED=1
86
+ RUN_WORKER=1
87
+ shift
88
+ ;;
89
+ --skip-tests)
90
+ RUN_TESTS=0
91
+ shift
92
+ ;;
93
+ --keep-temp)
94
+ KEEP_TEMP=1
95
+ shift
96
+ ;;
97
+ --codex-session-id)
98
+ CODEX_SESSION_ID="${2:-}"
99
+ shift 2
100
+ ;;
101
+ -h|--help)
102
+ usage
103
+ exit 0
104
+ ;;
105
+ *)
106
+ printf 'Unknown argument: %s\n' "$1" >&2
107
+ usage >&2
108
+ exit 1
109
+ ;;
110
+ esac
111
+ done
112
+
113
+ trap cleanup EXIT
114
+
115
+ command -v python3 >/dev/null
116
+ command -v npm >/dev/null
117
+ command -v node >/dev/null
118
+ command -v git >/dev/null
119
+
120
+ TMP_ROOT="$(mktemp -d /tmp/orp-release-smoke.XXXXXX)"
121
+ PACK_DIR="${TMP_ROOT}/pack"
122
+ PREFIX_DIR="${TMP_ROOT}/prefix"
123
+ REPO_DIR="${TMP_ROOT}/repo"
124
+ mkdir -p "${PACK_DIR}" "${PREFIX_DIR}" "${REPO_DIR}"
125
+
126
+ if [[ "${RUN_TESTS}" == "1" ]]; then
127
+ note "Running unit tests"
128
+ (
129
+ cd "${ROOT_DIR}"
130
+ env PYTHONPYCACHEPREFIX=/tmp/orp-pyc python3 -m unittest discover -s tests -v
131
+ )
132
+ fi
133
+
134
+ note "Checking published npm version"
135
+ (
136
+ cd "${ROOT_DIR}"
137
+ npm view open-research-protocol version dist-tags --json
138
+ )
139
+
140
+ note "Verifying npm pack and publish dry runs"
141
+ (
142
+ cd "${ROOT_DIR}"
143
+ npm pack --dry-run --cache /tmp/orp-npm-cache
144
+ npm publish --dry-run
145
+ )
146
+
147
+ note "Packing local release candidate"
148
+ (
149
+ cd "${PACK_DIR}"
150
+ npm pack "${ROOT_DIR}" --json > pack.json
151
+ )
152
+ TARBALL="${PACK_DIR}/$(json_field "${PACK_DIR}/pack.json" "0.filename")"
153
+
154
+ note "Installing tarball into temp prefix"
155
+ npm install -g --prefix "${PREFIX_DIR}" "${TARBALL}" >/dev/null
156
+ ORP_BIN="${PREFIX_DIR}/bin/orp"
157
+
158
+ note "Checking installed binary"
159
+ "${ORP_BIN}" -h >/dev/null
160
+
161
+ note "Running fresh-repo governance smoke"
162
+ (
163
+ cd "${REPO_DIR}"
164
+ "${ORP_BIN}" init --json >/dev/null
165
+ git config user.name "ORP Release Smoke"
166
+ git config user.email "orp-release@example.com"
167
+ "${ORP_BIN}" status --json >/dev/null
168
+ "${ORP_BIN}" branch start work/bootstrap --allow-dirty --json >/dev/null
169
+ "${ORP_BIN}" checkpoint create -m "bootstrap governance" --json >/dev/null
170
+ "${ORP_BIN}" backup -m "backup bootstrap governance" --json >/dev/null
171
+ "${ORP_BIN}" gate run --profile default --json >/dev/null
172
+ "${ORP_BIN}" checkpoint create -m "capture passing validation" --json >/dev/null
173
+ "${ORP_BIN}" ready --json >/dev/null
174
+ "${ORP_BIN}" packet emit --profile default --json >/dev/null
175
+ "${ORP_BIN}" report summary --json >/dev/null
176
+ )
177
+
178
+ if [[ "${RUN_HOSTED}" == "1" ]]; then
179
+ note "Running hosted workspace smoke"
180
+ "${ORP_BIN}" whoami --json >/dev/null
181
+ "${ORP_BIN}" ideas list --limit 5 --json >/dev/null
182
+
183
+ local_idea_json="${TMP_ROOT}/idea-add.json"
184
+ "${ORP_BIN}" idea add \
185
+ --title "ORP release smoke $(date '+%Y-%m-%d %H:%M:%S')" \
186
+ --notes "Temporary hosted smoke test for ORP CLI release readiness. Safe to purge." \
187
+ --json > "${local_idea_json}"
188
+ IDEA_ID="$(json_field "${local_idea_json}" "idea.id")"
189
+ if [[ -z "${IDEA_ID}" ]]; then
190
+ printf 'Hosted smoke failed: could not create idea.\n' >&2
191
+ exit 1
192
+ fi
193
+
194
+ "${ORP_BIN}" idea show "${IDEA_ID}" --json >/dev/null
195
+
196
+ if [[ -z "${CODEX_SESSION_ID}" ]]; then
197
+ printf 'Hosted smoke requires --codex-session-id or CODEX_THREAD_ID for world binding.\n' >&2
198
+ exit 1
199
+ fi
200
+
201
+ "${ORP_BIN}" world bind "${IDEA_ID}" \
202
+ --name "ORP release smoke" \
203
+ --project-root "${ROOT_DIR}" \
204
+ --github-url "https://github.com/SproutSeeds/orp" \
205
+ --codex-session-id "${CODEX_SESSION_ID}" \
206
+ --json >/dev/null
207
+
208
+ world_ok=0
209
+ for _ in 1 2 3 4 5; do
210
+ local_world_json="${TMP_ROOT}/world-show.json"
211
+ "${ORP_BIN}" world show "${IDEA_ID}" --json > "${local_world_json}"
212
+ if [[ "$(json_field "${local_world_json}" "world.id")" != "" ]]; then
213
+ world_ok=1
214
+ break
215
+ fi
216
+ sleep 1
217
+ done
218
+ if [[ "${world_ok}" != "1" ]]; then
219
+ printf 'Hosted smoke failed: world show did not return a bound world.\n' >&2
220
+ exit 1
221
+ fi
222
+
223
+ "${ORP_BIN}" checkpoint queue --idea-id "${IDEA_ID}" --json >/dev/null
224
+
225
+ if [[ "${RUN_WORKER}" == "1" ]]; then
226
+ note "Running hosted worker smoke"
227
+ "${ORP_BIN}" agent work --once --json >/dev/null
228
+ fi
229
+ fi
230
+
231
+ note "Release smoke passed"
232
+ if [[ "${KEEP_TEMP}" == "1" ]]; then
233
+ note "Temp files kept at ${TMP_ROOT}"
234
+ fi
@@ -0,0 +1,57 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://openresearchprotocol.com/spec/v1/link-project.schema.json",
4
+ "title": "ORP Linked Project",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": [
8
+ "schema_version",
9
+ "idea_id",
10
+ "project_root",
11
+ "linked_at_utc"
12
+ ],
13
+ "properties": {
14
+ "schema_version": {
15
+ "type": "string",
16
+ "const": "1.0.0"
17
+ },
18
+ "idea_id": {
19
+ "type": "string",
20
+ "minLength": 1
21
+ },
22
+ "idea_title": {
23
+ "type": "string"
24
+ },
25
+ "world_id": {
26
+ "type": "string"
27
+ },
28
+ "world_name": {
29
+ "type": "string"
30
+ },
31
+ "project_root": {
32
+ "type": "string",
33
+ "minLength": 1
34
+ },
35
+ "github_url": {
36
+ "type": "string"
37
+ },
38
+ "linked_at_utc": {
39
+ "type": "string",
40
+ "format": "date-time"
41
+ },
42
+ "linked_email": {
43
+ "type": "string"
44
+ },
45
+ "source": {
46
+ "type": "string",
47
+ "enum": [
48
+ "cli",
49
+ "rust-app",
50
+ "import-rust"
51
+ ]
52
+ },
53
+ "notes": {
54
+ "type": "string"
55
+ }
56
+ }
57
+ }
@@ -0,0 +1,97 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://openresearchprotocol.com/spec/v1/link-session.schema.json",
4
+ "title": "ORP Linked Session",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": [
8
+ "schema_version",
9
+ "orp_session_id",
10
+ "label",
11
+ "state",
12
+ "project_root",
13
+ "created_at_utc",
14
+ "last_active_at_utc",
15
+ "archived",
16
+ "primary"
17
+ ],
18
+ "properties": {
19
+ "schema_version": {
20
+ "type": "string",
21
+ "const": "1.0.0"
22
+ },
23
+ "orp_session_id": {
24
+ "type": "string",
25
+ "minLength": 1
26
+ },
27
+ "label": {
28
+ "type": "string",
29
+ "minLength": 1
30
+ },
31
+ "project_root": {
32
+ "type": "string",
33
+ "minLength": 1
34
+ },
35
+ "codex_session_id": {
36
+ "type": "string"
37
+ },
38
+ "role": {
39
+ "type": "string",
40
+ "enum": [
41
+ "primary",
42
+ "secondary",
43
+ "review",
44
+ "exploration",
45
+ "other"
46
+ ]
47
+ },
48
+ "state": {
49
+ "type": "string",
50
+ "enum": [
51
+ "active",
52
+ "closed"
53
+ ]
54
+ },
55
+ "created_at_utc": {
56
+ "type": "string",
57
+ "format": "date-time"
58
+ },
59
+ "last_active_at_utc": {
60
+ "type": "string",
61
+ "format": "date-time"
62
+ },
63
+ "archived": {
64
+ "type": "boolean"
65
+ },
66
+ "primary": {
67
+ "type": "boolean"
68
+ },
69
+ "terminal_target": {
70
+ "type": "object",
71
+ "additionalProperties": false,
72
+ "required": [
73
+ "window_id",
74
+ "tab_number"
75
+ ],
76
+ "properties": {
77
+ "window_id": {
78
+ "type": "integer"
79
+ },
80
+ "tab_number": {
81
+ "type": "integer"
82
+ }
83
+ }
84
+ },
85
+ "source": {
86
+ "type": "string",
87
+ "enum": [
88
+ "cli",
89
+ "rust-app",
90
+ "import-rust"
91
+ ]
92
+ },
93
+ "notes": {
94
+ "type": "string"
95
+ }
96
+ }
97
+ }
@@ -0,0 +1,48 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://openresearchprotocol.com/spec/v1/runner-machine.schema.json",
4
+ "title": "ORP Runner Machine",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": [
8
+ "schema_version",
9
+ "machine_id",
10
+ "machine_name",
11
+ "platform",
12
+ "runner_enabled"
13
+ ],
14
+ "properties": {
15
+ "schema_version": {
16
+ "type": "string",
17
+ "const": "1.0.0"
18
+ },
19
+ "machine_id": {
20
+ "type": "string",
21
+ "minLength": 1
22
+ },
23
+ "machine_name": {
24
+ "type": "string",
25
+ "minLength": 1
26
+ },
27
+ "platform": {
28
+ "type": "string"
29
+ },
30
+ "app_version": {
31
+ "type": "string"
32
+ },
33
+ "runner_enabled": {
34
+ "type": "boolean"
35
+ },
36
+ "linked_email": {
37
+ "type": "string"
38
+ },
39
+ "last_heartbeat_at_utc": {
40
+ "type": "string",
41
+ "format": "date-time"
42
+ },
43
+ "last_sync_at_utc": {
44
+ "type": "string",
45
+ "format": "date-time"
46
+ }
47
+ }
48
+ }
@@ -0,0 +1,130 @@
1
+ {
2
+ "$schema": "https://json-schema.org/draft/2020-12/schema",
3
+ "$id": "https://openresearchprotocol.com/spec/v1/runner-runtime.schema.json",
4
+ "title": "ORP Runner Runtime",
5
+ "type": "object",
6
+ "additionalProperties": false,
7
+ "required": [
8
+ "schema_version",
9
+ "status",
10
+ "active_job",
11
+ "last_job",
12
+ "recent_events"
13
+ ],
14
+ "properties": {
15
+ "schema_version": {
16
+ "type": "string",
17
+ "const": "1.0.0"
18
+ },
19
+ "status": {
20
+ "type": "string",
21
+ "enum": [
22
+ "idle",
23
+ "claimed",
24
+ "running"
25
+ ]
26
+ },
27
+ "updated_at_utc": {
28
+ "type": "string",
29
+ "format": "date-time"
30
+ },
31
+ "active_job": {
32
+ "$ref": "#/$defs/jobState"
33
+ },
34
+ "last_job": {
35
+ "$ref": "#/$defs/jobState"
36
+ },
37
+ "recent_events": {
38
+ "type": "array",
39
+ "items": {
40
+ "$ref": "#/$defs/runtimeEvent"
41
+ }
42
+ }
43
+ },
44
+ "$defs": {
45
+ "jobState": {
46
+ "type": "object",
47
+ "additionalProperties": false,
48
+ "properties": {
49
+ "job_id": {
50
+ "type": "string"
51
+ },
52
+ "job_kind": {
53
+ "type": "string"
54
+ },
55
+ "lease_id": {
56
+ "type": "string"
57
+ },
58
+ "idea_id": {
59
+ "type": "string"
60
+ },
61
+ "world_id": {
62
+ "type": "string"
63
+ },
64
+ "project_root": {
65
+ "type": "string"
66
+ },
67
+ "repo_root": {
68
+ "type": "string"
69
+ },
70
+ "orp_session_id": {
71
+ "type": "string"
72
+ },
73
+ "codex_session_id": {
74
+ "type": "string"
75
+ },
76
+ "status": {
77
+ "type": "string"
78
+ },
79
+ "summary": {
80
+ "type": "string"
81
+ },
82
+ "error": {
83
+ "type": "string"
84
+ },
85
+ "claimed_at_utc": {
86
+ "type": "string",
87
+ "format": "date-time"
88
+ },
89
+ "started_at_utc": {
90
+ "type": "string",
91
+ "format": "date-time"
92
+ },
93
+ "last_heartbeat_at_utc": {
94
+ "type": "string",
95
+ "format": "date-time"
96
+ },
97
+ "lease_expires_at_utc": {
98
+ "type": "string",
99
+ "format": "date-time"
100
+ },
101
+ "finished_at_utc": {
102
+ "type": "string",
103
+ "format": "date-time"
104
+ }
105
+ }
106
+ },
107
+ "runtimeEvent": {
108
+ "type": "object",
109
+ "additionalProperties": false,
110
+ "properties": {
111
+ "timestamp_utc": {
112
+ "type": "string",
113
+ "format": "date-time"
114
+ },
115
+ "status": {
116
+ "type": "string"
117
+ },
118
+ "job_id": {
119
+ "type": "string"
120
+ },
121
+ "lease_id": {
122
+ "type": "string"
123
+ },
124
+ "message": {
125
+ "type": "string"
126
+ }
127
+ }
128
+ }
129
+ }
130
+ }