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/src/config.ts
CHANGED
|
@@ -2,6 +2,21 @@ import { readFile, writeFile } from "node:fs/promises";
|
|
|
2
2
|
|
|
3
3
|
export type ContextMode = "turn" | "branch" | "isolated";
|
|
4
4
|
|
|
5
|
+
export interface JevJudgeConfig {
|
|
6
|
+
/** Whether the Jev (TypeSafe System One) backend may be used. */
|
|
7
|
+
enabled: boolean;
|
|
8
|
+
/** Model alias or pinned version passed to TypeSafe. */
|
|
9
|
+
model: string;
|
|
10
|
+
/** Environment variable holding the TypeSafe API key. */
|
|
11
|
+
apiKeyEnv: string;
|
|
12
|
+
}
|
|
13
|
+
|
|
14
|
+
export interface JudgmentConfig {
|
|
15
|
+
/** Default backend name: "llm", "jev", or a name registered by an extension. */
|
|
16
|
+
default: string;
|
|
17
|
+
jev: JevJudgeConfig;
|
|
18
|
+
}
|
|
19
|
+
|
|
5
20
|
export interface DeepClauseConfig {
|
|
6
21
|
version: 1;
|
|
7
22
|
contextMode: ContextMode;
|
|
@@ -10,6 +25,7 @@ export interface DeepClauseConfig {
|
|
|
10
25
|
maxTokens: number;
|
|
11
26
|
verbose: boolean;
|
|
12
27
|
modelToolEnabled: boolean;
|
|
28
|
+
judgment: JudgmentConfig;
|
|
13
29
|
}
|
|
14
30
|
|
|
15
31
|
export const DEFAULT_CONFIG: DeepClauseConfig = {
|
|
@@ -20,6 +36,10 @@ export const DEFAULT_CONFIG: DeepClauseConfig = {
|
|
|
20
36
|
maxTokens: 16_384,
|
|
21
37
|
verbose: false,
|
|
22
38
|
modelToolEnabled: false,
|
|
39
|
+
judgment: {
|
|
40
|
+
default: "llm",
|
|
41
|
+
jev: { enabled: false, model: "jev-latest", apiKeyEnv: "TYPESAFE_API_KEY" },
|
|
42
|
+
},
|
|
23
43
|
};
|
|
24
44
|
|
|
25
45
|
const isContextMode = (value: unknown): value is ContextMode =>
|
|
@@ -55,6 +75,42 @@ export async function loadConfig(path: string): Promise<DeepClauseConfig> {
|
|
|
55
75
|
maxTokens: positiveInteger("maxTokens", DEFAULT_CONFIG.maxTokens),
|
|
56
76
|
verbose: config.verbose === true,
|
|
57
77
|
modelToolEnabled: config.modelToolEnabled === true,
|
|
78
|
+
judgment: parseJudgmentConfig(config.judgment),
|
|
79
|
+
};
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function parseJudgmentConfig(value: unknown): JudgmentConfig {
|
|
83
|
+
if (value === undefined) return DEFAULT_CONFIG.judgment;
|
|
84
|
+
if (!value || typeof value !== "object" || Array.isArray(value)) {
|
|
85
|
+
throw new Error("judgment must be a JSON object");
|
|
86
|
+
}
|
|
87
|
+
const judgment = value as Record<string, unknown>;
|
|
88
|
+
const defaultBackend = judgment.default ?? DEFAULT_CONFIG.judgment.default;
|
|
89
|
+
if (typeof defaultBackend !== "string" || !defaultBackend.trim()) {
|
|
90
|
+
throw new Error("judgment.default must be a non-empty backend name");
|
|
91
|
+
}
|
|
92
|
+
|
|
93
|
+
const jevValue = judgment.jev ?? {};
|
|
94
|
+
if (!jevValue || typeof jevValue !== "object" || Array.isArray(jevValue)) {
|
|
95
|
+
throw new Error("judgment.jev must be a JSON object");
|
|
96
|
+
}
|
|
97
|
+
const jev = jevValue as Record<string, unknown>;
|
|
98
|
+
const model = jev.model ?? DEFAULT_CONFIG.judgment.jev.model;
|
|
99
|
+
const apiKeyEnv = jev.apiKeyEnv ?? DEFAULT_CONFIG.judgment.jev.apiKeyEnv;
|
|
100
|
+
if (typeof model !== "string" || !model.trim()) {
|
|
101
|
+
throw new Error("judgment.jev.model must be a non-empty string");
|
|
102
|
+
}
|
|
103
|
+
if (typeof apiKeyEnv !== "string" || !apiKeyEnv.trim()) {
|
|
104
|
+
throw new Error("judgment.jev.apiKeyEnv must be a non-empty environment variable name");
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
return {
|
|
108
|
+
default: defaultBackend.trim(),
|
|
109
|
+
jev: {
|
|
110
|
+
enabled: jev.enabled === true,
|
|
111
|
+
model: model.trim(),
|
|
112
|
+
apiKeyEnv: apiKeyEnv.trim(),
|
|
113
|
+
},
|
|
58
114
|
};
|
|
59
115
|
}
|
|
60
116
|
|
|
@@ -72,3 +128,38 @@ export async function setModelToolEnabled(configPath: string, enabled: boolean):
|
|
|
72
128
|
await writeFile(configPath, `${JSON.stringify({ ...existing, modelToolEnabled: enabled }, null, 2)}\n`, "utf8");
|
|
73
129
|
return loadConfig(configPath);
|
|
74
130
|
}
|
|
131
|
+
|
|
132
|
+
export interface JudgeConfigPatch {
|
|
133
|
+
/** Default backend name ("llm" or "jev"). */
|
|
134
|
+
default?: string;
|
|
135
|
+
/** Partial update of the Jev backend settings. */
|
|
136
|
+
jev?: Partial<JevJudgeConfig>;
|
|
137
|
+
}
|
|
138
|
+
|
|
139
|
+
/** Merge a judgment patch into the workspace config, preserving every other field. */
|
|
140
|
+
export async function setJudgeConfig(
|
|
141
|
+
configPath: string,
|
|
142
|
+
patch: JudgeConfigPatch,
|
|
143
|
+
): Promise<DeepClauseConfig> {
|
|
144
|
+
let existing: Record<string, unknown> = {};
|
|
145
|
+
try {
|
|
146
|
+
const parsed: unknown = JSON.parse(await readFile(configPath, "utf8"));
|
|
147
|
+
if (parsed && typeof parsed === "object" && !Array.isArray(parsed)) existing = parsed as Record<string, unknown>;
|
|
148
|
+
} catch (error) {
|
|
149
|
+
if ((error as NodeJS.ErrnoException).code !== "ENOENT") {
|
|
150
|
+
throw new Error(`Invalid DeepClause config: ${error instanceof Error ? error.message : String(error)}`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
|
|
154
|
+
const record = (value: unknown): Record<string, unknown> =>
|
|
155
|
+
value && typeof value === "object" && !Array.isArray(value) ? (value as Record<string, unknown>) : {};
|
|
156
|
+
|
|
157
|
+
const nextJudgment = {
|
|
158
|
+
...record(existing.judgment),
|
|
159
|
+
...(patch.default !== undefined ? { default: patch.default } : {}),
|
|
160
|
+
jev: { ...record(record(existing.judgment).jev), ...(patch.jev ?? {}) },
|
|
161
|
+
};
|
|
162
|
+
|
|
163
|
+
await writeFile(configPath, `${JSON.stringify({ ...existing, judgment: nextJudgment }, null, 2)}\n`, "utf8");
|
|
164
|
+
return loadConfig(configPath);
|
|
165
|
+
}
|
package/src/diagram/viewer.ts
CHANGED
|
@@ -108,6 +108,17 @@ export async function buildViewer(options: BuildViewerOptions): Promise<ViewerBu
|
|
|
108
108
|
return { viewerPath, diagramsDir: diagrams, entries };
|
|
109
109
|
}
|
|
110
110
|
|
|
111
|
+
export async function buildEntriesViewer(options: {
|
|
112
|
+
cwd: string;
|
|
113
|
+
templateText: string;
|
|
114
|
+
vendorAssetPath: string;
|
|
115
|
+
entries: DiagramEntry[];
|
|
116
|
+
}): Promise<ViewerBuildResult> {
|
|
117
|
+
const { diagrams, vendorFile } = await ensureDiagramDir(options.cwd, options.vendorAssetPath);
|
|
118
|
+
const viewerPath = await renderViewer(diagrams, options.entries, options.templateText, vendorFile);
|
|
119
|
+
return { viewerPath, diagramsDir: diagrams, entries: options.entries };
|
|
120
|
+
}
|
|
121
|
+
|
|
111
122
|
export async function writeSidecar(diagramsDir: string, name: string, grade: DiagramGrade, code: string): Promise<string> {
|
|
112
123
|
const file = path.join(diagramsDir, `${name}.${grade}.mmd`);
|
|
113
124
|
await writeFile(file, code.endsWith("\n") ? code : `${code}\n`, "utf8");
|