@ravefox/space 0.0.0-stage → 0.2.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.
- package/LICENSE +203 -0
- package/NOTICE +44 -0
- package/README.md +49 -2
- package/assets/webhook-sdk/python/bot.py +63 -0
- package/assets/webhook-sdk/python/commonly.py +232 -0
- package/node_modules/@commonlyai/seats/README.md +25 -0
- package/node_modules/@commonlyai/seats/package.json +22 -0
- package/node_modules/@commonlyai/seats/src/adapters/hermes.js +264 -0
- package/node_modules/@commonlyai/seats/src/adapters/stub.js +24 -0
- package/node_modules/@commonlyai/seats/src/contract.js +48 -0
- package/node_modules/@commonlyai/seats/src/failures.js +44 -0
- package/node_modules/@commonlyai/seats/src/harness-plan.js +329 -0
- package/node_modules/@commonlyai/seats/src/index.js +22 -0
- package/node_modules/@commonlyai/seats/src/process-group.js +269 -0
- package/node_modules/@commonlyai/seats/src/record/format.js +737 -0
- package/node_modules/@commonlyai/seats/src/record/otel.js +238 -0
- package/node_modules/@commonlyai/seats/src/runtime-observation.js +29 -0
- package/node_modules/@commonlyai/seats/src/seat-model.js +17 -0
- package/node_modules/@commonlyai/seats/src/supervisor.js +308 -0
- package/node_modules/@commonlyai/seats/src/trace/events.js +46 -0
- package/node_modules/@commonlyai/seats/src/trace/store.js +276 -0
- package/node_modules/@commonlyai/seats/src/turn-processes.js +226 -0
- package/node_modules/@commonlyai/seats/src/upstream-refusal.js +418 -0
- package/node_modules/@commonlyai/seats/src/valet/env.js +201 -0
- package/node_modules/@commonlyai/seats/src/valet/grant.js +123 -0
- package/node_modules/@commonlyai/seats/src/valet/permissions.js +213 -0
- package/node_modules/@commonlyai/seats/src/wire/provider-proxy.js +529 -0
- package/package.json +56 -4
- package/skills/commonly/SKILL.md +233 -0
- package/src/commands/agent.js +6334 -0
- package/src/commands/daemon.js +933 -0
- package/src/commands/dev.js +153 -0
- package/src/commands/doctor.js +141 -0
- package/src/commands/inbox.js +330 -0
- package/src/commands/login.js +194 -0
- package/src/commands/mcp.js +56 -0
- package/src/commands/pod.js +120 -0
- package/src/commands/task.js +279 -0
- package/src/commands/verify.js +48 -0
- package/src/index.js +99 -0
- package/src/lib/adapter-login.js +76 -0
- package/src/lib/adapters/broker-bridge-entry.js +76 -0
- package/src/lib/adapters/claude.js +2207 -0
- package/src/lib/adapters/codex-broker-bridge.mjs +298 -0
- package/src/lib/adapters/codex.js +1898 -0
- package/src/lib/adapters/dsh.js +513 -0
- package/src/lib/adapters/goose.js +510 -0
- package/src/lib/adapters/hermes.js +18 -0
- package/src/lib/adapters/index.js +68 -0
- package/src/lib/adapters/opencode.js +1681 -0
- package/src/lib/adapters/pi-commonly-mcp.mjs +71 -0
- package/src/lib/adapters/pi-mcp-client.mjs +617 -0
- package/src/lib/adapters/pi-shell-env.mjs +41 -0
- package/src/lib/adapters/pi.js +1025 -0
- package/src/lib/adapters/qwen.js +523 -0
- package/src/lib/adapters/seat-model.js +8 -0
- package/src/lib/adapters/stub.js +1 -0
- package/src/lib/adapters/tested-version.js +106 -0
- package/src/lib/api.js +205 -0
- package/src/lib/claim-outcome.js +128 -0
- package/src/lib/claimed-work-gate.js +73 -0
- package/src/lib/cli-hint.js +33 -0
- package/src/lib/commit-attribution.js +391 -0
- package/src/lib/config.js +155 -0
- package/src/lib/content-refusal.js +94 -0
- package/src/lib/credential-file.js +208 -0
- package/src/lib/daemon-agent-states.js +95 -0
- package/src/lib/daemon-hint.js +18 -0
- package/src/lib/daemon-logs.js +43 -0
- package/src/lib/daemon-service-windows.js +263 -0
- package/src/lib/daemon-service.js +486 -0
- package/src/lib/daemon-state.js +84 -0
- package/src/lib/daemon-store.js +119 -0
- package/src/lib/daemon-supervisor.js +629 -0
- package/src/lib/daemon-watch.js +115 -0
- package/src/lib/declared-mcp-guard.js +284 -0
- package/src/lib/default-environment.js +207 -0
- package/src/lib/device-login.js +126 -0
- package/src/lib/digest-frame.js +151 -0
- package/src/lib/doctor.js +291 -0
- package/src/lib/egress-proxy.js +160 -0
- package/src/lib/enforcement.js +946 -0
- package/src/lib/environment.js +681 -0
- package/src/lib/first-output-watchdog.js +191 -0
- package/src/lib/git-readonly-server.js +138 -0
- package/src/lib/git-readonly.js +463 -0
- package/src/lib/git-remote-commonly.mjs +100 -0
- package/src/lib/grant-broker-guard.js +345 -0
- package/src/lib/hooks-config.js +238 -0
- package/src/lib/host-gh-broker.js +152 -0
- package/src/lib/host-gh-shim.mjs +98 -0
- package/src/lib/inbox.js +483 -0
- package/src/lib/instance-proxy.js +76 -0
- package/src/lib/machine-host.js +29 -0
- package/src/lib/mcp-credential-delivery.js +121 -0
- package/src/lib/mcp-first-run.js +50 -0
- package/src/lib/mcp-home.js +644 -0
- package/src/lib/mcp-ready.js +68 -0
- package/src/lib/mcp-server-version.js +123 -0
- package/src/lib/mcp-token.js +36 -0
- package/src/lib/mcp-warm-child.mjs +412 -0
- package/src/lib/memory-bridge.js +191 -0
- package/src/lib/memory-import.js +156 -0
- package/src/lib/missing-harness.js +31 -0
- package/src/lib/model-unavailable.js +154 -0
- package/src/lib/native-runtime-inventory.js +40 -0
- package/src/lib/outsider-grant-mcp.js +82 -0
- package/src/lib/own-key-launch.js +42 -0
- package/src/lib/pod-catch-up.js +55 -0
- package/src/lib/pod-focus.js +224 -0
- package/src/lib/pod-tail.js +68 -0
- package/src/lib/poll-liveness.js +103 -0
- package/src/lib/poll-retry.js +81 -0
- package/src/lib/poller.js +200 -0
- package/src/lib/provider-proxy.js +42 -0
- package/src/lib/public-seat-mcp-flag.js +36 -0
- package/src/lib/public-tool-error.js +60 -0
- package/src/lib/public-withheld-tools.js +48 -0
- package/src/lib/reply-receipt.js +55 -0
- package/src/lib/resolve-on-path.js +22 -0
- package/src/lib/runtime-inventory.js +56 -0
- package/src/lib/runtime-observation.js +37 -0
- package/src/lib/sandbox/bwrap.js +275 -0
- package/src/lib/sandbox/codex-perimeter.js +16 -0
- package/src/lib/sandbox/host-check.js +268 -0
- package/src/lib/sandbox/mode.js +49 -0
- package/src/lib/sandbox/opencode-loopback.mjs +68 -0
- package/src/lib/sandbox/seatbelt.js +684 -0
- package/src/lib/sandbox/turn-dir.js +56 -0
- package/src/lib/sandbox/windows-unsandboxed.js +183 -0
- package/src/lib/sandbox/workspace-git-config.js +243 -0
- package/src/lib/sandbox/workspace-pin.js +158 -0
- package/src/lib/seat-runtime-controls.js +61 -0
- package/src/lib/seat-stop.js +97 -0
- package/src/lib/server-skills.js +32 -0
- package/src/lib/session-recycle.js +219 -0
- package/src/lib/session-store.js +215 -0
- package/src/lib/skill-prompt.js +74 -0
- package/src/lib/skills-import.js +113 -0
- package/src/lib/spawn-credential.js +402 -0
- package/src/lib/spawn-retry.js +311 -0
- package/src/lib/stable-install.js +176 -0
- package/src/lib/supervised-turn.js +352 -0
- package/src/lib/task.js +235 -0
- package/src/lib/turn-failure-notice.js +177 -0
- package/src/lib/unconfined-seat-guard.js +94 -0
- package/src/lib/update-check.js +192 -0
- package/src/lib/upstream-refusal.js +1 -0
- package/src/lib/webhook-server.js +109 -0
- package/src/lib/windows-command.js +393 -0
- package/src/lib/workspace-git.js +87 -0
- package/src/lib/workspace-trust.js +162 -0
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* How a declared MCP server receives the seat credential, for the two adapters
|
|
3
|
+
* that cannot hand it over on a pipe.
|
|
4
|
+
*
|
|
5
|
+
* The pi bridge spawns the server itself, so it can pipe the credential on an
|
|
6
|
+
* inherited fd (see `pi-mcp-client.mjs`). Claude and codex do not: each of them
|
|
7
|
+
* starts the server inside its own process tree, so the only two channels
|
|
8
|
+
* available are (a) a value in the runtime's environment, which the whole
|
|
9
|
+
* subtree inherits, or (b) a PATH in the declaration that the server itself
|
|
10
|
+
* reads. (b) is the one that leaves the token where it belongs.
|
|
11
|
+
*
|
|
12
|
+
* This module makes that choice in ONE place, because three call sites deciding
|
|
13
|
+
* version thresholds independently is how one of them ends up handing over the
|
|
14
|
+
* value while the others hand over the path.
|
|
15
|
+
*
|
|
16
|
+
* The rewrite is of the DECLARATION, not of the value: an entry that named
|
|
17
|
+
* `COMMONLY_AGENT_TOKEN` comes back naming `COMMONLY_TOKEN_FILE`, so the value
|
|
18
|
+
* never exists in the runtime's environment to be inherited, logged, or dumped
|
|
19
|
+
* by an unrelated MCP server that a seat was granted.
|
|
20
|
+
*/
|
|
21
|
+
import { CREDENTIAL_FILE_VAR, CREDENTIAL_KEY } from './credential-file.js';
|
|
22
|
+
import {
|
|
23
|
+
FILE_READER_VERSION, MCP_PACKAGE, describeMcpCommand, versionOlderThan,
|
|
24
|
+
} from './mcp-server-version.js';
|
|
25
|
+
|
|
26
|
+
/** What a declaration should say to receive the credential as a path. */
|
|
27
|
+
export const CREDENTIAL_FILE_PLACEHOLDER = '${COMMONLY_TOKEN_FILE}';
|
|
28
|
+
|
|
29
|
+
/**
|
|
30
|
+
* What a runtime's OWN environment may carry, once the declarations are settled.
|
|
31
|
+
*
|
|
32
|
+
* The rewrite above decides what a CHILD is told. It does not decide what the
|
|
33
|
+
* runtime process itself carries, and that is a separate leak with the same
|
|
34
|
+
* symptom: the credential is exported for bootstrap (`agent run`, the daemon),
|
|
35
|
+
* so an adapter that derives its runtime environment from `process.env` hands
|
|
36
|
+
* the value back to the runtime — and to every MCP child, hook and shell below
|
|
37
|
+
* it — however the declaration was rewritten. Measured (Vera, 70455): four tests
|
|
38
|
+
* that pass in a runner without the variable fail with it set, and the value
|
|
39
|
+
* they saw was the runner's own.
|
|
40
|
+
*
|
|
41
|
+
* So the PATH of this spawn's file goes in (a path is not a secret, and a hook
|
|
42
|
+
* process resolves its credential from it — see `hooks-config.resolveHookToken`)
|
|
43
|
+
* and the VALUE comes out, unless a carve-out genuinely needs the value here:
|
|
44
|
+
* a field the adapter substitutes LITERALLY has no file channel, so `keepsValue`
|
|
45
|
+
* is passed in by the adapter rather than inferred, and the spawn that keeps a
|
|
46
|
+
* secret says so in its own warning.
|
|
47
|
+
*
|
|
48
|
+
* The PATH comes out too when there is no file for THIS spawn. The runtime
|
|
49
|
+
* environment is derived from `process.env`, so a launcher whose own process was
|
|
50
|
+
* spawned by another seat inherits that seat's `COMMONLY_TOKEN_FILE` and hands
|
|
51
|
+
* it to the runtime and every MCP child below it — a path to a credential this
|
|
52
|
+
* launcher did not mint. The value was already deleted here for that reason; the
|
|
53
|
+
* path is the same leak with a smaller blast radius.
|
|
54
|
+
*/
|
|
55
|
+
export const withholdRuntimeCredential = (env, { credentialFile = null, keepsValue = false } = {}) => {
|
|
56
|
+
if (credentialFile) {
|
|
57
|
+
env[CREDENTIAL_FILE_VAR] = credentialFile;
|
|
58
|
+
} else {
|
|
59
|
+
delete env[CREDENTIAL_FILE_VAR];
|
|
60
|
+
}
|
|
61
|
+
if (!keepsValue) delete env[CREDENTIAL_KEY];
|
|
62
|
+
return env;
|
|
63
|
+
};
|
|
64
|
+
|
|
65
|
+
/** What a declaration says when it asks for the seat credential (the old shape). */
|
|
66
|
+
export const CREDENTIAL_PLACEHOLDER = '${COMMONLY_AGENT_TOKEN}';
|
|
67
|
+
|
|
68
|
+
/**
|
|
69
|
+
* Rewrite one server's declared environment so the credential arrives as a path.
|
|
70
|
+
*
|
|
71
|
+
* Returns `{ env, delivered }` where `delivered` is one of:
|
|
72
|
+
* 'path' — the declaration now names the file; the adapter expands it
|
|
73
|
+
* 'env' — the value stays in the environment, deliberately (see below)
|
|
74
|
+
* 'none' — nothing to deliver: the entry declares no credential
|
|
75
|
+
* 'unavailable' — no launcher credential file exists for this spawn
|
|
76
|
+
*
|
|
77
|
+
* `env` is a fresh object; the caller's declaration is never mutated.
|
|
78
|
+
*/
|
|
79
|
+
export const deliverSeatCredential = (server, {
|
|
80
|
+
credentialFile,
|
|
81
|
+
onWarn = (message) => process.stderr.write(`${message}\n`),
|
|
82
|
+
label = 'mcp',
|
|
83
|
+
} = {}) => {
|
|
84
|
+
const env = { ...((server || {}).env || {}) };
|
|
85
|
+
if (env[CREDENTIAL_FILE_VAR] !== undefined && String(env[CREDENTIAL_FILE_VAR]).trim() !== '') {
|
|
86
|
+
// Already on the launcher channel — an operator who set this by hand, or a
|
|
87
|
+
// record written after this shipped. Nothing to rewrite.
|
|
88
|
+
return { env, delivered: 'path' };
|
|
89
|
+
}
|
|
90
|
+
if (env[CREDENTIAL_KEY] === undefined) return { env, delivered: 'none' };
|
|
91
|
+
if (!credentialFile) {
|
|
92
|
+
// No launcher wrote a file, so there is nothing to point at. Leave the
|
|
93
|
+
// declaration exactly as it was rather than handing over a path to nowhere.
|
|
94
|
+
return { env, delivered: 'unavailable' };
|
|
95
|
+
}
|
|
96
|
+
const ours = describeMcpCommand((server || {}).command);
|
|
97
|
+
if (!ours) {
|
|
98
|
+
// Somebody else's server. Their declaration is theirs: we do not know their
|
|
99
|
+
// protocol, so replacing their variable with a path would break a server we
|
|
100
|
+
// have no business redefining.
|
|
101
|
+
onWarn(`[${label}] ${server?.name} is not ${MCP_PACKAGE} but declares ${CREDENTIAL_KEY}; leaving that declaration alone. Declare the seat credential on the commonly entry instead.`);
|
|
102
|
+
return { env, delivered: 'env' };
|
|
103
|
+
}
|
|
104
|
+
if (versionOlderThan(ours.version, FILE_READER_VERSION) === true) {
|
|
105
|
+
// Measured, not hypothetical: five seats run a hand-patched staging checkout
|
|
106
|
+
// at 0.3.7, whose reader only understands the environment. Handing it a path
|
|
107
|
+
// it cannot read would take its tools away rather than its secret.
|
|
108
|
+
onWarn(`[${label}] ${server.name} runs @commonlyai/mcp ${ours.version.join('.')}, which predates the credential file (${FILE_READER_VERSION.join('.')}): keeping the token in the environment. Unpin it, or move that seat off this checkout.`);
|
|
109
|
+
return { env, delivered: 'env' };
|
|
110
|
+
}
|
|
111
|
+
if (String(env[CREDENTIAL_KEY]) !== CREDENTIAL_PLACEHOLDER) {
|
|
112
|
+
// A literal token in a declaration is stale by construction — seat tokens
|
|
113
|
+
// rotate, and this one was read when the record was written. Superseding it
|
|
114
|
+
// with the live credential is a repair, but it IS a change in what the seat
|
|
115
|
+
// sends, so it is said out loud rather than done quietly.
|
|
116
|
+
onWarn(`[${label}] ${server.name} declares a literal ${CREDENTIAL_KEY}; superseding it with this spawn's credential file.`);
|
|
117
|
+
}
|
|
118
|
+
delete env[CREDENTIAL_KEY];
|
|
119
|
+
env[CREDENTIAL_FILE_VAR] = CREDENTIAL_FILE_PLACEHOLDER;
|
|
120
|
+
return { env, delivered: 'path' };
|
|
121
|
+
};
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Prepare the commonly MCP build before a confined seat's first poll.
|
|
3
|
+
*
|
|
4
|
+
* A confined seat (public, or workspace since TASK-294) runs its MCP server
|
|
5
|
+
* only from a host-prepared build (TASK-273),
|
|
6
|
+
* and the first spawn on an empty home only STARTS preparing one, then refuses
|
|
7
|
+
* its turn. On a fresh machine that refused turn was the person's first
|
|
8
|
+
* @mention, and it waited out the kernel's requeue, about ten minutes (BYO
|
|
9
|
+
* walk, 2026-10-16). `agent run` prepares the build once, before it polls.
|
|
10
|
+
*
|
|
11
|
+
* The gate is the adapters' own: claude.js refuses a workspace seat's turn
|
|
12
|
+
* without that build too. Gated on 'public' alone, a Connect-page Claude Code
|
|
13
|
+
* seat in private pods (trust 'workspace') skipped the warm and its first
|
|
14
|
+
* @mention was refused (prod walk, 2026-11-05).
|
|
15
|
+
*/
|
|
16
|
+
|
|
17
|
+
// The trusts whose spawn requires a host-prepared build.
|
|
18
|
+
const CONFINED_TRUSTS = new Set(['public', 'workspace']);
|
|
19
|
+
|
|
20
|
+
import { normalizeSandboxTrust } from './environment.js';
|
|
21
|
+
import { COMMONLY_MCP_SERVER_NAME } from './default-environment.js';
|
|
22
|
+
import { WARM_RESULTS, planMcpSpawn, resolveHomeDir } from './mcp-home.js';
|
|
23
|
+
import { warmMcpHome } from './mcp-warm-child.mjs';
|
|
24
|
+
|
|
25
|
+
/** The warm's result when it ran, or null when this seat needed none. */
|
|
26
|
+
export const prepareMcpBeforeFirstPoll = async ({
|
|
27
|
+
environment,
|
|
28
|
+
home,
|
|
29
|
+
plan = planMcpSpawn,
|
|
30
|
+
warm = warmMcpHome,
|
|
31
|
+
log = () => {},
|
|
32
|
+
} = {}) => {
|
|
33
|
+
if (!CONFINED_TRUSTS.has(normalizeSandboxTrust(environment?.sandbox)?.trust)) return null;
|
|
34
|
+
const server = Array.isArray(environment?.mcp)
|
|
35
|
+
? environment.mcp.find((entry) => entry?.name === COMMONLY_MCP_SERVER_NAME)
|
|
36
|
+
: null;
|
|
37
|
+
if (!Array.isArray(server?.command)) return null;
|
|
38
|
+
if (plan(server.command, { home }).reason !== 'home-empty') return null;
|
|
39
|
+
|
|
40
|
+
log("preparing Space's tools on this machine (first run only)...");
|
|
41
|
+
const result = await warm(resolveHomeDir(home), { now: Date.now() });
|
|
42
|
+
if (result === WARM_RESULTS.ADVANCED || result === WARM_RESULTS.CURRENT) {
|
|
43
|
+
log("Space's tools are ready");
|
|
44
|
+
} else {
|
|
45
|
+
log(`could not prepare Space's tools yet (${result}); the first turn will try again`);
|
|
46
|
+
}
|
|
47
|
+
return result;
|
|
48
|
+
};
|
|
49
|
+
|
|
50
|
+
export default { prepareMcpBeforeFirstPoll };
|