sessionpipe-conformance 0.9.0 → 0.10.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/cli.js +69 -7
- package/dist/cli.js.map +3 -3
- package/dist/index.js +69 -7
- package/dist/index.js.map +3 -3
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
-
// sessionpipe-conformance 0.
|
|
2
|
+
// sessionpipe-conformance 0.10.0 · Apache-2.0 · https://sessionpipe.org
|
|
3
3
|
|
|
4
4
|
// src/cli.ts
|
|
5
5
|
import { readdirSync as readdirSync5, realpathSync as realpathSync2, statSync as statSync4 } from "node:fs";
|
|
@@ -804,14 +804,28 @@ var claudeCode = {
|
|
|
804
804
|
case "SessionStart":
|
|
805
805
|
events.push(ev("session.started", { source: pickSource(s.source ?? s.trigger) }));
|
|
806
806
|
break;
|
|
807
|
-
case "UserPromptSubmit":
|
|
807
|
+
case "UserPromptSubmit": {
|
|
808
|
+
const prompt = typeof s.prompt === "string" ? s.prompt : void 0;
|
|
808
809
|
events.push(
|
|
809
810
|
ev("turn.started", {
|
|
810
811
|
turn_id,
|
|
811
|
-
prompt_chars:
|
|
812
|
+
prompt_chars: prompt === void 0 ? void 0 : [...prompt].length,
|
|
813
|
+
// Claude Code's hook schema documents `source`
|
|
814
|
+
// (user | sdk | system | loop_wakeup | schedule_wakeup | poll_event) and says a
|
|
815
|
+
// payload may omit it while the field rolls out; 2.1.304's payload has no such
|
|
816
|
+
// key at all. Forwarded verbatim, shape-guarded only: the list is the harness's
|
|
817
|
+
// to extend.
|
|
818
|
+
submitted_by: harnessWord(s.source),
|
|
819
|
+
// One of Claude Code's own prompt wrappers: the prompt is a block the harness
|
|
820
|
+
// wrote, so it is not the person's words. Absent is unknown, never "the person" —
|
|
821
|
+
// and `true` is never "no person caused this turn", because a Talk or
|
|
822
|
+
// `sessionpipe wait` delivery hands the person's own message over inside a
|
|
823
|
+
// <task-notification> (PROTOCOL.md §4).
|
|
824
|
+
injected: prompt !== void 0 && injectedBlock(prompt) ? true : void 0
|
|
812
825
|
})
|
|
813
826
|
);
|
|
814
827
|
break;
|
|
828
|
+
}
|
|
815
829
|
case "PreToolUse":
|
|
816
830
|
if (tool) events.push(ev("tool.started", { tool, call_id, turn_id, agent_id, input: s.tool_input }));
|
|
817
831
|
break;
|
|
@@ -866,7 +880,13 @@ var claudeCode = {
|
|
|
866
880
|
);
|
|
867
881
|
break;
|
|
868
882
|
case "Stop":
|
|
869
|
-
events.push(
|
|
883
|
+
events.push(
|
|
884
|
+
ev("turn.ended", {
|
|
885
|
+
turn_id,
|
|
886
|
+
reason: "stop",
|
|
887
|
+
background: Array.isArray(s.background_tasks) ? s.background_tasks.length : void 0
|
|
888
|
+
})
|
|
889
|
+
);
|
|
870
890
|
break;
|
|
871
891
|
case "StopFailure":
|
|
872
892
|
events.push(
|
|
@@ -909,6 +929,8 @@ var claudeCode = {
|
|
|
909
929
|
if (event === "UserPromptSubmit" && typeof s.prompt === "string") hints.prompt = s.prompt;
|
|
910
930
|
const host = input.env.CLAUDE_CODE_HOST_SESSION_ID;
|
|
911
931
|
if (host && DESKTOP_ID.test(host)) hints.desktop_id = host;
|
|
932
|
+
const attended = input.env.CLAUDE_CODE_SESSION_ATTENDED;
|
|
933
|
+
if (attended === "1" || attended === "0") hints.attended = attended === "1" || !!input.env.SESSIONPIPE_CONTROL_JOB;
|
|
912
934
|
if (event !== "PreToolUse" && event !== "PostToolUse") hints.claude_pid = claudePid(input.env);
|
|
913
935
|
const r = { session, events, hints };
|
|
914
936
|
if (typeof s.transcript_path === "string") r.transcript = s.transcript_path;
|
|
@@ -929,6 +951,7 @@ var claudeCode = {
|
|
|
929
951
|
const cwd = out.cwd ?? session.cwd;
|
|
930
952
|
Object.assign(out, gitFacts(cwd), out.branch ? { branch: out.branch } : {});
|
|
931
953
|
if (!out.url && typeof hints.desktop_id === "string") out.url = `claude://code/continue/${hints.desktop_id}`;
|
|
954
|
+
if (typeof hints.attended === "boolean") out.attended = hints.attended || !!out.url;
|
|
932
955
|
return out;
|
|
933
956
|
},
|
|
934
957
|
backfill(sinceMs, env = process.env) {
|
|
@@ -964,6 +987,9 @@ function notClaudeCode(id, s) {
|
|
|
964
987
|
function pickSource(v) {
|
|
965
988
|
return typeof v === "string" && ["startup", "resume", "clear", "compact", "fork"].includes(v) ? v : "unknown";
|
|
966
989
|
}
|
|
990
|
+
var harnessWord = (v) => typeof v === "string" && /^[A-Za-z0-9][A-Za-z0-9_.-]{0,39}$/.test(v) ? v : void 0;
|
|
991
|
+
var WRAPPER = /^<(?:task-notification|cross-session-message|system-reminder|local-command-stdout|command-[a-z-]+)[\s/>]/i;
|
|
992
|
+
var injectedBlock = (prompt) => WRAPPER.test(prompt.trim());
|
|
967
993
|
function errText(v) {
|
|
968
994
|
if (typeof v === "string") return v.slice(0, 2e3);
|
|
969
995
|
if (v && typeof v === "object") {
|
|
@@ -1080,7 +1106,27 @@ function claudeLogin(dir, home = homeDir()) {
|
|
|
1080
1106
|
} catch {
|
|
1081
1107
|
}
|
|
1082
1108
|
}
|
|
1083
|
-
return
|
|
1109
|
+
return apiAccount(dir);
|
|
1110
|
+
}
|
|
1111
|
+
var ANTHROPIC_HOST = /(^|\.)anthropic\.com$/i;
|
|
1112
|
+
function apiAccount(dir) {
|
|
1113
|
+
let base;
|
|
1114
|
+
try {
|
|
1115
|
+
base = JSON.parse(readFileSync3(settingsIn(dir), "utf8")).env?.ANTHROPIC_BASE_URL;
|
|
1116
|
+
} catch {
|
|
1117
|
+
return null;
|
|
1118
|
+
}
|
|
1119
|
+
if (typeof base !== "string") return null;
|
|
1120
|
+
let u;
|
|
1121
|
+
try {
|
|
1122
|
+
u = new URL(base.trim());
|
|
1123
|
+
} catch {
|
|
1124
|
+
return null;
|
|
1125
|
+
}
|
|
1126
|
+
if (u.protocol !== "https:" && u.protocol !== "http:" || !u.hostname || ANTHROPIC_HOST.test(u.hostname))
|
|
1127
|
+
return null;
|
|
1128
|
+
const origin = `${u.protocol}//${u.host}`;
|
|
1129
|
+
return { id: `api-${createHash("sha256").update(origin).digest("hex").slice(0, 16)}`, name: u.host };
|
|
1084
1130
|
}
|
|
1085
1131
|
var accountCache = /* @__PURE__ */ new Map();
|
|
1086
1132
|
function claudeAccount(dir) {
|
|
@@ -1561,7 +1607,7 @@ var codex = {
|
|
|
1561
1607
|
if (j && typeof j === "object" && !Array.isArray(j)) s = j;
|
|
1562
1608
|
} catch {
|
|
1563
1609
|
}
|
|
1564
|
-
const id = s.session_id;
|
|
1610
|
+
const id = s.session_id ?? s.thread_id ?? s.conversation_id ?? s["thread-id"] ?? s["session-id"];
|
|
1565
1611
|
if (!id) return null;
|
|
1566
1612
|
if (s.transcript_path === null) return null;
|
|
1567
1613
|
const session = { id: String(id), cwd: typeof s.cwd === "string" ? s.cwd : input.cwd };
|
|
@@ -2323,6 +2369,22 @@ function prune5(o) {
|
|
|
2323
2369
|
var ADAPTERS = [claudeCode, codex, geminiCli, antigravity, devin];
|
|
2324
2370
|
var adapterByName = (name) => ADAPTERS.find((a) => a.name === name);
|
|
2325
2371
|
|
|
2372
|
+
// ../core/src/launched-by.ts
|
|
2373
|
+
var LAUNCHED_BY_ENV = "SESSIONPIPE_LAUNCHED_BY";
|
|
2374
|
+
var LAUNCHED_BY = /^[a-z][a-z0-9-]{0,39}:[A-Za-z0-9._:-]{1,128}$/;
|
|
2375
|
+
function launchedBy(env) {
|
|
2376
|
+
const v = env[LAUNCHED_BY_ENV]?.trim();
|
|
2377
|
+
return v && LAUNCHED_BY.test(v) ? v : void 0;
|
|
2378
|
+
}
|
|
2379
|
+
function readHook(adapter, input) {
|
|
2380
|
+
const r = adapter.fromHook(input);
|
|
2381
|
+
if (r && !r.session.parent_id) {
|
|
2382
|
+
const launcher = launchedBy(input.env);
|
|
2383
|
+
if (launcher && launcher !== `${adapter.name}:${r.session.id}`) r.session.launched_by = launcher;
|
|
2384
|
+
}
|
|
2385
|
+
return r;
|
|
2386
|
+
}
|
|
2387
|
+
|
|
2326
2388
|
// src/index.ts
|
|
2327
2389
|
function matches(expect, got, pathStr = "") {
|
|
2328
2390
|
if (expect === "*") return null;
|
|
@@ -2353,7 +2415,7 @@ async function runAdapterFixtures(files) {
|
|
|
2353
2415
|
results.push({ file, ok: false, why: `no adapter ${fx.harness}` });
|
|
2354
2416
|
continue;
|
|
2355
2417
|
}
|
|
2356
|
-
const r = adapter
|
|
2418
|
+
const r = readHook(adapter, {
|
|
2357
2419
|
argv: fx.input.argv,
|
|
2358
2420
|
stdin: fx.input.stdin,
|
|
2359
2421
|
env: fx.input.env ?? {},
|