@code-yeongyu/senpi 2026.9.10-2 → 2026.9.10

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 (55) hide show
  1. package/CHANGELOG.md +0 -35
  2. package/dist/core/agent-session.d.ts +0 -36
  3. package/dist/core/agent-session.d.ts.map +1 -1
  4. package/dist/core/agent-session.js +18 -85
  5. package/dist/core/agent-session.js.map +1 -1
  6. package/dist/core/extensions/builtin/claude-sdk-oauth/session-binding.js +0 -3
  7. package/dist/core/extensions/builtin/claude-sdk-oauth/session-binding.js.map +1 -1
  8. package/dist/core/extensions/builtin/claude-sdk-oauth/session-reattach.d.ts.map +1 -1
  9. package/dist/core/extensions/builtin/claude-sdk-oauth/session-reattach.js +10 -19
  10. package/dist/core/extensions/builtin/claude-sdk-oauth/session-reattach.js.map +1 -1
  11. package/dist/core/high-reasoning-warning.d.ts.map +1 -1
  12. package/dist/core/high-reasoning-warning.js +1 -5
  13. package/dist/core/high-reasoning-warning.js.map +1 -1
  14. package/dist/core/manual-continue.d.ts +0 -14
  15. package/dist/core/manual-continue.d.ts.map +1 -1
  16. package/dist/core/manual-continue.js +0 -13
  17. package/dist/core/manual-continue.js.map +1 -1
  18. package/dist/core/session-manager.d.ts +1 -35
  19. package/dist/core/session-manager.d.ts.map +1 -1
  20. package/dist/core/session-manager.js +0 -15
  21. package/dist/core/session-manager.js.map +1 -1
  22. package/dist/modes/interactive/components/tree-selector.d.ts.map +1 -1
  23. package/dist/modes/interactive/components/tree-selector.js +0 -7
  24. package/dist/modes/interactive/components/tree-selector.js.map +1 -1
  25. package/dist/modes/interactive/interactive-mode.d.ts +4 -13
  26. package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
  27. package/dist/modes/interactive/interactive-mode.js +3 -23
  28. package/dist/modes/interactive/interactive-mode.js.map +1 -1
  29. package/dist/modes/rpc/connection-handler.d.ts.map +1 -1
  30. package/dist/modes/rpc/connection-handler.js +1 -3
  31. package/dist/modes/rpc/connection-handler.js.map +1 -1
  32. package/dist/modes/rpc/rpc-input-validation.d.ts.map +1 -1
  33. package/dist/modes/rpc/rpc-input-validation.js +0 -2
  34. package/dist/modes/rpc/rpc-input-validation.js.map +1 -1
  35. package/node_modules/@code-yeongyu/senpi-codemode/CHANGELOG.md +0 -12
  36. package/node_modules/@code-yeongyu/senpi-codemode/package.json +4 -4
  37. package/node_modules/@earendil-works/pi-agent-core/package.json +3 -3
  38. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-coding.d.ts.map +1 -1
  39. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-coding.js +1 -5
  40. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-coding.js.map +1 -1
  41. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js +1 -1
  42. package/node_modules/@earendil-works/pi-ai/dist/image-models.generated.js.map +1 -1
  43. package/node_modules/@earendil-works/pi-ai/dist/providers/data/.manifest.json +1 -1
  44. package/node_modules/@earendil-works/pi-ai/dist/providers/data/openrouter.json +1 -1
  45. package/node_modules/@earendil-works/pi-ai/dist/providers/data/venice.json +1 -1
  46. package/node_modules/@earendil-works/pi-ai/dist/providers/data/vercel-ai-gateway.json +1 -1
  47. package/node_modules/@earendil-works/pi-ai/package.json +2 -2
  48. package/node_modules/@earendil-works/pi-pty/package.json +1 -1
  49. package/node_modules/@earendil-works/pi-telemetry/package.json +1 -1
  50. package/node_modules/@earendil-works/pi-tui/package.json +1 -1
  51. package/package.json +7 -7
  52. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-identity.d.ts +0 -24
  53. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-identity.d.ts.map +0 -1
  54. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-identity.js +0 -86
  55. package/node_modules/@earendil-works/pi-ai/dist/auth/oauth/kimi-identity.js.map +0 -1
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@earendil-works/pi-ai",
3
- "version": "2026.9.10-2",
3
+ "version": "2026.9.10",
4
4
  "description": "Unified LLM API with automatic model discovery and provider configuration",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -76,7 +76,7 @@
76
76
  "dependencies": {
77
77
  "@anthropic-ai/sdk": "0.123.0",
78
78
  "@aws-sdk/client-bedrock-runtime": "3.1116.0",
79
- "@earendil-works/pi-telemetry": "npm:@code-yeongyu/senpi-telemetry@2026.9.10-2",
79
+ "@earendil-works/pi-telemetry": "npm:@code-yeongyu/senpi-telemetry@2026.9.10",
80
80
  "@google/genai": "2.18.0",
81
81
  "@smithy/node-http-handler": "4.11.3",
82
82
  "http-proxy-agent": "9.1.0",
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@earendil-works/pi-pty",
3
3
  "private": true,
4
- "version": "2026.9.10-2",
4
+ "version": "2026.9.10",
5
5
  "description": "Typed PTY session loader for Senpi persistent terminals",
6
6
  "type": "module",
7
7
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@earendil-works/pi-telemetry",
3
- "version": "2026.9.10-2",
3
+ "version": "2026.9.10",
4
4
  "description": "Vendor-neutral telemetry contracts and typed schema utilities for pi",
5
5
  "type": "module",
6
6
  "main": "./dist/index.js",
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@earendil-works/pi-tui",
3
- "version": "2026.9.10-2",
3
+ "version": "2026.9.10",
4
4
  "description": "Terminal User Interface library with differential rendering for efficient text-based applications",
5
5
  "type": "module",
6
6
  "main": "dist/index.js",
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@code-yeongyu/senpi",
3
- "version": "2026.9.10-2",
3
+ "version": "2026.9.10",
4
4
  "description": "Coding agent CLI with read, bash, edit, write tools and session management",
5
5
  "type": "module",
6
6
  "piConfig": {
@@ -48,9 +48,9 @@
48
48
  "qa:app-server": "node scripts/qa-app-server/run-all.mjs"
49
49
  },
50
50
  "dependencies": {
51
- "@earendil-works/pi-agent-core": "npm:@code-yeongyu/senpi-agent-core@2026.9.10-2",
52
- "@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.9.10-2",
53
- "@earendil-works/pi-tui": "npm:@code-yeongyu/senpi-tui@2026.9.10-2",
51
+ "@earendil-works/pi-agent-core": "npm:@code-yeongyu/senpi-agent-core@2026.9.10",
52
+ "@earendil-works/pi-ai": "npm:@code-yeongyu/senpi-ai@2026.9.10",
53
+ "@earendil-works/pi-tui": "npm:@code-yeongyu/senpi-tui@2026.9.10",
54
54
  "@silvia-odwyer/photon-node": "0.3.4",
55
55
  "chalk": "6.0.0",
56
56
  "cross-spawn": "7.0.6",
@@ -70,8 +70,8 @@
70
70
  "@anthropic-ai/sdk": "0.123.0",
71
71
  "@aws-sdk/client-bedrock-runtime": "3.1116.0",
72
72
  "@bufbuild/protobuf": "2.14.0",
73
- "@code-yeongyu/senpi-codemode": "2026.9.10-2",
74
- "@earendil-works/pi-pty": "npm:@code-yeongyu/senpi-pty@2026.9.10-2",
73
+ "@code-yeongyu/senpi-codemode": "2026.9.10",
74
+ "@earendil-works/pi-pty": "npm:@code-yeongyu/senpi-pty@2026.9.10",
75
75
  "@modelcontextprotocol/sdk": "1.30.0",
76
76
  "@mozilla/readability": "0.6.0",
77
77
  "@opentelemetry/api": "1.9.1",
@@ -119,7 +119,7 @@
119
119
  "@csstools/css-parser-algorithms": "4.0.0",
120
120
  "@csstools/css-syntax-patches-for-csstree": "1.1.8",
121
121
  "@csstools/css-tokenizer": "4.0.0",
122
- "@earendil-works/pi-telemetry": "npm:@code-yeongyu/senpi-telemetry@2026.9.10-2",
122
+ "@earendil-works/pi-telemetry": "npm:@code-yeongyu/senpi-telemetry@2026.9.10",
123
123
  "@exodus/bytes": "1.15.1",
124
124
  "@google/genai": "2.18.0",
125
125
  "@hono/node-server": "2.1.1",
@@ -1,24 +0,0 @@
1
- /**
2
- * Kimi Code client identity headers.
3
- *
4
- * `api.kimi.com/coding` identifies its clients by a product `User-Agent` plus
5
- * an `X-Msh-*` device header set, and the official Kimi Code client sends that
6
- * set on every OAuth and managed-API request (MoonshotAI/kimi-code
7
- * `packages/oauth/src/identity.ts`). senpi sent none of them, so a
8
- * subscription session never identified itself as a Kimi client at all.
9
- *
10
- * Three contract details that are not visible from the code: values must be
11
- * printable ASCII (the endpoint sits behind a CDN that answers 520 on raw
12
- * non-ASCII header bytes), the device id is expected to be stable per install,
13
- * and the platform string names a client family rather than the host product.
14
- * Device-id persistence is deliberately best-effort — an unwritable agent dir
15
- * must degrade to a per-process id, never throw, because these headers are
16
- * built for every request.
17
- *
18
- * Subscription (OAuth) path only: the api-key path authenticates with a
19
- * platform key rather than a client session and stays header-free.
20
- */
21
- /** Test seam: forget the memoized id so a fresh agent dir is re-read. */
22
- export declare function resetKimiDeviceIdForTests(): void;
23
- export declare function kimiCodeIdentityHeaders(): Record<string, string>;
24
- //# sourceMappingURL=kimi-identity.d.ts.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"kimi-identity.d.ts","sourceRoot":"","sources":["../../../src/auth/oauth/kimi-identity.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;;;;;;GAmBG;AA0DH,yEAAyE;AACzE,wBAAgB,yBAAyB,IAAI,IAAI,CAEhD;AAED,wBAAgB,uBAAuB,IAAI,MAAM,CAAC,MAAM,EAAE,MAAM,CAAC,CAUhE"}
@@ -1,86 +0,0 @@
1
- /**
2
- * Kimi Code client identity headers.
3
- *
4
- * `api.kimi.com/coding` identifies its clients by a product `User-Agent` plus
5
- * an `X-Msh-*` device header set, and the official Kimi Code client sends that
6
- * set on every OAuth and managed-API request (MoonshotAI/kimi-code
7
- * `packages/oauth/src/identity.ts`). senpi sent none of them, so a
8
- * subscription session never identified itself as a Kimi client at all.
9
- *
10
- * Three contract details that are not visible from the code: values must be
11
- * printable ASCII (the endpoint sits behind a CDN that answers 520 on raw
12
- * non-ASCII header bytes), the device id is expected to be stable per install,
13
- * and the platform string names a client family rather than the host product.
14
- * Device-id persistence is deliberately best-effort — an unwritable agent dir
15
- * must degrade to a per-process id, never throw, because these headers are
16
- * built for every request.
17
- *
18
- * Subscription (OAuth) path only: the api-key path authenticates with a
19
- * platform key rather than a client session and stays header-free.
20
- */
21
- import { randomUUID } from "node:crypto";
22
- import { mkdirSync, readFileSync, writeFileSync } from "node:fs";
23
- import { arch, hostname, platform, release } from "node:os";
24
- import { join } from "node:path";
25
- import { getProviderEnvValue } from "../../utils/provider-env.js";
26
- const KIMI_CLIENT_PLATFORM = "kimi_cli";
27
- const KIMI_CLIENT_VERSION = "1.0";
28
- const DEVICE_ID_FILENAME = "kimi-device-id";
29
- function sanitizeHeaderValue(value, fallback = "unknown") {
30
- const sanitized = value.replace(/[^\x20-\x7E]/g, "").trim();
31
- return sanitized || fallback;
32
- }
33
- function agentDir() {
34
- const configured = getProviderEnvValue("SENPI_CODING_AGENT_DIR") ?? getProviderEnvValue("CODING_AGENT_DIR");
35
- if (configured)
36
- return configured.replace(/\/$/, "");
37
- const home = getProviderEnvValue("HOME") ?? ".";
38
- return `${home.replace(/\/$/, "")}/.senpi/agent`;
39
- }
40
- function deviceModel() {
41
- const current = platform();
42
- const label = current === "darwin" ? "macOS" : current === "win32" ? "Windows" : current === "linux" ? "Linux" : current;
43
- return [label, release(), arch()].filter(Boolean).join(" ").trim();
44
- }
45
- function readOrMintDeviceId() {
46
- const directory = agentDir();
47
- const path = join(directory, DEVICE_ID_FILENAME);
48
- try {
49
- const existing = readFileSync(path, "utf-8").trim();
50
- if (existing)
51
- return existing;
52
- }
53
- catch {
54
- // Absent or unreadable: fall through and mint a replacement.
55
- }
56
- const minted = randomUUID().replace(/-/g, "");
57
- try {
58
- mkdirSync(directory, { recursive: true });
59
- writeFileSync(path, `${minted}\n`, { mode: 0o600 });
60
- }
61
- catch {
62
- // Unwritable agent dir: this id lives for the current process only.
63
- }
64
- return minted;
65
- }
66
- let cachedDeviceId;
67
- function deviceId() {
68
- cachedDeviceId ??= readOrMintDeviceId();
69
- return cachedDeviceId;
70
- }
71
- /** Test seam: forget the memoized id so a fresh agent dir is re-read. */
72
- export function resetKimiDeviceIdForTests() {
73
- cachedDeviceId = undefined;
74
- }
75
- export function kimiCodeIdentityHeaders() {
76
- return {
77
- "User-Agent": `KimiCLI/${KIMI_CLIENT_VERSION}`,
78
- "X-Msh-Platform": KIMI_CLIENT_PLATFORM,
79
- "X-Msh-Version": KIMI_CLIENT_VERSION,
80
- "X-Msh-Device-Name": sanitizeHeaderValue(hostname()),
81
- "X-Msh-Device-Model": sanitizeHeaderValue(deviceModel()),
82
- "X-Msh-Os-Version": sanitizeHeaderValue(release()),
83
- "X-Msh-Device-Id": sanitizeHeaderValue(deviceId()),
84
- };
85
- }
86
- //# sourceMappingURL=kimi-identity.js.map
@@ -1 +0,0 @@
1
- {"version":3,"file":"kimi-identity.js","sourceRoot":"","sources":["../../../src/auth/oauth/kimi-identity.ts"],"names":[],"mappings":"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","sourcesContent":["/**\n * Kimi Code client identity headers.\n *\n * `api.kimi.com/coding` identifies its clients by a product `User-Agent` plus\n * an `X-Msh-*` device header set, and the official Kimi Code client sends that\n * set on every OAuth and managed-API request (MoonshotAI/kimi-code\n * `packages/oauth/src/identity.ts`). senpi sent none of them, so a\n * subscription session never identified itself as a Kimi client at all.\n *\n * Three contract details that are not visible from the code: values must be\n * printable ASCII (the endpoint sits behind a CDN that answers 520 on raw\n * non-ASCII header bytes), the device id is expected to be stable per install,\n * and the platform string names a client family rather than the host product.\n * Device-id persistence is deliberately best-effort — an unwritable agent dir\n * must degrade to a per-process id, never throw, because these headers are\n * built for every request.\n *\n * Subscription (OAuth) path only: the api-key path authenticates with a\n * platform key rather than a client session and stays header-free.\n */\n\nimport { randomUUID } from \"node:crypto\";\nimport { mkdirSync, readFileSync, writeFileSync } from \"node:fs\";\nimport { arch, hostname, platform, release } from \"node:os\";\nimport { join } from \"node:path\";\nimport { getProviderEnvValue } from \"../../utils/provider-env.ts\";\n\nconst KIMI_CLIENT_PLATFORM = \"kimi_cli\";\nconst KIMI_CLIENT_VERSION = \"1.0\";\nconst DEVICE_ID_FILENAME = \"kimi-device-id\";\n\nfunction sanitizeHeaderValue(value: string, fallback = \"unknown\"): string {\n\tconst sanitized = value.replace(/[^\\x20-\\x7E]/g, \"\").trim();\n\treturn sanitized || fallback;\n}\n\nfunction agentDir(): string {\n\tconst configured = getProviderEnvValue(\"SENPI_CODING_AGENT_DIR\") ?? getProviderEnvValue(\"CODING_AGENT_DIR\");\n\tif (configured) return configured.replace(/\\/$/, \"\");\n\tconst home = getProviderEnvValue(\"HOME\") ?? \".\";\n\treturn `${home.replace(/\\/$/, \"\")}/.senpi/agent`;\n}\n\nfunction deviceModel(): string {\n\tconst current = platform();\n\tconst label =\n\t\tcurrent === \"darwin\" ? \"macOS\" : current === \"win32\" ? \"Windows\" : current === \"linux\" ? \"Linux\" : current;\n\treturn [label, release(), arch()].filter(Boolean).join(\" \").trim();\n}\n\nfunction readOrMintDeviceId(): string {\n\tconst directory = agentDir();\n\tconst path = join(directory, DEVICE_ID_FILENAME);\n\ttry {\n\t\tconst existing = readFileSync(path, \"utf-8\").trim();\n\t\tif (existing) return existing;\n\t} catch {\n\t\t// Absent or unreadable: fall through and mint a replacement.\n\t}\n\n\tconst minted = randomUUID().replace(/-/g, \"\");\n\ttry {\n\t\tmkdirSync(directory, { recursive: true });\n\t\twriteFileSync(path, `${minted}\\n`, { mode: 0o600 });\n\t} catch {\n\t\t// Unwritable agent dir: this id lives for the current process only.\n\t}\n\treturn minted;\n}\n\nlet cachedDeviceId: string | undefined;\n\nfunction deviceId(): string {\n\tcachedDeviceId ??= readOrMintDeviceId();\n\treturn cachedDeviceId;\n}\n\n/** Test seam: forget the memoized id so a fresh agent dir is re-read. */\nexport function resetKimiDeviceIdForTests(): void {\n\tcachedDeviceId = undefined;\n}\n\nexport function kimiCodeIdentityHeaders(): Record<string, string> {\n\treturn {\n\t\t\"User-Agent\": `KimiCLI/${KIMI_CLIENT_VERSION}`,\n\t\t\"X-Msh-Platform\": KIMI_CLIENT_PLATFORM,\n\t\t\"X-Msh-Version\": KIMI_CLIENT_VERSION,\n\t\t\"X-Msh-Device-Name\": sanitizeHeaderValue(hostname()),\n\t\t\"X-Msh-Device-Model\": sanitizeHeaderValue(deviceModel()),\n\t\t\"X-Msh-Os-Version\": sanitizeHeaderValue(release()),\n\t\t\"X-Msh-Device-Id\": sanitizeHeaderValue(deviceId()),\n\t};\n}\n"]}