deepclause-pi 0.2.0 → 0.4.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/README.md +13 -0
- package/dist/config.d.ts +22 -0
- package/dist/config.js +60 -0
- package/dist/diagram/viewer.d.ts +6 -0
- package/dist/diagram/viewer.js +5 -0
- package/dist/index.d.ts +9 -1
- package/dist/index.js +423 -22
- package/dist/planner.d.ts +27 -2
- package/dist/planner.js +109 -4
- package/dist/runtime.d.ts +17 -1
- package/dist/runtime.js +139 -4
- package/dist/workspace.d.ts +3 -0
- package/dist/workspace.js +20 -0
- package/docs/SPECKIT.md +232 -0
- package/docs/SPEC_LAYER_PROPOSAL.md +1893 -0
- package/package.json +2 -2
- package/src/assets/AGENTS.md +66 -0
- package/src/assets/apply.dml +188 -0
- package/src/assets/spec_apply.dml +20 -0
- package/src/assets/spec_archive.dml +11 -0
- package/src/assets/spec_coverage.dml +26 -0
- package/src/assets/spec_graph.dml +12 -0
- package/src/assets/spec_merge.dml +10 -0
- package/src/assets/spec_query.dml +10 -0
- package/src/assets/spec_scaffold.dml +10 -0
- package/src/assets/spec_status.dml +7 -0
- package/src/assets/spec_validate.dml +9 -0
- package/src/assets/specs.dml +995 -0
- package/src/config.ts +91 -0
- package/src/diagram/viewer.ts +11 -0
- package/src/index.ts +454 -20
- package/src/planner.ts +123 -3
- package/src/runtime.ts +147 -4
- package/src/workspace.ts +24 -0
package/README.md
CHANGED
|
@@ -131,6 +131,19 @@ The resulting `.dml` file is the plan. Steps use one of two executors:
|
|
|
131
131
|
|
|
132
132
|
For each pi step, only the exact tools named in the committed plan are temporarily active. They must still be installed and active when execution begins; existing tool policies, UI, and approvals remain authoritative. DeepClause control tools cannot be requested recursively. The prior active-tool set is restored after success, failure, or cancellation.
|
|
133
133
|
|
|
134
|
+
## deepclause-pi speckit
|
|
135
|
+
|
|
136
|
+
Spec-driven changes, built on the same runtime: behaviour specs in plain Markdown, reviewable change deltas, and an executable `tasks.dml` that pi runs with deterministic validation, per-task verification, rollback and resume.
|
|
137
|
+
|
|
138
|
+
```text
|
|
139
|
+
/dc-plan <request> --change=<slug> propose
|
|
140
|
+
/dc-check <slug> validate (0 tokens)
|
|
141
|
+
/dc-apply <slug> execute, verify, retry, resume
|
|
142
|
+
/dc-archive <slug> merge into specs/
|
|
143
|
+
```
|
|
144
|
+
|
|
145
|
+
See the [deepclause-pi speckit guide](docs/SPECKIT.md) for the getting-started walkthrough and reference.
|
|
146
|
+
|
|
134
147
|
## Diagrams
|
|
135
148
|
|
|
136
149
|
Ask pi for a diagram of any DML file in plain language:
|
package/dist/config.d.ts
CHANGED
|
@@ -1,4 +1,17 @@
|
|
|
1
1
|
export type ContextMode = "turn" | "branch" | "isolated";
|
|
2
|
+
export interface JevJudgeConfig {
|
|
3
|
+
/** Whether the Jev (TypeSafe System One) backend may be used. */
|
|
4
|
+
enabled: boolean;
|
|
5
|
+
/** Model alias or pinned version passed to TypeSafe. */
|
|
6
|
+
model: string;
|
|
7
|
+
/** Environment variable holding the TypeSafe API key. */
|
|
8
|
+
apiKeyEnv: string;
|
|
9
|
+
}
|
|
10
|
+
export interface JudgmentConfig {
|
|
11
|
+
/** Default backend name: "llm", "jev", or a name registered by an extension. */
|
|
12
|
+
default: string;
|
|
13
|
+
jev: JevJudgeConfig;
|
|
14
|
+
}
|
|
2
15
|
export interface DeepClauseConfig {
|
|
3
16
|
version: 1;
|
|
4
17
|
contextMode: ContextMode;
|
|
@@ -7,7 +20,16 @@ export interface DeepClauseConfig {
|
|
|
7
20
|
maxTokens: number;
|
|
8
21
|
verbose: boolean;
|
|
9
22
|
modelToolEnabled: boolean;
|
|
23
|
+
judgment: JudgmentConfig;
|
|
10
24
|
}
|
|
11
25
|
export declare const DEFAULT_CONFIG: DeepClauseConfig;
|
|
12
26
|
export declare function loadConfig(path: string): Promise<DeepClauseConfig>;
|
|
13
27
|
export declare function setModelToolEnabled(configPath: string, enabled: boolean): Promise<DeepClauseConfig>;
|
|
28
|
+
export interface JudgeConfigPatch {
|
|
29
|
+
/** Default backend name ("llm" or "jev"). */
|
|
30
|
+
default?: string;
|
|
31
|
+
/** Partial update of the Jev backend settings. */
|
|
32
|
+
jev?: Partial<JevJudgeConfig>;
|
|
33
|
+
}
|
|
34
|
+
/** Merge a judgment patch into the workspace config, preserving every other field. */
|
|
35
|
+
export declare function setJudgeConfig(configPath: string, patch: JudgeConfigPatch): Promise<DeepClauseConfig>;
|
package/dist/config.js
CHANGED
|
@@ -7,6 +7,10 @@ export const DEFAULT_CONFIG = {
|
|
|
7
7
|
maxTokens: 16_384,
|
|
8
8
|
verbose: false,
|
|
9
9
|
modelToolEnabled: false,
|
|
10
|
+
judgment: {
|
|
11
|
+
default: "llm",
|
|
12
|
+
jev: { enabled: false, model: "jev-latest", apiKeyEnv: "TYPESAFE_API_KEY" },
|
|
13
|
+
},
|
|
10
14
|
};
|
|
11
15
|
const isContextMode = (value) => value === "turn" || value === "branch" || value === "isolated";
|
|
12
16
|
export async function loadConfig(path) {
|
|
@@ -40,6 +44,40 @@ export async function loadConfig(path) {
|
|
|
40
44
|
maxTokens: positiveInteger("maxTokens", DEFAULT_CONFIG.maxTokens),
|
|
41
45
|
verbose: config.verbose === true,
|
|
42
46
|
modelToolEnabled: config.modelToolEnabled === true,
|
|
47
|
+
judgment: parseJudgmentConfig(config.judgment),
|
|
48
|
+
};
|
|
49
|
+
}
|
|
50
|
+
function parseJudgmentConfig(value) {
|
|
51
|
+
if (value === undefined)
|
|
52
|
+
return DEFAULT_CONFIG.judgment;
|
|
53
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
54
|
+
throw new Error("judgment must be a JSON object");
|
|
55
|
+
}
|
|
56
|
+
const judgment = value;
|
|
57
|
+
const defaultBackend = judgment.default ?? DEFAULT_CONFIG.judgment.default;
|
|
58
|
+
if (typeof defaultBackend !== "string" || !defaultBackend.trim()) {
|
|
59
|
+
throw new Error("judgment.default must be a non-empty backend name");
|
|
60
|
+
}
|
|
61
|
+
const jevValue = judgment.jev ?? {};
|
|
62
|
+
if (!jevValue || typeof jevValue !== "object" || Array.isArray(jevValue)) {
|
|
63
|
+
throw new Error("judgment.jev must be a JSON object");
|
|
64
|
+
}
|
|
65
|
+
const jev = jevValue;
|
|
66
|
+
const model = jev.model ?? DEFAULT_CONFIG.judgment.jev.model;
|
|
67
|
+
const apiKeyEnv = jev.apiKeyEnv ?? DEFAULT_CONFIG.judgment.jev.apiKeyEnv;
|
|
68
|
+
if (typeof model !== "string" || !model.trim()) {
|
|
69
|
+
throw new Error("judgment.jev.model must be a non-empty string");
|
|
70
|
+
}
|
|
71
|
+
if (typeof apiKeyEnv !== "string" || !apiKeyEnv.trim()) {
|
|
72
|
+
throw new Error("judgment.jev.apiKeyEnv must be a non-empty environment variable name");
|
|
73
|
+
}
|
|
74
|
+
return {
|
|
75
|
+
default: defaultBackend.trim(),
|
|
76
|
+
jev: {
|
|
77
|
+
enabled: jev.enabled === true,
|
|
78
|
+
model: model.trim(),
|
|
79
|
+
apiKeyEnv: apiKeyEnv.trim(),
|
|
80
|
+
},
|
|
43
81
|
};
|
|
44
82
|
}
|
|
45
83
|
export async function setModelToolEnabled(configPath, enabled) {
|
|
@@ -57,3 +95,25 @@ export async function setModelToolEnabled(configPath, enabled) {
|
|
|
57
95
|
await writeFile(configPath, `${JSON.stringify({ ...existing, modelToolEnabled: enabled }, null, 2)}\n`, "utf8");
|
|
58
96
|
return loadConfig(configPath);
|
|
59
97
|
}
|
|
98
|
+
/** Merge a judgment patch into the workspace config, preserving every other field. */
|
|
99
|
+
export async function setJudgeConfig(configPath, patch) {
|
|
100
|
+
let existing = {};
|
|
101
|
+
try {
|
|
102
|
+
const parsed = JSON.parse(await readFile(configPath, "utf8"));
|
|
103
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed))
|
|
104
|
+
existing = parsed;
|
|
105
|
+
}
|
|
106
|
+
catch (error) {
|
|
107
|
+
if (error.code !== "ENOENT") {
|
|
108
|
+
throw new Error(`Invalid DeepClause config: ${error instanceof Error ? error.message : String(error)}`);
|
|
109
|
+
}
|
|
110
|
+
}
|
|
111
|
+
const record = (value) => value && typeof value === "object" && !Array.isArray(value) ? value : {};
|
|
112
|
+
const nextJudgment = {
|
|
113
|
+
...record(existing.judgment),
|
|
114
|
+
...(patch.default !== undefined ? { default: patch.default } : {}),
|
|
115
|
+
jev: { ...record(record(existing.judgment).jev), ...(patch.jev ?? {}) },
|
|
116
|
+
};
|
|
117
|
+
await writeFile(configPath, `${JSON.stringify({ ...existing, judgment: nextJudgment }, null, 2)}\n`, "utf8");
|
|
118
|
+
return loadConfig(configPath);
|
|
119
|
+
}
|
package/dist/diagram/viewer.d.ts
CHANGED
|
@@ -25,6 +25,12 @@ export interface BuildViewerOptions {
|
|
|
25
25
|
* sidecars, and write the self-contained viewer plus per-skill Markdown.
|
|
26
26
|
*/
|
|
27
27
|
export declare function buildViewer(options: BuildViewerOptions): Promise<ViewerBuildResult>;
|
|
28
|
+
export declare function buildEntriesViewer(options: {
|
|
29
|
+
cwd: string;
|
|
30
|
+
templateText: string;
|
|
31
|
+
vendorAssetPath: string;
|
|
32
|
+
entries: DiagramEntry[];
|
|
33
|
+
}): Promise<ViewerBuildResult>;
|
|
28
34
|
export declare function writeSidecar(diagramsDir: string, name: string, grade: DiagramGrade, code: string): Promise<string>;
|
|
29
35
|
/** Open the viewer at a specific diagram and view using a fixed, OS-native argv. */
|
|
30
36
|
export declare function openViewerInBrowser(pi: Pick<ExtensionAPI, "exec">, viewerPath: string, name: string, view: string): Promise<boolean>;
|
package/dist/diagram/viewer.js
CHANGED
|
@@ -71,6 +71,11 @@ export async function buildViewer(options) {
|
|
|
71
71
|
const viewerPath = await renderViewer(diagrams, entries, options.templateText, vendorFile);
|
|
72
72
|
return { viewerPath, diagramsDir: diagrams, entries };
|
|
73
73
|
}
|
|
74
|
+
export async function buildEntriesViewer(options) {
|
|
75
|
+
const { diagrams, vendorFile } = await ensureDiagramDir(options.cwd, options.vendorAssetPath);
|
|
76
|
+
const viewerPath = await renderViewer(diagrams, options.entries, options.templateText, vendorFile);
|
|
77
|
+
return { viewerPath, diagramsDir: diagrams, entries: options.entries };
|
|
78
|
+
}
|
|
74
79
|
export async function writeSidecar(diagramsDir, name, grade, code) {
|
|
75
80
|
const file = path.join(diagramsDir, `${name}.${grade}.mmd`);
|
|
76
81
|
await writeFile(file, code.endsWith("\n") ? code : `${code}\n`, "utf8");
|
package/dist/index.d.ts
CHANGED
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
1
|
+
import type { ExtensionAPI, ExtensionContext } from "@earendil-works/pi-coding-agent";
|
|
2
2
|
import { type ContextMode } from "./config.js";
|
|
3
3
|
export interface ParsedRun {
|
|
4
4
|
target: string;
|
|
@@ -6,14 +6,22 @@ export interface ParsedRun {
|
|
|
6
6
|
contextMode?: ContextMode;
|
|
7
7
|
verbose: boolean;
|
|
8
8
|
debug: boolean;
|
|
9
|
+
judge?: string;
|
|
9
10
|
}
|
|
10
11
|
interface ParsedPlan {
|
|
11
12
|
request: string;
|
|
12
13
|
name?: string;
|
|
14
|
+
change?: string;
|
|
15
|
+
update?: boolean;
|
|
13
16
|
debug: boolean;
|
|
14
17
|
}
|
|
15
18
|
export declare function splitArguments(input: string): string[];
|
|
16
19
|
export declare function parseRun(input: string): ParsedRun;
|
|
17
20
|
export declare function parsePlan(input: string): ParsedPlan;
|
|
21
|
+
/**
|
|
22
|
+
* After a step that leaves the tree dirty, offer to commit it (or remind the user).
|
|
23
|
+
* A clean tree is what lets the next /dc-apply take a rollback snapshot.
|
|
24
|
+
*/
|
|
25
|
+
export declare function offerCommit(pi: ExtensionAPI, ctx: ExtensionContext, action: string, change: string): Promise<void>;
|
|
18
26
|
export default function deepClauseExtension(pi: ExtensionAPI): void;
|
|
19
27
|
export {};
|