localptp 0.1.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 (186) hide show
  1. package/LICENSE +23 -0
  2. package/README.md +159 -0
  3. package/dist/cli.d.ts +24 -0
  4. package/dist/cli.js +344 -0
  5. package/dist/cli.js.map +1 -0
  6. package/dist/commands/config.d.ts +14 -0
  7. package/dist/commands/config.js +65 -0
  8. package/dist/commands/config.js.map +1 -0
  9. package/dist/commands/context.d.ts +12 -0
  10. package/dist/commands/context.js +176 -0
  11. package/dist/commands/context.js.map +1 -0
  12. package/dist/commands/doctor.d.ts +16 -0
  13. package/dist/commands/doctor.js +54 -0
  14. package/dist/commands/doctor.js.map +1 -0
  15. package/dist/commands/index.d.ts +13 -0
  16. package/dist/commands/index.js +70 -0
  17. package/dist/commands/index.js.map +1 -0
  18. package/dist/commands/init.d.ts +15 -0
  19. package/dist/commands/init.js +46 -0
  20. package/dist/commands/init.js.map +1 -0
  21. package/dist/commands/plan.d.ts +17 -0
  22. package/dist/commands/plan.js +170 -0
  23. package/dist/commands/plan.js.map +1 -0
  24. package/dist/commands/resume.d.ts +17 -0
  25. package/dist/commands/resume.js +75 -0
  26. package/dist/commands/resume.js.map +1 -0
  27. package/dist/commands/review.d.ts +17 -0
  28. package/dist/commands/review.js +67 -0
  29. package/dist/commands/review.js.map +1 -0
  30. package/dist/commands/run.d.ts +24 -0
  31. package/dist/commands/run.js +65 -0
  32. package/dist/commands/run.js.map +1 -0
  33. package/dist/commands/step.d.ts +44 -0
  34. package/dist/commands/step.js +50 -0
  35. package/dist/commands/step.js.map +1 -0
  36. package/dist/commands/summarize.d.ts +17 -0
  37. package/dist/commands/summarize.js +276 -0
  38. package/dist/commands/summarize.js.map +1 -0
  39. package/dist/commands/task.d.ts +13 -0
  40. package/dist/commands/task.js +53 -0
  41. package/dist/commands/task.js.map +1 -0
  42. package/dist/core/activePointer.d.ts +28 -0
  43. package/dist/core/activePointer.js +84 -0
  44. package/dist/core/activePointer.js.map +1 -0
  45. package/dist/core/approval.d.ts +12 -0
  46. package/dist/core/approval.js +34 -0
  47. package/dist/core/approval.js.map +1 -0
  48. package/dist/core/configManager.d.ts +32 -0
  49. package/dist/core/configManager.js +177 -0
  50. package/dist/core/configManager.js.map +1 -0
  51. package/dist/core/contextBuilder.d.ts +40 -0
  52. package/dist/core/contextBuilder.js +406 -0
  53. package/dist/core/contextBuilder.js.map +1 -0
  54. package/dist/core/memoryLoader.d.ts +4 -0
  55. package/dist/core/memoryLoader.js +35 -0
  56. package/dist/core/memoryLoader.js.map +1 -0
  57. package/dist/core/memoryManager.d.ts +41 -0
  58. package/dist/core/memoryManager.js +181 -0
  59. package/dist/core/memoryManager.js.map +1 -0
  60. package/dist/core/memoryPolicy.d.ts +23 -0
  61. package/dist/core/memoryPolicy.js +73 -0
  62. package/dist/core/memoryPolicy.js.map +1 -0
  63. package/dist/core/modelClient.d.ts +37 -0
  64. package/dist/core/modelClient.js +160 -0
  65. package/dist/core/modelClient.js.map +1 -0
  66. package/dist/core/patchManager.d.ts +89 -0
  67. package/dist/core/patchManager.js +801 -0
  68. package/dist/core/patchManager.js.map +1 -0
  69. package/dist/core/plannerJson.d.ts +23 -0
  70. package/dist/core/plannerJson.js +118 -0
  71. package/dist/core/plannerJson.js.map +1 -0
  72. package/dist/core/promptManager.d.ts +16 -0
  73. package/dist/core/promptManager.js +35 -0
  74. package/dist/core/promptManager.js.map +1 -0
  75. package/dist/core/prompts.d.ts +8 -0
  76. package/dist/core/prompts.js +18 -0
  77. package/dist/core/prompts.js.map +1 -0
  78. package/dist/core/repoIndexer.d.ts +21 -0
  79. package/dist/core/repoIndexer.js +557 -0
  80. package/dist/core/repoIndexer.js.map +1 -0
  81. package/dist/core/reviewEngine.d.ts +53 -0
  82. package/dist/core/reviewEngine.js +229 -0
  83. package/dist/core/reviewEngine.js.map +1 -0
  84. package/dist/core/runLoop.d.ts +26 -0
  85. package/dist/core/runLoop.js +103 -0
  86. package/dist/core/runLoop.js.map +1 -0
  87. package/dist/core/runStep.d.ts +42 -0
  88. package/dist/core/runStep.js +586 -0
  89. package/dist/core/runStep.js.map +1 -0
  90. package/dist/core/safetyManager.d.ts +7 -0
  91. package/dist/core/safetyManager.js +202 -0
  92. package/dist/core/safetyManager.js.map +1 -0
  93. package/dist/core/sessionManager.d.ts +35 -0
  94. package/dist/core/sessionManager.js +265 -0
  95. package/dist/core/sessionManager.js.map +1 -0
  96. package/dist/core/stopConditions.d.ts +24 -0
  97. package/dist/core/stopConditions.js +18 -0
  98. package/dist/core/stopConditions.js.map +1 -0
  99. package/dist/core/taskManager.d.ts +26 -0
  100. package/dist/core/taskManager.js +312 -0
  101. package/dist/core/taskManager.js.map +1 -0
  102. package/dist/core/testRunner.d.ts +27 -0
  103. package/dist/core/testRunner.js +71 -0
  104. package/dist/core/testRunner.js.map +1 -0
  105. package/dist/prompts/coder.d.ts +3 -0
  106. package/dist/prompts/coder.js +46 -0
  107. package/dist/prompts/coder.js.map +1 -0
  108. package/dist/prompts/planner.d.ts +3 -0
  109. package/dist/prompts/planner.js +44 -0
  110. package/dist/prompts/planner.js.map +1 -0
  111. package/dist/prompts/reviewer.d.ts +3 -0
  112. package/dist/prompts/reviewer.js +41 -0
  113. package/dist/prompts/reviewer.js.map +1 -0
  114. package/dist/prompts/summarizer.d.ts +3 -0
  115. package/dist/prompts/summarizer.js +65 -0
  116. package/dist/prompts/summarizer.js.map +1 -0
  117. package/dist/prompts/testFixer.d.ts +3 -0
  118. package/dist/prompts/testFixer.js +33 -0
  119. package/dist/prompts/testFixer.js.map +1 -0
  120. package/dist/repl/approver.d.ts +15 -0
  121. package/dist/repl/approver.js +21 -0
  122. package/dist/repl/approver.js.map +1 -0
  123. package/dist/repl/dispatch.d.ts +48 -0
  124. package/dist/repl/dispatch.js +164 -0
  125. package/dist/repl/dispatch.js.map +1 -0
  126. package/dist/repl/loop.d.ts +14 -0
  127. package/dist/repl/loop.js +124 -0
  128. package/dist/repl/loop.js.map +1 -0
  129. package/dist/repl/tokenize.d.ts +13 -0
  130. package/dist/repl/tokenize.js +56 -0
  131. package/dist/repl/tokenize.js.map +1 -0
  132. package/dist/templates/memory.d.ts +13 -0
  133. package/dist/templates/memory.js +32 -0
  134. package/dist/templates/memory.js.map +1 -0
  135. package/dist/types/config.d.ts +235 -0
  136. package/dist/types/config.js +66 -0
  137. package/dist/types/config.js.map +1 -0
  138. package/dist/types/context.d.ts +78 -0
  139. package/dist/types/context.js +141 -0
  140. package/dist/types/context.js.map +1 -0
  141. package/dist/types/index.d.ts +117 -0
  142. package/dist/types/index.js +24 -0
  143. package/dist/types/index.js.map +1 -0
  144. package/dist/types/model.d.ts +35 -0
  145. package/dist/types/model.js +16 -0
  146. package/dist/types/model.js.map +1 -0
  147. package/dist/types/patch.d.ts +38 -0
  148. package/dist/types/patch.js +11 -0
  149. package/dist/types/patch.js.map +1 -0
  150. package/dist/types/plan.d.ts +86 -0
  151. package/dist/types/plan.js +27 -0
  152. package/dist/types/plan.js.map +1 -0
  153. package/dist/types/review.d.ts +33 -0
  154. package/dist/types/review.js +24 -0
  155. package/dist/types/review.js.map +1 -0
  156. package/dist/types/run.d.ts +34 -0
  157. package/dist/types/run.js +2 -0
  158. package/dist/types/run.js.map +1 -0
  159. package/dist/types/session.d.ts +21 -0
  160. package/dist/types/session.js +2 -0
  161. package/dist/types/session.js.map +1 -0
  162. package/dist/types/summary.d.ts +65 -0
  163. package/dist/types/summary.js +26 -0
  164. package/dist/types/summary.js.map +1 -0
  165. package/dist/types/task.d.ts +31 -0
  166. package/dist/types/task.js +10 -0
  167. package/dist/types/task.js.map +1 -0
  168. package/dist/types/test.d.ts +16 -0
  169. package/dist/types/test.js +2 -0
  170. package/dist/types/test.js.map +1 -0
  171. package/dist/utils/fs.d.ts +13 -0
  172. package/dist/utils/fs.js +65 -0
  173. package/dist/utils/fs.js.map +1 -0
  174. package/dist/utils/gitRoot.d.ts +5 -0
  175. package/dist/utils/gitRoot.js +21 -0
  176. package/dist/utils/gitRoot.js.map +1 -0
  177. package/dist/utils/logger.d.ts +15 -0
  178. package/dist/utils/logger.js +60 -0
  179. package/dist/utils/logger.js.map +1 -0
  180. package/dist/utils/paths.d.ts +13 -0
  181. package/dist/utils/paths.js +24 -0
  182. package/dist/utils/paths.js.map +1 -0
  183. package/dist/utils/tokenEstimate.d.ts +5 -0
  184. package/dist/utils/tokenEstimate.js +8 -0
  185. package/dist/utils/tokenEstimate.js.map +1 -0
  186. package/package.json +44 -0
@@ -0,0 +1,65 @@
1
+ /**
2
+ * Summarizer prompt template (HLD-SRD §3.9, §10.1, 0001_07).
3
+ *
4
+ * The system prompt embeds the §10.1 base coding rules and instructs the model
5
+ * to summarize the just-finished work. The user framing wraps the Context
6
+ * Builder's assembled context and demands ONLY the §3.9 summarizer JSON
7
+ * object.
8
+ *
9
+ * Key constraints (§3.4, §13):
10
+ * - The model MUST declare changeType from the ONLY allowed set.
11
+ * - The code (not the model) picks the target file from the policy table.
12
+ * - One concise line per entry.
13
+ */
14
+ import { CODER_SYSTEM_PROMPT } from "../core/prompts.js";
15
+ export const SUMMARIZER_SYSTEM = `${CODER_SYSTEM_PROMPT}
16
+
17
+ You are acting as the SUMMARIZER. Review the work done in this session and
18
+ produce a compact, structured summary for memory updates.
19
+
20
+ Return ONLY a single JSON object — no prose, no markdown fences — with this shape:
21
+
22
+ {
23
+ "sessionUpdate": {
24
+ "currentState": "one concise paragraph of what was accomplished",
25
+ "filesChanged": ["list", "of", "files", "touched"],
26
+ "decisions": ["brief decision taken"],
27
+ "risks": ["brief risk or open issue"]
28
+ },
29
+ "memoryUpdates": [
30
+ {
31
+ "changeType": "<ONLY one of the allowed types listed below>",
32
+ "content": "one concise line describing the change"
33
+ }
34
+ ],
35
+ "nextStep": "the single most important next action"
36
+ }
37
+
38
+ Allowed changeType values (ONLY these — the system uses this to determine which
39
+ memory file to update; you must NOT specify a file name):
40
+ - file-responsibility → file ownership / responsibility changes
41
+ - api-behavior → API contract or endpoint behavior changes
42
+ - data-model → data structure or schema changes
43
+ - architectural-decision → significant design decisions
44
+ - external-integration → third-party or external service integration changes
45
+ - testing-process → testing strategy or process changes
46
+ - risk → risks, bugs found, or known issues
47
+
48
+ Rules:
49
+ - Keep every entry CONCISE — one brief line per memoryUpdates entry.
50
+ - Omit empty arrays (include only what applies).
51
+ - Do NOT include a changeType outside the allowed list above.
52
+ - Do NOT suggest a file path in your response.
53
+ - If no Git diff is present, summarize task/session progress only.`;
54
+ /** Render the summarizer user message from an assembled context string. */
55
+ export function renderSummarizerUser(context) {
56
+ return `${context}
57
+
58
+ ---
59
+
60
+ Produce the summary now. Return ONLY the JSON object with these keys:
61
+ sessionUpdate (currentState, filesChanged[], decisions[], risks[]),
62
+ memoryUpdates (each with changeType and content — use ONLY the allowed change types),
63
+ nextStep.`;
64
+ }
65
+ //# sourceMappingURL=summarizer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"summarizer.js","sourceRoot":"","sources":["../../src/prompts/summarizer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;GAYG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAEzD,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,mBAAmB;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;;mEAsCY,CAAC;AAEpE,2EAA2E;AAC3E,MAAM,UAAU,oBAAoB,CAAC,OAAe;IAClD,OAAO,GAAG,OAAO;;;;;;;UAOT,CAAC;AACX,CAAC"}
@@ -0,0 +1,3 @@
1
+ export declare const TEST_FIXER_SYSTEM = "You are a careful coding assistant working inside an existing codebase.\n\nRules:\n- Work in small, safe patches.\n- Do not rewrite unrelated code.\n- Preserve existing behavior unless explicitly instructed.\n- Prefer existing project patterns.\n- If context is insufficient, request exact files instead of guessing.\n- Do not modify risky areas unless explicitly required.\n- Return machine-parseable output when requested.\n\nYou are acting as the TEST-FIXER. One or more configured tests failed after a\npatch was applied. Using the captured failure output, make the SMALLEST safe\nchange that makes the failing test(s) pass. Do not refactor unrelated code, do\nnot weaken or delete the test to make it pass, and do not touch files outside the\nfix.\n\nReturn ONLY a single unified diff in git format (the kind `git apply` accepts)\n\u2014 `diff --git a/<path> b/<path>` headers, `---`/`+++` file lines, and\n`@@` hunks, repo-relative paths. Nothing else: no prose, no markdown fences.";
2
+ /** Render the test-fixer user message from an assembled context string. */
3
+ export declare function renderTestFixerUser(context: string): string;
@@ -0,0 +1,33 @@
1
+ /**
2
+ * Test-fixer prompt template (HLD-SRD §3.11, §10.1, §10.2 output contract).
3
+ *
4
+ * The system prompt embeds the §10.1 base coding rules and instructs the model,
5
+ * acting as the TEST-FIXER, to make the SMALLEST safe change that repairs the
6
+ * failing test(s), given the captured failure output, and to return EXACTLY one
7
+ * unified diff (the same machine-parseable shape the coder uses, §10.2) — so the
8
+ * fix patch flows through the identical extract → parse → safety → approval →
9
+ * apply path as any other patch. No prose, no fences.
10
+ */
11
+ import { CODER_SYSTEM_PROMPT } from "../core/prompts.js";
12
+ export const TEST_FIXER_SYSTEM = `${CODER_SYSTEM_PROMPT}
13
+
14
+ You are acting as the TEST-FIXER. One or more configured tests failed after a
15
+ patch was applied. Using the captured failure output, make the SMALLEST safe
16
+ change that makes the failing test(s) pass. Do not refactor unrelated code, do
17
+ not weaken or delete the test to make it pass, and do not touch files outside the
18
+ fix.
19
+
20
+ Return ONLY a single unified diff in git format (the kind \`git apply\` accepts)
21
+ — \`diff --git a/<path> b/<path>\` headers, \`---\`/\`+++\` file lines, and
22
+ \`@@\` hunks, repo-relative paths. Nothing else: no prose, no markdown fences.`;
23
+ /** Render the test-fixer user message from an assembled context string. */
24
+ export function renderTestFixerUser(context) {
25
+ return `${context}
26
+
27
+ ---
28
+
29
+ Produce the minimal fix now. Return ONLY a single unified diff (git format) that
30
+ \`git apply\` can apply and that makes the failing test(s) pass. No prose, no
31
+ fences.`;
32
+ }
33
+ //# sourceMappingURL=testFixer.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"testFixer.js","sourceRoot":"","sources":["../../src/prompts/testFixer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,mBAAmB,EAAE,MAAM,oBAAoB,CAAC;AAEzD,MAAM,CAAC,MAAM,iBAAiB,GAAG,GAAG,mBAAmB;;;;;;;;;;+EAUwB,CAAC;AAEhF,2EAA2E;AAC3E,MAAM,UAAU,mBAAmB,CAAC,OAAe;IACjD,OAAO,GAAG,OAAO;;;;;;QAMX,CAAC;AACT,CAAC"}
@@ -0,0 +1,15 @@
1
+ /**
2
+ * REPL-aware Approver (HLD-SRD § interactive-repl).
3
+ *
4
+ * Reuses the loop's already-open `readline.Interface` instead of creating a
5
+ * second competing reader on the same stdin — so approval prompts inside the
6
+ * REPL never contend with the loop's interface.
7
+ */
8
+ import type readline from "node:readline";
9
+ import type { Approver } from "../core/approval.js";
10
+ /**
11
+ * Returns an `Approver` that asks `prompt [y/N]` via the given
12
+ * `readline.Interface` and resolves `true` for `y`/`yes` (any case, any
13
+ * surrounding whitespace), `false` for everything else (deny-by-default).
14
+ */
15
+ export declare function replApprover(rl: readline.Interface): Approver;
@@ -0,0 +1,21 @@
1
+ /**
2
+ * Returns an `Approver` that asks `prompt [y/N]` via the given
3
+ * `readline.Interface` and resolves `true` for `y`/`yes` (any case, any
4
+ * surrounding whitespace), `false` for everything else (deny-by-default).
5
+ */
6
+ export function replApprover(rl) {
7
+ return (prompt) => new Promise((resolve) => {
8
+ // If the interface closes while the question is outstanding, settle the
9
+ // approval as declined (false) so the in-flight dispatch can complete and
10
+ // the loop can resolve normally (no hang on 'close').
11
+ function onClose() {
12
+ resolve(false);
13
+ }
14
+ rl.once("close", onClose);
15
+ rl.question(`${prompt} [y/N] `, (answer) => {
16
+ rl.removeListener("close", onClose);
17
+ resolve(/^\s*y(es)?\s*$/i.test(answer));
18
+ });
19
+ });
20
+ }
21
+ //# sourceMappingURL=approver.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"approver.js","sourceRoot":"","sources":["../../src/repl/approver.ts"],"names":[],"mappings":"AAUA;;;;GAIG;AACH,MAAM,UAAU,YAAY,CAAC,EAAsB;IACjD,OAAO,CAAC,MAAc,EAAE,EAAE,CACxB,IAAI,OAAO,CAAU,CAAC,OAAO,EAAE,EAAE;QAC/B,wEAAwE;QACxE,0EAA0E;QAC1E,sDAAsD;QACtD,SAAS,OAAO;YACd,OAAO,CAAC,KAAK,CAAC,CAAC;QACjB,CAAC;QACD,EAAE,CAAC,IAAI,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;QAC1B,EAAE,CAAC,QAAQ,CAAC,GAAG,MAAM,SAAS,EAAE,CAAC,MAAM,EAAE,EAAE;YACzC,EAAE,CAAC,cAAc,CAAC,OAAO,EAAE,OAAO,CAAC,CAAC;YACpC,OAAO,CAAC,iBAAiB,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC,CAAC;QAC1C,CAAC,CAAC,CAAC;IACL,CAAC,CAAC,CAAC;AACP,CAAC"}
@@ -0,0 +1,48 @@
1
+ /**
2
+ * REPL command dispatcher (HLD-SRD § interactive-repl).
3
+ *
4
+ * `dispatch(line, ctx, commands)` handles every `/`-prefixed line from the
5
+ * REPL loop:
6
+ * - Meta (bare `/help` | `/exit` | `/clear`): built-in handlers.
7
+ * - `/lp:<cmd> [args]`: look up `<cmd>` in the COMMANDS table, map tokens
8
+ * to options via `buildOptions`, call the core `run`, write `format` output.
9
+ * - Unknown bare `/…` or unknown `/lp:<cmd>`: friendly message.
10
+ * - Any throw (TokenizeError, parse error, core error): friendly message,
11
+ * loop survives.
12
+ *
13
+ * The third `commands` parameter (defaulting to the production `COMMANDS`) is
14
+ * the concrete test seam: tests pass a fake table of vi.fn() entries to avoid
15
+ * importing or executing any real core.
16
+ */
17
+ import type readline from "node:readline";
18
+ export interface DispatchCtx {
19
+ cwd: string;
20
+ rl: readline.Interface;
21
+ output: NodeJS.WritableStream;
22
+ }
23
+ export interface DispatchResult {
24
+ exit: boolean;
25
+ }
26
+ interface CommandEntry {
27
+ run: (opts: any) => Promise<any>;
28
+ format: (result: any) => string;
29
+ buildOptions: (tokens: string[], ctx: DispatchCtx) => Record<string, unknown>;
30
+ }
31
+ /**
32
+ * The production COMMANDS table.
33
+ *
34
+ * Exported so tests can assert identity (`COMMANDS.plan.run === runPlan`) and
35
+ * inspect `buildOptions` mappings directly.
36
+ */
37
+ export declare const COMMANDS: Record<string, CommandEntry>;
38
+ /**
39
+ * Dispatch a `/`-prefixed REPL line.
40
+ *
41
+ * @param line The raw input line (should start with `/`).
42
+ * @param ctx Context: `cwd`, the open `rl` interface, and the `output` stream.
43
+ * @param commands The command table (defaults to the production `COMMANDS`).
44
+ * Override in tests with a fake table to avoid real cores.
45
+ * @returns `{ exit: true }` only for `/exit`; `{ exit: false }` for everything else.
46
+ */
47
+ export declare function dispatch(line: string, ctx: DispatchCtx, commands?: Record<string, CommandEntry>): Promise<DispatchResult>;
48
+ export {};
@@ -0,0 +1,164 @@
1
+ import { tokenize, TokenizeError } from "./tokenize.js";
2
+ import { replApprover } from "./approver.js";
3
+ import { runTask, formatTaskResult } from "../commands/task.js";
4
+ import { runPlan, formatPlanResult } from "../commands/plan.js";
5
+ import { runStep, formatStepResult } from "../commands/step.js";
6
+ import { run as runRun, formatRunResult } from "../commands/run.js";
7
+ import { runIndex, formatIndexResult } from "../commands/index.js";
8
+ import { runContext, formatContextResult } from "../commands/context.js";
9
+ import { runResume, formatResumeResult } from "../commands/resume.js";
10
+ import { runReview, formatReviewResult } from "../commands/review.js";
11
+ import { runSummarize, formatSummarizeResult } from "../commands/summarize.js";
12
+ import { runInit, formatInitReport } from "../commands/init.js";
13
+ import { runConfig, formatConfigResult } from "../commands/config.js";
14
+ import { runDoctor, formatDoctorResult } from "../commands/doctor.js";
15
+ const UNKNOWN_MSG = "Unknown command. Type /help for commands.";
16
+ const LP_PREFIX = "/lp:";
17
+ /**
18
+ * Validate and parse a resume index token.
19
+ *
20
+ * Accepts only canonical positive-integer syntax (no leading zeros, no
21
+ * decimals, no unsafe/overflowing integers). An invalid value throws a
22
+ * `TokenizeError` (caught by the dispatch try/catch) rather than forwarding
23
+ * a NaN or wrong value to `runResume`.
24
+ *
25
+ * When `tok` is `undefined` (i.e., the user omitted the index), returns
26
+ * `undefined` — this is NOT an error; the resume core handles the missing index
27
+ * with its own semantics (listing sessions, guidance, etc.).
28
+ */
29
+ function parseIndex(tok) {
30
+ if (tok === undefined)
31
+ return undefined;
32
+ const n = Number(tok);
33
+ if (!/^[1-9]\d*$/.test(tok) || !Number.isSafeInteger(n)) {
34
+ throw new TokenizeError(`Invalid resume index: ${tok} (expected a positive integer).`);
35
+ }
36
+ return n;
37
+ }
38
+ /**
39
+ * The production COMMANDS table.
40
+ *
41
+ * Exported so tests can assert identity (`COMMANDS.plan.run === runPlan`) and
42
+ * inspect `buildOptions` mappings directly.
43
+ */
44
+ export const COMMANDS = {
45
+ task: {
46
+ run: runTask,
47
+ format: formatTaskResult,
48
+ buildOptions: (tokens) => ({ text: tokens.join(" ") }),
49
+ },
50
+ plan: {
51
+ run: runPlan,
52
+ format: formatPlanResult,
53
+ buildOptions: () => ({}),
54
+ },
55
+ step: {
56
+ run: runStep,
57
+ format: formatStepResult,
58
+ buildOptions: (_tokens, ctx) => ({ approve: replApprover(ctx.rl) }),
59
+ },
60
+ run: {
61
+ run: runRun,
62
+ format: formatRunResult,
63
+ buildOptions: (_tokens, ctx) => ({ approve: replApprover(ctx.rl) }),
64
+ },
65
+ index: {
66
+ run: runIndex,
67
+ format: formatIndexResult,
68
+ buildOptions: () => ({}),
69
+ },
70
+ context: {
71
+ run: runContext,
72
+ format: formatContextResult,
73
+ buildOptions: (tokens) => ({ role: tokens[0] }),
74
+ },
75
+ resume: {
76
+ run: runResume,
77
+ format: formatResumeResult,
78
+ buildOptions: (tokens) => ({ index: parseIndex(tokens[0]) }),
79
+ },
80
+ review: {
81
+ run: runReview,
82
+ format: formatReviewResult,
83
+ buildOptions: () => ({}),
84
+ },
85
+ summarize: {
86
+ run: runSummarize,
87
+ format: formatSummarizeResult,
88
+ buildOptions: () => ({}),
89
+ },
90
+ init: {
91
+ run: runInit,
92
+ format: formatInitReport,
93
+ buildOptions: () => ({}),
94
+ },
95
+ config: {
96
+ run: runConfig,
97
+ format: formatConfigResult,
98
+ buildOptions: (tokens) => ({ key: tokens[0], value: tokens[1] }),
99
+ },
100
+ doctor: {
101
+ run: runDoctor,
102
+ format: formatDoctorResult,
103
+ buildOptions: () => ({}),
104
+ },
105
+ };
106
+ /**
107
+ * Dispatch a `/`-prefixed REPL line.
108
+ *
109
+ * @param line The raw input line (should start with `/`).
110
+ * @param ctx Context: `cwd`, the open `rl` interface, and the `output` stream.
111
+ * @param commands The command table (defaults to the production `COMMANDS`).
112
+ * Override in tests with a fake table to avoid real cores.
113
+ * @returns `{ exit: true }` only for `/exit`; `{ exit: false }` for everything else.
114
+ */
115
+ export async function dispatch(line, ctx, commands = COMMANDS) {
116
+ const trimmed = line.trim();
117
+ // ── Meta branch (bare `/…`, not `/lp:`) ─────────────────────────────────
118
+ // Meta lines are matched on the whole trimmed line — they are NOT tokenized,
119
+ // so an unbalanced quote in a bare `/…` line is just an unknown command, not
120
+ // a parse error.
121
+ if (!trimmed.startsWith(LP_PREFIX)) {
122
+ if (trimmed === "/help") {
123
+ const lpLines = Object.keys(commands).map((name) => ` /lp:${name}`);
124
+ const metaLines = [" /help", " /exit", " /clear"];
125
+ ctx.output.write(["Available commands:", ...lpLines, ...metaLines].join("\n") + "\n");
126
+ return { exit: false };
127
+ }
128
+ if (trimmed === "/exit") {
129
+ return { exit: true };
130
+ }
131
+ if (trimmed === "/clear") {
132
+ ctx.output.write("\x1b[2J\x1b[H");
133
+ return { exit: false };
134
+ }
135
+ // Unknown bare slash command.
136
+ ctx.output.write(UNKNOWN_MSG + "\n");
137
+ return { exit: false };
138
+ }
139
+ // ── /lp:<cmd> branch ────────────────────────────────────────────────────
140
+ // A single try/catch wraps tokenize, lookup, buildOptions (may throw, e.g.
141
+ // parseIndex), the core run, and format — so anything that throws is caught
142
+ // and the loop survives.
143
+ try {
144
+ const remainder = trimmed.slice(LP_PREFIX.length); // everything after "/lp:"
145
+ const [cmd, ...rest] = tokenize(remainder);
146
+ // Empty /lp: or whitespace-only → cmd is undefined.
147
+ // Use Object.hasOwn so prototype members (constructor, toString, __proto__)
148
+ // are never treated as commands.
149
+ if (!cmd || !Object.hasOwn(commands, cmd)) {
150
+ ctx.output.write(UNKNOWN_MSG + "\n");
151
+ return { exit: false };
152
+ }
153
+ const entry = commands[cmd];
154
+ // buildOptions is inside the try so parseIndex errors are caught here.
155
+ const opts = { cwd: ctx.cwd, ...entry.buildOptions(rest, ctx) };
156
+ const result = await entry.run(opts);
157
+ ctx.output.write(entry.format(result) + "\n");
158
+ }
159
+ catch (e) {
160
+ ctx.output.write((e instanceof Error ? e.message : String(e)) + "\n");
161
+ }
162
+ return { exit: false };
163
+ }
164
+ //# sourceMappingURL=dispatch.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"dispatch.js","sourceRoot":"","sources":["../../src/repl/dispatch.ts"],"names":[],"mappings":"AAiBA,OAAO,EAAE,QAAQ,EAAE,aAAa,EAAE,MAAM,eAAe,CAAC;AACxD,OAAO,EAAE,YAAY,EAAE,MAAM,eAAe,CAAC;AAC7C,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,GAAG,IAAI,MAAM,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACpE,OAAO,EAAE,QAAQ,EAAE,iBAAiB,EAAE,MAAM,sBAAsB,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,mBAAmB,EAAE,MAAM,wBAAwB,CAAC;AACzE,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAAE,YAAY,EAAE,qBAAqB,EAAE,MAAM,0BAA0B,CAAC;AAC/E,OAAO,EAAE,OAAO,EAAE,gBAAgB,EAAE,MAAM,qBAAqB,CAAC;AAChE,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AACtE,OAAO,EAAE,SAAS,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAoBtE,MAAM,WAAW,GAAG,2CAA2C,CAAC;AAChE,MAAM,SAAS,GAAG,MAAM,CAAC;AAEzB;;;;;;;;;;;GAWG;AACH,SAAS,UAAU,CAAC,GAAuB;IACzC,IAAI,GAAG,KAAK,SAAS;QAAE,OAAO,SAAS,CAAC;IACxC,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC;IACtB,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,GAAG,CAAC,IAAI,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC;QACxD,MAAM,IAAI,aAAa,CAAC,yBAAyB,GAAG,iCAAiC,CAAC,CAAC;IACzF,CAAC;IACD,OAAO,CAAC,CAAC;AACX,CAAC;AAED;;;;;GAKG;AACH,MAAM,CAAC,MAAM,QAAQ,GAAiC;IACpD,IAAI,EAAE;QACJ,GAAG,EAAE,OAAO;QACZ,MAAM,EAAE,gBAAgB;QACxB,YAAY,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC;KACvD;IACD,IAAI,EAAE;QACJ,GAAG,EAAE,OAAO;QACZ,MAAM,EAAE,gBAAgB;QACxB,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;KACzB;IACD,IAAI,EAAE;QACJ,GAAG,EAAE,OAAO;QACZ,MAAM,EAAE,gBAAgB;QACxB,YAAY,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;KACpE;IACD,GAAG,EAAE;QACH,GAAG,EAAE,MAAM;QACX,MAAM,EAAE,eAAe;QACvB,YAAY,EAAE,CAAC,OAAO,EAAE,GAAG,EAAE,EAAE,CAAC,CAAC,EAAE,OAAO,EAAE,YAAY,CAAC,GAAG,CAAC,EAAE,CAAC,EAAE,CAAC;KACpE;IACD,KAAK,EAAE;QACL,GAAG,EAAE,QAAQ;QACb,MAAM,EAAE,iBAAiB;QACzB,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;KACzB;IACD,OAAO,EAAE;QACP,GAAG,EAAE,UAAU;QACf,MAAM,EAAE,mBAAmB;QAC3B,YAAY,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;KAChD;IACD,MAAM,EAAE;QACN,GAAG,EAAE,SAAS;QACd,MAAM,EAAE,kBAAkB;QAC1B,YAAY,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,EAAE,KAAK,EAAE,UAAU,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;KAC7D;IACD,MAAM,EAAE;QACN,GAAG,EAAE,SAAS;QACd,MAAM,EAAE,kBAAkB;QAC1B,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;KACzB;IACD,SAAS,EAAE;QACT,GAAG,EAAE,YAAY;QACjB,MAAM,EAAE,qBAAqB;QAC7B,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;KACzB;IACD,IAAI,EAAE;QACJ,GAAG,EAAE,OAAO;QACZ,MAAM,EAAE,gBAAgB;QACxB,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;KACzB;IACD,MAAM,EAAE;QACN,GAAG,EAAE,SAAS;QACd,MAAM,EAAE,kBAAkB;QAC1B,YAAY,EAAE,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC,EAAE,GAAG,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,EAAE,CAAC;KACjE;IACD,MAAM,EAAE;QACN,GAAG,EAAE,SAAS;QACd,MAAM,EAAE,kBAAkB;QAC1B,YAAY,EAAE,GAAG,EAAE,CAAC,CAAC,EAAE,CAAC;KACzB;CACF,CAAC;AAEF;;;;;;;;GAQG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,IAAY,EACZ,GAAgB,EAChB,WAAyC,QAAQ;IAEjD,MAAM,OAAO,GAAG,IAAI,CAAC,IAAI,EAAE,CAAC;IAE5B,2EAA2E;IAC3E,6EAA6E;IAC7E,6EAA6E;IAC7E,iBAAiB;IACjB,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,SAAS,CAAC,EAAE,CAAC;QACnC,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;YACxB,MAAM,OAAO,GAAG,MAAM,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC;YACrE,MAAM,SAAS,GAAG,CAAC,SAAS,EAAE,SAAS,EAAE,UAAU,CAAC,CAAC;YACrD,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,qBAAqB,EAAE,GAAG,OAAO,EAAE,GAAG,SAAS,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,CAAC;YACtF,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;QACzB,CAAC;QACD,IAAI,OAAO,KAAK,OAAO,EAAE,CAAC;YACxB,OAAO,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC;QACxB,CAAC;QACD,IAAI,OAAO,KAAK,QAAQ,EAAE,CAAC;YACzB,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,eAAe,CAAC,CAAC;YAClC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;QACzB,CAAC;QACD,8BAA8B;QAC9B,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;QACrC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;IACzB,CAAC;IAED,2EAA2E;IAC3E,2EAA2E;IAC3E,4EAA4E;IAC5E,yBAAyB;IACzB,IAAI,CAAC;QACH,MAAM,SAAS,GAAG,OAAO,CAAC,KAAK,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,0BAA0B;QAC7E,MAAM,CAAC,GAAG,EAAE,GAAG,IAAI,CAAC,GAAG,QAAQ,CAAC,SAAS,CAAC,CAAC;QAE3C,oDAAoD;QACpD,4EAA4E;QAC5E,iCAAiC;QACjC,IAAI,CAAC,GAAG,IAAI,CAAC,MAAM,CAAC,MAAM,CAAC,QAAQ,EAAE,GAAG,CAAC,EAAE,CAAC;YAC1C,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,WAAW,GAAG,IAAI,CAAC,CAAC;YACrC,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;QACzB,CAAC;QAED,MAAM,KAAK,GAAG,QAAQ,CAAC,GAAG,CAAC,CAAC;QAC5B,uEAAuE;QACvE,MAAM,IAAI,GAAG,EAAE,GAAG,EAAE,GAAG,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC,YAAY,CAAC,IAAI,EAAE,GAAG,CAAC,EAAE,CAAC;QAChE,MAAM,MAAM,GAAG,MAAM,KAAK,CAAC,GAAG,CAAC,IAA+B,CAAC,CAAC;QAChE,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,KAAK,CAAC,MAAM,CAAC,MAAM,CAAC,GAAG,IAAI,CAAC,CAAC;IAChD,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,GAAG,CAAC,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC,YAAY,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,CAAC,GAAG,IAAI,CAAC,CAAC;IACxE,CAAC;IAED,OAAO,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AACzB,CAAC"}
@@ -0,0 +1,14 @@
1
+ import type { TaskResult } from "../commands/task.js";
2
+ export interface ReplOptions {
3
+ cwd: string;
4
+ /** Defaults to process.stdin. */
5
+ input?: NodeJS.ReadableStream;
6
+ /** Defaults to process.stdout. */
7
+ output?: NodeJS.WritableStream;
8
+ /** Defaults to the real runTask; override in tests. */
9
+ runTaskFn?: (opts: {
10
+ cwd: string;
11
+ text: string;
12
+ }) => Promise<TaskResult>;
13
+ }
14
+ export declare function startRepl(opts: ReplOptions): Promise<number>;
@@ -0,0 +1,124 @@
1
+ /**
2
+ * Interactive REPL core loop (HLD-SRD § interactive-repl).
3
+ *
4
+ * `startRepl(opts)` creates exactly one readline.Interface and drives a
5
+ * read-eval-print loop:
6
+ * - Banner on start, then "> " prompt.
7
+ * - Empty / whitespace line → re-prompt (no task created).
8
+ * - Line starting with "/" → unknown-command message → re-prompt.
9
+ * - Bare text → runTaskFn({ cwd, text }) → formatTaskResult → re-prompt.
10
+ * - Thrown runTask error → print err.message → re-prompt (loop continues).
11
+ * - Ctrl-C (SIGINT): non-empty partial line → clear → re-prompt;
12
+ * empty line → rl.close() → resolve 0.
13
+ * - Ctrl-D / EOF (close) → await any in-flight task → resolve 0.
14
+ *
15
+ * Concurrency / close contract
16
+ * ─────────────────────────────
17
+ * readline can buffer and emit multiple "line" events before the first async
18
+ * handler returns (e.g. a multi-line paste). We serialize with an explicit
19
+ * chained promise queue (NOT rl.pause() alone) so at most one runTaskFn is
20
+ * in flight at a time.
21
+ *
22
+ * On "close", any already-in-flight task is awaited and its result/error
23
+ * written. Lines queued-but-not-yet-started are abandoned — no further
24
+ * runTaskFn calls are initiated after close. No prompt/resume is issued on
25
+ * the now-closed interface.
26
+ */
27
+ import readline from "node:readline";
28
+ import { runTask, formatTaskResult } from "../commands/task.js";
29
+ import { dispatch } from "./dispatch.js";
30
+ const BANNER = "LocalPTP REPL — type text to create a task, /help for commands, Ctrl-D to exit.";
31
+ export function startRepl(opts) {
32
+ const { cwd, input = process.stdin, output = process.stdout, runTaskFn = runTask, } = opts;
33
+ return new Promise((resolve) => {
34
+ const rl = readline.createInterface({ input, output, prompt: "> " });
35
+ let closed = false;
36
+ let resolvedOnce = false;
37
+ function finish() {
38
+ if (!resolvedOnce) {
39
+ resolvedOnce = true;
40
+ resolve(0);
41
+ }
42
+ }
43
+ // ── Serialization queue ─────────────────────────────────────────────────
44
+ // We chain handlers off this promise so lines are processed FIFO with no
45
+ // overlap, even if readline emits several "line" events before the first
46
+ // async handler returns.
47
+ //
48
+ // `inflightPromise` always points to the currently-running (or last-settled)
49
+ // handler chain. On "close", the "close" handler awaits this same promise
50
+ // so the in-flight task can complete and write its output before we resolve.
51
+ let inflightPromise = Promise.resolve();
52
+ // ── "line" handler ──────────────────────────────────────────────────────
53
+ rl.on("line", (line) => {
54
+ const trimmed = line.trim();
55
+ // Capture the previous tail of the queue and chain off it.
56
+ const prev = inflightPromise;
57
+ inflightPromise = (async () => {
58
+ // Always wait for the previous handler to finish first (serialization).
59
+ await prev;
60
+ // If the interface was closed while we were waiting, abandon this line.
61
+ if (closed)
62
+ return;
63
+ // Empty / whitespace-only line → re-prompt only.
64
+ if (trimmed === "") {
65
+ rl.prompt();
66
+ return;
67
+ }
68
+ // Slash-prefixed line → delegate to dispatcher.
69
+ if (trimmed.startsWith("/")) {
70
+ const { exit } = await dispatch(line, { cwd, rl, output });
71
+ if (exit) {
72
+ rl.close();
73
+ }
74
+ else if (!closed) {
75
+ rl.prompt();
76
+ }
77
+ return;
78
+ }
79
+ // Bare text → run the task.
80
+ try {
81
+ const result = await runTaskFn({ cwd, text: trimmed });
82
+ // Always write the result — even if close fired while the task was
83
+ // in flight, the spec requires us to write the output before resolving.
84
+ output.write(formatTaskResult(result) + "\n");
85
+ // Only re-prompt if the interface is still open.
86
+ if (!closed) {
87
+ rl.prompt();
88
+ }
89
+ }
90
+ catch (err) {
91
+ // Same: always write the error, skip the re-prompt if closed.
92
+ output.write(err.message + "\n");
93
+ if (!closed) {
94
+ rl.prompt();
95
+ }
96
+ }
97
+ })();
98
+ });
99
+ // ── "SIGINT" handler ────────────────────────────────────────────────────
100
+ rl.on("SIGINT", () => {
101
+ if (rl.line && rl.line.length > 0) {
102
+ // Clear the partial line and re-prompt.
103
+ rl.write(null, { ctrl: true, name: "u" });
104
+ rl.prompt();
105
+ }
106
+ else {
107
+ rl.close();
108
+ }
109
+ });
110
+ // ── "close" handler ─────────────────────────────────────────────────────
111
+ rl.on("close", () => {
112
+ if (closed)
113
+ return; // guard against double-close
114
+ closed = true;
115
+ // Await the in-flight task (if any) so its output is written before we
116
+ // resolve. We do NOT call rl.prompt() or rl.resume() after this point.
117
+ inflightPromise.then(finish, finish);
118
+ });
119
+ // Print banner and initial prompt.
120
+ output.write(BANNER + "\n");
121
+ rl.prompt();
122
+ });
123
+ }
124
+ //# sourceMappingURL=loop.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"loop.js","sourceRoot":"","sources":["../../src/repl/loop.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * REPL quote-aware tokenizer.
3
+ *
4
+ * `tokenize(input)` splits the input string on whitespace, while keeping
5
+ * `"…"` and `'…'` spans as single tokens (with quotes stripped).
6
+ * An unbalanced quote throws `TokenizeError`.
7
+ *
8
+ * Intentionally minimal: no escape sequences, no env expansion, no globbing.
9
+ */
10
+ export declare class TokenizeError extends Error {
11
+ constructor(message: string);
12
+ }
13
+ export declare function tokenize(input: string): string[];
@@ -0,0 +1,56 @@
1
+ /**
2
+ * REPL quote-aware tokenizer.
3
+ *
4
+ * `tokenize(input)` splits the input string on whitespace, while keeping
5
+ * `"…"` and `'…'` spans as single tokens (with quotes stripped).
6
+ * An unbalanced quote throws `TokenizeError`.
7
+ *
8
+ * Intentionally minimal: no escape sequences, no env expansion, no globbing.
9
+ */
10
+ export class TokenizeError extends Error {
11
+ constructor(message) {
12
+ super(message);
13
+ this.name = "TokenizeError";
14
+ }
15
+ }
16
+ export function tokenize(input) {
17
+ const tokens = [];
18
+ let cur = "";
19
+ let quote = null;
20
+ let started = false; // distinguishes empty quoted token from no token
21
+ for (const ch of input) {
22
+ if (quote) {
23
+ if (ch === quote) {
24
+ // closing quote
25
+ quote = null;
26
+ }
27
+ else {
28
+ cur += ch;
29
+ }
30
+ }
31
+ else if (ch === '"' || ch === "'") {
32
+ // opening quote
33
+ quote = ch;
34
+ started = true;
35
+ }
36
+ else if (/\s/.test(ch)) {
37
+ if (started) {
38
+ tokens.push(cur);
39
+ cur = "";
40
+ started = false;
41
+ }
42
+ }
43
+ else {
44
+ cur += ch;
45
+ started = true;
46
+ }
47
+ }
48
+ if (quote) {
49
+ throw new TokenizeError("Unbalanced quote in command.");
50
+ }
51
+ if (started) {
52
+ tokens.push(cur);
53
+ }
54
+ return tokens;
55
+ }
56
+ //# sourceMappingURL=tokenize.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tokenize.js","sourceRoot":"","sources":["../../src/repl/tokenize.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AAEH,MAAM,OAAO,aAAc,SAAQ,KAAK;IACtC,YAAY,OAAe;QACzB,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,eAAe,CAAC;IAC9B,CAAC;CACF;AAED,MAAM,UAAU,QAAQ,CAAC,KAAa;IACpC,MAAM,MAAM,GAAa,EAAE,CAAC;IAC5B,IAAI,GAAG,GAAG,EAAE,CAAC;IACb,IAAI,KAAK,GAAqB,IAAI,CAAC;IACnC,IAAI,OAAO,GAAG,KAAK,CAAC,CAAC,iDAAiD;IAEtE,KAAK,MAAM,EAAE,IAAI,KAAK,EAAE,CAAC;QACvB,IAAI,KAAK,EAAE,CAAC;YACV,IAAI,EAAE,KAAK,KAAK,EAAE,CAAC;gBACjB,gBAAgB;gBAChB,KAAK,GAAG,IAAI,CAAC;YACf,CAAC;iBAAM,CAAC;gBACN,GAAG,IAAI,EAAE,CAAC;YACZ,CAAC;QACH,CAAC;aAAM,IAAI,EAAE,KAAK,GAAG,IAAI,EAAE,KAAK,GAAG,EAAE,CAAC;YACpC,gBAAgB;YAChB,KAAK,GAAG,EAAE,CAAC;YACX,OAAO,GAAG,IAAI,CAAC;QACjB,CAAC;aAAM,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,EAAE,CAAC;YACzB,IAAI,OAAO,EAAE,CAAC;gBACZ,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;gBACjB,GAAG,GAAG,EAAE,CAAC;gBACT,OAAO,GAAG,KAAK,CAAC;YAClB,CAAC;QACH,CAAC;aAAM,CAAC;YACN,GAAG,IAAI,EAAE,CAAC;YACV,OAAO,GAAG,IAAI,CAAC;QACjB,CAAC;IACH,CAAC;IAED,IAAI,KAAK,EAAE,CAAC;QACV,MAAM,IAAI,aAAa,CAAC,8BAA8B,CAAC,CAAC;IAC1D,CAAC;IAED,IAAI,OAAO,EAAE,CAAC;QACZ,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IACnB,CAAC;IAED,OAAO,MAAM,CAAC;AAChB,CAAC"}
@@ -0,0 +1,13 @@
1
+ /**
2
+ * The 14 `/ai/*` starter memory templates (HLD-SRD §3.4).
3
+ *
4
+ * Each carries a human-visible, Git-diffable `Last updated:` marker header
5
+ * instead of a sidecar manifest. `{{date}}` is filled at scaffold time.
6
+ */
7
+ export interface MemoryTemplate {
8
+ name: string;
9
+ /** Returns the file body for a given ISO date stamp. */
10
+ render(dateStamp: string): string;
11
+ }
12
+ export declare const MEMORY_TEMPLATES: MemoryTemplate[];
13
+ export declare const MEMORY_FILE_NAMES: string[];
@@ -0,0 +1,32 @@
1
+ /**
2
+ * The 14 `/ai/*` starter memory templates (HLD-SRD §3.4).
3
+ *
4
+ * Each carries a human-visible, Git-diffable `Last updated:` marker header
5
+ * instead of a sidecar manifest. `{{date}}` is filled at scaffold time.
6
+ */
7
+ function tpl(name, title, body) {
8
+ return {
9
+ name,
10
+ render(dateStamp) {
11
+ return `# ${title}\n\nLast updated: ${dateStamp}\n\n${body}\n`;
12
+ },
13
+ };
14
+ }
15
+ export const MEMORY_TEMPLATES = [
16
+ tpl("project-brief.md", "Project Brief", "One-paragraph description of what this project does and who it is for.\n\n## Goals\n\n- \n\n## Non-goals\n\n- "),
17
+ tpl("repo-map.md", "Repo Map", "High-level map of the repository's top-level directories and their responsibilities.\n\n_(Generated/updated by `localptp index`.)_"),
18
+ tpl("architecture.md", "Architecture", "The system's main components and how they fit together."),
19
+ tpl("file-index.md", "File Index", "Per-file responsibilities for the important source files.\n\n| File | Responsibility |\n|---|---|"),
20
+ tpl("data-model.md", "Data Model", "Core entities, their fields, and relationships."),
21
+ tpl("api-map.md", "API Map", "Public/internal API surface: endpoints, commands, or exported functions."),
22
+ tpl("external-integrations.md", "External Integrations", "Third-party services, APIs, and infrastructure this project depends on."),
23
+ tpl("coding-rules.md", "Coding Rules", "Project conventions the model must follow.\n\n- Work in small, safe patches.\n- Prefer existing project patterns.\n- Do not rewrite unrelated code."),
24
+ tpl("decisions.md", "Decisions", "Durable architectural and product decisions, newest first.\n\n## Log\n\n- "),
25
+ tpl("known-issues.md", "Known Issues", "Known bugs, risks, and technical debt.\n\n- "),
26
+ tpl("test-plan.md", "Test Plan", "How this project is tested and which commands to run.\n\n- typecheck\n- lint\n- test\n- build"),
27
+ tpl("local-model-workflow.md", "Local Model Workflow", "How to drive the local coding model over this repo with `localptp` (init → index → task → plan → step → review → summarize)."),
28
+ tpl("task-template.md", "Task Template", "Template for `/ai/tasks/*` files.\n\n## Goal\n\n## Background\n\n## Requirements\n\n## Non-goals\n\n## Acceptance Criteria\n\n## Subtasks\n\n- [ ] \n\n## Tests"),
29
+ tpl("session-start.md", "Session Start", "Read this at the start of every working session before touching code: load the active task and session, review coding rules, and confirm the next step."),
30
+ ];
31
+ export const MEMORY_FILE_NAMES = MEMORY_TEMPLATES.map((t) => t.name);
32
+ //# sourceMappingURL=memory.js.map