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,176 @@
1
+ /**
2
+ * `localptp context` (HLD-SRD §3.7, §9, §15 Test 5; CLI.md).
3
+ *
4
+ * Read-only preview of the context package the Context Builder would assemble
5
+ * for a role. Makes NO model call. Workflow:
6
+ * 1. Detect repo root + load config.
7
+ * 2. Load .ai-orchestrator/index.json (actionable error if missing).
8
+ * 3. Load /ai memory.
9
+ * 4. Find + tolerantly parse the newest /ai/tasks/* and /ai/sessions/* (optional).
10
+ * 5. Read indexed file bodies into a fileContents map; a file that fails to
11
+ * read (e.g. deleted since index) is omitted and a warning is collected.
12
+ * 6. buildContext(...) → ContextPackage.
13
+ * 7. Print the CLI.md summary, or the structured package with --json.
14
+ */
15
+ import { promises as fs } from "node:fs";
16
+ import path from "node:path";
17
+ import { detectGitRoot } from "../utils/gitRoot.js";
18
+ import { layout } from "../utils/paths.js";
19
+ import { readIfExists } from "../utils/fs.js";
20
+ import { ConfigManager } from "../core/configManager.js";
21
+ import { loadMemoryFiles } from "../core/memoryLoader.js";
22
+ import { buildContext } from "../core/contextBuilder.js";
23
+ import { resolveActive } from "../core/activePointer.js";
24
+ import { parseActiveTask, parseActiveSession, } from "../types/context.js";
25
+ import { repoIndexSchema } from "../types/index.js";
26
+ const VALID_ROLES = [
27
+ "planner",
28
+ "retriever",
29
+ "coder",
30
+ "reviewer",
31
+ "test-fixer",
32
+ "summarizer",
33
+ ];
34
+ class CommandError extends Error {
35
+ exitCode;
36
+ constructor(message, exitCode = 1) {
37
+ super(message);
38
+ this.name = "CommandError";
39
+ this.exitCode = exitCode;
40
+ }
41
+ }
42
+ function resolveRole(role) {
43
+ if (role === undefined)
44
+ return "coder";
45
+ if (VALID_ROLES.includes(role))
46
+ return role;
47
+ throw new CommandError(`Unknown role: ${role}. Valid roles: ${VALID_ROLES.join(", ")}.`);
48
+ }
49
+ /** Return the newest (by mtime) `*.md` file body under `dir`, or undefined. */
50
+ async function newestMarkdown(dir) {
51
+ let entries;
52
+ try {
53
+ entries = await fs.readdir(dir, { withFileTypes: true });
54
+ }
55
+ catch {
56
+ return undefined;
57
+ }
58
+ let newest;
59
+ for (const entry of entries) {
60
+ if (!entry.isFile() || !entry.name.toLowerCase().endsWith(".md"))
61
+ continue;
62
+ const full = path.join(dir, entry.name);
63
+ try {
64
+ const stat = await fs.stat(full);
65
+ const body = await fs.readFile(full, "utf8");
66
+ const mtimeMs = stat.mtimeMs;
67
+ if (newest === undefined ||
68
+ mtimeMs > newest.mtimeMs ||
69
+ // Deterministic tiebreak when mtimes are equal: latest name wins.
70
+ (mtimeMs === newest.mtimeMs && entry.name > newest.name)) {
71
+ newest = { body, mtimeMs, name: entry.name };
72
+ }
73
+ }
74
+ catch {
75
+ // Skip unreadable entries.
76
+ }
77
+ }
78
+ return newest?.body;
79
+ }
80
+ export async function runContext(opts) {
81
+ const { cwd } = opts;
82
+ const role = resolveRole(opts.role);
83
+ // 1. Root + config.
84
+ const git = await detectGitRoot(cwd);
85
+ const root = git.root ?? cwd;
86
+ const l = layout(root);
87
+ const config = await new ConfigManager(l.configFile).load();
88
+ // 2. Load index.
89
+ const indexPath = path.join(l.orchestratorDir, "index.json");
90
+ const rawIndex = await readIfExists(indexPath);
91
+ if (rawIndex === undefined) {
92
+ throw new CommandError("No repository index found. Run `localptp index` first.");
93
+ }
94
+ let index;
95
+ try {
96
+ const parsed = repoIndexSchema.safeParse(JSON.parse(rawIndex));
97
+ if (!parsed.success) {
98
+ throw new CommandError("The repository index is malformed. Re-run `localptp index`.");
99
+ }
100
+ index = parsed.data;
101
+ }
102
+ catch (err) {
103
+ if (err instanceof CommandError)
104
+ throw err;
105
+ throw new CommandError("The repository index could not be read as JSON. Re-run `localptp index`.");
106
+ }
107
+ // 3. Memory.
108
+ const memory = await loadMemoryFiles(root);
109
+ // 4. Optional active task / session. Prefer the explicit active pointer
110
+ // (0001_04); fall back to the newest-file heuristic when the pointer is
111
+ // absent or dangles.
112
+ let task;
113
+ let session;
114
+ const active = await resolveActive(l.orchestratorDir);
115
+ if (active.kind === "ok") {
116
+ const taskMd = await readIfExists(active.pointer.taskPath);
117
+ if (taskMd !== undefined)
118
+ task = parseActiveTask(taskMd);
119
+ const sessionMd = await readIfExists(active.pointer.sessionPath);
120
+ if (sessionMd !== undefined)
121
+ session = parseActiveSession(sessionMd);
122
+ }
123
+ if (task === undefined) {
124
+ const taskMd = await newestMarkdown(l.tasksDir);
125
+ if (taskMd !== undefined)
126
+ task = parseActiveTask(taskMd);
127
+ }
128
+ if (session === undefined) {
129
+ const sessionMd = await newestMarkdown(l.sessionsDir);
130
+ if (sessionMd !== undefined)
131
+ session = parseActiveSession(sessionMd);
132
+ }
133
+ // 5. Read indexed file bodies; omit unreadable/deleted files with a warning.
134
+ const fileContents = {};
135
+ const preWarnings = [];
136
+ for (const f of index.files) {
137
+ const rel = f.path.replace(/\\/g, "/");
138
+ const full = path.join(root, rel);
139
+ try {
140
+ fileContents[rel] = await fs.readFile(full, "utf8");
141
+ }
142
+ catch {
143
+ preWarnings.push(`Indexed file missing: ${rel}; re-run \`localptp index\`.`);
144
+ }
145
+ }
146
+ // 6. Build.
147
+ const pkg = buildContext({
148
+ role,
149
+ config,
150
+ index,
151
+ memory,
152
+ task,
153
+ session,
154
+ fileContents,
155
+ });
156
+ // Surface the content-loading warnings ahead of the builder's own.
157
+ pkg.warnings = [...preWarnings, ...pkg.warnings];
158
+ return { pkg, maxContextTokens: config.model.maxContextTokens };
159
+ }
160
+ function fmtList(items) {
161
+ return items.length > 0 ? items.join(", ") : "(none)";
162
+ }
163
+ export function formatContextResult(result) {
164
+ const { pkg, maxContextTokens } = result;
165
+ const lines = [
166
+ `Role: ${pkg.role}`,
167
+ `Memory: ${fmtList(pkg.includedMemoryFiles)}`,
168
+ `Source: ${fmtList(pkg.includedSourceFiles)}`,
169
+ `Tests: ${fmtList(pkg.includedTestFiles)}`,
170
+ `Estimated tokens: ${pkg.estimatedTokens.toLocaleString("en-US")} / ${maxContextTokens.toLocaleString("en-US")}`,
171
+ ];
172
+ for (const w of pkg.warnings)
173
+ lines.push(`! ${w}`);
174
+ return lines.join("\n");
175
+ }
176
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../../src/commands/context.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,16 @@
1
+ import type { ModelClient } from "../types/model.js";
2
+ import type { AppConfig } from "../types/config.js";
3
+ export interface DoctorOptions {
4
+ cwd: string;
5
+ json?: boolean;
6
+ /** Injectable for tests; defaults to the real LM Studio client. */
7
+ clientFactory?: (config: AppConfig) => ModelClient;
8
+ }
9
+ export interface DoctorResult {
10
+ reachable: boolean;
11
+ model?: string;
12
+ latencyMs: number;
13
+ models: string[];
14
+ }
15
+ export declare function runDoctor(opts: DoctorOptions): Promise<DoctorResult>;
16
+ export declare function formatDoctorResult(result: DoctorResult): string;
@@ -0,0 +1,54 @@
1
+ /**
2
+ * `localptp doctor` (HLD-SRD §3.8, §12, §15 Test 3).
3
+ *
4
+ * Load+validate config → `health()` (GET /models) → `complete()` with a tiny
5
+ * prompt → assert non-empty → return reachable + latency. Transport/protocol
6
+ * failures surface as the typed `ModelClientError` so the caller can print the
7
+ * matching §12 message and exit non-zero.
8
+ */
9
+ import { layout } from "../utils/paths.js";
10
+ import { detectGitRoot } from "../utils/gitRoot.js";
11
+ import { ConfigManager } from "../core/configManager.js";
12
+ import { LmStudioClient } from "../core/modelClient.js";
13
+ function defaultClientFactory(config) {
14
+ return new LmStudioClient({
15
+ baseUrl: config.model.baseUrl,
16
+ model: config.model.model,
17
+ apiKey: config.model.apiKey,
18
+ temperature: config.model.temperature,
19
+ timeoutMs: config.model.timeoutMs,
20
+ });
21
+ }
22
+ export async function runDoctor(opts) {
23
+ // Resolve the repo root (like `init`) so doctor reads the repo-root config
24
+ // regardless of the subdirectory it runs from; fall back to cwd outside Git.
25
+ const git = await detectGitRoot(opts.cwd);
26
+ const l = layout(git.root ?? opts.cwd);
27
+ const config = await new ConfigManager(l.configFile).load();
28
+ const client = (opts.clientFactory ?? defaultClientFactory)(config);
29
+ const health = await client.health();
30
+ const models = health.models ?? [];
31
+ const start = Date.now();
32
+ const response = await client.complete({
33
+ role: "summarizer",
34
+ systemPrompt: "You are a health check. Reply with a single short word.",
35
+ userPrompt: "ping",
36
+ });
37
+ const latencyMs = Date.now() - start;
38
+ // complete() already throws on empty/malformed; assert defensively.
39
+ if (response.content.length === 0) {
40
+ throw new Error("Model returned an empty/invalid response.");
41
+ }
42
+ return {
43
+ reachable: true,
44
+ model: models[0] ?? config.model.model,
45
+ latencyMs,
46
+ models,
47
+ };
48
+ }
49
+ export function formatDoctorResult(result) {
50
+ return (`✓ reachable\n` +
51
+ `model: ${result.model ?? "(unknown)"}\n` +
52
+ `model responded (${result.latencyMs}ms)`);
53
+ }
54
+ //# sourceMappingURL=doctor.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"doctor.js","sourceRoot":"","sources":["../../src/commands/doctor.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AACzD,OAAO,EAAE,cAAc,EAAE,MAAM,wBAAwB,CAAC;AAkBxD,SAAS,oBAAoB,CAAC,MAAiB;IAC7C,OAAO,IAAI,cAAc,CAAC;QACxB,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,OAAO;QAC7B,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,KAAK;QACzB,MAAM,EAAE,MAAM,CAAC,KAAK,CAAC,MAAM;QAC3B,WAAW,EAAE,MAAM,CAAC,KAAK,CAAC,WAAW;QACrC,SAAS,EAAE,MAAM,CAAC,KAAK,CAAC,SAAS;KAClC,CAAC,CAAC;AACL,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,IAAmB;IACjD,2EAA2E;IAC3E,6EAA6E;IAC7E,MAAM,GAAG,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1C,MAAM,CAAC,GAAG,MAAM,CAAC,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC,CAAC;IACvC,MAAM,MAAM,GAAG,MAAM,IAAI,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,IAAI,EAAE,CAAC;IAC5D,MAAM,MAAM,GAAG,CAAC,IAAI,CAAC,aAAa,IAAI,oBAAoB,CAAC,CAAC,MAAM,CAAC,CAAC;IAEpE,MAAM,MAAM,GAAG,MAAM,MAAM,CAAC,MAAM,EAAE,CAAC;IACrC,MAAM,MAAM,GAAG,MAAM,CAAC,MAAM,IAAI,EAAE,CAAC;IAEnC,MAAM,KAAK,GAAG,IAAI,CAAC,GAAG,EAAE,CAAC;IACzB,MAAM,QAAQ,GAAG,MAAM,MAAM,CAAC,QAAQ,CAAC;QACrC,IAAI,EAAE,YAAY;QAClB,YAAY,EAAE,yDAAyD;QACvE,UAAU,EAAE,MAAM;KACnB,CAAC,CAAC;IACH,MAAM,SAAS,GAAG,IAAI,CAAC,GAAG,EAAE,GAAG,KAAK,CAAC;IAErC,oEAAoE;IACpE,IAAI,QAAQ,CAAC,OAAO,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAClC,MAAM,IAAI,KAAK,CAAC,2CAA2C,CAAC,CAAC;IAC/D,CAAC;IAED,OAAO;QACL,SAAS,EAAE,IAAI;QACf,KAAK,EAAE,MAAM,CAAC,CAAC,CAAC,IAAI,MAAM,CAAC,KAAK,CAAC,KAAK;QACtC,SAAS;QACT,MAAM;KACP,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,kBAAkB,CAAC,MAAoB;IACrD,OAAO,CACL,eAAe;QACf,UAAU,MAAM,CAAC,KAAK,IAAI,WAAW,IAAI;QACzC,oBAAoB,MAAM,CAAC,SAAS,KAAK,CAC1C,CAAC;AACJ,CAAC"}
@@ -0,0 +1,13 @@
1
+ export interface IndexOptions {
2
+ cwd: string;
3
+ json?: boolean;
4
+ onWarning?: (msg: string) => void;
5
+ }
6
+ export interface IndexResult {
7
+ indexed: number;
8
+ ignored: number;
9
+ durationMs: number;
10
+ root: string;
11
+ }
12
+ export declare function runIndex(opts: IndexOptions): Promise<IndexResult>;
13
+ export declare function formatIndexResult(result: IndexResult): string;
@@ -0,0 +1,70 @@
1
+ /**
2
+ * `localptp index` (HLD-SRD §3.3, §5, §9).
3
+ *
4
+ * Offline filesystem scan: no model call, no stdin. Workflow:
5
+ * 1. Detect repo root (warn when non-git).
6
+ * 2. Load config.
7
+ * 3. buildIndex(root, config) → RepoIndex.
8
+ * 4. Write .ai-orchestrator/index.json (pretty JSON).
9
+ * 5. updateMarkerSection × 2 (ai/repo-map.md, ai/file-index.md).
10
+ * 6. Return structured summary.
11
+ */
12
+ import { promises as fs } from "node:fs";
13
+ import path from "node:path";
14
+ import { detectGitRoot } from "../utils/gitRoot.js";
15
+ import { ensureDir } from "../utils/fs.js";
16
+ import { layout } from "../utils/paths.js";
17
+ import { ConfigManager } from "../core/configManager.js";
18
+ import { buildIndex, renderRepoMap, renderFileIndex } from "../core/repoIndexer.js";
19
+ import { updateMarkerSection } from "../core/memoryManager.js";
20
+ export async function runIndex(opts) {
21
+ const { cwd, onWarning } = opts;
22
+ const warn = (msg) => {
23
+ if (onWarning) {
24
+ onWarning(msg);
25
+ }
26
+ else {
27
+ process.stderr.write(`warning: ${msg}\n`);
28
+ }
29
+ };
30
+ const t0 = Date.now();
31
+ // 1. Detect root
32
+ const git = await detectGitRoot(cwd);
33
+ if (!git.isRepo) {
34
+ warn("This directory is not a Git repository. localptp index will use config + baseline ignore only.");
35
+ }
36
+ const root = git.root ?? cwd;
37
+ const l = layout(root);
38
+ // 2. Load config
39
+ const config = await new ConfigManager(l.configFile).load();
40
+ // 3. Build index
41
+ const index = await buildIndex(root, config);
42
+ // Extract ignored count (stored as side-channel property)
43
+ const ignored = index._ignoredCount ?? 0;
44
+ // 4. Write index.json
45
+ const indexJsonPath = path.join(l.orchestratorDir, "index.json");
46
+ await ensureDir(l.orchestratorDir);
47
+ // Remove the internal _ignoredCount before serializing
48
+ const toWrite = { ...index };
49
+ delete toWrite._ignoredCount;
50
+ await fs.writeFile(indexJsonPath, JSON.stringify(toWrite, null, 2) + "\n", "utf8");
51
+ // 5. Update marker sections in memory files
52
+ const repoMapPath = path.join(l.aiDir, "repo-map.md");
53
+ const fileIndexPath = path.join(l.aiDir, "file-index.md");
54
+ const repoMapBody = renderRepoMap(index);
55
+ const fileIndexBody = renderFileIndex(index);
56
+ await updateMarkerSection(repoMapPath, "index", repoMapBody);
57
+ await updateMarkerSection(fileIndexPath, "index", fileIndexBody);
58
+ const durationMs = Date.now() - t0;
59
+ return {
60
+ indexed: index.files.length,
61
+ ignored,
62
+ durationMs,
63
+ root,
64
+ };
65
+ }
66
+ export function formatIndexResult(result) {
67
+ const s = (result.durationMs / 1000).toFixed(1);
68
+ return `Indexed ${result.indexed} files (ignored ${result.ignored}) · ${s}s`;
69
+ }
70
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/commands/index.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,15 @@
1
+ import { type ScaffoldReport } from "../core/memoryManager.js";
2
+ export interface InitOptions {
3
+ cwd: string;
4
+ json?: boolean;
5
+ }
6
+ export interface InitReport {
7
+ root: string;
8
+ isGitRepo: boolean;
9
+ memory: ScaffoldReport;
10
+ configCreated: boolean;
11
+ gitignoreAppended: boolean;
12
+ warnings: string[];
13
+ }
14
+ export declare function runInit(opts: InitOptions): Promise<InitReport>;
15
+ export declare function formatInitReport(report: InitReport): string;
@@ -0,0 +1,46 @@
1
+ /**
2
+ * `localptp init` (HLD-SRD §3.4, §15 Test 1).
3
+ *
4
+ * Detect repo root (warn, don't fail, if no `.git`) → ensure dirs → Memory
5
+ * scaffold (write-if-absent) → write default config if absent → append the
6
+ * marker-guarded `.gitignore` stanza → return a created/preserved report.
7
+ * NEVER touches files outside `/ai`, `.ai-orchestrator`, and `.gitignore`.
8
+ */
9
+ import { layout } from "../utils/paths.js";
10
+ import { detectGitRoot } from "../utils/gitRoot.js";
11
+ import { appendGitignoreStanza } from "../utils/fs.js";
12
+ import { MemoryManager } from "../core/memoryManager.js";
13
+ import { ConfigManager } from "../core/configManager.js";
14
+ export async function runInit(opts) {
15
+ const warnings = [];
16
+ const git = await detectGitRoot(opts.cwd);
17
+ if (!git.isRepo) {
18
+ warnings.push("This directory is not a Git repository. localptp will still scaffold, " +
19
+ "but Git-dependent safety features require a repo.");
20
+ }
21
+ const root = git.root ?? opts.cwd;
22
+ const l = layout(root);
23
+ const memory = await new MemoryManager(l).scaffold();
24
+ const configCreated = await new ConfigManager(l.configFile).writeDefaultIfAbsent();
25
+ const gitignoreAppended = await appendGitignoreStanza(l.gitignoreFile);
26
+ return {
27
+ root,
28
+ isGitRepo: git.isRepo,
29
+ memory,
30
+ configCreated,
31
+ gitignoreAppended,
32
+ warnings,
33
+ };
34
+ }
35
+ export function formatInitReport(report) {
36
+ const lines = [];
37
+ for (const w of report.warnings) {
38
+ lines.push(`warning: ${w}`);
39
+ }
40
+ lines.push(`Scaffolded localptp memory at ${report.root}`);
41
+ lines.push(` memory files: ${report.memory.created.length} created, ${report.memory.preserved.length} preserved`);
42
+ lines.push(` config.yml: ${report.configCreated ? "created" : "preserved"}`);
43
+ lines.push(` .gitignore stanza: ${report.gitignoreAppended ? "appended" : "already present"}`);
44
+ return lines.join("\n");
45
+ }
46
+ //# sourceMappingURL=init.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"init.js","sourceRoot":"","sources":["../../src/commands/init.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG;AACH,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EAAE,aAAa,EAAE,MAAM,qBAAqB,CAAC;AACpD,OAAO,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AACvD,OAAO,EAAE,aAAa,EAAuB,MAAM,0BAA0B,CAAC;AAC9E,OAAO,EAAE,aAAa,EAAE,MAAM,0BAA0B,CAAC;AAgBzD,MAAM,CAAC,KAAK,UAAU,OAAO,CAAC,IAAiB;IAC7C,MAAM,QAAQ,GAAa,EAAE,CAAC;IAC9B,MAAM,GAAG,GAAG,MAAM,aAAa,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;IAC1C,IAAI,CAAC,GAAG,CAAC,MAAM,EAAE,CAAC;QAChB,QAAQ,CAAC,IAAI,CACX,wEAAwE;YACtE,mDAAmD,CACtD,CAAC;IACJ,CAAC;IACD,MAAM,IAAI,GAAG,GAAG,CAAC,IAAI,IAAI,IAAI,CAAC,GAAG,CAAC;IAClC,MAAM,CAAC,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC;IAEvB,MAAM,MAAM,GAAG,MAAM,IAAI,aAAa,CAAC,CAAC,CAAC,CAAC,QAAQ,EAAE,CAAC;IACrD,MAAM,aAAa,GAAG,MAAM,IAAI,aAAa,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,oBAAoB,EAAE,CAAC;IACnF,MAAM,iBAAiB,GAAG,MAAM,qBAAqB,CAAC,CAAC,CAAC,aAAa,CAAC,CAAC;IAEvE,OAAO;QACL,IAAI;QACJ,SAAS,EAAE,GAAG,CAAC,MAAM;QACrB,MAAM;QACN,aAAa;QACb,iBAAiB;QACjB,QAAQ;KACT,CAAC;AACJ,CAAC;AAED,MAAM,UAAU,gBAAgB,CAAC,MAAkB;IACjD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,QAAQ,EAAE,CAAC;QAChC,KAAK,CAAC,IAAI,CAAC,YAAY,CAAC,EAAE,CAAC,CAAC;IAC9B,CAAC;IACD,KAAK,CAAC,IAAI,CAAC,iCAAiC,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IAC3D,KAAK,CAAC,IAAI,CACR,mBAAmB,MAAM,CAAC,MAAM,CAAC,OAAO,CAAC,MAAM,aAAa,MAAM,CAAC,MAAM,CAAC,SAAS,CAAC,MAAM,YAAY,CACvG,CAAC;IACF,KAAK,CAAC,IAAI,CACR,iBAAiB,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,WAAW,EAAE,CAClE,CAAC;IACF,KAAK,CAAC,IAAI,CACR,wBAAwB,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC,UAAU,CAAC,CAAC,CAAC,iBAAiB,EAAE,CACpF,CAAC;IACF,OAAO,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AAC1B,CAAC"}
@@ -0,0 +1,17 @@
1
+ import { type NormalizedPlan } from "../core/plannerJson.js";
2
+ import type { ModelClient } from "../types/model.js";
3
+ import type { AppConfig } from "../types/config.js";
4
+ export interface PlanOptions {
5
+ cwd: string;
6
+ json?: boolean;
7
+ /** Injectable for tests; defaults to the real LM Studio client. */
8
+ clientFactory?: (config: AppConfig) => ModelClient;
9
+ }
10
+ export interface PlanResult {
11
+ plan: NormalizedPlan;
12
+ json: boolean;
13
+ taskPath: string;
14
+ sessionPath: string;
15
+ }
16
+ export declare function runPlan(opts: PlanOptions): Promise<PlanResult>;
17
+ export declare function formatPlanResult(result: PlanResult): string;
@@ -0,0 +1,170 @@
1
+ /**
2
+ * `localptp plan` (HLD-SRD §3.9, §11.2, §12; CLI.md).
3
+ *
4
+ * The first command that calls the model for real work. Flow (writes happen
5
+ * ONLY after a valid plan exists, so a model/parse failure saves nothing):
6
+ * 1. Detect root + load config.
7
+ * 2. resolveActive() — none → "create a task" error; missing-target → advise
8
+ * task/resume; ok → load the active task + session.
9
+ * 3. Load index (tolerant: empty if absent) + memory + file bodies.
10
+ * 4. buildContext({ role: 'planner', task, session }).
11
+ * 5. ModelClient.complete(planner system + rendered user). A §12
12
+ * ModelClientError propagates unchanged (the CLI prints its message).
13
+ * 6. extractAndValidatePlannerJson(content) — failure → §11.2 stop.
14
+ * 7. setSubtasks into the task (task-first, the source of truth), then update
15
+ * the session Current State / Next Step / Risks / Decisions(questions).
16
+ * 8. Return the validated plan; `--json` makes the CLI emit only the plan.
17
+ */
18
+ import { promises as fs } from "node:fs";
19
+ import path from "node:path";
20
+ import { detectGitRoot } from "../utils/gitRoot.js";
21
+ import { layout } from "../utils/paths.js";
22
+ import { readIfExists } from "../utils/fs.js";
23
+ import { ConfigManager } from "../core/configManager.js";
24
+ import { loadMemoryFiles } from "../core/memoryLoader.js";
25
+ import { buildContext } from "../core/contextBuilder.js";
26
+ import { resolveActive } from "../core/activePointer.js";
27
+ import { parseTask, setSubtasks, serializeTask } from "../core/taskManager.js";
28
+ import { loadSession, updateSession } from "../core/sessionManager.js";
29
+ import { getPrompt } from "../core/promptManager.js";
30
+ import { extractAndValidatePlannerJson, UnparseablePlanError, } from "../core/plannerJson.js";
31
+ import { LmStudioClient } from "../core/modelClient.js";
32
+ import { parseActiveTask, parseActiveSession } from "../types/context.js";
33
+ import { repoIndexSchema } from "../types/index.js";
34
+ class CommandError extends Error {
35
+ exitCode;
36
+ constructor(message, exitCode = 1) {
37
+ super(message);
38
+ this.name = "CommandError";
39
+ this.exitCode = exitCode;
40
+ }
41
+ }
42
+ function defaultClientFactory(config) {
43
+ return new LmStudioClient({
44
+ baseUrl: config.model.baseUrl,
45
+ model: config.model.model,
46
+ apiKey: config.model.apiKey,
47
+ temperature: config.model.temperature,
48
+ timeoutMs: config.model.timeoutMs,
49
+ });
50
+ }
51
+ const EMPTY_INDEX = {
52
+ generatedAt: "",
53
+ root: "",
54
+ files: [],
55
+ };
56
+ /** Load the repo index if present + valid, else an empty index (planning is tolerant). */
57
+ async function loadIndex(orchestratorDir) {
58
+ const raw = await readIfExists(path.join(orchestratorDir, "index.json"));
59
+ if (raw === undefined)
60
+ return EMPTY_INDEX;
61
+ try {
62
+ const parsed = repoIndexSchema.safeParse(JSON.parse(raw));
63
+ return parsed.success ? parsed.data : EMPTY_INDEX;
64
+ }
65
+ catch {
66
+ return EMPTY_INDEX;
67
+ }
68
+ }
69
+ async function loadFileContents(root, index) {
70
+ const out = {};
71
+ for (const f of index.files) {
72
+ const rel = f.path.replace(/\\/g, "/");
73
+ try {
74
+ out[rel] = await fs.readFile(path.join(root, rel), "utf8");
75
+ }
76
+ catch {
77
+ // Omit unreadable/deleted files; planning degrades gracefully.
78
+ }
79
+ }
80
+ return out;
81
+ }
82
+ export async function runPlan(opts) {
83
+ const git = await detectGitRoot(opts.cwd);
84
+ const root = git.root ?? opts.cwd;
85
+ const l = layout(root);
86
+ // 1. Resolve the active task/session.
87
+ const active = await resolveActive(l.orchestratorDir);
88
+ if (active.kind === "none") {
89
+ throw new CommandError('No active task. Create one first with `localptp task "…"`.');
90
+ }
91
+ if (active.kind === "missing-target") {
92
+ throw new CommandError(`The active pointer references a missing file: ${active.missing.join(", ")}. ` +
93
+ "Create a new task with `localptp task \"…\"` or pick another with `localptp resume`.");
94
+ }
95
+ const { taskPath, sessionPath } = active.pointer;
96
+ // 2. Load config, task, session.
97
+ const config = await new ConfigManager(l.configFile).load();
98
+ const task = await parseTask(taskPath);
99
+ const session = await loadSession(sessionPath);
100
+ // 3. Build the planner context (tolerant of a missing index).
101
+ const index = await loadIndex(l.orchestratorDir);
102
+ const memory = await loadMemoryFiles(root);
103
+ const fileContents = await loadFileContents(root, index);
104
+ const pkg = buildContext({
105
+ role: "planner",
106
+ config,
107
+ index,
108
+ memory,
109
+ task: parseActiveTask(task.raw),
110
+ session: parseActiveSession(session.raw),
111
+ fileContents,
112
+ });
113
+ // 4. Call the model. A §12 ModelClientError propagates unchanged — no writes
114
+ // have happened yet, so nothing is saved.
115
+ const client = (opts.clientFactory ?? defaultClientFactory)(config);
116
+ const planner = getPrompt("planner");
117
+ const response = await client.complete({
118
+ role: "planner",
119
+ systemPrompt: planner.system,
120
+ userPrompt: planner.renderUser(pkg.userPrompt),
121
+ });
122
+ // 5. Extract + validate. Failure → §11.2 stop, nothing saved.
123
+ let plan;
124
+ try {
125
+ plan = extractAndValidatePlannerJson(response.content);
126
+ }
127
+ catch (err) {
128
+ if (err instanceof UnparseablePlanError) {
129
+ throw new CommandError("The model output could not be parsed into a valid plan. Nothing was saved. " +
130
+ "Try `localptp plan` again or narrow the task.");
131
+ }
132
+ throw err;
133
+ }
134
+ // 6. Persist — task first (source of truth for subtasks), then the session.
135
+ const subtasks = plan.subtasks.map((s) => ({
136
+ id: s.id,
137
+ title: s.title,
138
+ description: s.description,
139
+ status: "pending",
140
+ risk: s.risk,
141
+ likelyFiles: s.likelyFiles,
142
+ acceptanceCriteria: s.acceptanceCriteria,
143
+ }));
144
+ const edited = setSubtasks(task, subtasks);
145
+ await fs.writeFile(edited.path, serializeTask(edited), "utf8");
146
+ const first = plan.subtasks[0];
147
+ const decisions = plan.questions.map((q) => `Open question: ${q}`);
148
+ await updateSession(session, {
149
+ currentState: plan.summary,
150
+ nextStep: `${first.id}: ${first.title}`,
151
+ risks: plan.risks,
152
+ decisions,
153
+ });
154
+ return { plan, json: opts.json ?? false, taskPath, sessionPath };
155
+ }
156
+ export function formatPlanResult(result) {
157
+ const { plan } = result;
158
+ const lines = [`Plan (${plan.subtasks.length} subtasks):`];
159
+ for (const s of plan.subtasks) {
160
+ const risk = s.risk === "high" ? "HIGH" : s.risk;
161
+ lines.push(` ${s.id} ${s.title} risk: ${risk}`);
162
+ }
163
+ if (plan.questions.length > 0) {
164
+ lines.push("Questions:");
165
+ for (const q of plan.questions)
166
+ lines.push(` - ${q}`);
167
+ }
168
+ return lines.join("\n");
169
+ }
170
+ //# sourceMappingURL=plan.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"plan.js","sourceRoot":"","sources":["../../src/commands/plan.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,17 @@
1
+ import type { Session } from "../types/session.js";
2
+ export interface ResumeOptions {
3
+ cwd: string;
4
+ /** 1-based index into the newest-first list (CLI arg). */
5
+ index?: number;
6
+ json?: boolean;
7
+ /** Whether stdin is interactive; defaults to process.stdin.isTTY. */
8
+ isTTY?: boolean;
9
+ /** Injectable interactive picker (returns a 1-based index) for TTY runs. */
10
+ prompt?: (sessions: Session[]) => Promise<number | undefined>;
11
+ }
12
+ export interface ResumeResult {
13
+ sessions: Session[];
14
+ selected?: Session;
15
+ }
16
+ export declare function runResume(opts: ResumeOptions): Promise<ResumeResult>;
17
+ export declare function formatResumeResult(result: ResumeResult): string;