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.
- package/LICENSE +23 -0
- package/README.md +159 -0
- package/dist/cli.d.ts +24 -0
- package/dist/cli.js +344 -0
- package/dist/cli.js.map +1 -0
- package/dist/commands/config.d.ts +14 -0
- package/dist/commands/config.js +65 -0
- package/dist/commands/config.js.map +1 -0
- package/dist/commands/context.d.ts +12 -0
- package/dist/commands/context.js +176 -0
- package/dist/commands/context.js.map +1 -0
- package/dist/commands/doctor.d.ts +16 -0
- package/dist/commands/doctor.js +54 -0
- package/dist/commands/doctor.js.map +1 -0
- package/dist/commands/index.d.ts +13 -0
- package/dist/commands/index.js +70 -0
- package/dist/commands/index.js.map +1 -0
- package/dist/commands/init.d.ts +15 -0
- package/dist/commands/init.js +46 -0
- package/dist/commands/init.js.map +1 -0
- package/dist/commands/plan.d.ts +17 -0
- package/dist/commands/plan.js +170 -0
- package/dist/commands/plan.js.map +1 -0
- package/dist/commands/resume.d.ts +17 -0
- package/dist/commands/resume.js +75 -0
- package/dist/commands/resume.js.map +1 -0
- package/dist/commands/review.d.ts +17 -0
- package/dist/commands/review.js +67 -0
- package/dist/commands/review.js.map +1 -0
- package/dist/commands/run.d.ts +24 -0
- package/dist/commands/run.js +65 -0
- package/dist/commands/run.js.map +1 -0
- package/dist/commands/step.d.ts +44 -0
- package/dist/commands/step.js +50 -0
- package/dist/commands/step.js.map +1 -0
- package/dist/commands/summarize.d.ts +17 -0
- package/dist/commands/summarize.js +276 -0
- package/dist/commands/summarize.js.map +1 -0
- package/dist/commands/task.d.ts +13 -0
- package/dist/commands/task.js +53 -0
- package/dist/commands/task.js.map +1 -0
- package/dist/core/activePointer.d.ts +28 -0
- package/dist/core/activePointer.js +84 -0
- package/dist/core/activePointer.js.map +1 -0
- package/dist/core/approval.d.ts +12 -0
- package/dist/core/approval.js +34 -0
- package/dist/core/approval.js.map +1 -0
- package/dist/core/configManager.d.ts +32 -0
- package/dist/core/configManager.js +177 -0
- package/dist/core/configManager.js.map +1 -0
- package/dist/core/contextBuilder.d.ts +40 -0
- package/dist/core/contextBuilder.js +406 -0
- package/dist/core/contextBuilder.js.map +1 -0
- package/dist/core/memoryLoader.d.ts +4 -0
- package/dist/core/memoryLoader.js +35 -0
- package/dist/core/memoryLoader.js.map +1 -0
- package/dist/core/memoryManager.d.ts +41 -0
- package/dist/core/memoryManager.js +181 -0
- package/dist/core/memoryManager.js.map +1 -0
- package/dist/core/memoryPolicy.d.ts +23 -0
- package/dist/core/memoryPolicy.js +73 -0
- package/dist/core/memoryPolicy.js.map +1 -0
- package/dist/core/modelClient.d.ts +37 -0
- package/dist/core/modelClient.js +160 -0
- package/dist/core/modelClient.js.map +1 -0
- package/dist/core/patchManager.d.ts +89 -0
- package/dist/core/patchManager.js +801 -0
- package/dist/core/patchManager.js.map +1 -0
- package/dist/core/plannerJson.d.ts +23 -0
- package/dist/core/plannerJson.js +118 -0
- package/dist/core/plannerJson.js.map +1 -0
- package/dist/core/promptManager.d.ts +16 -0
- package/dist/core/promptManager.js +35 -0
- package/dist/core/promptManager.js.map +1 -0
- package/dist/core/prompts.d.ts +8 -0
- package/dist/core/prompts.js +18 -0
- package/dist/core/prompts.js.map +1 -0
- package/dist/core/repoIndexer.d.ts +21 -0
- package/dist/core/repoIndexer.js +557 -0
- package/dist/core/repoIndexer.js.map +1 -0
- package/dist/core/reviewEngine.d.ts +53 -0
- package/dist/core/reviewEngine.js +229 -0
- package/dist/core/reviewEngine.js.map +1 -0
- package/dist/core/runLoop.d.ts +26 -0
- package/dist/core/runLoop.js +103 -0
- package/dist/core/runLoop.js.map +1 -0
- package/dist/core/runStep.d.ts +42 -0
- package/dist/core/runStep.js +586 -0
- package/dist/core/runStep.js.map +1 -0
- package/dist/core/safetyManager.d.ts +7 -0
- package/dist/core/safetyManager.js +202 -0
- package/dist/core/safetyManager.js.map +1 -0
- package/dist/core/sessionManager.d.ts +35 -0
- package/dist/core/sessionManager.js +265 -0
- package/dist/core/sessionManager.js.map +1 -0
- package/dist/core/stopConditions.d.ts +24 -0
- package/dist/core/stopConditions.js +18 -0
- package/dist/core/stopConditions.js.map +1 -0
- package/dist/core/taskManager.d.ts +26 -0
- package/dist/core/taskManager.js +312 -0
- package/dist/core/taskManager.js.map +1 -0
- package/dist/core/testRunner.d.ts +27 -0
- package/dist/core/testRunner.js +71 -0
- package/dist/core/testRunner.js.map +1 -0
- package/dist/prompts/coder.d.ts +3 -0
- package/dist/prompts/coder.js +46 -0
- package/dist/prompts/coder.js.map +1 -0
- package/dist/prompts/planner.d.ts +3 -0
- package/dist/prompts/planner.js +44 -0
- package/dist/prompts/planner.js.map +1 -0
- package/dist/prompts/reviewer.d.ts +3 -0
- package/dist/prompts/reviewer.js +41 -0
- package/dist/prompts/reviewer.js.map +1 -0
- package/dist/prompts/summarizer.d.ts +3 -0
- package/dist/prompts/summarizer.js +65 -0
- package/dist/prompts/summarizer.js.map +1 -0
- package/dist/prompts/testFixer.d.ts +3 -0
- package/dist/prompts/testFixer.js +33 -0
- package/dist/prompts/testFixer.js.map +1 -0
- package/dist/repl/approver.d.ts +15 -0
- package/dist/repl/approver.js +21 -0
- package/dist/repl/approver.js.map +1 -0
- package/dist/repl/dispatch.d.ts +48 -0
- package/dist/repl/dispatch.js +164 -0
- package/dist/repl/dispatch.js.map +1 -0
- package/dist/repl/loop.d.ts +14 -0
- package/dist/repl/loop.js +124 -0
- package/dist/repl/loop.js.map +1 -0
- package/dist/repl/tokenize.d.ts +13 -0
- package/dist/repl/tokenize.js +56 -0
- package/dist/repl/tokenize.js.map +1 -0
- package/dist/templates/memory.d.ts +13 -0
- package/dist/templates/memory.js +32 -0
- package/dist/templates/memory.js.map +1 -0
- package/dist/types/config.d.ts +235 -0
- package/dist/types/config.js +66 -0
- package/dist/types/config.js.map +1 -0
- package/dist/types/context.d.ts +78 -0
- package/dist/types/context.js +141 -0
- package/dist/types/context.js.map +1 -0
- package/dist/types/index.d.ts +117 -0
- package/dist/types/index.js +24 -0
- package/dist/types/index.js.map +1 -0
- package/dist/types/model.d.ts +35 -0
- package/dist/types/model.js +16 -0
- package/dist/types/model.js.map +1 -0
- package/dist/types/patch.d.ts +38 -0
- package/dist/types/patch.js +11 -0
- package/dist/types/patch.js.map +1 -0
- package/dist/types/plan.d.ts +86 -0
- package/dist/types/plan.js +27 -0
- package/dist/types/plan.js.map +1 -0
- package/dist/types/review.d.ts +33 -0
- package/dist/types/review.js +24 -0
- package/dist/types/review.js.map +1 -0
- package/dist/types/run.d.ts +34 -0
- package/dist/types/run.js +2 -0
- package/dist/types/run.js.map +1 -0
- package/dist/types/session.d.ts +21 -0
- package/dist/types/session.js +2 -0
- package/dist/types/session.js.map +1 -0
- package/dist/types/summary.d.ts +65 -0
- package/dist/types/summary.js +26 -0
- package/dist/types/summary.js.map +1 -0
- package/dist/types/task.d.ts +31 -0
- package/dist/types/task.js +10 -0
- package/dist/types/task.js.map +1 -0
- package/dist/types/test.d.ts +16 -0
- package/dist/types/test.js +2 -0
- package/dist/types/test.js.map +1 -0
- package/dist/utils/fs.d.ts +13 -0
- package/dist/utils/fs.js +65 -0
- package/dist/utils/fs.js.map +1 -0
- package/dist/utils/gitRoot.d.ts +5 -0
- package/dist/utils/gitRoot.js +21 -0
- package/dist/utils/gitRoot.js.map +1 -0
- package/dist/utils/logger.d.ts +15 -0
- package/dist/utils/logger.js +60 -0
- package/dist/utils/logger.js.map +1 -0
- package/dist/utils/paths.d.ts +13 -0
- package/dist/utils/paths.js +24 -0
- package/dist/utils/paths.js.map +1 -0
- package/dist/utils/tokenEstimate.d.ts +5 -0
- package/dist/utils/tokenEstimate.js +8 -0
- package/dist/utils/tokenEstimate.js.map +1 -0
- package/package.json +44 -0
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.js","sourceRoot":"","sources":["../../src/types/index.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAoBxB,MAAM,CAAC,MAAM,cAAc,GAAG,CAAC,CAAC,MAAM,CAAC;IACrC,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE;IACrB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;IACpB,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC9B,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IACxC,OAAO,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IACxC,MAAM,EAAE,CAAC,CAAC,OAAO,EAAE;IACnB,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE;CACtB,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,eAAe,GAAG,CAAC,CAAC,MAAM,CAAC;IACtC,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE;IACvB,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE;IAChB,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,cAAc,CAAC;CAC/B,CAAC,CAAC"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model client types — the single swappable provider seam (HLD-SRD §3.8, §9).
|
|
3
|
+
*/
|
|
4
|
+
export type AgentRole = "planner" | "retriever" | "coder" | "reviewer" | "test-fixer" | "summarizer";
|
|
5
|
+
export interface ModelRequest {
|
|
6
|
+
role: AgentRole;
|
|
7
|
+
systemPrompt: string;
|
|
8
|
+
userPrompt: string;
|
|
9
|
+
temperature?: number;
|
|
10
|
+
maxTokens?: number;
|
|
11
|
+
}
|
|
12
|
+
export interface ModelResponse {
|
|
13
|
+
content: string;
|
|
14
|
+
raw?: unknown;
|
|
15
|
+
}
|
|
16
|
+
export interface HealthResult {
|
|
17
|
+
reachable: boolean;
|
|
18
|
+
models?: string[];
|
|
19
|
+
error?: string;
|
|
20
|
+
}
|
|
21
|
+
export interface ModelClient {
|
|
22
|
+
complete(request: ModelRequest): Promise<ModelResponse>;
|
|
23
|
+
health(): Promise<HealthResult>;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* The distinct §12 failure kinds. Callers (e.g. `doctor`) branch on `kind`
|
|
27
|
+
* instead of string-matching messages.
|
|
28
|
+
*/
|
|
29
|
+
export type ModelClientErrorKind = "refused" | "timeout" | "model-not-loaded" | "empty" | "malformed";
|
|
30
|
+
export declare class ModelClientError extends Error {
|
|
31
|
+
readonly kind: ModelClientErrorKind;
|
|
32
|
+
readonly baseUrl: string;
|
|
33
|
+
readonly cause?: unknown;
|
|
34
|
+
constructor(kind: ModelClientErrorKind, message: string, baseUrl: string, cause?: unknown);
|
|
35
|
+
}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Model client types — the single swappable provider seam (HLD-SRD §3.8, §9).
|
|
3
|
+
*/
|
|
4
|
+
export class ModelClientError extends Error {
|
|
5
|
+
kind;
|
|
6
|
+
baseUrl;
|
|
7
|
+
cause;
|
|
8
|
+
constructor(kind, message, baseUrl, cause) {
|
|
9
|
+
super(message);
|
|
10
|
+
this.name = "ModelClientError";
|
|
11
|
+
this.kind = kind;
|
|
12
|
+
this.baseUrl = baseUrl;
|
|
13
|
+
this.cause = cause;
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
//# sourceMappingURL=model.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"model.js","sourceRoot":"","sources":["../../src/types/model.ts"],"names":[],"mappings":"AAAA;;GAEG;AA6CH,MAAM,OAAO,gBAAiB,SAAQ,KAAK;IAChC,IAAI,CAAuB;IAC3B,OAAO,CAAS;IACP,KAAK,CAAW;IAElC,YACE,IAA0B,EAC1B,OAAe,EACf,OAAe,EACf,KAAe;QAEf,KAAK,CAAC,OAAO,CAAC,CAAC;QACf,IAAI,CAAC,IAAI,GAAG,kBAAkB,CAAC;QAC/B,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACjB,IAAI,CAAC,OAAO,GAAG,OAAO,CAAC;QACvB,IAAI,CAAC,KAAK,GAAG,KAAK,CAAC;IACrB,CAAC;CACF"}
|
|
@@ -0,0 +1,38 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Patch + safety types (HLD-SRD §3.10, §11, §13; design.md "Data contracts").
|
|
3
|
+
*
|
|
4
|
+
* `PatchPlan` is the parsed, classified view of a single unified diff: the set
|
|
5
|
+
* of touched repo-relative paths split by operation (add / modify / delete),
|
|
6
|
+
* a binary flag, and the raw diff text retained for `git apply`. The Safety
|
|
7
|
+
* Manager turns a `PatchPlan` + config into a `SafetyVerdict` — a PURE decision
|
|
8
|
+
* (`allow` | `refuse`) plus any extra confirmations the command must prompt for.
|
|
9
|
+
*/
|
|
10
|
+
/** A parsed, classified unified diff. */
|
|
11
|
+
export interface PatchPlan {
|
|
12
|
+
/** Every repo-relative POSIX path the diff touches (adds ∪ modifies ∪ deletes). */
|
|
13
|
+
touchedFiles: string[];
|
|
14
|
+
/** Paths the diff creates (no prior file). */
|
|
15
|
+
adds: string[];
|
|
16
|
+
/** Paths the diff edits in place. */
|
|
17
|
+
modifies: string[];
|
|
18
|
+
/** Paths the diff removes. */
|
|
19
|
+
deletes: string[];
|
|
20
|
+
/** True when any file section is a binary patch (`GIT binary patch`). */
|
|
21
|
+
isBinary: boolean;
|
|
22
|
+
/** The raw unified diff text (what `git apply` consumes). */
|
|
23
|
+
diff: string;
|
|
24
|
+
}
|
|
25
|
+
export type SafetyDecision = "allow" | "refuse";
|
|
26
|
+
/** The extra interactive confirmations a patch requires before applying. */
|
|
27
|
+
export type SafetyConfirm = "risky-path" | "delete";
|
|
28
|
+
/**
|
|
29
|
+
* The pure outcome of `safetyManager.evaluate`. `refuse` stops the step with
|
|
30
|
+
* the matching §11/§13 reason; `allow` may still carry `needsConfirm` prompts
|
|
31
|
+
* the command turns into explicit confirmations.
|
|
32
|
+
*/
|
|
33
|
+
export interface SafetyVerdict {
|
|
34
|
+
decision: SafetyDecision;
|
|
35
|
+
needsConfirm: SafetyConfirm[];
|
|
36
|
+
/** Human-readable messages keyed to §11/§13 (one per triggered rule). */
|
|
37
|
+
reasons: string[];
|
|
38
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Patch + safety types (HLD-SRD §3.10, §11, §13; design.md "Data contracts").
|
|
3
|
+
*
|
|
4
|
+
* `PatchPlan` is the parsed, classified view of a single unified diff: the set
|
|
5
|
+
* of touched repo-relative paths split by operation (add / modify / delete),
|
|
6
|
+
* a binary flag, and the raw diff text retained for `git apply`. The Safety
|
|
7
|
+
* Manager turns a `PatchPlan` + config into a `SafetyVerdict` — a PURE decision
|
|
8
|
+
* (`allow` | `refuse`) plus any extra confirmations the command must prompt for.
|
|
9
|
+
*/
|
|
10
|
+
export {};
|
|
11
|
+
//# sourceMappingURL=patch.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"patch.js","sourceRoot":"","sources":["../../src/types/patch.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG"}
|
|
@@ -0,0 +1,86 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Planner output schema (HLD-SRD §3.9).
|
|
3
|
+
*
|
|
4
|
+
* The model is asked to return `{ summary, subtasks[…], risks, questions }`.
|
|
5
|
+
* The schema is strict on shape (a subtask MUST carry a `title`; at least one
|
|
6
|
+
* subtask is required) but tolerant on optional fields (defaults fill omitted
|
|
7
|
+
* `description`/`likelyFiles`/`acceptanceCriteria`/`risks`/`questions`). The
|
|
8
|
+
* subtask `id` and `risk` are validated loosely here and normalized after
|
|
9
|
+
* parse (id → `step-N`, risk → `low|medium|high`).
|
|
10
|
+
*/
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
export declare const plannerSubtaskSchema: z.ZodObject<{
|
|
13
|
+
id: z.ZodOptional<z.ZodString>;
|
|
14
|
+
title: z.ZodString;
|
|
15
|
+
description: z.ZodDefault<z.ZodString>;
|
|
16
|
+
risk: z.ZodOptional<z.ZodString>;
|
|
17
|
+
likelyFiles: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
18
|
+
acceptanceCriteria: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
19
|
+
}, "strip", z.ZodTypeAny, {
|
|
20
|
+
likelyFiles: string[];
|
|
21
|
+
title: string;
|
|
22
|
+
description: string;
|
|
23
|
+
acceptanceCriteria: string[];
|
|
24
|
+
id?: string | undefined;
|
|
25
|
+
risk?: string | undefined;
|
|
26
|
+
}, {
|
|
27
|
+
title: string;
|
|
28
|
+
likelyFiles?: string[] | undefined;
|
|
29
|
+
id?: string | undefined;
|
|
30
|
+
description?: string | undefined;
|
|
31
|
+
risk?: string | undefined;
|
|
32
|
+
acceptanceCriteria?: string[] | undefined;
|
|
33
|
+
}>;
|
|
34
|
+
export declare const plannerSchema: z.ZodObject<{
|
|
35
|
+
summary: z.ZodString;
|
|
36
|
+
subtasks: z.ZodArray<z.ZodObject<{
|
|
37
|
+
id: z.ZodOptional<z.ZodString>;
|
|
38
|
+
title: z.ZodString;
|
|
39
|
+
description: z.ZodDefault<z.ZodString>;
|
|
40
|
+
risk: z.ZodOptional<z.ZodString>;
|
|
41
|
+
likelyFiles: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
42
|
+
acceptanceCriteria: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
43
|
+
}, "strip", z.ZodTypeAny, {
|
|
44
|
+
likelyFiles: string[];
|
|
45
|
+
title: string;
|
|
46
|
+
description: string;
|
|
47
|
+
acceptanceCriteria: string[];
|
|
48
|
+
id?: string | undefined;
|
|
49
|
+
risk?: string | undefined;
|
|
50
|
+
}, {
|
|
51
|
+
title: string;
|
|
52
|
+
likelyFiles?: string[] | undefined;
|
|
53
|
+
id?: string | undefined;
|
|
54
|
+
description?: string | undefined;
|
|
55
|
+
risk?: string | undefined;
|
|
56
|
+
acceptanceCriteria?: string[] | undefined;
|
|
57
|
+
}>, "many">;
|
|
58
|
+
risks: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
59
|
+
questions: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
60
|
+
}, "strip", z.ZodTypeAny, {
|
|
61
|
+
summary: string;
|
|
62
|
+
subtasks: {
|
|
63
|
+
likelyFiles: string[];
|
|
64
|
+
title: string;
|
|
65
|
+
description: string;
|
|
66
|
+
acceptanceCriteria: string[];
|
|
67
|
+
id?: string | undefined;
|
|
68
|
+
risk?: string | undefined;
|
|
69
|
+
}[];
|
|
70
|
+
risks: string[];
|
|
71
|
+
questions: string[];
|
|
72
|
+
}, {
|
|
73
|
+
summary: string;
|
|
74
|
+
subtasks: {
|
|
75
|
+
title: string;
|
|
76
|
+
likelyFiles?: string[] | undefined;
|
|
77
|
+
id?: string | undefined;
|
|
78
|
+
description?: string | undefined;
|
|
79
|
+
risk?: string | undefined;
|
|
80
|
+
acceptanceCriteria?: string[] | undefined;
|
|
81
|
+
}[];
|
|
82
|
+
risks?: string[] | undefined;
|
|
83
|
+
questions?: string[] | undefined;
|
|
84
|
+
}>;
|
|
85
|
+
export type PlannerPlan = z.infer<typeof plannerSchema>;
|
|
86
|
+
export type PlannerSubtask = z.infer<typeof plannerSubtaskSchema>;
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Planner output schema (HLD-SRD §3.9).
|
|
3
|
+
*
|
|
4
|
+
* The model is asked to return `{ summary, subtasks[…], risks, questions }`.
|
|
5
|
+
* The schema is strict on shape (a subtask MUST carry a `title`; at least one
|
|
6
|
+
* subtask is required) but tolerant on optional fields (defaults fill omitted
|
|
7
|
+
* `description`/`likelyFiles`/`acceptanceCriteria`/`risks`/`questions`). The
|
|
8
|
+
* subtask `id` and `risk` are validated loosely here and normalized after
|
|
9
|
+
* parse (id → `step-N`, risk → `low|medium|high`).
|
|
10
|
+
*/
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
export const plannerSubtaskSchema = z.object({
|
|
13
|
+
id: z.string().optional(),
|
|
14
|
+
title: z.string(),
|
|
15
|
+
description: z.string().default(""),
|
|
16
|
+
// Normalized post-parse to low|medium|high (default medium).
|
|
17
|
+
risk: z.string().optional(),
|
|
18
|
+
likelyFiles: z.array(z.string()).default([]),
|
|
19
|
+
acceptanceCriteria: z.array(z.string()).default([]),
|
|
20
|
+
});
|
|
21
|
+
export const plannerSchema = z.object({
|
|
22
|
+
summary: z.string(),
|
|
23
|
+
subtasks: z.array(plannerSubtaskSchema).min(1),
|
|
24
|
+
risks: z.array(z.string()).default([]),
|
|
25
|
+
questions: z.array(z.string()).default([]),
|
|
26
|
+
});
|
|
27
|
+
//# sourceMappingURL=plan.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"plan.js","sourceRoot":"","sources":["../../src/types/plan.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,oBAAoB,GAAG,CAAC,CAAC,MAAM,CAAC;IAC3C,EAAE,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IACzB,KAAK,EAAE,CAAC,CAAC,MAAM,EAAE;IACjB,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IACnC,6DAA6D;IAC7D,IAAI,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE;IAC3B,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IAC5C,kBAAkB,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;CACpD,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,aAAa,GAAG,CAAC,CAAC,MAAM,CAAC;IACpC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE;IACnB,QAAQ,EAAE,CAAC,CAAC,KAAK,CAAC,oBAAoB,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;IAC9C,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;IACtC,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;CAC3C,CAAC,CAAC"}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Review report type + schema (HLD-SRD §3.12; 0001_06).
|
|
3
|
+
*
|
|
4
|
+
* The advisory `review` command asks the model for a structured report and
|
|
5
|
+
* tolerantly extracts it. The schema mirrors the §3.12 shape; every array
|
|
6
|
+
* defaults to `[]` and the two strings default to `""` so a partial or
|
|
7
|
+
* key-light model response still validates into a complete, printable report.
|
|
8
|
+
* Array members that are not strings are dropped (tolerant of local-model noise).
|
|
9
|
+
*/
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
export declare const reviewReportSchema: z.ZodObject<{
|
|
12
|
+
summary: z.ZodDefault<z.ZodString>;
|
|
13
|
+
blocking: z.ZodDefault<z.ZodEffects<z.ZodArray<z.ZodUnknown, "many">, string[], unknown[]>>;
|
|
14
|
+
nonBlocking: z.ZodDefault<z.ZodEffects<z.ZodArray<z.ZodUnknown, "many">, string[], unknown[]>>;
|
|
15
|
+
missingTests: z.ZodDefault<z.ZodEffects<z.ZodArray<z.ZodUnknown, "many">, string[], unknown[]>>;
|
|
16
|
+
scopeCreep: z.ZodDefault<z.ZodEffects<z.ZodArray<z.ZodUnknown, "many">, string[], unknown[]>>;
|
|
17
|
+
recommendation: z.ZodDefault<z.ZodString>;
|
|
18
|
+
}, "strip", z.ZodTypeAny, {
|
|
19
|
+
summary: string;
|
|
20
|
+
blocking: string[];
|
|
21
|
+
nonBlocking: string[];
|
|
22
|
+
missingTests: string[];
|
|
23
|
+
scopeCreep: string[];
|
|
24
|
+
recommendation: string;
|
|
25
|
+
}, {
|
|
26
|
+
summary?: string | undefined;
|
|
27
|
+
blocking?: unknown[] | undefined;
|
|
28
|
+
nonBlocking?: unknown[] | undefined;
|
|
29
|
+
missingTests?: unknown[] | undefined;
|
|
30
|
+
scopeCreep?: unknown[] | undefined;
|
|
31
|
+
recommendation?: string | undefined;
|
|
32
|
+
}>;
|
|
33
|
+
export type ReviewReport = z.infer<typeof reviewReportSchema>;
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Review report type + schema (HLD-SRD §3.12; 0001_06).
|
|
3
|
+
*
|
|
4
|
+
* The advisory `review` command asks the model for a structured report and
|
|
5
|
+
* tolerantly extracts it. The schema mirrors the §3.12 shape; every array
|
|
6
|
+
* defaults to `[]` and the two strings default to `""` so a partial or
|
|
7
|
+
* key-light model response still validates into a complete, printable report.
|
|
8
|
+
* Array members that are not strings are dropped (tolerant of local-model noise).
|
|
9
|
+
*/
|
|
10
|
+
import { z } from "zod";
|
|
11
|
+
/** A string-array field that tolerantly drops non-string members and defaults []. */
|
|
12
|
+
const stringArray = z
|
|
13
|
+
.array(z.unknown())
|
|
14
|
+
.transform((arr) => arr.filter((x) => typeof x === "string"))
|
|
15
|
+
.default([]);
|
|
16
|
+
export const reviewReportSchema = z.object({
|
|
17
|
+
summary: z.string().default(""),
|
|
18
|
+
blocking: stringArray,
|
|
19
|
+
nonBlocking: stringArray,
|
|
20
|
+
missingTests: stringArray,
|
|
21
|
+
scopeCreep: stringArray,
|
|
22
|
+
recommendation: z.string().default(""),
|
|
23
|
+
});
|
|
24
|
+
//# sourceMappingURL=review.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"review.js","sourceRoot":"","sources":["../../src/types/review.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,qFAAqF;AACrF,MAAM,WAAW,GAAG,CAAC;KAClB,KAAK,CAAC,CAAC,CAAC,OAAO,EAAE,CAAC;KAClB,SAAS,CAAC,CAAC,GAAG,EAAE,EAAE,CAAC,GAAG,CAAC,MAAM,CAAC,CAAC,CAAC,EAAe,EAAE,CAAC,OAAO,CAAC,KAAK,QAAQ,CAAC,CAAC;KACzE,OAAO,CAAC,EAAE,CAAC,CAAC;AAEf,MAAM,CAAC,MAAM,kBAAkB,GAAG,CAAC,CAAC,MAAM,CAAC;IACzC,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;IAC/B,QAAQ,EAAE,WAAW;IACrB,WAAW,EAAE,WAAW;IACxB,YAAY,EAAE,WAAW;IACzB,UAAU,EAAE,WAAW;IACvB,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;CACvC,CAAC,CAAC"}
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run-loop types (HLD-SRD §3.13, §11.2; 0001_06).
|
|
3
|
+
*
|
|
4
|
+
* `StopReason` is the closed set of named reasons the run loop can stop for —
|
|
5
|
+
* one per §11.2 condition plus the hard iteration-cap guard. `StepOutcome` is
|
|
6
|
+
* the structured result of one `runStep` invocation that the pure `decideStop`
|
|
7
|
+
* function reasons over; `LoopState` is the loop's accumulated bookkeeping.
|
|
8
|
+
*/
|
|
9
|
+
import type { TestResult } from "./test.js";
|
|
10
|
+
/**
|
|
11
|
+
* The closed set of reasons the `run` loop stops. Each maps to an HLD-SRD §11.2
|
|
12
|
+
* condition; `iteration-cap-exceeded` is the loop's own hard infinite-loop guard.
|
|
13
|
+
*/
|
|
14
|
+
export type StopReason = "risky-change" | "repeated-failure" | "acceptance-met" | "unparseable-output" | "needs-context" | "budget-exceeded" | "unsafe-tree" | "model-unavailable" | "approval-denied" | "patch-invalid" | "broad-rewrite-requested" | "iteration-cap-exceeded";
|
|
15
|
+
/**
|
|
16
|
+
* The structured result of one `runStep` invocation. `subtaskId` is null when
|
|
17
|
+
* there was no pending subtask (task complete). `applied` is true once a patch
|
|
18
|
+
* (coder or fix) reached the working tree. `stopReason` is set when the step
|
|
19
|
+
* itself hit a stop condition (safety refusal, approval denied, unparseable,
|
|
20
|
+
* etc.) that `decideStop` bubbles up. `fixAttempts` counts test-fix iterations.
|
|
21
|
+
*/
|
|
22
|
+
export interface StepOutcome {
|
|
23
|
+
subtaskId: string | null;
|
|
24
|
+
applied: boolean;
|
|
25
|
+
stopReason?: StopReason;
|
|
26
|
+
testResults: TestResult[];
|
|
27
|
+
fixAttempts: number;
|
|
28
|
+
}
|
|
29
|
+
/** Accumulated run-loop bookkeeping across iterations. */
|
|
30
|
+
export interface LoopState {
|
|
31
|
+
iterations: number;
|
|
32
|
+
consecutiveFailures: number;
|
|
33
|
+
filesChanged: number;
|
|
34
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"run.js","sourceRoot":"","sources":["../../src/types/run.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Session type (HLD-SRD §3.6).
|
|
3
|
+
*
|
|
4
|
+
* A `Session` is the parsed view of a `/ai/sessions/*.md` file. It references
|
|
5
|
+
* its task (`taskPath`) and tracks the working state the user resumes from.
|
|
6
|
+
* `raw` is retained so the Session Manager can rewrite individual sections
|
|
7
|
+
* without losing other content.
|
|
8
|
+
*/
|
|
9
|
+
import type { TaskStatus } from "./task.js";
|
|
10
|
+
export interface Session {
|
|
11
|
+
/** Absolute path of the session file on disk. */
|
|
12
|
+
path: string;
|
|
13
|
+
/** Path of the task this session is working on. */
|
|
14
|
+
taskPath: string;
|
|
15
|
+
status: TaskStatus;
|
|
16
|
+
objective: string;
|
|
17
|
+
currentState: string;
|
|
18
|
+
nextStep: string;
|
|
19
|
+
/** The original markdown, retained verbatim. */
|
|
20
|
+
raw: string;
|
|
21
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"session.js","sourceRoot":"","sources":["../../src/types/session.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Summarizer output schema (HLD-SRD §3.9, 0001_07).
|
|
3
|
+
*
|
|
4
|
+
* The model is asked to return:
|
|
5
|
+
* { sessionUpdate{currentState, filesChanged[], decisions[], risks[]},
|
|
6
|
+
* memoryUpdates[{changeType, content}],
|
|
7
|
+
* nextStep }
|
|
8
|
+
*
|
|
9
|
+
* All fields use defaults so a partial response still yields a usable object.
|
|
10
|
+
*/
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
export declare const summarizerSchema: z.ZodObject<{
|
|
13
|
+
sessionUpdate: z.ZodDefault<z.ZodObject<{
|
|
14
|
+
currentState: z.ZodDefault<z.ZodString>;
|
|
15
|
+
filesChanged: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
16
|
+
decisions: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
17
|
+
risks: z.ZodDefault<z.ZodArray<z.ZodString, "many">>;
|
|
18
|
+
}, "strip", z.ZodTypeAny, {
|
|
19
|
+
currentState: string;
|
|
20
|
+
risks: string[];
|
|
21
|
+
filesChanged: string[];
|
|
22
|
+
decisions: string[];
|
|
23
|
+
}, {
|
|
24
|
+
currentState?: string | undefined;
|
|
25
|
+
risks?: string[] | undefined;
|
|
26
|
+
filesChanged?: string[] | undefined;
|
|
27
|
+
decisions?: string[] | undefined;
|
|
28
|
+
}>>;
|
|
29
|
+
memoryUpdates: z.ZodDefault<z.ZodArray<z.ZodObject<{
|
|
30
|
+
changeType: z.ZodString;
|
|
31
|
+
content: z.ZodString;
|
|
32
|
+
}, "strip", z.ZodTypeAny, {
|
|
33
|
+
content: string;
|
|
34
|
+
changeType: string;
|
|
35
|
+
}, {
|
|
36
|
+
content: string;
|
|
37
|
+
changeType: string;
|
|
38
|
+
}>, "many">>;
|
|
39
|
+
nextStep: z.ZodDefault<z.ZodString>;
|
|
40
|
+
}, "strip", z.ZodTypeAny, {
|
|
41
|
+
nextStep: string;
|
|
42
|
+
sessionUpdate: {
|
|
43
|
+
currentState: string;
|
|
44
|
+
risks: string[];
|
|
45
|
+
filesChanged: string[];
|
|
46
|
+
decisions: string[];
|
|
47
|
+
};
|
|
48
|
+
memoryUpdates: {
|
|
49
|
+
content: string;
|
|
50
|
+
changeType: string;
|
|
51
|
+
}[];
|
|
52
|
+
}, {
|
|
53
|
+
nextStep?: string | undefined;
|
|
54
|
+
sessionUpdate?: {
|
|
55
|
+
currentState?: string | undefined;
|
|
56
|
+
risks?: string[] | undefined;
|
|
57
|
+
filesChanged?: string[] | undefined;
|
|
58
|
+
decisions?: string[] | undefined;
|
|
59
|
+
} | undefined;
|
|
60
|
+
memoryUpdates?: {
|
|
61
|
+
content: string;
|
|
62
|
+
changeType: string;
|
|
63
|
+
}[] | undefined;
|
|
64
|
+
}>;
|
|
65
|
+
export type SummarizerOutput = z.infer<typeof summarizerSchema>;
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Summarizer output schema (HLD-SRD §3.9, 0001_07).
|
|
3
|
+
*
|
|
4
|
+
* The model is asked to return:
|
|
5
|
+
* { sessionUpdate{currentState, filesChanged[], decisions[], risks[]},
|
|
6
|
+
* memoryUpdates[{changeType, content}],
|
|
7
|
+
* nextStep }
|
|
8
|
+
*
|
|
9
|
+
* All fields use defaults so a partial response still yields a usable object.
|
|
10
|
+
*/
|
|
11
|
+
import { z } from "zod";
|
|
12
|
+
export const summarizerSchema = z.object({
|
|
13
|
+
sessionUpdate: z
|
|
14
|
+
.object({
|
|
15
|
+
currentState: z.string().default(""),
|
|
16
|
+
filesChanged: z.array(z.string()).default([]),
|
|
17
|
+
decisions: z.array(z.string()).default([]),
|
|
18
|
+
risks: z.array(z.string()).default([]),
|
|
19
|
+
})
|
|
20
|
+
.default({}),
|
|
21
|
+
memoryUpdates: z
|
|
22
|
+
.array(z.object({ changeType: z.string(), content: z.string() }))
|
|
23
|
+
.default([]),
|
|
24
|
+
nextStep: z.string().default(""),
|
|
25
|
+
});
|
|
26
|
+
//# sourceMappingURL=summary.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"summary.js","sourceRoot":"","sources":["../../src/types/summary.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,CAAC,EAAE,MAAM,KAAK,CAAC;AAExB,MAAM,CAAC,MAAM,gBAAgB,GAAG,CAAC,CAAC,MAAM,CAAC;IACvC,aAAa,EAAE,CAAC;SACb,MAAM,CAAC;QACN,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;QACpC,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;QAC7C,SAAS,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;QAC1C,KAAK,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;KACvC,CAAC;SACD,OAAO,CAAC,EAAE,CAAC;IACd,aAAa,EAAE,CAAC;SACb,KAAK,CAAC,CAAC,CAAC,MAAM,CAAC,EAAE,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,OAAO,EAAE,CAAC,CAAC,MAAM,EAAE,EAAE,CAAC,CAAC;SAChE,OAAO,CAAC,EAAE,CAAC;IACd,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;CACjC,CAAC,CAAC"}
|
|
@@ -0,0 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task types (HLD-SRD §3.5).
|
|
3
|
+
*
|
|
4
|
+
* A `Task` is the parsed view of a `/ai/tasks/*.md` file: a title, lifecycle
|
|
5
|
+
* status, the free-form goal, and an ordered list of `step-N` subtasks. The
|
|
6
|
+
* `raw` markdown is retained so the Task Manager can rewrite only the
|
|
7
|
+
* `## Subtasks` block without losing other user content.
|
|
8
|
+
*/
|
|
9
|
+
export type TaskStatus = "active" | "done" | "blocked";
|
|
10
|
+
export type SubtaskStatus = "pending" | "active" | "done" | "blocked";
|
|
11
|
+
export type Risk = "low" | "medium" | "high";
|
|
12
|
+
export interface Subtask {
|
|
13
|
+
/** Positional id, normalized to `step-N` (1-based) by the planner. */
|
|
14
|
+
id: string;
|
|
15
|
+
title: string;
|
|
16
|
+
description: string;
|
|
17
|
+
status: SubtaskStatus;
|
|
18
|
+
risk: Risk;
|
|
19
|
+
likelyFiles: string[];
|
|
20
|
+
acceptanceCriteria?: string[];
|
|
21
|
+
}
|
|
22
|
+
export interface Task {
|
|
23
|
+
/** Absolute path of the task file on disk. */
|
|
24
|
+
path: string;
|
|
25
|
+
title: string;
|
|
26
|
+
status: TaskStatus;
|
|
27
|
+
goal: string;
|
|
28
|
+
subtasks: Subtask[];
|
|
29
|
+
/** The original markdown, retained verbatim. */
|
|
30
|
+
raw: string;
|
|
31
|
+
}
|
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Task types (HLD-SRD §3.5).
|
|
3
|
+
*
|
|
4
|
+
* A `Task` is the parsed view of a `/ai/tasks/*.md` file: a title, lifecycle
|
|
5
|
+
* status, the free-form goal, and an ordered list of `step-N` subtasks. The
|
|
6
|
+
* `raw` markdown is retained so the Task Manager can rewrite only the
|
|
7
|
+
* `## Subtasks` block without losing other user content.
|
|
8
|
+
*/
|
|
9
|
+
export {};
|
|
10
|
+
//# sourceMappingURL=task.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"task.js","sourceRoot":"","sources":["../../src/types/task.ts"],"names":[],"mappings":"AAAA;;;;;;;GAOG"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Test Runner result type (HLD-SRD §3.11).
|
|
3
|
+
*
|
|
4
|
+
* The captured outcome of one configured test command. Report-only this slice:
|
|
5
|
+
* the runner never retries and a non-zero `exitCode` never rolls back the patch.
|
|
6
|
+
*/
|
|
7
|
+
export interface TestResult {
|
|
8
|
+
/** The command line as displayed (e.g. `npm test`). */
|
|
9
|
+
command: string;
|
|
10
|
+
/** Process exit code; 0 = pass. */
|
|
11
|
+
exitCode: number;
|
|
12
|
+
stdout: string;
|
|
13
|
+
stderr: string;
|
|
14
|
+
/** Wall-clock duration of the command, milliseconds. */
|
|
15
|
+
durationMs: number;
|
|
16
|
+
}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"test.js","sourceRoot":"","sources":["../../src/types/test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
export declare const GITIGNORE_MARKER = "# localcoder";
|
|
2
|
+
export declare function ensureDir(dir: string): Promise<void>;
|
|
3
|
+
/**
|
|
4
|
+
* Write `content` to `file` only if it does not already exist.
|
|
5
|
+
* Returns true if the file was created, false if it was preserved.
|
|
6
|
+
*/
|
|
7
|
+
export declare function writeIfAbsent(file: string, content: string): Promise<boolean>;
|
|
8
|
+
export declare function readIfExists(file: string): Promise<string | undefined>;
|
|
9
|
+
/**
|
|
10
|
+
* Append the localcoder `.gitignore` stanza unless its marker is already present.
|
|
11
|
+
* Returns true if the stanza was appended, false if it was already there.
|
|
12
|
+
*/
|
|
13
|
+
export declare function appendGitignoreStanza(gitignoreFile: string): Promise<boolean>;
|
package/dist/utils/fs.js
ADDED
|
@@ -0,0 +1,65 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Filesystem helpers: idempotent dir creation, write-if-absent (no clobber),
|
|
3
|
+
* read-if-exists, and a marker-guarded `.gitignore` stanza appender.
|
|
4
|
+
*/
|
|
5
|
+
import { promises as fs } from "node:fs";
|
|
6
|
+
import path from "node:path";
|
|
7
|
+
export const GITIGNORE_MARKER = "# localcoder";
|
|
8
|
+
const GITIGNORE_STANZA = `${GITIGNORE_MARKER}
|
|
9
|
+
.ai-orchestrator/logs/
|
|
10
|
+
.ai-orchestrator/context-packages/
|
|
11
|
+
`;
|
|
12
|
+
export async function ensureDir(dir) {
|
|
13
|
+
await fs.mkdir(dir, { recursive: true });
|
|
14
|
+
}
|
|
15
|
+
/**
|
|
16
|
+
* Write `content` to `file` only if it does not already exist.
|
|
17
|
+
* Returns true if the file was created, false if it was preserved.
|
|
18
|
+
*/
|
|
19
|
+
export async function writeIfAbsent(file, content) {
|
|
20
|
+
await ensureDir(path.dirname(file));
|
|
21
|
+
try {
|
|
22
|
+
// wx fails if the path exists — atomic no-clobber.
|
|
23
|
+
await fs.writeFile(file, content, { encoding: "utf8", flag: "wx" });
|
|
24
|
+
return true;
|
|
25
|
+
}
|
|
26
|
+
catch (err) {
|
|
27
|
+
if (err.code === "EEXIST") {
|
|
28
|
+
return false;
|
|
29
|
+
}
|
|
30
|
+
throw err;
|
|
31
|
+
}
|
|
32
|
+
}
|
|
33
|
+
export async function readIfExists(file) {
|
|
34
|
+
try {
|
|
35
|
+
return await fs.readFile(file, "utf8");
|
|
36
|
+
}
|
|
37
|
+
catch (err) {
|
|
38
|
+
if (err.code === "ENOENT") {
|
|
39
|
+
return undefined;
|
|
40
|
+
}
|
|
41
|
+
throw err;
|
|
42
|
+
}
|
|
43
|
+
}
|
|
44
|
+
/**
|
|
45
|
+
* Append the localcoder `.gitignore` stanza unless its marker is already present.
|
|
46
|
+
* Returns true if the stanza was appended, false if it was already there.
|
|
47
|
+
*/
|
|
48
|
+
export async function appendGitignoreStanza(gitignoreFile) {
|
|
49
|
+
const existing = await readIfExists(gitignoreFile);
|
|
50
|
+
if (existing !== undefined && existing.includes(GITIGNORE_MARKER)) {
|
|
51
|
+
return false;
|
|
52
|
+
}
|
|
53
|
+
let next;
|
|
54
|
+
if (existing === undefined || existing.length === 0) {
|
|
55
|
+
next = GITIGNORE_STANZA;
|
|
56
|
+
}
|
|
57
|
+
else {
|
|
58
|
+
const sep = existing.endsWith("\n") ? "\n" : "\n\n";
|
|
59
|
+
next = existing + sep + GITIGNORE_STANZA;
|
|
60
|
+
}
|
|
61
|
+
await ensureDir(path.dirname(gitignoreFile));
|
|
62
|
+
await fs.writeFile(gitignoreFile, next, "utf8");
|
|
63
|
+
return true;
|
|
64
|
+
}
|
|
65
|
+
//# sourceMappingURL=fs.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"fs.js","sourceRoot":"","sources":["../../src/utils/fs.ts"],"names":[],"mappings":"AAAA;;;GAGG;AACH,OAAO,EAAE,QAAQ,IAAI,EAAE,EAAE,MAAM,SAAS,CAAC;AACzC,OAAO,IAAI,MAAM,WAAW,CAAC;AAE7B,MAAM,CAAC,MAAM,gBAAgB,GAAG,cAAc,CAAC;AAE/C,MAAM,gBAAgB,GAAG,GAAG,gBAAgB;;;CAG3C,CAAC;AAEF,MAAM,CAAC,KAAK,UAAU,SAAS,CAAC,GAAW;IACzC,MAAM,EAAE,CAAC,KAAK,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;AAC3C,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,aAAa,CACjC,IAAY,EACZ,OAAe;IAEf,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC;IACpC,IAAI,CAAC;QACH,mDAAmD;QACnD,MAAM,EAAE,CAAC,SAAS,CAAC,IAAI,EAAE,OAAO,EAAE,EAAE,QAAQ,EAAE,MAAM,EAAE,IAAI,EAAE,IAAI,EAAE,CAAC,CAAC;QACpE,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACrD,OAAO,KAAK,CAAC;QACf,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,YAAY,CAAC,IAAY;IAC7C,IAAI,CAAC;QACH,OAAO,MAAM,EAAE,CAAC,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAC,CAAC;IACzC,CAAC;IAAC,OAAO,GAAG,EAAE,CAAC;QACb,IAAK,GAA6B,CAAC,IAAI,KAAK,QAAQ,EAAE,CAAC;YACrD,OAAO,SAAS,CAAC;QACnB,CAAC;QACD,MAAM,GAAG,CAAC;IACZ,CAAC;AACH,CAAC;AAED;;;GAGG;AACH,MAAM,CAAC,KAAK,UAAU,qBAAqB,CACzC,aAAqB;IAErB,MAAM,QAAQ,GAAG,MAAM,YAAY,CAAC,aAAa,CAAC,CAAC;IACnD,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,QAAQ,CAAC,gBAAgB,CAAC,EAAE,CAAC;QAClE,OAAO,KAAK,CAAC;IACf,CAAC;IACD,IAAI,IAAY,CAAC;IACjB,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QACpD,IAAI,GAAG,gBAAgB,CAAC;IAC1B,CAAC;SAAM,CAAC;QACN,MAAM,GAAG,GAAG,QAAQ,CAAC,QAAQ,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;QACpD,IAAI,GAAG,QAAQ,GAAG,GAAG,GAAG,gBAAgB,CAAC;IAC3C,CAAC;IACD,MAAM,SAAS,CAAC,IAAI,CAAC,OAAO,CAAC,aAAa,CAAC,CAAC,CAAC;IAC7C,MAAM,EAAE,CAAC,SAAS,CAAC,aAAa,EAAE,IAAI,EAAE,MAAM,CAAC,CAAC;IAChD,OAAO,IAAI,CAAC;AACd,CAAC"}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Repo-root detection (HLD-SRD §3.1). Warn — never fail — when the directory is
|
|
3
|
+
* not a Git repo; later Git-dependent safety features require `.git`, this slice
|
|
4
|
+
* does not.
|
|
5
|
+
*/
|
|
6
|
+
import { simpleGit } from "simple-git";
|
|
7
|
+
export async function detectGitRoot(cwd) {
|
|
8
|
+
const git = simpleGit(cwd);
|
|
9
|
+
try {
|
|
10
|
+
const isRepo = await git.checkIsRepo();
|
|
11
|
+
if (!isRepo) {
|
|
12
|
+
return { isRepo: false };
|
|
13
|
+
}
|
|
14
|
+
const root = (await git.revparse(["--show-toplevel"])).trim();
|
|
15
|
+
return { isRepo: true, root };
|
|
16
|
+
}
|
|
17
|
+
catch {
|
|
18
|
+
return { isRepo: false };
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
//# sourceMappingURL=gitRoot.js.map
|