@scanton/phase2s 0.13.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.
Files changed (103) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +137 -0
  3. package/dist/bin/phase2s.d.ts +3 -0
  4. package/dist/bin/phase2s.d.ts.map +1 -0
  5. package/dist/bin/phase2s.js +7 -0
  6. package/dist/bin/phase2s.js.map +1 -0
  7. package/dist/src/cli/index.d.ts +2 -0
  8. package/dist/src/cli/index.d.ts.map +1 -0
  9. package/dist/src/cli/index.js +499 -0
  10. package/dist/src/cli/index.js.map +1 -0
  11. package/dist/src/core/agent.d.ts +63 -0
  12. package/dist/src/core/agent.d.ts.map +1 -0
  13. package/dist/src/core/agent.js +178 -0
  14. package/dist/src/core/agent.js.map +1 -0
  15. package/dist/src/core/config.d.ts +52 -0
  16. package/dist/src/core/config.d.ts.map +1 -0
  17. package/dist/src/core/config.js +103 -0
  18. package/dist/src/core/config.js.map +1 -0
  19. package/dist/src/core/conversation.d.ts +44 -0
  20. package/dist/src/core/conversation.d.ts.map +1 -0
  21. package/dist/src/core/conversation.js +128 -0
  22. package/dist/src/core/conversation.js.map +1 -0
  23. package/dist/src/core/memory.d.ts +24 -0
  24. package/dist/src/core/memory.d.ts.map +1 -0
  25. package/dist/src/core/memory.js +65 -0
  26. package/dist/src/core/memory.js.map +1 -0
  27. package/dist/src/mcp/server.d.ts +73 -0
  28. package/dist/src/mcp/server.d.ts.map +1 -0
  29. package/dist/src/mcp/server.js +215 -0
  30. package/dist/src/mcp/server.js.map +1 -0
  31. package/dist/src/providers/codex.d.ts +28 -0
  32. package/dist/src/providers/codex.d.ts.map +1 -0
  33. package/dist/src/providers/codex.js +162 -0
  34. package/dist/src/providers/codex.js.map +1 -0
  35. package/dist/src/providers/index.d.ts +6 -0
  36. package/dist/src/providers/index.d.ts.map +1 -0
  37. package/dist/src/providers/index.js +13 -0
  38. package/dist/src/providers/index.js.map +1 -0
  39. package/dist/src/providers/openai.d.ts +36 -0
  40. package/dist/src/providers/openai.d.ts.map +1 -0
  41. package/dist/src/providers/openai.js +117 -0
  42. package/dist/src/providers/openai.js.map +1 -0
  43. package/dist/src/providers/types.d.ts +34 -0
  44. package/dist/src/providers/types.d.ts.map +1 -0
  45. package/dist/src/providers/types.js +2 -0
  46. package/dist/src/providers/types.js.map +1 -0
  47. package/dist/src/skills/index.d.ts +3 -0
  48. package/dist/src/skills/index.d.ts.map +1 -0
  49. package/dist/src/skills/index.js +2 -0
  50. package/dist/src/skills/index.js.map +1 -0
  51. package/dist/src/skills/loader.d.ts +23 -0
  52. package/dist/src/skills/loader.d.ts.map +1 -0
  53. package/dist/src/skills/loader.js +136 -0
  54. package/dist/src/skills/loader.js.map +1 -0
  55. package/dist/src/skills/types.d.ts +14 -0
  56. package/dist/src/skills/types.d.ts.map +1 -0
  57. package/dist/src/skills/types.js +2 -0
  58. package/dist/src/skills/types.js.map +1 -0
  59. package/dist/src/tools/file-read.d.ts +3 -0
  60. package/dist/src/tools/file-read.d.ts.map +1 -0
  61. package/dist/src/tools/file-read.js +50 -0
  62. package/dist/src/tools/file-read.js.map +1 -0
  63. package/dist/src/tools/file-write.d.ts +3 -0
  64. package/dist/src/tools/file-write.d.ts.map +1 -0
  65. package/dist/src/tools/file-write.js +90 -0
  66. package/dist/src/tools/file-write.js.map +1 -0
  67. package/dist/src/tools/glob-tool.d.ts +3 -0
  68. package/dist/src/tools/glob-tool.d.ts.map +1 -0
  69. package/dist/src/tools/glob-tool.js +38 -0
  70. package/dist/src/tools/glob-tool.js.map +1 -0
  71. package/dist/src/tools/grep-tool.d.ts +3 -0
  72. package/dist/src/tools/grep-tool.d.ts.map +1 -0
  73. package/dist/src/tools/grep-tool.js +59 -0
  74. package/dist/src/tools/grep-tool.js.map +1 -0
  75. package/dist/src/tools/index.d.ts +5 -0
  76. package/dist/src/tools/index.d.ts.map +1 -0
  77. package/dist/src/tools/index.js +17 -0
  78. package/dist/src/tools/index.js.map +1 -0
  79. package/dist/src/tools/registry.d.ts +13 -0
  80. package/dist/src/tools/registry.d.ts.map +1 -0
  81. package/dist/src/tools/registry.js +50 -0
  82. package/dist/src/tools/registry.js.map +1 -0
  83. package/dist/src/tools/sandbox.d.ts +29 -0
  84. package/dist/src/tools/sandbox.d.ts.map +1 -0
  85. package/dist/src/tools/sandbox.js +84 -0
  86. package/dist/src/tools/sandbox.js.map +1 -0
  87. package/dist/src/tools/shell.d.ts +10 -0
  88. package/dist/src/tools/shell.d.ts.map +1 -0
  89. package/dist/src/tools/shell.js +108 -0
  90. package/dist/src/tools/shell.js.map +1 -0
  91. package/dist/src/tools/types.d.ts +25 -0
  92. package/dist/src/tools/types.d.ts.map +1 -0
  93. package/dist/src/tools/types.js +54 -0
  94. package/dist/src/tools/types.js.map +1 -0
  95. package/dist/src/utils/logger.d.ts +10 -0
  96. package/dist/src/utils/logger.d.ts.map +1 -0
  97. package/dist/src/utils/logger.js +25 -0
  98. package/dist/src/utils/logger.js.map +1 -0
  99. package/dist/src/utils/prompt.d.ts +3 -0
  100. package/dist/src/utils/prompt.d.ts.map +1 -0
  101. package/dist/src/utils/prompt.js +26 -0
  102. package/dist/src/utils/prompt.js.map +1 -0
  103. package/package.json +55 -0
@@ -0,0 +1 @@
1
+ {"version":3,"file":"conversation.js","sourceRoot":"","sources":["../../../src/core/conversation.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,24 @@
1
+ export interface Learning {
2
+ key: string;
3
+ insight: string;
4
+ confidence?: number;
5
+ type?: string;
6
+ ts?: string;
7
+ }
8
+ /**
9
+ * Load learnings from .phase2s/memory/learnings.jsonl.
10
+ *
11
+ * Returns an empty array if the file doesn't exist (first session, normal case).
12
+ * Invalid JSON lines are skipped silently — a corrupted line shouldn't block
13
+ * the rest of memory from loading.
14
+ */
15
+ export declare function loadLearnings(cwd: string): Promise<Learning[]>;
16
+ /**
17
+ * Format learnings for injection into the system prompt.
18
+ *
19
+ * Returns an empty string if there are no learnings (no injection).
20
+ * Trims oldest learnings first if the total character count exceeds MAX_LEARNINGS_CHARS.
21
+ * This keeps the most recent decisions and preferences, which are most relevant.
22
+ */
23
+ export declare function formatLearningsForPrompt(learnings: Learning[]): string;
24
+ //# sourceMappingURL=memory.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.d.ts","sourceRoot":"","sources":["../../../src/core/memory.ts"],"names":[],"mappings":"AAGA,MAAM,WAAW,QAAQ;IACvB,GAAG,EAAE,MAAM,CAAC;IACZ,OAAO,EAAE,MAAM,CAAC;IAChB,UAAU,CAAC,EAAE,MAAM,CAAC;IACpB,IAAI,CAAC,EAAE,MAAM,CAAC;IACd,EAAE,CAAC,EAAE,MAAM,CAAC;CACb;AAKD;;;;;;GAMG;AACH,wBAAsB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,QAAQ,EAAE,CAAC,CAyBpE;AAED;;;;;;GAMG;AACH,wBAAgB,wBAAwB,CAAC,SAAS,EAAE,QAAQ,EAAE,GAAG,MAAM,CAmBtE"}
@@ -0,0 +1,65 @@
1
+ import { readFile } from "node:fs/promises";
2
+ import { join } from "node:path";
3
+ const LEARNINGS_FILE = ".phase2s/memory/learnings.jsonl";
4
+ const MAX_LEARNINGS_CHARS = 2000;
5
+ /**
6
+ * Load learnings from .phase2s/memory/learnings.jsonl.
7
+ *
8
+ * Returns an empty array if the file doesn't exist (first session, normal case).
9
+ * Invalid JSON lines are skipped silently — a corrupted line shouldn't block
10
+ * the rest of memory from loading.
11
+ */
12
+ export async function loadLearnings(cwd) {
13
+ const filePath = join(cwd, LEARNINGS_FILE);
14
+ let raw;
15
+ try {
16
+ raw = await readFile(filePath, "utf-8");
17
+ }
18
+ catch {
19
+ return [];
20
+ }
21
+ const results = [];
22
+ for (const line of raw.split("\n")) {
23
+ const trimmed = line.trim();
24
+ if (!trimmed)
25
+ continue;
26
+ try {
27
+ const parsed = JSON.parse(trimmed);
28
+ // Require key and insight as non-empty strings — minimum viable learning
29
+ if (typeof parsed.key === "string" && parsed.key.length > 0 &&
30
+ typeof parsed.insight === "string" && parsed.insight.length > 0) {
31
+ results.push(parsed);
32
+ }
33
+ }
34
+ catch {
35
+ // Skip invalid lines silently — don't block session startup on parse errors
36
+ }
37
+ }
38
+ return results;
39
+ }
40
+ /**
41
+ * Format learnings for injection into the system prompt.
42
+ *
43
+ * Returns an empty string if there are no learnings (no injection).
44
+ * Trims oldest learnings first if the total character count exceeds MAX_LEARNINGS_CHARS.
45
+ * This keeps the most recent decisions and preferences, which are most relevant.
46
+ */
47
+ export function formatLearningsForPrompt(learnings) {
48
+ if (learnings.length === 0)
49
+ return "";
50
+ const lines = learnings.map((l) => `- [${l.key}]: ${l.insight}`);
51
+ // Trim oldest first (front of array) until within char budget
52
+ let trimmed = [...lines];
53
+ while (trimmed.join("\n").length > MAX_LEARNINGS_CHARS && trimmed.length > 0) {
54
+ trimmed = trimmed.slice(1);
55
+ }
56
+ if (trimmed.length === 0)
57
+ return "";
58
+ return [
59
+ "## Project memory",
60
+ "The following learnings from previous sessions apply to this project:",
61
+ ...trimmed,
62
+ `(${trimmed.length} learning${trimmed.length === 1 ? "" : "s"} loaded from .phase2s/memory/learnings.jsonl)`,
63
+ ].join("\n");
64
+ }
65
+ //# sourceMappingURL=memory.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"memory.js","sourceRoot":"","sources":["../../../src/core/memory.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,EAAE,IAAI,EAAE,MAAM,WAAW,CAAC;AAUjC,MAAM,cAAc,GAAG,iCAAiC,CAAC;AACzD,MAAM,mBAAmB,GAAG,IAAI,CAAC;AAEjC;;;;;;GAMG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CAAC,GAAW;IAC7C,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,CAAC;IAC3C,IAAI,GAAW,CAAC;IAChB,IAAI,CAAC;QACH,GAAG,GAAG,MAAM,QAAQ,CAAC,QAAQ,EAAE,OAAO,CAAC,CAAC;IAC1C,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAC;IACZ,CAAC;IAED,MAAM,OAAO,GAAe,EAAE,CAAC;IAC/B,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,EAAE,CAAC;QACnC,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;QAC5B,IAAI,CAAC,OAAO;YAAE,SAAS;QACvB,IAAI,CAAC;YACH,MAAM,MAAM,GAAG,IAAI,CAAC,KAAK,CAAC,OAAO,CAAa,CAAC;YAC/C,yEAAyE;YACzE,IAAI,OAAO,MAAM,CAAC,GAAG,KAAK,QAAQ,IAAI,MAAM,CAAC,GAAG,CAAC,MAAM,GAAG,CAAC;gBACvD,OAAO,MAAM,CAAC,OAAO,KAAK,QAAQ,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;gBACpE,OAAO,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;YACvB,CAAC;QACH,CAAC;QAAC,MAAM,CAAC;YACP,4EAA4E;QAC9E,CAAC;IACH,CAAC;IACD,OAAO,OAAO,CAAC;AACjB,CAAC;AAED;;;;;;GAMG;AACH,MAAM,UAAU,wBAAwB,CAAC,SAAqB;IAC5D,IAAI,SAAS,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEtC,MAAM,KAAK,GAAG,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,MAAM,CAAC,CAAC,GAAG,MAAM,CAAC,CAAC,OAAO,EAAE,CAAC,CAAC;IAEjE,8DAA8D;IAC9D,IAAI,OAAO,GAAG,CAAC,GAAG,KAAK,CAAC,CAAC;IACzB,OAAO,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC,MAAM,GAAG,mBAAmB,IAAI,OAAO,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7E,OAAO,GAAG,OAAO,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC;IAC7B,CAAC;IAED,IAAI,OAAO,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEpC,OAAO;QACL,mBAAmB;QACnB,uEAAuE;QACvE,GAAG,OAAO;QACV,IAAI,OAAO,CAAC,MAAM,YAAY,OAAO,CAAC,MAAM,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,GAAG,+CAA+C;KAC7G,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC"}
@@ -0,0 +1,73 @@
1
+ /**
2
+ * Phase2S MCP server.
3
+ *
4
+ * Implements the Model Context Protocol (JSON-RPC 2.0 over stdio) so that
5
+ * Claude Code can invoke Phase2S skills as tools. Every SKILL.md file in
6
+ * .phase2s/skills/ becomes a Claude Code tool dynamically at server startup.
7
+ *
8
+ * Transport: stdio (one JSON message per line, responses on stdout).
9
+ * Protocol: MCP 2024-11-05.
10
+ *
11
+ * Start via: phase2s mcp
12
+ * Configure in: .claude/settings.json
13
+ */
14
+ import type { Skill } from "../skills/types.js";
15
+ export declare const MCP_SERVER_VERSION = "0.13.0";
16
+ interface JSONRPCRequest {
17
+ jsonrpc: "2.0";
18
+ id: number | string | null;
19
+ method: string;
20
+ params?: unknown;
21
+ }
22
+ interface JSONRPCResponse {
23
+ jsonrpc: "2.0";
24
+ id: number | string | null;
25
+ result?: unknown;
26
+ error?: {
27
+ code: number;
28
+ message: string;
29
+ };
30
+ }
31
+ export interface MCPTool {
32
+ name: string;
33
+ description: string;
34
+ inputSchema: {
35
+ type: "object";
36
+ properties: Record<string, unknown>;
37
+ required: string[];
38
+ };
39
+ }
40
+ /**
41
+ * Convert a Phase2S Skill into an MCP tool descriptor.
42
+ *
43
+ * Naming convention: `phase2s__<skill-name-with-underscores>`
44
+ * e.g. "adversarial" → "phase2s__adversarial"
45
+ * "consensus-plan" → "phase2s__consensus_plan"
46
+ */
47
+ export declare function skillToTool(skill: Skill): MCPTool;
48
+ /**
49
+ * Reverse the tool naming convention back to a skill name.
50
+ * "phase2s__consensus_plan" → "consensus-plan"
51
+ */
52
+ export declare function toolNameToSkillName(toolName: string): string;
53
+ /**
54
+ * Handle a single JSON-RPC request and return the response.
55
+ *
56
+ * Exported so tests can call it directly without stdio.
57
+ *
58
+ * @param request Parsed JSON-RPC request
59
+ * @param skills Loaded Phase2S skills (passed in so tests can inject fixtures)
60
+ * @param cwd Working directory for config loading and agent runs
61
+ */
62
+ export declare function handleRequest(request: JSONRPCRequest, skills: Skill[], cwd: string): Promise<JSONRPCResponse>;
63
+ /**
64
+ * Start the MCP server. Reads JSON-RPC messages from stdin, writes responses
65
+ * to stdout. Runs until stdin closes (i.e. Claude Code terminates the session).
66
+ *
67
+ * Uses a manual event-queue pattern (same as the CLI REPL) to avoid the known
68
+ * issue where the readline async iterator terminates if the event loop drains
69
+ * while awaiting between messages.
70
+ */
71
+ export declare function runMCPServer(cwd: string): Promise<void>;
72
+ export {};
73
+ //# sourceMappingURL=server.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.d.ts","sourceRoot":"","sources":["../../../src/mcp/server.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AAOH,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,oBAAoB,CAAC;AAEhD,eAAO,MAAM,kBAAkB,WAAW,CAAC;AAM3C,UAAU,cAAc;IACtB,OAAO,EAAE,KAAK,CAAC;IACf,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,EAAE,MAAM,CAAC;IACf,MAAM,CAAC,EAAE,OAAO,CAAC;CAClB;AAED,UAAU,eAAe;IACvB,OAAO,EAAE,KAAK,CAAC;IACf,EAAE,EAAE,MAAM,GAAG,MAAM,GAAG,IAAI,CAAC;IAC3B,MAAM,CAAC,EAAE,OAAO,CAAC;IACjB,KAAK,CAAC,EAAE;QAAE,IAAI,EAAE,MAAM,CAAC;QAAC,OAAO,EAAE,MAAM,CAAA;KAAE,CAAC;CAC3C;AAED,MAAM,WAAW,OAAO;IACtB,IAAI,EAAE,MAAM,CAAC;IACb,WAAW,EAAE,MAAM,CAAC;IACpB,WAAW,EAAE;QACX,IAAI,EAAE,QAAQ,CAAC;QACf,UAAU,EAAE,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC;QACpC,QAAQ,EAAE,MAAM,EAAE,CAAC;KACpB,CAAC;CACH;AAMD;;;;;;GAMG;AACH,wBAAgB,WAAW,CAAC,KAAK,EAAE,KAAK,GAAG,OAAO,CAejD;AAED;;;GAGG;AACH,wBAAgB,mBAAmB,CAAC,QAAQ,EAAE,MAAM,GAAG,MAAM,CAE5D;AAMD;;;;;;;;GAQG;AACH,wBAAsB,aAAa,CACjC,OAAO,EAAE,cAAc,EACvB,MAAM,EAAE,KAAK,EAAE,EACf,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,eAAe,CAAC,CA+E1B;AAMD;;;;;;;GAOG;AACH,wBAAsB,YAAY,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAAC,IAAI,CAAC,CAmE7D"}
@@ -0,0 +1,215 @@
1
+ /**
2
+ * Phase2S MCP server.
3
+ *
4
+ * Implements the Model Context Protocol (JSON-RPC 2.0 over stdio) so that
5
+ * Claude Code can invoke Phase2S skills as tools. Every SKILL.md file in
6
+ * .phase2s/skills/ becomes a Claude Code tool dynamically at server startup.
7
+ *
8
+ * Transport: stdio (one JSON message per line, responses on stdout).
9
+ * Protocol: MCP 2024-11-05.
10
+ *
11
+ * Start via: phase2s mcp
12
+ * Configure in: .claude/settings.json
13
+ */
14
+ import { createInterface } from "node:readline";
15
+ import { loadSkillsFromDir } from "../skills/loader.js";
16
+ import { loadConfig } from "../core/config.js";
17
+ import { Agent } from "../core/agent.js";
18
+ import { join } from "node:path";
19
+ export const MCP_SERVER_VERSION = "0.13.0";
20
+ // ---------------------------------------------------------------------------
21
+ // Tool generation
22
+ // ---------------------------------------------------------------------------
23
+ /**
24
+ * Convert a Phase2S Skill into an MCP tool descriptor.
25
+ *
26
+ * Naming convention: `phase2s__<skill-name-with-underscores>`
27
+ * e.g. "adversarial" → "phase2s__adversarial"
28
+ * "consensus-plan" → "phase2s__consensus_plan"
29
+ */
30
+ export function skillToTool(skill) {
31
+ return {
32
+ name: `phase2s__${skill.name.replace(/-/g, "_")}`,
33
+ description: skill.description || `Run the ${skill.name} skill`,
34
+ inputSchema: {
35
+ type: "object",
36
+ properties: {
37
+ prompt: {
38
+ type: "string",
39
+ description: `Task or content for the ${skill.name} skill. Paste the text you want analyzed or acted on.`,
40
+ },
41
+ },
42
+ required: ["prompt"],
43
+ },
44
+ };
45
+ }
46
+ /**
47
+ * Reverse the tool naming convention back to a skill name.
48
+ * "phase2s__consensus_plan" → "consensus-plan"
49
+ */
50
+ export function toolNameToSkillName(toolName) {
51
+ return toolName.replace(/^phase2s__/, "").replace(/_/g, "-");
52
+ }
53
+ // ---------------------------------------------------------------------------
54
+ // Request handler (exported for testing)
55
+ // ---------------------------------------------------------------------------
56
+ /**
57
+ * Handle a single JSON-RPC request and return the response.
58
+ *
59
+ * Exported so tests can call it directly without stdio.
60
+ *
61
+ * @param request Parsed JSON-RPC request
62
+ * @param skills Loaded Phase2S skills (passed in so tests can inject fixtures)
63
+ * @param cwd Working directory for config loading and agent runs
64
+ */
65
+ export async function handleRequest(request, skills, cwd) {
66
+ // -----------------------------------------------------------------------
67
+ // initialize
68
+ // -----------------------------------------------------------------------
69
+ if (request.method === "initialize") {
70
+ return {
71
+ jsonrpc: "2.0",
72
+ id: request.id,
73
+ result: {
74
+ protocolVersion: "2024-11-05",
75
+ capabilities: { tools: {} },
76
+ serverInfo: { name: "phase2s", version: MCP_SERVER_VERSION },
77
+ },
78
+ };
79
+ }
80
+ // -----------------------------------------------------------------------
81
+ // tools/list
82
+ // -----------------------------------------------------------------------
83
+ if (request.method === "tools/list") {
84
+ return {
85
+ jsonrpc: "2.0",
86
+ id: request.id,
87
+ result: { tools: skills.map(skillToTool) },
88
+ };
89
+ }
90
+ // -----------------------------------------------------------------------
91
+ // tools/call
92
+ // -----------------------------------------------------------------------
93
+ if (request.method === "tools/call") {
94
+ const params = request.params;
95
+ const toolName = params?.name ?? "";
96
+ const skillName = toolNameToSkillName(toolName);
97
+ const skill = skills.find((s) => s.name === skillName);
98
+ if (!skill) {
99
+ return {
100
+ jsonrpc: "2.0",
101
+ id: request.id,
102
+ error: { code: -32601, message: `Tool not found: ${toolName}` },
103
+ };
104
+ }
105
+ const userPrompt = params?.arguments?.prompt ?? "";
106
+ // Prepend the skill's system prompt to the user's content
107
+ const fullPrompt = skill.promptTemplate + (userPrompt ? `\n\n## Input\n\n${userPrompt}` : "");
108
+ try {
109
+ const config = await loadConfig();
110
+ const agent = new Agent({ config });
111
+ const text = await agent.run(fullPrompt, { modelOverride: skill.model });
112
+ return {
113
+ jsonrpc: "2.0",
114
+ id: request.id,
115
+ result: {
116
+ content: [{ type: "text", text }],
117
+ },
118
+ };
119
+ }
120
+ catch (err) {
121
+ return {
122
+ jsonrpc: "2.0",
123
+ id: request.id,
124
+ error: {
125
+ code: -32603,
126
+ message: err instanceof Error ? err.message : String(err),
127
+ },
128
+ };
129
+ }
130
+ }
131
+ // -----------------------------------------------------------------------
132
+ // Unknown method
133
+ // -----------------------------------------------------------------------
134
+ return {
135
+ jsonrpc: "2.0",
136
+ id: request.id,
137
+ error: { code: -32601, message: `Method not found: ${request.method}` },
138
+ };
139
+ }
140
+ // ---------------------------------------------------------------------------
141
+ // Server entry point
142
+ // ---------------------------------------------------------------------------
143
+ /**
144
+ * Start the MCP server. Reads JSON-RPC messages from stdin, writes responses
145
+ * to stdout. Runs until stdin closes (i.e. Claude Code terminates the session).
146
+ *
147
+ * Uses a manual event-queue pattern (same as the CLI REPL) to avoid the known
148
+ * issue where the readline async iterator terminates if the event loop drains
149
+ * while awaiting between messages.
150
+ */
151
+ export async function runMCPServer(cwd) {
152
+ const skillsDir = join(cwd, ".phase2s", "skills");
153
+ const skills = await loadSkillsFromDir(skillsDir);
154
+ const respond = (response) => {
155
+ process.stdout.write(JSON.stringify(response) + "\n");
156
+ };
157
+ // Manual event queue — safer than readline async iterator for long-lived servers
158
+ const lineQueue = [];
159
+ let pendingResolve = null;
160
+ let isOpen = true;
161
+ const rl = createInterface({ input: process.stdin, terminal: false });
162
+ rl.on("line", (line) => {
163
+ if (pendingResolve) {
164
+ const resolve = pendingResolve;
165
+ pendingResolve = null;
166
+ resolve(line);
167
+ }
168
+ else {
169
+ lineQueue.push(line);
170
+ }
171
+ });
172
+ rl.on("close", () => {
173
+ isOpen = false;
174
+ if (pendingResolve) {
175
+ pendingResolve(null);
176
+ pendingResolve = null;
177
+ }
178
+ // Force exit so any in-flight codex subprocess doesn't keep us alive after
179
+ // Claude Code has closed the connection. The "exit" event still fires on
180
+ // process.exit(), so codex.ts cleanupTempDirs() runs before we die.
181
+ process.exit(0);
182
+ });
183
+ const nextLine = () => {
184
+ if (lineQueue.length > 0)
185
+ return Promise.resolve(lineQueue.shift());
186
+ if (!isOpen)
187
+ return Promise.resolve(null);
188
+ return new Promise((resolve) => {
189
+ pendingResolve = resolve;
190
+ });
191
+ };
192
+ while (true) {
193
+ const line = await nextLine();
194
+ if (line === null)
195
+ break; // stdin closed
196
+ const trimmed = line.trim();
197
+ if (!trimmed)
198
+ continue;
199
+ let request;
200
+ try {
201
+ request = JSON.parse(trimmed);
202
+ }
203
+ catch {
204
+ respond({
205
+ jsonrpc: "2.0",
206
+ id: null,
207
+ error: { code: -32700, message: "Parse error" },
208
+ });
209
+ continue;
210
+ }
211
+ const response = await handleRequest(request, skills, cwd);
212
+ respond(response);
213
+ }
214
+ }
215
+ //# sourceMappingURL=server.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"server.js","sourceRoot":"","sources":["../../../src/mcp/server.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,28 @@
1
+ import type { Config } from "../core/config.js";
2
+ import type { Provider, Message, ProviderEvent } from "./types.js";
3
+ import type { OpenAIFunctionDef } from "../tools/types.js";
4
+ /**
5
+ * Codex CLI provider.
6
+ *
7
+ * Uses `codex exec` in fully non-interactive scripting mode:
8
+ * --json suppresses the terminal UI (outputs JSONL instead)
9
+ * --output-last-message writes the final response to a temp file
10
+ *
11
+ * This means codex never needs to open /dev/tty, so it cannot corrupt
12
+ * the parent process's terminal/readline session.
13
+ *
14
+ * Real Codex streaming is deferred — the JSONL stdout format is undocumented.
15
+ * `chatStream()` wraps `_chat()` in a passthrough single-event generator
16
+ * (same batch UX as before, but through the Provider streaming interface).
17
+ * Tool calling is not supported via the --output-last-message mechanism;
18
+ * toolCalls is always [].
19
+ */
20
+ export declare class CodexProvider implements Provider {
21
+ name: string;
22
+ private codexPath;
23
+ private model;
24
+ constructor(config: Config);
25
+ chatStream(messages: Message[], tools: OpenAIFunctionDef[], options?: import("./types.js").ChatStreamOptions): AsyncIterable<ProviderEvent>;
26
+ private _chat;
27
+ }
28
+ //# sourceMappingURL=codex.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex.d.ts","sourceRoot":"","sources":["../../../src/providers/codex.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,QAAQ,EAAE,OAAO,EAAY,aAAa,EAAE,MAAM,YAAY,CAAC;AAC7E,OAAO,KAAK,EAAE,iBAAiB,EAAE,MAAM,mBAAmB,CAAC;AAsC3D;;;;;;;;;;;;;;;GAeG;AACH,qBAAa,aAAc,YAAW,QAAQ;IAC5C,IAAI,SAAe;IACnB,OAAO,CAAC,SAAS,CAAS;IAC1B,OAAO,CAAC,KAAK,CAAS;gBAEV,MAAM,EAAE,MAAM;IAKnB,UAAU,CACf,QAAQ,EAAE,OAAO,EAAE,EACnB,KAAK,EAAE,iBAAiB,EAAE,EAC1B,OAAO,CAAC,EAAE,OAAO,YAAY,EAAE,iBAAiB,GAC/C,aAAa,CAAC,aAAa,CAAC;YAejB,KAAK;CAmGpB"}
@@ -0,0 +1,162 @@
1
+ import { spawn } from "node:child_process";
2
+ import { rmSync } from "node:fs";
3
+ import { mkdtemp, readFile, rm } from "node:fs/promises";
4
+ import { join } from "node:path";
5
+ import { tmpdir } from "node:os";
6
+ /** Track all temp dirs created this process so we can clean up on crash/exit. */
7
+ const activeTempDirs = new Set();
8
+ function cleanupTempDirs() {
9
+ // Synchronous cleanup — rmSync is available here (unlike the async rm).
10
+ for (const dir of activeTempDirs) {
11
+ try {
12
+ rmSync(dir, { recursive: true, force: true });
13
+ }
14
+ catch {
15
+ // Best-effort — ignore errors (e.g. already deleted by normal path)
16
+ }
17
+ }
18
+ }
19
+ /**
20
+ * Guard against double-registration if the module is evaluated multiple times.
21
+ * In vitest environments, modules may be re-evaluated between test files, which
22
+ * would register duplicate handlers and trigger MaxListenersExceededWarning.
23
+ */
24
+ let _signalHandlersRegistered = false;
25
+ if (!_signalHandlersRegistered) {
26
+ _signalHandlersRegistered = true;
27
+ process.on("exit", cleanupTempDirs);
28
+ // SIGTERM and SIGINT don't trigger "exit" automatically — register them explicitly
29
+ // so that temp dirs (which may contain prompt text) are cleaned up on Ctrl+C and kill.
30
+ process.on("SIGTERM", () => {
31
+ cleanupTempDirs();
32
+ process.exit(0);
33
+ });
34
+ process.on("SIGINT", () => {
35
+ cleanupTempDirs();
36
+ process.exit(0);
37
+ });
38
+ }
39
+ /**
40
+ * Codex CLI provider.
41
+ *
42
+ * Uses `codex exec` in fully non-interactive scripting mode:
43
+ * --json suppresses the terminal UI (outputs JSONL instead)
44
+ * --output-last-message writes the final response to a temp file
45
+ *
46
+ * This means codex never needs to open /dev/tty, so it cannot corrupt
47
+ * the parent process's terminal/readline session.
48
+ *
49
+ * Real Codex streaming is deferred — the JSONL stdout format is undocumented.
50
+ * `chatStream()` wraps `_chat()` in a passthrough single-event generator
51
+ * (same batch UX as before, but through the Provider streaming interface).
52
+ * Tool calling is not supported via the --output-last-message mechanism;
53
+ * toolCalls is always [].
54
+ */
55
+ export class CodexProvider {
56
+ name = "codex-cli";
57
+ codexPath;
58
+ model;
59
+ constructor(config) {
60
+ this.codexPath = config.codexPath;
61
+ this.model = config.model;
62
+ }
63
+ async *chatStream(messages, tools, options) {
64
+ const result = await this._chat(messages, tools, options?.model);
65
+ if (result.text) {
66
+ yield { type: "text", content: result.text };
67
+ }
68
+ // Codex provider currently always returns toolCalls: [] — tool calling
69
+ // is not supported via the --output-last-message mechanism.
70
+ if (result.toolCalls.length > 0) {
71
+ yield { type: "tool_calls", calls: result.toolCalls };
72
+ yield { type: "done", stopReason: "tool_calls" };
73
+ }
74
+ else {
75
+ yield { type: "done", stopReason: "stop" };
76
+ }
77
+ }
78
+ async _chat(messages, _tools, modelOverride) {
79
+ // Build the full prompt: system context + conversation history
80
+ const parts = [];
81
+ const systemMessages = messages.filter((m) => m.role === "system");
82
+ if (systemMessages.length > 0) {
83
+ parts.push(systemMessages.map((m) => m.content).join("\n"));
84
+ parts.push("---");
85
+ }
86
+ const nonSystem = messages.filter((m) => m.role !== "system");
87
+ for (const msg of nonSystem) {
88
+ if (msg.role === "user") {
89
+ parts.push(`User: ${msg.content}`);
90
+ }
91
+ else if (msg.role === "assistant" && msg.content) {
92
+ parts.push(`Assistant: ${msg.content}`);
93
+ }
94
+ }
95
+ const prompt = parts.join("\n\n");
96
+ // Use a temp dir for the output file so we don't pollute the project
97
+ const tmpDir = await mkdtemp(join(tmpdir(), "phase2s-"));
98
+ activeTempDirs.add(tmpDir);
99
+ const outputFile = join(tmpDir, "last-message.txt");
100
+ // codex exec --json suppresses the interactive UI (no /dev/tty access)
101
+ // --output-last-message writes the final response to a file we control
102
+ //
103
+ // The "--" separator signals end-of-flags to codex's own arg parser.
104
+ // Without it, a prompt beginning with "--" (e.g. "--help" or "--flags")
105
+ // would be misinterpreted as a codex CLI flag rather than as the prompt.
106
+ // spawn() with an array is NOT shell-injected, so this is the only risk.
107
+ const args = [
108
+ "exec",
109
+ "-m", modelOverride ?? this.model,
110
+ "--full-auto",
111
+ "-C", process.cwd(),
112
+ "--json",
113
+ "--output-last-message", outputFile,
114
+ "--",
115
+ prompt,
116
+ ];
117
+ return new Promise((resolve, reject) => {
118
+ const proc = spawn(this.codexPath, args, {
119
+ stdio: ["ignore", "pipe", "pipe"],
120
+ env: {
121
+ ...process.env,
122
+ NO_COLOR: "1",
123
+ FORCE_COLOR: "0",
124
+ },
125
+ });
126
+ let stderr = "";
127
+ // Consume stdout (JSONL events) so the pipe buffer never fills and
128
+ // blocks codex. We don't parse it — we use --output-last-message instead.
129
+ proc.stdout.resume();
130
+ proc.stderr.on("data", (data) => {
131
+ stderr += data.toString();
132
+ });
133
+ proc.on("close", async (code) => {
134
+ // Try reading the output file first (most reliable)
135
+ try {
136
+ const text = await readFile(outputFile, "utf-8");
137
+ await rm(tmpDir, { recursive: true }).catch(() => { });
138
+ activeTempDirs.delete(tmpDir);
139
+ resolve({ text: text.trim(), toolCalls: [] });
140
+ return;
141
+ }
142
+ catch {
143
+ // Output file missing — fall through to error handling
144
+ }
145
+ await rm(tmpDir, { recursive: true }).catch(() => { });
146
+ activeTempDirs.delete(tmpDir);
147
+ if (code !== 0) {
148
+ reject(new Error(`Codex exited with code ${code}: ${stderr.trim()}`));
149
+ return;
150
+ }
151
+ // Unexpected: exited 0 but no output file
152
+ reject(new Error("Codex produced no output"));
153
+ });
154
+ proc.on("error", async (err) => {
155
+ await rm(tmpDir, { recursive: true }).catch(() => { });
156
+ activeTempDirs.delete(tmpDir);
157
+ reject(new Error(`Failed to spawn codex: ${err.message}`));
158
+ });
159
+ });
160
+ }
161
+ }
162
+ //# sourceMappingURL=codex.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"codex.js","sourceRoot":"","sources":["../../../src/providers/codex.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,6 @@
1
+ import type { Config } from "../core/config.js";
2
+ import type { Provider } from "./types.js";
3
+ export declare function createProvider(config: Config): Provider;
4
+ export type { Provider, Message, ToolCall, ProviderEvent } from "./types.js";
5
+ export type { OpenAIClientLike } from "./openai.js";
6
+ //# sourceMappingURL=index.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../../../src/providers/index.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAChD,OAAO,KAAK,EAAE,QAAQ,EAAE,MAAM,YAAY,CAAC;AAI3C,wBAAgB,cAAc,CAAC,MAAM,EAAE,MAAM,GAAG,QAAQ,CASvD;AAED,YAAY,EAAE,QAAQ,EAAE,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC7E,YAAY,EAAE,gBAAgB,EAAE,MAAM,aAAa,CAAC"}
@@ -0,0 +1,13 @@
1
+ import { CodexProvider } from "./codex.js";
2
+ import { OpenAIProvider } from "./openai.js";
3
+ export function createProvider(config) {
4
+ switch (config.provider) {
5
+ case "codex-cli":
6
+ return new CodexProvider(config);
7
+ case "openai-api":
8
+ return new OpenAIProvider(config);
9
+ default:
10
+ throw new Error(`Unknown provider: ${config.provider}`);
11
+ }
12
+ }
13
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/providers/index.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,aAAa,EAAE,MAAM,YAAY,CAAC;AAC3C,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAC;AAE7C,MAAM,UAAU,cAAc,CAAC,MAAc;IAC3C,QAAQ,MAAM,CAAC,QAAQ,EAAE,CAAC;QACxB,KAAK,WAAW;YACd,OAAO,IAAI,aAAa,CAAC,MAAM,CAAC,CAAC;QACnC,KAAK,YAAY;YACf,OAAO,IAAI,cAAc,CAAC,MAAM,CAAC,CAAC;QACpC;YACE,MAAM,IAAI,KAAK,CAAC,qBAAqB,MAAM,CAAC,QAAQ,EAAE,CAAC,CAAC;IAC5D,CAAC;AACH,CAAC"}