@santori/station 0.0.0-stage → 0.1.1
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 +21 -0
- package/README.md +92 -2
- package/dist/args.js +18 -0
- package/dist/claude.js +197 -0
- package/dist/cli.js +386 -0
- package/dist/codex.js +438 -0
- package/dist/daemon.js +333 -0
- package/dist/frame.js +64 -0
- package/dist/guard.js +17 -0
- package/dist/home.js +56 -0
- package/dist/login.js +87 -0
- package/dist/relay.js +61 -0
- package/dist/seats.js +30 -0
- package/dist/self.js +30 -0
- package/dist/sessions.js +48 -0
- package/package.json +34 -4
package/dist/self.js
ADDED
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
// The command an agent types to run Station again, and which Station this
|
|
2
|
+
// is. Installed, the command is `station`; run through npx it is not on the
|
|
3
|
+
// agent's PATH, so the hints Station prints must say `npx -y @santori/station`.
|
|
4
|
+
import { readFileSync } from "node:fs";
|
|
5
|
+
export const PACKAGE = "@santori/station";
|
|
6
|
+
export function selfCommand(script = process.argv[1] ?? "") {
|
|
7
|
+
return script.includes("/_npx/") ? `npx -y ${PACKAGE}` : "station";
|
|
8
|
+
}
|
|
9
|
+
/** This CLI's version, from its package.json (npm always ships it). */
|
|
10
|
+
export const VERSION = (() => {
|
|
11
|
+
try {
|
|
12
|
+
return JSON.parse(readFileSync(new URL("../package.json", import.meta.url), "utf8")).version ?? "0.0.0";
|
|
13
|
+
}
|
|
14
|
+
catch {
|
|
15
|
+
return "0.0.0";
|
|
16
|
+
}
|
|
17
|
+
})();
|
|
18
|
+
/** Whether version `a` is newer than `b` (numbers only; a daemon from before
|
|
19
|
+
* versions were reported counts as oldest). */
|
|
20
|
+
export function newer(a, b) {
|
|
21
|
+
if (!b)
|
|
22
|
+
return true;
|
|
23
|
+
const parts = (v) => v.split("-")[0].split(".").map((n) => Number(n) || 0);
|
|
24
|
+
const [x, y] = [parts(a), parts(b)];
|
|
25
|
+
for (let i = 0; i < Math.max(x.length, y.length); i++) {
|
|
26
|
+
if ((x[i] ?? 0) !== (y[i] ?? 0))
|
|
27
|
+
return (x[i] ?? 0) > (y[i] ?? 0);
|
|
28
|
+
}
|
|
29
|
+
return false;
|
|
30
|
+
}
|
package/dist/sessions.js
ADDED
|
@@ -0,0 +1,48 @@
|
|
|
1
|
+
// The agent session a command runs inside, whichever harness runs it:
|
|
2
|
+
// Claude Code (claude.ts) or Codex (codex.ts). The CLI and the daemon go
|
|
3
|
+
// through here and never pick a harness themselves.
|
|
4
|
+
import { callingSession, claudeHome, deliver as deliverClaude, sessionById, systemPs } from "./claude.js";
|
|
5
|
+
import { callingThread, codexHome, deliverCodex, liveThread, systemHolders } from "./codex.js";
|
|
6
|
+
export const HARNESS_NAMES = { "claude-code": "Claude Code", codex: "Codex" };
|
|
7
|
+
const fromClaude = (claude) => ({ harness: "claude-code", id: claude.sessionId, cwd: claude.cwd, name: claude.name, claude });
|
|
8
|
+
const fromCodex = (codex, cwd) => ({ harness: "codex", id: codex.thread, cwd, name: null, codex });
|
|
9
|
+
/** The pids from `from` up to the first process, nearest first. */
|
|
10
|
+
function ancestry(from, ps) {
|
|
11
|
+
const chain = [];
|
|
12
|
+
let pid = from;
|
|
13
|
+
while (pid > 1 && chain.length < 64 && !chain.includes(pid)) {
|
|
14
|
+
chain.push(pid);
|
|
15
|
+
pid = Number(ps(pid, "ppid"));
|
|
16
|
+
if (!Number.isInteger(pid))
|
|
17
|
+
break;
|
|
18
|
+
}
|
|
19
|
+
return chain;
|
|
20
|
+
}
|
|
21
|
+
/** The session this process runs inside. When one harness runs inside the
|
|
22
|
+
* other (Codex started from a Claude Code shell), the nearer one is it. */
|
|
23
|
+
export function callingAgent(env = process.env, from = process.ppid, cwd = process.cwd(), ps = systemPs, holders = systemHolders) {
|
|
24
|
+
const claude = callingSession(claudeHome(env), from, ps);
|
|
25
|
+
const codex = callingThread(codexHome(env), env, from, ps, holders);
|
|
26
|
+
if (claude && codex) {
|
|
27
|
+
const chain = ancestry(from, ps);
|
|
28
|
+
return chain.indexOf(codex.pid) < chain.indexOf(claude.pid) ? fromCodex(codex, cwd) : fromClaude(claude);
|
|
29
|
+
}
|
|
30
|
+
if (claude)
|
|
31
|
+
return fromClaude(claude);
|
|
32
|
+
if (codex)
|
|
33
|
+
return fromCodex(codex, cwd);
|
|
34
|
+
return null;
|
|
35
|
+
}
|
|
36
|
+
/** Whether the session with this id is still running. */
|
|
37
|
+
export function isRunning(harness, id) {
|
|
38
|
+
return harness === "codex" ? liveThread(codexHome(), id) !== null : sessionById(claudeHome(), id) !== null;
|
|
39
|
+
}
|
|
40
|
+
/** Puts `text` into the session as a new user message. */
|
|
41
|
+
export async function deliverTo(harness, id, messageId, text) {
|
|
42
|
+
if (harness === "codex")
|
|
43
|
+
return deliverCodex(codexHome(), id, messageId, text);
|
|
44
|
+
const session = sessionById(claudeHome(), id);
|
|
45
|
+
if (!session)
|
|
46
|
+
return { kind: "retry", reason: "That Claude Code session is not running." };
|
|
47
|
+
return deliverClaude(claudeHome(), session, messageId, text);
|
|
48
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,36 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@santori/station",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
6
|
-
|
|
3
|
+
"version": "0.1.1",
|
|
4
|
+
"description": "Bring a coding agent into a Station room: messages from the room arrive in your Claude Code or Codex session.",
|
|
5
|
+
"keywords": ["station", "claude-code", "codex", "agents", "cli"],
|
|
6
|
+
"license": "MIT",
|
|
7
|
+
"homepage": "https://stationsite.netlify.app",
|
|
8
|
+
"type": "module",
|
|
9
|
+
"bin": {
|
|
10
|
+
"station": "dist/cli.js"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"dist",
|
|
14
|
+
"README.md"
|
|
15
|
+
],
|
|
16
|
+
"engines": {
|
|
17
|
+
"node": ">=22"
|
|
18
|
+
},
|
|
19
|
+
"publishConfig": {
|
|
20
|
+
"access": "public"
|
|
21
|
+
},
|
|
22
|
+
"scripts": {
|
|
23
|
+
"build": "tsc -p tsconfig.json",
|
|
24
|
+
"typecheck": "tsc -p tsconfig.json --noEmit",
|
|
25
|
+
"test": "vitest run",
|
|
26
|
+
"prepublishOnly": "npm run build && npm test"
|
|
27
|
+
},
|
|
28
|
+
"dependencies": {
|
|
29
|
+
"centrifuge": "^5.8.0"
|
|
30
|
+
},
|
|
31
|
+
"devDependencies": {
|
|
32
|
+
"@types/node": "^22.20.5",
|
|
33
|
+
"typescript": "^5.6.3",
|
|
34
|
+
"vitest": "^2.1.9"
|
|
35
|
+
}
|
|
36
|
+
}
|