syntaur 0.34.0 → 0.35.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/dist/index.js +146 -10
- package/dist/index.js.map +1 -1
- package/package.json +1 -1
- package/platforms/SESSION-ID-RESOLUTION.md +117 -0
- package/platforms/claude-code/agents/syntaur-expert.md +1 -1
- package/platforms/claude-code/commands/track-session/track-session.md +5 -4
- package/platforms/claude-code/hooks/hooks.json +1 -1
- package/platforms/claude-code/hooks/session-cleanup.sh +16 -8
- package/platforms/claude-code/skills/clear-assignment/SKILL.md +1 -1
- package/platforms/claude-code/skills/complete-assignment/SKILL.md +1 -1
- package/platforms/claude-code/skills/grab-assignment/SKILL.md +5 -4
- package/platforms/claude-code/skills/save-session-summary/SKILL.md +15 -6
- package/platforms/claude-code/skills/track-session/SKILL.md +5 -4
- package/platforms/codex/agents/syntaur-operator.md +1 -1
- package/platforms/codex/commands/save-session-summary.md +1 -1
- package/platforms/codex/scripts/session-cleanup.sh +63 -6
- package/platforms/codex/skills/clear-assignment/SKILL.md +1 -1
- package/platforms/codex/skills/complete-assignment/SKILL.md +1 -1
- package/platforms/codex/skills/grab-assignment/SKILL.md +5 -4
- package/platforms/codex/skills/save-session-summary/SKILL.md +15 -6
- package/platforms/codex/skills/track-session/SKILL.md +5 -4
- package/platforms/cursor/hooks/README.md +49 -0
- package/platforms/hermes/plugins/syntaur/__pycache__/__init__.cpython-312.pyc +0 -0
- package/platforms/hermes/plugins/syntaur/__pycache__/boundary.cpython-312.pyc +0 -0
- package/platforms/opencode/plugin/syntaur-session-env.js +30 -0
- package/platforms/pi/README.md +50 -0
- package/skills/clear-assignment/SKILL.md +1 -1
- package/skills/complete-assignment/SKILL.md +1 -1
- package/skills/grab-assignment/SKILL.md +5 -4
- package/skills/save-session-summary/SKILL.md +15 -6
- package/skills/track-session/SKILL.md +5 -4
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
# Pi Integration (Reference Only)
|
|
2
|
+
|
|
3
|
+
Syntaur resolves the **real** agent session id from the running process, not the
|
|
4
|
+
shared `.syntaur/context.json` scalar (a co-tenant clobbers it). For Pi, the job
|
|
5
|
+
is to inject `PI_SESSION_ID` per spawn so the CLI's `resolveOwnSessionId` picks
|
|
6
|
+
it up at layer 2. See `../SESSION-ID-RESOLUTION.md` for the full design.
|
|
7
|
+
|
|
8
|
+
> **Status:** Syntaur already ships a Pi extension at
|
|
9
|
+
> `extensions/syntaur/index.ts` (it tracks the dashboard session via
|
|
10
|
+
> `ctx.sessionId`). That extension does **not** yet inject `PI_SESSION_ID` into
|
|
11
|
+
> spawned commands — adding the `spawnHook` below to it is the remaining piece
|
|
12
|
+
> so Pi commands self-identify to `resolveOwnSessionId` (layer 2). This file
|
|
13
|
+
> documents that injector and its verification gate.
|
|
14
|
+
|
|
15
|
+
## Injector — a `spawnHook` extension
|
|
16
|
+
|
|
17
|
+
Pi extensions (`@earendil-works/pi-coding-agent`, see its `docs/extensions.md`)
|
|
18
|
+
can capture the session id at `session_start` and inject env on every spawned
|
|
19
|
+
command via a bash `spawnHook`:
|
|
20
|
+
|
|
21
|
+
```js
|
|
22
|
+
// syntaur-session-env extension (reference; verify against your Pi version)
|
|
23
|
+
export default {
|
|
24
|
+
name: 'syntaur-session-env',
|
|
25
|
+
session_start(ctx) {
|
|
26
|
+
// Capture the real id once, at session start.
|
|
27
|
+
this.sessionId = ctx.sessionManager.getSessionId();
|
|
28
|
+
},
|
|
29
|
+
// Injected into the environment of every spawned shell command.
|
|
30
|
+
spawnHook() {
|
|
31
|
+
return this.sessionId ? { env: { PI_SESSION_ID: this.sessionId } } : {};
|
|
32
|
+
},
|
|
33
|
+
};
|
|
34
|
+
```
|
|
35
|
+
|
|
36
|
+
Alternatively, if Pi's start hook exposes the process pid, stamp the generic
|
|
37
|
+
marker `~/.syntaur/runtime/sessions/<pid>.json` (see `../SESSION-ID-RESOLUTION.md`)
|
|
38
|
+
and the resolver's layer-4 ancestor walk will find it without env injection.
|
|
39
|
+
|
|
40
|
+
## Verification (needs a live Pi build — cannot run in CI)
|
|
41
|
+
|
|
42
|
+
From a Pi tool call:
|
|
43
|
+
|
|
44
|
+
```bash
|
|
45
|
+
echo "$PI_SESSION_ID" # prints the real Pi session id
|
|
46
|
+
```
|
|
47
|
+
|
|
48
|
+
`PI_SESSION_ID` is already in the resolver's layer-2 precedence list
|
|
49
|
+
(`src/utils/session-id.ts`), so once injected, `syntaur session save` (etc.)
|
|
50
|
+
attribute to the correct session automatically.
|
|
@@ -90,7 +90,7 @@ Do not delete the `.syntaur/` directory itself — other tooling may use it.
|
|
|
90
90
|
|
|
91
91
|
## Step 5: Close Session (optional)
|
|
92
92
|
|
|
93
|
-
If the
|
|
93
|
+
If the Syntaur dashboard is running, mark this session as cleared so the dashboard does not keep showing it as active. Resolve `<session-id>` from *your* running process — prefer `$CLAUDE_CODE_SESSION_ID` (or the peer `OPENCODE_SESSION_ID` / `PI_SESSION_ID`), otherwise run `syntaur session resolve-id`. Only if neither yields an id, fall back to the `sessionId` you captured from the original `context.json` in Step 1 (before deletion) — that scalar is a shared, legacy hint a co-tenant can clobber, so don't treat it as authoritative:
|
|
94
94
|
|
|
95
95
|
```bash
|
|
96
96
|
curl -s -X PATCH "http://localhost:$(cat ~/.syntaur/dashboard-port 2>/dev/null || echo 4800)/api/agent-sessions/<session-id>/status" \
|
|
@@ -101,7 +101,7 @@ Do NOT uncheck or rewrite superseded todo lines matching `- [x] ~~...~~ (superse
|
|
|
101
101
|
|
|
102
102
|
## Step 6: Close Session (optional)
|
|
103
103
|
|
|
104
|
-
If `.syntaur/context.json`
|
|
104
|
+
If the Syntaur dashboard is running, mark this session as completed. Resolve `<session-id>` from *your* running process — prefer `$CLAUDE_CODE_SESSION_ID` (or the peer `OPENCODE_SESSION_ID` / `PI_SESSION_ID`), otherwise run `syntaur session resolve-id`; fall back to the `sessionId` scalar in `.syntaur/context.json` only as a last resort (it is a shared, legacy hint a co-tenant can clobber, not authoritative):
|
|
105
105
|
|
|
106
106
|
```bash
|
|
107
107
|
curl -s -X PATCH "http://localhost:$(cat ~/.syntaur/dashboard-port 2>/dev/null || echo 4800)/api/agent-sessions/<session-id>/status" \
|
|
@@ -113,14 +113,15 @@ Use absolute paths (expand `~` to the home directory). If `workspace.repository`
|
|
|
113
113
|
|
|
114
114
|
## Step 6: Register Agent Session (real IDs only — no UUIDs)
|
|
115
115
|
|
|
116
|
-
`syntaur track-session` requires a `--session-id` from the agent runtime. Synthetic UUIDs are rejected. Source the real id in this order:
|
|
116
|
+
`syntaur track-session` requires a `--session-id` from the agent runtime. Synthetic UUIDs are rejected. Source the real per-process id in this order:
|
|
117
117
|
|
|
118
|
-
1.
|
|
118
|
+
1. Prefer the env var your runtime injects: `$CLAUDE_CODE_SESSION_ID` (or the peer `OPENCODE_SESSION_ID` / `PI_SESSION_ID`).
|
|
119
119
|
2. Otherwise, fall back to the per-agent lookup:
|
|
120
|
-
- **Claude Code**: the most-recently-modified `~/.claude/sessions
|
|
120
|
+
- **Claude Code**: the most-recently-modified `~/.claude/sessions/<pid>.json` whose `cwd` matches `$(pwd)` — read its `sessionId`. The transcript path is `~/.claude/projects/<encoded-cwd>/<session-id>.jsonl` (omit if the file is absent).
|
|
121
121
|
- **Codex**: the most-recently-modified file under `~/.codex/sessions/YYYY/MM/DD/rollout-*.jsonl` whose first-line `session_meta.payload.cwd` matches `$(pwd)`. Use `payload.id` as the session id and the full rollout path as the transcript path.
|
|
122
122
|
- **Other agents**: use whatever real session identifier the runtime exposes. Do not invent one.
|
|
123
|
-
3.
|
|
123
|
+
3. Only as a last resort, fall back to the `sessionId` scalar already in `.syntaur/context.json` (and the companion `transcriptPath` if present). That scalar is a shared, legacy hint a co-tenant sharing this workspace can clobber — never treat it as authoritative.
|
|
124
|
+
4. If no real id can be resolved, stop and tell the user to restart the session so the platform hook can populate it, or to run `/rename <assignment-slug>` (Claude Code) and retry.
|
|
124
125
|
|
|
125
126
|
After resolving, merge `sessionId` + `transcriptPath` back into context.json. Then register:
|
|
126
127
|
|
|
@@ -32,9 +32,14 @@ If the file does not exist, tell the user: "No active assignment found. Run `gra
|
|
|
32
32
|
|
|
33
33
|
Extract:
|
|
34
34
|
- `assignmentDir` (absolute path) — required.
|
|
35
|
-
- `sessionId` — required, must be the real agent runtime session id.
|
|
36
35
|
|
|
37
|
-
|
|
36
|
+
**Do not read the session id from `context.json` for identity.** That scalar is
|
|
37
|
+
a shared, legacy hint a co-tenant can clobber. The session id is resolved from
|
|
38
|
+
*your* running process — prefer, in order:
|
|
39
|
+
1. `$CLAUDE_CODE_SESSION_ID` (or the peer `OPENCODE_SESSION_ID` / `PI_SESSION_ID`) if your runtime injects it.
|
|
40
|
+
2. Otherwise omit `--session-id` entirely and let `syntaur session save` resolve it (it walks env → process tree → transcript, and falls back to the `context.json` hint only as a last resort).
|
|
41
|
+
|
|
42
|
+
Never invent or generate a session id.
|
|
38
43
|
|
|
39
44
|
## Step 2: Author the summary body
|
|
40
45
|
|
|
@@ -75,13 +80,17 @@ Pass the body to `syntaur session save` (it owns the directory, frontmatter,
|
|
|
75
80
|
and `created`-preservation):
|
|
76
81
|
|
|
77
82
|
```bash
|
|
78
|
-
|
|
79
|
-
|
|
83
|
+
# Recommended: omit --session-id and let the CLI resolve YOUR own session id.
|
|
84
|
+
printf '%s' "$BODY" | syntaur session save
|
|
85
|
+
# or from a file: syntaur session save --from-file <body.md>
|
|
86
|
+
# Pass --session-id <id> only to override (e.g. you already have $CLAUDE_CODE_SESSION_ID).
|
|
80
87
|
```
|
|
81
88
|
|
|
82
89
|
Resolves the active assignment from `.syntaur/context.json` (or pass
|
|
83
|
-
`--assignment <slug> [--project <slug>]`)
|
|
84
|
-
|
|
90
|
+
`--assignment <slug> [--project <slug>]`). `--session-id` now defaults to the
|
|
91
|
+
**resolved** session (env → process tree → transcript), falling back to the
|
|
92
|
+
`context.json` hint only as a last resort — so a co-tenant that clobbered the
|
|
93
|
+
shared scalar can't make you write under the wrong id. The command:
|
|
85
94
|
|
|
86
95
|
- Creates `<assignmentDir>/sessions/<sessionId>/` (idempotent) and writes
|
|
87
96
|
`summary.md` — a **single document per session id**, overwritten in place;
|
|
@@ -29,11 +29,12 @@ Extract optional flags from the argument string:
|
|
|
29
29
|
|
|
30
30
|
### Step 2: Source the real session id + transcript path
|
|
31
31
|
|
|
32
|
-
|
|
32
|
+
Resolve the session id from *your* running process, in priority order:
|
|
33
33
|
|
|
34
|
-
1.
|
|
35
|
-
2. Otherwise, read the most-recently-modified file under `~/.claude/sessions
|
|
36
|
-
3.
|
|
34
|
+
1. `$CLAUDE_CODE_SESSION_ID` (or the peer `OPENCODE_SESSION_ID` / `PI_SESSION_ID`) if your runtime injects it.
|
|
35
|
+
2. Otherwise, read the most-recently-modified file under `~/.claude/sessions/<pid>.json` whose `cwd` matches `$(pwd)` and use its `sessionId` field. The transcript path is conventionally `~/.claude/projects/<encoded-cwd>/<sessionId>.jsonl`; include it if the file exists, otherwise omit.
|
|
36
|
+
3. Only as a last resort, fall back to the `sessionId` scalar in `.syntaur/context.json` (and the companion `transcriptPath` if present). This scalar is a shared, legacy hint a co-tenant sharing this workspace can clobber — never treat it as authoritative.
|
|
37
|
+
4. If no source yields an id, abort with: "Could not resolve a real Claude Code session id. Restart the Claude session so the SessionStart hook can populate `.syntaur/context.json`, or run `/rename <slug>` then try again."
|
|
37
38
|
|
|
38
39
|
DO NOT generate a UUID. `syntaur track-session` rejects missing session IDs.
|
|
39
40
|
|