@ravefox/space 0.2.0 → 0.3.0

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 (163) hide show
  1. package/LICENSE +21 -203
  2. package/README.md +89 -26
  3. package/bin/space.js +106 -0
  4. package/lib/agents.js +119 -0
  5. package/lib/credentials.js +95 -0
  6. package/lib/daemon.js +294 -0
  7. package/lib/harness.js +166 -0
  8. package/lib/http.js +101 -0
  9. package/lib/login.js +68 -0
  10. package/lib/mcp.js +34 -0
  11. package/lib/runtime.js +241 -0
  12. package/lib/store.js +96 -0
  13. package/lib/tools.js +93 -0
  14. package/package.json +28 -40
  15. package/NOTICE +0 -44
  16. package/assets/webhook-sdk/python/bot.py +0 -63
  17. package/assets/webhook-sdk/python/commonly.py +0 -232
  18. package/node_modules/@commonlyai/seats/README.md +0 -25
  19. package/node_modules/@commonlyai/seats/package.json +0 -22
  20. package/node_modules/@commonlyai/seats/src/adapters/hermes.js +0 -264
  21. package/node_modules/@commonlyai/seats/src/adapters/stub.js +0 -24
  22. package/node_modules/@commonlyai/seats/src/contract.js +0 -48
  23. package/node_modules/@commonlyai/seats/src/failures.js +0 -44
  24. package/node_modules/@commonlyai/seats/src/harness-plan.js +0 -329
  25. package/node_modules/@commonlyai/seats/src/index.js +0 -22
  26. package/node_modules/@commonlyai/seats/src/process-group.js +0 -269
  27. package/node_modules/@commonlyai/seats/src/record/format.js +0 -737
  28. package/node_modules/@commonlyai/seats/src/record/otel.js +0 -238
  29. package/node_modules/@commonlyai/seats/src/runtime-observation.js +0 -29
  30. package/node_modules/@commonlyai/seats/src/seat-model.js +0 -17
  31. package/node_modules/@commonlyai/seats/src/supervisor.js +0 -308
  32. package/node_modules/@commonlyai/seats/src/trace/events.js +0 -46
  33. package/node_modules/@commonlyai/seats/src/trace/store.js +0 -276
  34. package/node_modules/@commonlyai/seats/src/turn-processes.js +0 -226
  35. package/node_modules/@commonlyai/seats/src/upstream-refusal.js +0 -418
  36. package/node_modules/@commonlyai/seats/src/valet/env.js +0 -201
  37. package/node_modules/@commonlyai/seats/src/valet/grant.js +0 -123
  38. package/node_modules/@commonlyai/seats/src/valet/permissions.js +0 -213
  39. package/node_modules/@commonlyai/seats/src/wire/provider-proxy.js +0 -529
  40. package/skills/commonly/SKILL.md +0 -233
  41. package/src/commands/agent.js +0 -6334
  42. package/src/commands/daemon.js +0 -933
  43. package/src/commands/dev.js +0 -153
  44. package/src/commands/doctor.js +0 -141
  45. package/src/commands/inbox.js +0 -330
  46. package/src/commands/login.js +0 -194
  47. package/src/commands/mcp.js +0 -56
  48. package/src/commands/pod.js +0 -120
  49. package/src/commands/task.js +0 -279
  50. package/src/commands/verify.js +0 -48
  51. package/src/index.js +0 -99
  52. package/src/lib/adapter-login.js +0 -76
  53. package/src/lib/adapters/broker-bridge-entry.js +0 -76
  54. package/src/lib/adapters/claude.js +0 -2207
  55. package/src/lib/adapters/codex-broker-bridge.mjs +0 -298
  56. package/src/lib/adapters/codex.js +0 -1898
  57. package/src/lib/adapters/dsh.js +0 -513
  58. package/src/lib/adapters/goose.js +0 -510
  59. package/src/lib/adapters/hermes.js +0 -18
  60. package/src/lib/adapters/index.js +0 -68
  61. package/src/lib/adapters/opencode.js +0 -1681
  62. package/src/lib/adapters/pi-commonly-mcp.mjs +0 -71
  63. package/src/lib/adapters/pi-mcp-client.mjs +0 -617
  64. package/src/lib/adapters/pi-shell-env.mjs +0 -41
  65. package/src/lib/adapters/pi.js +0 -1025
  66. package/src/lib/adapters/qwen.js +0 -523
  67. package/src/lib/adapters/seat-model.js +0 -8
  68. package/src/lib/adapters/stub.js +0 -1
  69. package/src/lib/adapters/tested-version.js +0 -106
  70. package/src/lib/api.js +0 -205
  71. package/src/lib/claim-outcome.js +0 -128
  72. package/src/lib/claimed-work-gate.js +0 -73
  73. package/src/lib/cli-hint.js +0 -33
  74. package/src/lib/commit-attribution.js +0 -391
  75. package/src/lib/config.js +0 -155
  76. package/src/lib/content-refusal.js +0 -94
  77. package/src/lib/credential-file.js +0 -208
  78. package/src/lib/daemon-agent-states.js +0 -95
  79. package/src/lib/daemon-hint.js +0 -18
  80. package/src/lib/daemon-logs.js +0 -43
  81. package/src/lib/daemon-service-windows.js +0 -263
  82. package/src/lib/daemon-service.js +0 -486
  83. package/src/lib/daemon-state.js +0 -84
  84. package/src/lib/daemon-store.js +0 -119
  85. package/src/lib/daemon-supervisor.js +0 -629
  86. package/src/lib/daemon-watch.js +0 -115
  87. package/src/lib/declared-mcp-guard.js +0 -284
  88. package/src/lib/default-environment.js +0 -207
  89. package/src/lib/device-login.js +0 -126
  90. package/src/lib/digest-frame.js +0 -151
  91. package/src/lib/doctor.js +0 -291
  92. package/src/lib/egress-proxy.js +0 -160
  93. package/src/lib/enforcement.js +0 -946
  94. package/src/lib/environment.js +0 -681
  95. package/src/lib/first-output-watchdog.js +0 -191
  96. package/src/lib/git-readonly-server.js +0 -138
  97. package/src/lib/git-readonly.js +0 -463
  98. package/src/lib/git-remote-commonly.mjs +0 -100
  99. package/src/lib/grant-broker-guard.js +0 -345
  100. package/src/lib/hooks-config.js +0 -238
  101. package/src/lib/host-gh-broker.js +0 -152
  102. package/src/lib/host-gh-shim.mjs +0 -98
  103. package/src/lib/inbox.js +0 -483
  104. package/src/lib/instance-proxy.js +0 -76
  105. package/src/lib/machine-host.js +0 -29
  106. package/src/lib/mcp-credential-delivery.js +0 -121
  107. package/src/lib/mcp-first-run.js +0 -50
  108. package/src/lib/mcp-home.js +0 -644
  109. package/src/lib/mcp-ready.js +0 -68
  110. package/src/lib/mcp-server-version.js +0 -123
  111. package/src/lib/mcp-token.js +0 -36
  112. package/src/lib/mcp-warm-child.mjs +0 -412
  113. package/src/lib/memory-bridge.js +0 -191
  114. package/src/lib/memory-import.js +0 -156
  115. package/src/lib/missing-harness.js +0 -31
  116. package/src/lib/model-unavailable.js +0 -154
  117. package/src/lib/native-runtime-inventory.js +0 -40
  118. package/src/lib/outsider-grant-mcp.js +0 -82
  119. package/src/lib/own-key-launch.js +0 -42
  120. package/src/lib/pod-catch-up.js +0 -55
  121. package/src/lib/pod-focus.js +0 -224
  122. package/src/lib/pod-tail.js +0 -68
  123. package/src/lib/poll-liveness.js +0 -103
  124. package/src/lib/poll-retry.js +0 -81
  125. package/src/lib/poller.js +0 -200
  126. package/src/lib/provider-proxy.js +0 -42
  127. package/src/lib/public-seat-mcp-flag.js +0 -36
  128. package/src/lib/public-tool-error.js +0 -60
  129. package/src/lib/public-withheld-tools.js +0 -48
  130. package/src/lib/reply-receipt.js +0 -55
  131. package/src/lib/resolve-on-path.js +0 -22
  132. package/src/lib/runtime-inventory.js +0 -56
  133. package/src/lib/runtime-observation.js +0 -37
  134. package/src/lib/sandbox/bwrap.js +0 -275
  135. package/src/lib/sandbox/codex-perimeter.js +0 -16
  136. package/src/lib/sandbox/host-check.js +0 -268
  137. package/src/lib/sandbox/mode.js +0 -49
  138. package/src/lib/sandbox/opencode-loopback.mjs +0 -68
  139. package/src/lib/sandbox/seatbelt.js +0 -684
  140. package/src/lib/sandbox/turn-dir.js +0 -56
  141. package/src/lib/sandbox/windows-unsandboxed.js +0 -183
  142. package/src/lib/sandbox/workspace-git-config.js +0 -243
  143. package/src/lib/sandbox/workspace-pin.js +0 -158
  144. package/src/lib/seat-runtime-controls.js +0 -61
  145. package/src/lib/seat-stop.js +0 -97
  146. package/src/lib/server-skills.js +0 -32
  147. package/src/lib/session-recycle.js +0 -219
  148. package/src/lib/session-store.js +0 -215
  149. package/src/lib/skill-prompt.js +0 -74
  150. package/src/lib/skills-import.js +0 -113
  151. package/src/lib/spawn-credential.js +0 -402
  152. package/src/lib/spawn-retry.js +0 -311
  153. package/src/lib/stable-install.js +0 -176
  154. package/src/lib/supervised-turn.js +0 -352
  155. package/src/lib/task.js +0 -235
  156. package/src/lib/turn-failure-notice.js +0 -177
  157. package/src/lib/unconfined-seat-guard.js +0 -94
  158. package/src/lib/update-check.js +0 -192
  159. package/src/lib/upstream-refusal.js +0 -1
  160. package/src/lib/webhook-server.js +0 -109
  161. package/src/lib/windows-command.js +0 -393
  162. package/src/lib/workspace-git.js +0 -87
  163. package/src/lib/workspace-trust.js +0 -162
package/package.json CHANGED
@@ -1,56 +1,44 @@
1
1
  {
2
2
  "name": "@ravefox/space",
3
- "version": "0.2.0",
4
- "license": "Apache-2.0",
5
- "description": "Space CLI \u2014 connect agents and run them in the background",
3
+ "version": "0.3.0",
4
+ "description": "Space CLI — connect and manage AI agents in your workspace",
6
5
  "type": "module",
7
- "main": "./src/index.js",
8
- "bin": {
9
- "space": "src/index.js",
10
- "commonly": "src/index.js"
6
+ "license": "MIT",
7
+ "author": {
8
+ "name": "Ravefox",
9
+ "url": "https://t.me/ravefoxlab"
10
+ },
11
+ "homepage": "https://space.ravefox.dev",
12
+ "bugs": {
13
+ "url": "https://vote.ravefox.dev/support"
11
14
  },
12
- "files": [
13
- "src",
14
- "assets",
15
- "README.md",
16
- "skills",
17
- "LICENSE",
18
- "NOTICE"
19
- ],
20
15
  "repository": {
21
16
  "type": "git",
22
17
  "url": "git+https://github.com/grootbro/space.git",
23
18
  "directory": "cli"
24
19
  },
25
- "homepage": "https://github.com/grootbro/space#readme",
26
- "keywords": [
27
- "space",
28
- "ai-agents",
29
- "agent",
30
- "cli",
31
- "mcp"
32
- ],
33
- "scripts": {
34
- "start": "node src/index.js",
35
- "lint": "eslint src --ext .js",
36
- "lint:fix": "eslint src --ext .js --fix",
37
- "test": "node --experimental-vm-modules node_modules/.bin/jest",
38
- "test:temp-cleanup": "node scripts/verify-temp-cleanup.mjs",
39
- "prepack": "node scripts/require-bundled-seats.mjs && node scripts/bundle-sdk-examples.mjs"
20
+ "bin": {
21
+ "space": "bin/space.js"
40
22
  },
41
- "dependencies": {
42
- "@commonlyai/seats": "file:../packages/seats",
43
- "commander": "^12.0.0"
23
+ "exports": {
24
+ "./runtime": "./lib/runtime.js",
25
+ "./store": "./lib/store.js"
44
26
  },
45
- "bundleDependencies": [
46
- "@commonlyai/seats"
27
+ "files": [
28
+ "bin",
29
+ "lib",
30
+ "README.md",
31
+ "LICENSE"
47
32
  ],
48
- "devDependencies": {
49
- "eslint": "^8.56.0",
50
- "jest": "^29.7.0"
51
- },
52
33
  "engines": {
53
- "node": ">=22.0.0"
34
+ "node": ">=22"
35
+ },
36
+ "scripts": {
37
+ "test": "node --test test/*.test.js"
38
+ },
39
+ "dependencies": {
40
+ "@modelcontextprotocol/sdk": "1.32.2",
41
+ "commander": "12.1.0"
54
42
  },
55
43
  "publishConfig": {
56
44
  "access": "public"
package/NOTICE DELETED
@@ -1,44 +0,0 @@
1
- Commonly
2
- Copyright 2026 Commonly (Team-Commonly) and contributors
3
-
4
- This product is licensed under the Apache License, Version 2.0.
5
- The Commonly name, logo, and brand assets are trademarks of the
6
- Commonly project and are not licensed under the Apache License.
7
-
8
- Third-party notices
9
- -------------------
10
-
11
- OpenAI Codex
12
- Copyright 2025 OpenAI
13
-
14
- This project includes code derived from [Ratatui](https://github.com/ratatui/ratatui), licensed under the MIT license.
15
- Copyright (c) 2016-2022 Florian Dehau
16
- Copyright (c) 2023-2025 The Ratatui Developers
17
-
18
- Source repository: https://github.com/openai/codex
19
- Source commit: e476fc16ce810495cbfabe4f815d20947da0ba79
20
- Source path: codex-rs/sandboxing/src/seatbelt_base_policy.sbpl
21
-
22
- The Codex-derived Seatbelt policy is used in
23
- cli/src/lib/sandbox/seatbelt.js.
24
-
25
- OfficeCLI
26
- Copyright 2026 OfficeCLI (https://OfficeCLI.AI)
27
-
28
- Created and maintained by goworm.
29
-
30
- This product is licensed under the Apache License, Version 2.0.
31
- You may obtain a copy of the License in the LICENSE file or at
32
- http://www.apache.org/licenses/LICENSE-2.0
33
-
34
- This NOTICE file is part of the required attribution under
35
- Section 4 of the Apache License, Version 2.0. Redistributions
36
- of this work, with or without modification, must retain this
37
- notice.
38
-
39
- Source repository: https://github.com/iOfficeAI/OfficeCLI
40
- Source commit: a1498dbd3cb350abde04a1cda1f2eded61ea8a74
41
- Source path: NOTICE
42
-
43
- The OfficeCLI skill bundle is vendored under
44
- backend/commonly-bundled-skills/officecli/.
@@ -1,63 +0,0 @@
1
- """
2
- Hello-world Commonly agent — emitted by `commonly agent init --language python`.
3
-
4
- Reads its runtime token from .commonly-env (or COMMONLY_TOKEN) and echoes
5
- chat events back into the pod. Replace `handle_event()` with your logic.
6
- """
7
-
8
- # PEP 604 unions (`str | None`) need 3.10+ at runtime; this keeps the bot
9
- # importable on macOS's stock /usr/bin/python3 (3.9).
10
- from __future__ import annotations
11
-
12
- import os
13
- import sys
14
- from pathlib import Path
15
-
16
- # `commonly.py` is dropped in the same dir by the scaffolder.
17
- sys.path.insert(0, str(Path(__file__).parent))
18
- from commonly import Commonly # noqa: E402
19
-
20
- CHAT_EVENT_TYPES = {"chat.mention", "message.posted", "dm.message"}
21
-
22
-
23
- def load_token() -> str:
24
- if os.environ.get("COMMONLY_TOKEN"):
25
- return os.environ["COMMONLY_TOKEN"]
26
- env_file = Path(__file__).parent / ".commonly-env"
27
- if env_file.exists():
28
- # KEY=VALUE format so `source .commonly-env` works too. We only need
29
- # the token line; ignore comments and other keys.
30
- for line in env_file.read_text(encoding="utf-8").splitlines():
31
- line = line.strip()
32
- if not line or line.startswith("#"):
33
- continue
34
- if line.startswith("COMMONLY_TOKEN="):
35
- return line.split("=", 1)[1].strip().strip("'\"")
36
- raise SystemExit("No runtime token found. Set COMMONLY_TOKEN or write .commonly-env.")
37
-
38
-
39
- def handle_event(evt: dict) -> str | None:
40
- """Echo the user's message back. Replace this with your real logic."""
41
- if evt.get("type") not in CHAT_EVENT_TYPES:
42
- return None
43
- payload = evt.get("payload") or {}
44
- # rawContent is the message exactly as its author typed it. content is what
45
- # a model should read: the kernel's context frames, a blank line, then the
46
- # message. Older servers send only content/prompt/text.
47
- incoming = payload.get("rawContent")
48
- if incoming is None:
49
- incoming = payload.get("content") or payload.get("prompt") or payload.get("text")
50
- if not incoming:
51
- return None
52
- return f"echo: {incoming}"
53
-
54
-
55
- def main() -> None:
56
- base_url = os.environ.get("COMMONLY_BASE_URL", "https://api.commonly.me")
57
- bot = Commonly(base_url=base_url, runtime_token=load_token())
58
- print(f"[hello-world] polling {base_url} (Ctrl+C to stop)", flush=True)
59
- bot.run(handle_event)
60
-
61
-
62
- if __name__ == "__main__":
63
- main()
@@ -1,232 +0,0 @@
1
- """
2
- Commonly Python SDK — single-file reference implementation of the four
3
- Commonly Agent Protocol (CAP) verbs. ADR-006 §SDK shape.
4
-
5
- Stdlib only. No deps. Drop-copy this file into your project and import.
6
-
7
- Usage (high-level):
8
-
9
- from commonly import Commonly
10
-
11
- bot = Commonly(base_url="https://api.commonly.me", runtime_token="cm_agent_…")
12
- bot.run(lambda evt: f"echo: {evt['payload'].get('rawContent', evt['payload'].get('content', ''))}")
13
-
14
- Usage (manual loop):
15
-
16
- bot = Commonly(...)
17
- while True:
18
- for evt in bot.poll_events():
19
- try:
20
- reply = handle(evt)
21
- if reply and evt.get("podId"):
22
- bot.get_pod_context(evt["podId"]) # read first, or the send guard refuses
23
- bot.post_message(evt["podId"], reply)
24
- finally:
25
- bot.ack(evt["_id"], delivery_id=evt.get("payload", {}).get("deliveryId"))
26
- time.sleep(5)
27
- """
28
-
29
- from __future__ import annotations
30
-
31
- import json
32
- import time
33
- import urllib.error
34
- import urllib.request
35
- from typing import Any, Callable, Optional
36
-
37
-
38
- # --------------------------------------------------------------------------- #
39
- # HTTP error type — subclasses propagate `status` so callers can branch on
40
- # 401/403/404 without parsing the message string.
41
- # --------------------------------------------------------------------------- #
42
-
43
-
44
- class CommonlyError(Exception):
45
- def __init__(self, message: str, status: Optional[int] = None, body: Any = None):
46
- super().__init__(message)
47
- self.status = status
48
- self.body = body
49
-
50
-
51
- def _describe_http_error(status: int, method: str, path: str, payload: Any) -> str:
52
- """Name the server's reason on every 4xx. A 409 from the freshness guard
53
- carries `message` ("N new messages … Read the conversation …"); dropping it
54
- left the stock bot logging a bare status with no cause."""
55
- head = f"HTTP {status} {method} {path}"
56
- if isinstance(payload, dict):
57
- reason = payload.get("message") or payload.get("error") or payload.get("code")
58
- if reason:
59
- return f"{head}: {reason}"
60
- elif isinstance(payload, str) and payload.strip():
61
- return f"{head}: {payload.strip()[:200]}"
62
- return head
63
-
64
-
65
- # --------------------------------------------------------------------------- #
66
- # Client
67
- # --------------------------------------------------------------------------- #
68
-
69
-
70
- class Commonly:
71
- """Thin client over the four CAP verbs. Sync; one HTTP request per call."""
72
-
73
- def __init__(self, *, base_url: str, runtime_token: str, timeout_s: float = 30.0):
74
- self.base_url = base_url.rstrip("/")
75
- self.runtime_token = runtime_token
76
- self.timeout_s = timeout_s
77
-
78
- # ----- internal -------------------------------------------------------- #
79
-
80
- @staticmethod
81
- def _path(base_path: str, **params: Any) -> str:
82
- from urllib.parse import urlencode
83
- kept = {k: v for k, v in params.items() if v is not None}
84
- if not kept:
85
- return base_path
86
- return f"{base_path}?{urlencode(kept)}"
87
-
88
- def _request(self, method: str, path: str, body: Optional[dict] = None) -> Any:
89
- url = f"{self.base_url}{path}"
90
- data = json.dumps(body).encode("utf-8") if body is not None else None
91
- req = urllib.request.Request(url, data=data, method=method)
92
- req.add_header("Authorization", f"Bearer {self.runtime_token}")
93
- req.add_header("User-Agent", "commonly-sdk/0.1")
94
- if data is not None:
95
- req.add_header("Content-Type", "application/json")
96
- try:
97
- with urllib.request.urlopen(req, timeout=self.timeout_s) as resp:
98
- raw = resp.read().decode("utf-8") or "{}"
99
- return json.loads(raw)
100
- except urllib.error.HTTPError as e:
101
- raw = e.read().decode("utf-8", errors="replace") if e.fp else ""
102
- try:
103
- payload = json.loads(raw) if raw else None
104
- except Exception:
105
- payload = raw
106
- raise CommonlyError(_describe_http_error(e.code, method, path, payload),
107
- status=e.code, body=payload) from e
108
-
109
- # ----- CAP verbs ------------------------------------------------------- #
110
-
111
- def poll_events(self, *, limit: int = 10) -> list:
112
- """CAP verb 1 — pull queued events. Immediate return; no long-poll."""
113
- body = self._request("GET", self._path("/api/agents/runtime/events", limit=int(limit)))
114
- return body.get("events", []) if isinstance(body, dict) else []
115
-
116
- def ack(self, event_id: str, *, delivery_id: Optional[str] = None,
117
- outcome: str = "acknowledged", content: Optional[str] = None) -> None:
118
- """CAP verb 2 — acknowledge an event. Forward the delivery_id from
119
- event.payload.deliveryId when present; skip on adapter errors so the
120
- kernel re-delivers (ADR-005 §Spawning semantics)."""
121
- result = {"outcome": outcome}
122
- if content is not None:
123
- result["content"] = content
124
- body: dict = {"result": result}
125
- if delivery_id:
126
- body["deliveryId"] = delivery_id
127
- self._request("POST", f"/api/agents/runtime/events/{event_id}/ack", body)
128
-
129
- def post_message(self, pod_id: str, content: str, *,
130
- reply_to_message_id: Optional[str] = None,
131
- metadata: Optional[dict] = None) -> dict:
132
- """CAP verb 3 — post a chat message into a pod."""
133
- body: dict = {"content": content}
134
- if reply_to_message_id is not None:
135
- body["reply_to_message_id"] = reply_to_message_id
136
- if metadata is not None:
137
- body["metadata"] = metadata
138
- return self._request("POST", f"/api/agents/runtime/pods/{pod_id}/messages", body)
139
-
140
- def get_pod_context(self, pod_id: str) -> dict:
141
- """Read the pod before replying. The server records this read; the
142
- send guard refuses a post to a pod the agent has not read since its
143
- newest message (409 unseen_messages). Reading first is the contract."""
144
- return self._request("GET", f"/api/agents/runtime/pods/{pod_id}/context")
145
-
146
- def _post_reply(self, pod_id: str, content: str) -> dict:
147
- """Read the pod, then post. If a message lands between the read and the
148
- post, read once more and retry; a second 409 propagates with its reason."""
149
- self.get_pod_context(pod_id)
150
- try:
151
- return self.post_message(pod_id, content)
152
- except CommonlyError as exc:
153
- if exc.status != 409:
154
- raise
155
- self.get_pod_context(pod_id)
156
- return self.post_message(pod_id, content)
157
-
158
- def get_memory(self) -> dict:
159
- """CAP verb 4a — read the agent's memory envelope (ADR-003)."""
160
- return self._request("GET", "/api/agents/runtime/memory")
161
-
162
- def sync_memory(self, sections: dict, *, mode: str = "patch",
163
- source_runtime: str = "webhook-sdk-py") -> dict:
164
- """CAP verb 4b — patch-or-replace the memory envelope.
165
-
166
- ADR-003 invariant #9: callers supply `content` + `visibility` only on
167
- each section. byteSize / updatedAt / schemaVersion are server-stamped
168
- and silently discarded if sent.
169
- """
170
- if mode not in ("patch", "full"):
171
- raise ValueError("mode must be 'patch' or 'full'")
172
- return self._request("POST", "/api/agents/runtime/memory/sync",
173
- {"mode": mode, "sourceRuntime": source_runtime,
174
- "sections": sections})
175
-
176
- # ----- run loop -------------------------------------------------------- #
177
-
178
- def run(self, on_event: Callable[[dict], Optional[str]], *,
179
- interval_s: float = 5.0, max_auth_errors: int = 3) -> None:
180
- """Convenience loop. Calls `on_event(evt)` for each polled event; if
181
- the handler returns a non-empty string AND the event has a podId, the
182
- string is posted back, then the event is acked.
183
-
184
- On handler exception the ack is SKIPPED so the kernel re-delivers
185
- (matches ADR-005 §Spawning semantics — at-least-once + driver
186
- idempotency). Override `run()` if you want custom retry semantics.
187
-
188
- Exits after `max_auth_errors` consecutive 401/403 poll responses so a
189
- revoked token doesn't produce an invisible infinite backoff loop. The
190
- caller should surface the exit to the user (e.g. prompt them to
191
- re-issue a token)."""
192
- consecutive_auth_errors = 0
193
- while True:
194
- try:
195
- events = self.poll_events()
196
- consecutive_auth_errors = 0
197
- except CommonlyError as exc:
198
- if exc.status in (401, 403):
199
- consecutive_auth_errors += 1
200
- if consecutive_auth_errors >= max_auth_errors:
201
- print(
202
- f"[commonly] runtime token rejected {consecutive_auth_errors}x in a row — exiting. "
203
- "Check COMMONLY_TOKEN: it must hold the bare cm_agent_... value, not the "
204
- "KEY=VALUE line from .commonly-env. If it is right, re-issue the token or uninstall the agent.",
205
- flush=True,
206
- )
207
- return
208
- print(f"[commonly] poll failed ({exc.status}): {exc}", flush=True)
209
- time.sleep(min(interval_s * 4, 60))
210
- continue
211
- for evt in events:
212
- pod_id = evt.get("podId")
213
- try:
214
- reply = on_event(evt)
215
- except Exception as exc: # adapter-side error — skip ack so kernel re-delivers
216
- print(f"[commonly] handler error on {evt.get('_id')}: {exc}", flush=True)
217
- continue
218
- if reply and pod_id:
219
- try:
220
- self._post_reply(pod_id, reply)
221
- except CommonlyError as exc:
222
- print(f"[commonly] post failed ({exc.status}): {exc}", flush=True)
223
- continue
224
- try:
225
- self.ack(
226
- evt["_id"],
227
- delivery_id=evt.get("payload", {}).get("deliveryId"),
228
- outcome="posted" if reply else "no_action",
229
- )
230
- except CommonlyError as exc:
231
- print(f"[commonly] ack failed ({exc.status}): {exc}", flush=True)
232
- time.sleep(interval_s)
@@ -1,25 +0,0 @@
1
- # packages/seats
2
-
3
- The adapters that run an agent CLI as a supervised seat: one prompt in, one CLI run, one reply out. The package holds the contract, the registry, the failure naming, the spawn observation, the run supervisor (`superviseRun`: a turn with no progress signal for `stallMs` is traced as stuck, cancelled, and settled even if its adapter ignores the cancel), the first adapters (`stub`, `hermes`), and the per-spawn loopback provider proxy that holds a seat's provider key (`wire/provider-proxy`).
4
-
5
- It is private and is not published on its own. `@commonlyai/cli` depends on it as `file:../packages/seats` and lists it in `bundleDependencies`, so it ships inside the CLI tarball.
6
-
7
- ## Release path
8
-
9
- - A push to `main` touching `cli/` or `packages/seats/` triggers
10
- [npm publish](../../.github/workflows/npm-publish.yml). If the packed files changed,
11
- it publishes the next CLI patch with seats bundled ([CLI package](../../cli/package.json)).
12
- [Deploy Dev](../../.github/workflows/deploy-dev.yml) is manually dispatched and builds service images separately.
13
- - The publish job assigns the version. PRs leave version lines alone
14
- ([version guard](../../.github/workflows/package-version-guard.yml), TASK-466).
15
- - Operator-pinned fleet seats select their CLI path in each seat's local `run.sh` launcher,
16
- outside this repo. Update that pin and restart the seat to load a release.
17
- Global CLI installs must be upgraded too; publishing does not update a running seat.
18
- - Check the running wrapper's CLI path and the live spawn argv to see what it runs.
19
- The registry describes configuration; it does not prove what was loaded.
20
-
21
- **Rule:** nothing here imports Commonly code. An adapter that needs Commonly policy (the memory preamble, the legacy sandbox-trust names, the fleet seat-model switch) takes it as a host object through its factory, for example `createHermesAdapter(host)`. The CLI binds that host in `cli/src/lib/adapters/<name>.js`. `cli/__tests__/seats-package.test.mjs` enforces the import rule and checks that the tarball carries every source file.
22
-
23
- The extraction plan is extract-in-place.
24
-
25
- **Run record.** The trace store writes each run as a versioned, hash-chained JSONL record. It covers who granted which agent what access for which task, who approved each call, what was attempted, and the result. A tool outside this package can read, verify and export it to OTLP. The format is specified in [`docs/record-v1.md`](docs/record-v1.md), and a generated sample is in [`docs/examples/`](docs/examples/).
@@ -1,22 +0,0 @@
1
- {
2
- "name": "@commonlyai/seats",
3
- "version": "0.0.0",
4
- "private": true,
5
- "license": "Apache-2.0",
6
- "description": "Adapters that run agent CLIs as supervised seats. Bundled inside @commonlyai/cli; not published on its own.",
7
- "type": "module",
8
- "exports": {
9
- ".": "./src/index.js",
10
- "./*": "./src/*.js"
11
- },
12
- "files": [
13
- "src",
14
- "README.md"
15
- ],
16
- "engines": {
17
- "node": ">=22.0.0"
18
- },
19
- "scripts": {
20
- "test": "node --test $([ -z \"$CI\" ] && echo --test-concurrency=4) \"test/**/*.test.js\""
21
- }
22
- }