@wrongstack/sdd 0.308.7 → 0.309.1
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/dist/index.js +26 -8
- package/dist/task-graph-store.d.ts +9 -0
- package/package.json +4 -4
package/dist/index.js
CHANGED
|
@@ -935,8 +935,26 @@ var TaskGraphStore = class {
|
|
|
935
935
|
async deleteGraph(id) {
|
|
936
936
|
await this.delete(id);
|
|
937
937
|
}
|
|
938
|
+
/**
|
|
939
|
+
* Resolve a graph id to its file, refusing anything that escapes `baseDir`.
|
|
940
|
+
*
|
|
941
|
+
* `id` arrives straight from a WebSocket payload (`specs.taskStatus` casts it
|
|
942
|
+
* with no validation), and this used to be a bare `path.join` — so
|
|
943
|
+
* `../../../Users/me/secret` resolved outside the store and `load()` returned
|
|
944
|
+
* its contents to the caller. Mirrors the containment `kanban/storage.ts`
|
|
945
|
+
* already applies to board ids.
|
|
946
|
+
*/
|
|
938
947
|
filePath(id) {
|
|
939
|
-
|
|
948
|
+
if (typeof id !== "string" || id.length === 0 || id.length > 200 || /[\0]/.test(id)) {
|
|
949
|
+
throw new Error(`Invalid task-graph id: ${JSON.stringify(id)}`);
|
|
950
|
+
}
|
|
951
|
+
const dir = path2.resolve(this.baseDir);
|
|
952
|
+
const resolved = path2.resolve(dir, `${id}.json`);
|
|
953
|
+
const rel = path2.relative(dir, resolved);
|
|
954
|
+
if (rel.startsWith("..") || path2.isAbsolute(rel) || rel.includes(path2.sep)) {
|
|
955
|
+
throw new Error(`Invalid task-graph id: ${JSON.stringify(id)}`);
|
|
956
|
+
}
|
|
957
|
+
return resolved;
|
|
940
958
|
}
|
|
941
959
|
async readIndex() {
|
|
942
960
|
try {
|
|
@@ -5479,7 +5497,7 @@ function makeCommandVerifier(options = {}) {
|
|
|
5479
5497
|
return { ok: false, reason: `verification command is malformed: ${rawCommand}` };
|
|
5480
5498
|
}
|
|
5481
5499
|
const [executable, ...args] = argv;
|
|
5482
|
-
return await new Promise((
|
|
5500
|
+
return await new Promise((resolve2) => {
|
|
5483
5501
|
const child = spawn(executable, args, {
|
|
5484
5502
|
cwd: info.cwd,
|
|
5485
5503
|
shell: false,
|
|
@@ -5490,18 +5508,18 @@ function makeCommandVerifier(options = {}) {
|
|
|
5490
5508
|
const timer = setTimeout(() => {
|
|
5491
5509
|
timedOut = true;
|
|
5492
5510
|
child.kill();
|
|
5493
|
-
|
|
5511
|
+
resolve2({ ok: false, reason: `verification timed out: ${rawCommand}` });
|
|
5494
5512
|
}, timeoutMs);
|
|
5495
5513
|
child.on("exit", (code) => {
|
|
5496
5514
|
clearTimeout(timer);
|
|
5497
5515
|
if (timedOut) return;
|
|
5498
|
-
|
|
5516
|
+
resolve2(
|
|
5499
5517
|
code === 0 ? { ok: true } : { ok: false, reason: `verification failed (exit ${code}): ${rawCommand}` }
|
|
5500
5518
|
);
|
|
5501
5519
|
});
|
|
5502
5520
|
child.on("error", (err) => {
|
|
5503
5521
|
clearTimeout(timer);
|
|
5504
|
-
|
|
5522
|
+
resolve2({ ok: false, reason: `verification spawn error: ${String(err)}` });
|
|
5505
5523
|
});
|
|
5506
5524
|
});
|
|
5507
5525
|
};
|
|
@@ -5662,7 +5680,7 @@ async function decomposeNonAtomicTasks(opts) {
|
|
|
5662
5680
|
|
|
5663
5681
|
// src/conflict-resolver.ts
|
|
5664
5682
|
import { readFile as readFile6, writeFile } from "node:fs/promises";
|
|
5665
|
-
import { isAbsolute, join as join6 } from "node:path";
|
|
5683
|
+
import { isAbsolute as isAbsolute2, join as join6 } from "node:path";
|
|
5666
5684
|
import { readBundledInstructionText as readBundledInstructionText2, renderInstructionTemplate as renderInstructionTemplate2 } from "@wrongstack/core/utils";
|
|
5667
5685
|
var defaultFileIO = {
|
|
5668
5686
|
read: (path6) => readFile6(path6, "utf8"),
|
|
@@ -5711,7 +5729,7 @@ function makePreferSideConflictResolver(side, io = defaultFileIO) {
|
|
|
5711
5729
|
return async function conflictResolver(info) {
|
|
5712
5730
|
if (info.conflictFiles.length === 0) return false;
|
|
5713
5731
|
for (const rel of info.conflictFiles) {
|
|
5714
|
-
const abs =
|
|
5732
|
+
const abs = isAbsolute2(rel) ? rel : join6(info.cwd, rel);
|
|
5715
5733
|
let content;
|
|
5716
5734
|
try {
|
|
5717
5735
|
content = await io.read(abs);
|
|
@@ -5745,7 +5763,7 @@ function makeLlmConflictResolver(opts) {
|
|
|
5745
5763
|
return async function conflictResolver(info) {
|
|
5746
5764
|
if (info.conflictFiles.length === 0) return false;
|
|
5747
5765
|
for (const rel of info.conflictFiles) {
|
|
5748
|
-
const abs =
|
|
5766
|
+
const abs = isAbsolute2(rel) ? rel : join6(info.cwd, rel);
|
|
5749
5767
|
let content;
|
|
5750
5768
|
try {
|
|
5751
5769
|
content = await io.read(abs);
|
|
@@ -35,6 +35,15 @@ export declare class TaskGraphStore implements TaskStore {
|
|
|
35
35
|
updatedAt: number;
|
|
36
36
|
}>>;
|
|
37
37
|
deleteGraph(id: string): Promise<void>;
|
|
38
|
+
/**
|
|
39
|
+
* Resolve a graph id to its file, refusing anything that escapes `baseDir`.
|
|
40
|
+
*
|
|
41
|
+
* `id` arrives straight from a WebSocket payload (`specs.taskStatus` casts it
|
|
42
|
+
* with no validation), and this used to be a bare `path.join` — so
|
|
43
|
+
* `../../../Users/me/secret` resolved outside the store and `load()` returned
|
|
44
|
+
* its contents to the caller. Mirrors the containment `kanban/storage.ts`
|
|
45
|
+
* already applies to board ids.
|
|
46
|
+
*/
|
|
38
47
|
private filePath;
|
|
39
48
|
private readIndex;
|
|
40
49
|
private updateIndex;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wrongstack/sdd",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.309.1",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "WrongStack Spec-Driven Development engine — standalone package extracted from @wrongstack/core. Task graph generation, tracking, execution, lifecycle management, and AI-driven spec building for SDD workflows.",
|
|
6
6
|
"repository": {
|
|
@@ -27,9 +27,9 @@
|
|
|
27
27
|
"!dist/**/*.map"
|
|
28
28
|
],
|
|
29
29
|
"dependencies": {
|
|
30
|
-
"@wrongstack/
|
|
31
|
-
"@wrongstack/
|
|
32
|
-
"@wrongstack/
|
|
30
|
+
"@wrongstack/requirement-intake": "0.309.1",
|
|
31
|
+
"@wrongstack/core": "0.309.1",
|
|
32
|
+
"@wrongstack/kanban": "0.309.1"
|
|
33
33
|
},
|
|
34
34
|
"devDependencies": {
|
|
35
35
|
"@types/node": "^26.2.0",
|