sequant 1.0.0 → 1.1.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/README.md +12 -8
- package/dist/bin/cli.js +12 -0
- package/dist/bin/cli.js.map +1 -1
- package/dist/src/commands/doctor.d.ts.map +1 -1
- package/dist/src/commands/doctor.js +46 -0
- package/dist/src/commands/doctor.js.map +1 -1
- package/dist/src/commands/doctor.test.d.ts +2 -0
- package/dist/src/commands/doctor.test.d.ts.map +1 -0
- package/dist/src/commands/doctor.test.js +140 -0
- package/dist/src/commands/doctor.test.js.map +1 -0
- package/dist/src/commands/init.d.ts.map +1 -1
- package/dist/src/commands/init.js +45 -2
- package/dist/src/commands/init.js.map +1 -1
- package/dist/src/commands/init.test.d.ts +2 -0
- package/dist/src/commands/init.test.d.ts.map +1 -0
- package/dist/src/commands/init.test.js +152 -0
- package/dist/src/commands/init.test.js.map +1 -0
- package/dist/src/commands/logs.d.ts +18 -0
- package/dist/src/commands/logs.d.ts.map +1 -0
- package/dist/src/commands/logs.js +188 -0
- package/dist/src/commands/logs.js.map +1 -0
- package/dist/src/commands/run.d.ts +2 -0
- package/dist/src/commands/run.d.ts.map +1 -1
- package/dist/src/commands/run.js +114 -29
- package/dist/src/commands/run.js.map +1 -1
- package/dist/src/lib/stacks.d.ts.map +1 -1
- package/dist/src/lib/stacks.js +39 -0
- package/dist/src/lib/stacks.js.map +1 -1
- package/dist/src/lib/stacks.test.d.ts +2 -0
- package/dist/src/lib/stacks.test.d.ts.map +1 -0
- package/dist/src/lib/stacks.test.js +145 -0
- package/dist/src/lib/stacks.test.js.map +1 -0
- package/dist/src/lib/system.d.ts +16 -0
- package/dist/src/lib/system.d.ts.map +1 -0
- package/dist/src/lib/system.js +52 -0
- package/dist/src/lib/system.js.map +1 -0
- package/dist/src/lib/system.test.d.ts +2 -0
- package/dist/src/lib/system.test.d.ts.map +1 -0
- package/dist/src/lib/system.test.js +80 -0
- package/dist/src/lib/system.test.js.map +1 -0
- package/dist/src/lib/workflow/log-writer.d.ts +83 -0
- package/dist/src/lib/workflow/log-writer.d.ts.map +1 -0
- package/dist/src/lib/workflow/log-writer.js +193 -0
- package/dist/src/lib/workflow/log-writer.js.map +1 -0
- package/dist/src/lib/workflow/run-log-schema.d.ts +261 -0
- package/dist/src/lib/workflow/run-log-schema.d.ts.map +1 -0
- package/dist/src/lib/workflow/run-log-schema.js +234 -0
- package/dist/src/lib/workflow/run-log-schema.js.map +1 -0
- package/package.json +6 -4
- package/stacks/astro.yaml +35 -0
- package/templates/hooks/post-tool.sh +0 -11
- package/templates/hooks/pre-tool.sh +2 -2
- package/templates/memory/constitution.md +8 -0
- package/templates/scripts/cleanup-worktree.sh +1 -1
- package/templates/scripts/new-feature.sh +7 -5
- package/templates/skills/assess/SKILL.md +31 -16
- package/templates/skills/clean/SKILL.md +17 -2
- package/templates/skills/docs/SKILL.md +48 -34
- package/templates/skills/exec/SKILL.md +31 -25
- package/templates/skills/fullsolve/SKILL.md +34 -16
- package/templates/skills/loop/SKILL.md +22 -5
- package/templates/skills/qa/SKILL.md +89 -4
- package/templates/skills/qa/references/code-quality-exemplars.md +23 -28
- package/templates/skills/qa/references/code-review-checklist.md +6 -17
- package/templates/skills/qa/scripts/quality-checks.sh +4 -17
- package/templates/skills/reflect/SKILL.md +18 -2
- package/templates/skills/reflect/references/documentation-tiers.md +3 -3
- package/templates/skills/security-review/SKILL.md +15 -0
- package/templates/skills/security-review/references/security-checklists.md +10 -8
- package/templates/skills/solve/SKILL.md +147 -149
- package/templates/skills/spec/SKILL.md +61 -3
- package/templates/skills/spec/references/parallel-groups.md +1 -1
- package/templates/skills/spec/references/verification-criteria.md +1 -1
- package/templates/skills/test/SKILL.md +20 -5
- package/templates/skills/testgen/SKILL.md +15 -1
- package/templates/skills/verify/SKILL.md +20 -5
- package/templates/skills/reflect/scripts/workflow-queries.ts +0 -165
|
@@ -0,0 +1,145 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
import { detectStack, getStackConfig, STACKS } from "./stacks.js";
|
|
3
|
+
// Mock the fs module
|
|
4
|
+
vi.mock("./fs.js", () => ({
|
|
5
|
+
fileExists: vi.fn(),
|
|
6
|
+
readFile: vi.fn(),
|
|
7
|
+
}));
|
|
8
|
+
import { fileExists, readFile } from "./fs.js";
|
|
9
|
+
const mockFileExists = vi.mocked(fileExists);
|
|
10
|
+
const mockReadFile = vi.mocked(readFile);
|
|
11
|
+
describe("STACKS", () => {
|
|
12
|
+
describe("astro config", () => {
|
|
13
|
+
it("has correct detection files", () => {
|
|
14
|
+
expect(STACKS.astro.detection.files).toEqual([
|
|
15
|
+
"astro.config.mjs",
|
|
16
|
+
"astro.config.js",
|
|
17
|
+
"astro.config.ts",
|
|
18
|
+
]);
|
|
19
|
+
});
|
|
20
|
+
it("has astro in packageDeps", () => {
|
|
21
|
+
expect(STACKS.astro.detection.packageDeps).toContain("astro");
|
|
22
|
+
});
|
|
23
|
+
it("has correct commands", () => {
|
|
24
|
+
expect(STACKS.astro.commands.build).toBe("npm run build");
|
|
25
|
+
expect(STACKS.astro.commands.dev).toBe("npm run dev");
|
|
26
|
+
expect(STACKS.astro.commands.test).toBe("npm test");
|
|
27
|
+
expect(STACKS.astro.commands.lint).toBe("npm run lint");
|
|
28
|
+
});
|
|
29
|
+
});
|
|
30
|
+
});
|
|
31
|
+
describe("detectStack", () => {
|
|
32
|
+
beforeEach(() => {
|
|
33
|
+
vi.resetAllMocks();
|
|
34
|
+
mockFileExists.mockResolvedValue(false);
|
|
35
|
+
mockReadFile.mockResolvedValue("{}");
|
|
36
|
+
});
|
|
37
|
+
describe("Astro detection", () => {
|
|
38
|
+
it("detects astro.config.mjs", async () => {
|
|
39
|
+
mockFileExists.mockImplementation(async (path) => {
|
|
40
|
+
return path === "astro.config.mjs";
|
|
41
|
+
});
|
|
42
|
+
const result = await detectStack();
|
|
43
|
+
expect(result).toBe("astro");
|
|
44
|
+
});
|
|
45
|
+
it("detects astro.config.js", async () => {
|
|
46
|
+
mockFileExists.mockImplementation(async (path) => {
|
|
47
|
+
return path === "astro.config.js";
|
|
48
|
+
});
|
|
49
|
+
const result = await detectStack();
|
|
50
|
+
expect(result).toBe("astro");
|
|
51
|
+
});
|
|
52
|
+
it("detects astro.config.ts", async () => {
|
|
53
|
+
mockFileExists.mockImplementation(async (path) => {
|
|
54
|
+
return path === "astro.config.ts";
|
|
55
|
+
});
|
|
56
|
+
const result = await detectStack();
|
|
57
|
+
expect(result).toBe("astro");
|
|
58
|
+
});
|
|
59
|
+
it("detects astro in dependencies via package.json", async () => {
|
|
60
|
+
mockFileExists.mockImplementation(async (path) => {
|
|
61
|
+
return path === "package.json";
|
|
62
|
+
});
|
|
63
|
+
mockReadFile.mockResolvedValue(JSON.stringify({
|
|
64
|
+
dependencies: { astro: "^4.0.0" },
|
|
65
|
+
}));
|
|
66
|
+
const result = await detectStack();
|
|
67
|
+
expect(result).toBe("astro");
|
|
68
|
+
});
|
|
69
|
+
it("detects astro in devDependencies via package.json", async () => {
|
|
70
|
+
mockFileExists.mockImplementation(async (path) => {
|
|
71
|
+
return path === "package.json";
|
|
72
|
+
});
|
|
73
|
+
mockReadFile.mockResolvedValue(JSON.stringify({
|
|
74
|
+
devDependencies: { astro: "^4.0.0" },
|
|
75
|
+
}));
|
|
76
|
+
const result = await detectStack();
|
|
77
|
+
expect(result).toBe("astro");
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
describe("priority", () => {
|
|
81
|
+
it("Next.js takes priority over Astro when both present", async () => {
|
|
82
|
+
mockFileExists.mockImplementation(async (path) => {
|
|
83
|
+
return path === "next.config.js" || path === "astro.config.mjs";
|
|
84
|
+
});
|
|
85
|
+
const result = await detectStack();
|
|
86
|
+
expect(result).toBe("nextjs");
|
|
87
|
+
});
|
|
88
|
+
it("Next.js dep takes priority over Astro dep", async () => {
|
|
89
|
+
mockFileExists.mockImplementation(async (path) => {
|
|
90
|
+
return path === "package.json";
|
|
91
|
+
});
|
|
92
|
+
mockReadFile.mockResolvedValue(JSON.stringify({
|
|
93
|
+
dependencies: { next: "^14.0.0", astro: "^4.0.0" },
|
|
94
|
+
}));
|
|
95
|
+
const result = await detectStack();
|
|
96
|
+
expect(result).toBe("nextjs");
|
|
97
|
+
});
|
|
98
|
+
it("Astro config file takes priority over Rust", async () => {
|
|
99
|
+
mockFileExists.mockImplementation(async (path) => {
|
|
100
|
+
return path === "astro.config.mjs" || path === "Cargo.toml";
|
|
101
|
+
});
|
|
102
|
+
const result = await detectStack();
|
|
103
|
+
expect(result).toBe("astro");
|
|
104
|
+
});
|
|
105
|
+
});
|
|
106
|
+
describe("edge cases", () => {
|
|
107
|
+
it("returns null when no stack detected", async () => {
|
|
108
|
+
mockFileExists.mockResolvedValue(false);
|
|
109
|
+
const result = await detectStack();
|
|
110
|
+
expect(result).toBeNull();
|
|
111
|
+
});
|
|
112
|
+
it("handles malformed package.json gracefully", async () => {
|
|
113
|
+
mockFileExists.mockImplementation(async (path) => {
|
|
114
|
+
return path === "package.json";
|
|
115
|
+
});
|
|
116
|
+
mockReadFile.mockResolvedValue("{ invalid json }");
|
|
117
|
+
const result = await detectStack();
|
|
118
|
+
expect(result).toBeNull();
|
|
119
|
+
});
|
|
120
|
+
it("handles empty package.json", async () => {
|
|
121
|
+
mockFileExists.mockImplementation(async (path) => {
|
|
122
|
+
return path === "package.json";
|
|
123
|
+
});
|
|
124
|
+
mockReadFile.mockResolvedValue("{}");
|
|
125
|
+
const result = await detectStack();
|
|
126
|
+
expect(result).toBeNull();
|
|
127
|
+
});
|
|
128
|
+
});
|
|
129
|
+
});
|
|
130
|
+
describe("getStackConfig", () => {
|
|
131
|
+
it("returns astro config for astro stack", () => {
|
|
132
|
+
const config = getStackConfig("astro");
|
|
133
|
+
expect(config.name).toBe("astro");
|
|
134
|
+
expect(config.displayName).toBe("Astro");
|
|
135
|
+
});
|
|
136
|
+
it("returns generic config for unknown stack", () => {
|
|
137
|
+
const config = getStackConfig("unknown-stack");
|
|
138
|
+
expect(config.name).toBe("generic");
|
|
139
|
+
});
|
|
140
|
+
it("returns generic config for empty string", () => {
|
|
141
|
+
const config = getStackConfig("");
|
|
142
|
+
expect(config.name).toBe("generic");
|
|
143
|
+
});
|
|
144
|
+
});
|
|
145
|
+
//# sourceMappingURL=stacks.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"stacks.test.js","sourceRoot":"","sources":["../../../src/lib/stacks.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* System utility functions for checking prerequisites
|
|
3
|
+
*/
|
|
4
|
+
/**
|
|
5
|
+
* Check if a command exists on the system
|
|
6
|
+
*/
|
|
7
|
+
export declare function commandExists(cmd: string): boolean;
|
|
8
|
+
/**
|
|
9
|
+
* Check if gh CLI is authenticated
|
|
10
|
+
*/
|
|
11
|
+
export declare function isGhAuthenticated(): boolean;
|
|
12
|
+
/**
|
|
13
|
+
* Get platform-specific install hint for a package
|
|
14
|
+
*/
|
|
15
|
+
export declare function getInstallHint(pkg: string): string;
|
|
16
|
+
//# sourceMappingURL=system.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"system.d.ts","sourceRoot":"","sources":["../../../src/lib/system.ts"],"names":[],"mappings":"AAAA;;GAEG;AAIH;;GAEG;AACH,wBAAgB,aAAa,CAAC,GAAG,EAAE,MAAM,GAAG,OAAO,CAOlD;AAED;;GAEG;AACH,wBAAgB,iBAAiB,IAAI,OAAO,CAO3C;AAED;;GAEG;AACH,wBAAgB,cAAc,CAAC,GAAG,EAAE,MAAM,GAAG,MAAM,CAsBlD"}
|
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* System utility functions for checking prerequisites
|
|
3
|
+
*/
|
|
4
|
+
import { execSync } from "child_process";
|
|
5
|
+
/**
|
|
6
|
+
* Check if a command exists on the system
|
|
7
|
+
*/
|
|
8
|
+
export function commandExists(cmd) {
|
|
9
|
+
try {
|
|
10
|
+
execSync(`command -v ${cmd}`, { stdio: "ignore" });
|
|
11
|
+
return true;
|
|
12
|
+
}
|
|
13
|
+
catch {
|
|
14
|
+
return false;
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
/**
|
|
18
|
+
* Check if gh CLI is authenticated
|
|
19
|
+
*/
|
|
20
|
+
export function isGhAuthenticated() {
|
|
21
|
+
try {
|
|
22
|
+
execSync("gh auth status", { stdio: "ignore" });
|
|
23
|
+
return true;
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return false;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Get platform-specific install hint for a package
|
|
31
|
+
*/
|
|
32
|
+
export function getInstallHint(pkg) {
|
|
33
|
+
const platform = process.platform;
|
|
34
|
+
const hints = {
|
|
35
|
+
jq: {
|
|
36
|
+
darwin: "brew install jq",
|
|
37
|
+
linux: "apt install jq # or: yum install jq",
|
|
38
|
+
win32: "choco install jq # or: scoop install jq",
|
|
39
|
+
},
|
|
40
|
+
gh: {
|
|
41
|
+
darwin: "brew install gh",
|
|
42
|
+
linux: "apt install gh # see: https://cli.github.com",
|
|
43
|
+
win32: "choco install gh # or: winget install GitHub.cli",
|
|
44
|
+
},
|
|
45
|
+
};
|
|
46
|
+
const pkgHints = hints[pkg];
|
|
47
|
+
if (!pkgHints) {
|
|
48
|
+
return `Install ${pkg}`;
|
|
49
|
+
}
|
|
50
|
+
return pkgHints[platform] || pkgHints["linux"] || `Install ${pkg}`;
|
|
51
|
+
}
|
|
52
|
+
//# sourceMappingURL=system.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"system.js","sourceRoot":"","sources":["../../../src/lib/system.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,QAAQ,EAAE,MAAM,eAAe,CAAC;AAEzC;;GAEG;AACH,MAAM,UAAU,aAAa,CAAC,GAAW;IACvC,IAAI,CAAC;QACH,QAAQ,CAAC,cAAc,GAAG,EAAE,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QACnD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,iBAAiB;IAC/B,IAAI,CAAC;QACH,QAAQ,CAAC,gBAAgB,EAAE,EAAE,KAAK,EAAE,QAAQ,EAAE,CAAC,CAAC;QAChD,OAAO,IAAI,CAAC;IACd,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,KAAK,CAAC;IACf,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,cAAc,CAAC,GAAW;IACxC,MAAM,QAAQ,GAAG,OAAO,CAAC,QAAQ,CAAC;IAElC,MAAM,KAAK,GAA2C;QACpD,EAAE,EAAE;YACF,MAAM,EAAE,iBAAiB;YACzB,KAAK,EAAE,sCAAsC;YAC7C,KAAK,EAAE,0CAA0C;SAClD;QACD,EAAE,EAAE;YACF,MAAM,EAAE,iBAAiB;YACzB,KAAK,EAAE,+CAA+C;YACtD,KAAK,EAAE,mDAAmD;SAC3D;KACF,CAAC;IAEF,MAAM,QAAQ,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC;IAC5B,IAAI,CAAC,QAAQ,EAAE,CAAC;QACd,OAAO,WAAW,GAAG,EAAE,CAAC;IAC1B,CAAC;IAED,OAAO,QAAQ,CAAC,QAAQ,CAAC,IAAI,QAAQ,CAAC,OAAO,CAAC,IAAI,WAAW,GAAG,EAAE,CAAC;AACrE,CAAC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"system.test.d.ts","sourceRoot":"","sources":["../../../src/lib/system.test.ts"],"names":[],"mappings":""}
|
|
@@ -0,0 +1,80 @@
|
|
|
1
|
+
import { describe, it, expect, vi, beforeEach } from "vitest";
|
|
2
|
+
import { execSync } from "child_process";
|
|
3
|
+
// Mock child_process
|
|
4
|
+
vi.mock("child_process", () => ({
|
|
5
|
+
execSync: vi.fn(),
|
|
6
|
+
}));
|
|
7
|
+
import { commandExists, isGhAuthenticated, getInstallHint } from "./system.js";
|
|
8
|
+
const mockExecSync = vi.mocked(execSync);
|
|
9
|
+
describe("system utilities", () => {
|
|
10
|
+
beforeEach(() => {
|
|
11
|
+
vi.resetAllMocks();
|
|
12
|
+
});
|
|
13
|
+
describe("commandExists", () => {
|
|
14
|
+
it("returns true when command exists", () => {
|
|
15
|
+
mockExecSync.mockReturnValue(Buffer.from("/usr/local/bin/gh"));
|
|
16
|
+
expect(commandExists("gh")).toBe(true);
|
|
17
|
+
expect(mockExecSync).toHaveBeenCalledWith("command -v gh", {
|
|
18
|
+
stdio: "ignore",
|
|
19
|
+
});
|
|
20
|
+
});
|
|
21
|
+
it("returns false when command does not exist", () => {
|
|
22
|
+
mockExecSync.mockImplementation(() => {
|
|
23
|
+
throw new Error("command not found");
|
|
24
|
+
});
|
|
25
|
+
expect(commandExists("nonexistent")).toBe(false);
|
|
26
|
+
});
|
|
27
|
+
it("checks different commands correctly", () => {
|
|
28
|
+
mockExecSync.mockReturnValue(Buffer.from("/usr/local/bin/jq"));
|
|
29
|
+
expect(commandExists("jq")).toBe(true);
|
|
30
|
+
expect(mockExecSync).toHaveBeenCalledWith("command -v jq", {
|
|
31
|
+
stdio: "ignore",
|
|
32
|
+
});
|
|
33
|
+
});
|
|
34
|
+
});
|
|
35
|
+
describe("isGhAuthenticated", () => {
|
|
36
|
+
it("returns true when gh is authenticated", () => {
|
|
37
|
+
mockExecSync.mockReturnValue(Buffer.from(""));
|
|
38
|
+
expect(isGhAuthenticated()).toBe(true);
|
|
39
|
+
expect(mockExecSync).toHaveBeenCalledWith("gh auth status", {
|
|
40
|
+
stdio: "ignore",
|
|
41
|
+
});
|
|
42
|
+
});
|
|
43
|
+
it("returns false when gh is not authenticated", () => {
|
|
44
|
+
mockExecSync.mockImplementation(() => {
|
|
45
|
+
throw new Error("not authenticated");
|
|
46
|
+
});
|
|
47
|
+
expect(isGhAuthenticated()).toBe(false);
|
|
48
|
+
});
|
|
49
|
+
});
|
|
50
|
+
describe("getInstallHint", () => {
|
|
51
|
+
const originalPlatform = process.platform;
|
|
52
|
+
beforeEach(() => {
|
|
53
|
+
// Reset platform after each test
|
|
54
|
+
Object.defineProperty(process, "platform", {
|
|
55
|
+
value: originalPlatform,
|
|
56
|
+
writable: true,
|
|
57
|
+
});
|
|
58
|
+
});
|
|
59
|
+
it("returns macOS hint for gh on darwin", () => {
|
|
60
|
+
Object.defineProperty(process, "platform", { value: "darwin" });
|
|
61
|
+
expect(getInstallHint("gh")).toBe("brew install gh");
|
|
62
|
+
});
|
|
63
|
+
it("returns macOS hint for jq on darwin", () => {
|
|
64
|
+
Object.defineProperty(process, "platform", { value: "darwin" });
|
|
65
|
+
expect(getInstallHint("jq")).toBe("brew install jq");
|
|
66
|
+
});
|
|
67
|
+
it("returns Linux hint for gh on linux", () => {
|
|
68
|
+
Object.defineProperty(process, "platform", { value: "linux" });
|
|
69
|
+
expect(getInstallHint("gh")).toContain("apt install gh");
|
|
70
|
+
});
|
|
71
|
+
it("returns Windows hint for gh on win32", () => {
|
|
72
|
+
Object.defineProperty(process, "platform", { value: "win32" });
|
|
73
|
+
expect(getInstallHint("gh")).toContain("choco install gh");
|
|
74
|
+
});
|
|
75
|
+
it("returns generic hint for unknown package", () => {
|
|
76
|
+
expect(getInstallHint("unknown-package")).toBe("Install unknown-package");
|
|
77
|
+
});
|
|
78
|
+
});
|
|
79
|
+
});
|
|
80
|
+
//# sourceMappingURL=system.test.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"system.test.js","sourceRoot":"","sources":["../../../src/lib/system.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log writer for structured workflow run logs
|
|
3
|
+
*
|
|
4
|
+
* Writes JSON logs to disk for analysis and debugging.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { LogWriter } from './log-writer';
|
|
9
|
+
*
|
|
10
|
+
* const writer = new LogWriter({ projectPath: '.sequant/logs' });
|
|
11
|
+
* await writer.initialize(config);
|
|
12
|
+
* await writer.logPhase(phaseLog);
|
|
13
|
+
* await writer.finalize();
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
import { type RunLog, type RunConfig, type PhaseLog, type Phase } from "./run-log-schema.js";
|
|
17
|
+
export interface LogWriterOptions {
|
|
18
|
+
/** Path to log directory (default: .sequant/logs in current directory) */
|
|
19
|
+
logPath?: string;
|
|
20
|
+
/** Whether to also write to user-level logs */
|
|
21
|
+
writeToUserLogs?: boolean;
|
|
22
|
+
/** Enable verbose logging */
|
|
23
|
+
verbose?: boolean;
|
|
24
|
+
}
|
|
25
|
+
/**
|
|
26
|
+
* Manages writing structured run logs to disk
|
|
27
|
+
*/
|
|
28
|
+
export declare class LogWriter {
|
|
29
|
+
private runLog;
|
|
30
|
+
private currentIssue;
|
|
31
|
+
private logPath;
|
|
32
|
+
private writeToUserLogs;
|
|
33
|
+
private verbose;
|
|
34
|
+
constructor(options?: LogWriterOptions);
|
|
35
|
+
/**
|
|
36
|
+
* Initialize a new run log
|
|
37
|
+
*
|
|
38
|
+
* @param config - Run configuration
|
|
39
|
+
*/
|
|
40
|
+
initialize(config: RunConfig): Promise<void>;
|
|
41
|
+
/**
|
|
42
|
+
* Start logging a new issue
|
|
43
|
+
*
|
|
44
|
+
* @param issueNumber - GitHub issue number
|
|
45
|
+
* @param title - Issue title
|
|
46
|
+
* @param labels - Issue labels
|
|
47
|
+
*/
|
|
48
|
+
startIssue(issueNumber: number, title: string, labels: string[]): void;
|
|
49
|
+
/**
|
|
50
|
+
* Log a completed phase
|
|
51
|
+
*
|
|
52
|
+
* @param phaseLog - Complete phase log entry
|
|
53
|
+
*/
|
|
54
|
+
logPhase(phaseLog: PhaseLog): void;
|
|
55
|
+
/**
|
|
56
|
+
* Complete the current issue and add it to the run log
|
|
57
|
+
*/
|
|
58
|
+
completeIssue(): void;
|
|
59
|
+
/**
|
|
60
|
+
* Finalize the run log and write to disk
|
|
61
|
+
*
|
|
62
|
+
* @returns Path to the written log file
|
|
63
|
+
*/
|
|
64
|
+
finalize(): Promise<string>;
|
|
65
|
+
/**
|
|
66
|
+
* Get the current run log (for inspection)
|
|
67
|
+
*/
|
|
68
|
+
getRunLog(): Omit<RunLog, "endTime"> | null;
|
|
69
|
+
/**
|
|
70
|
+
* Get the run ID
|
|
71
|
+
*/
|
|
72
|
+
getRunId(): string | null;
|
|
73
|
+
private resolvePath;
|
|
74
|
+
private ensureLogDirectory;
|
|
75
|
+
private writeLogFile;
|
|
76
|
+
}
|
|
77
|
+
/**
|
|
78
|
+
* Create a simple phase log from timing data
|
|
79
|
+
*
|
|
80
|
+
* Utility function for creating phase logs when you have start/end times.
|
|
81
|
+
*/
|
|
82
|
+
export declare function createPhaseLogFromTiming(phase: Phase, issueNumber: number, startTime: Date, endTime: Date, status: PhaseLog["status"], options?: Partial<Pick<PhaseLog, "error" | "iterations" | "filesModified" | "testsRun" | "testsPassed">>): PhaseLog;
|
|
83
|
+
//# sourceMappingURL=log-writer.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-writer.d.ts","sourceRoot":"","sources":["../../../../src/lib/workflow/log-writer.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;;;;;GAcG;AAKH,OAAO,EACL,KAAK,MAAM,EACX,KAAK,SAAS,EAEd,KAAK,QAAQ,EACb,KAAK,KAAK,EAMX,MAAM,qBAAqB,CAAC;AAE7B,MAAM,WAAW,gBAAgB;IAC/B,0EAA0E;IAC1E,OAAO,CAAC,EAAE,MAAM,CAAC;IACjB,+CAA+C;IAC/C,eAAe,CAAC,EAAE,OAAO,CAAC;IAC1B,6BAA6B;IAC7B,OAAO,CAAC,EAAE,OAAO,CAAC;CACnB;AAED;;GAEG;AACH,qBAAa,SAAS;IACpB,OAAO,CAAC,MAAM,CAAwC;IACtD,OAAO,CAAC,YAAY,CAAkC;IACtD,OAAO,CAAC,OAAO,CAAS;IACxB,OAAO,CAAC,eAAe,CAAU;IACjC,OAAO,CAAC,OAAO,CAAU;gBAEb,OAAO,GAAE,gBAAqB;IAM1C;;;;OAIG;IACG,UAAU,CAAC,MAAM,EAAE,SAAS,GAAG,OAAO,CAAC,IAAI,CAAC;IAgBlD;;;;;;OAMG;IACH,UAAU,CAAC,WAAW,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,GAAG,IAAI;IAmBtE;;;;OAIG;IACH,QAAQ,CAAC,QAAQ,EAAE,QAAQ,GAAG,IAAI;IAwBlC;;OAEG;IACH,aAAa,IAAI,IAAI;IA+BrB;;;;OAIG;IACG,QAAQ,IAAI,OAAO,CAAC,MAAM,CAAC;IAiCjC;;OAEG;IACH,SAAS,IAAI,IAAI,CAAC,MAAM,EAAE,SAAS,CAAC,GAAG,IAAI;IAI3C;;OAEG;IACH,QAAQ,IAAI,MAAM,GAAG,IAAI;IAIzB,OAAO,CAAC,WAAW;YAIL,kBAAkB;YAOlB,YAAY;CAO3B;AAED;;;;GAIG;AACH,wBAAgB,wBAAwB,CACtC,KAAK,EAAE,KAAK,EACZ,WAAW,EAAE,MAAM,EACnB,SAAS,EAAE,IAAI,EACf,OAAO,EAAE,IAAI,EACb,MAAM,EAAE,QAAQ,CAAC,QAAQ,CAAC,EAC1B,OAAO,CAAC,EAAE,OAAO,CACf,IAAI,CACF,QAAQ,EACR,OAAO,GAAG,YAAY,GAAG,eAAe,GAAG,UAAU,GAAG,aAAa,CACtE,CACF,GACA,QAAQ,CAYV"}
|
|
@@ -0,0 +1,193 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Log writer for structured workflow run logs
|
|
3
|
+
*
|
|
4
|
+
* Writes JSON logs to disk for analysis and debugging.
|
|
5
|
+
*
|
|
6
|
+
* @example
|
|
7
|
+
* ```typescript
|
|
8
|
+
* import { LogWriter } from './log-writer';
|
|
9
|
+
*
|
|
10
|
+
* const writer = new LogWriter({ projectPath: '.sequant/logs' });
|
|
11
|
+
* await writer.initialize(config);
|
|
12
|
+
* await writer.logPhase(phaseLog);
|
|
13
|
+
* await writer.finalize();
|
|
14
|
+
* ```
|
|
15
|
+
*/
|
|
16
|
+
import * as fs from "fs";
|
|
17
|
+
import * as path from "path";
|
|
18
|
+
import * as os from "os";
|
|
19
|
+
import { createEmptyRunLog, finalizeRunLog, generateLogFilename, LOG_PATHS, } from "./run-log-schema.js";
|
|
20
|
+
/**
|
|
21
|
+
* Manages writing structured run logs to disk
|
|
22
|
+
*/
|
|
23
|
+
export class LogWriter {
|
|
24
|
+
runLog = null;
|
|
25
|
+
currentIssue = null;
|
|
26
|
+
logPath;
|
|
27
|
+
writeToUserLogs;
|
|
28
|
+
verbose;
|
|
29
|
+
constructor(options = {}) {
|
|
30
|
+
this.logPath = options.logPath ?? LOG_PATHS.project;
|
|
31
|
+
this.writeToUserLogs = options.writeToUserLogs ?? false;
|
|
32
|
+
this.verbose = options.verbose ?? false;
|
|
33
|
+
}
|
|
34
|
+
/**
|
|
35
|
+
* Initialize a new run log
|
|
36
|
+
*
|
|
37
|
+
* @param config - Run configuration
|
|
38
|
+
*/
|
|
39
|
+
async initialize(config) {
|
|
40
|
+
this.runLog = createEmptyRunLog(config);
|
|
41
|
+
// Ensure log directory exists
|
|
42
|
+
await this.ensureLogDirectory(this.logPath);
|
|
43
|
+
if (this.writeToUserLogs) {
|
|
44
|
+
const userPath = LOG_PATHS.user.replace("~", os.homedir());
|
|
45
|
+
await this.ensureLogDirectory(userPath);
|
|
46
|
+
}
|
|
47
|
+
if (this.verbose && this.runLog) {
|
|
48
|
+
console.log(`📝 Log initialized: ${this.runLog.runId}`);
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
/**
|
|
52
|
+
* Start logging a new issue
|
|
53
|
+
*
|
|
54
|
+
* @param issueNumber - GitHub issue number
|
|
55
|
+
* @param title - Issue title
|
|
56
|
+
* @param labels - Issue labels
|
|
57
|
+
*/
|
|
58
|
+
startIssue(issueNumber, title, labels) {
|
|
59
|
+
if (!this.runLog) {
|
|
60
|
+
throw new Error("LogWriter not initialized. Call initialize() first.");
|
|
61
|
+
}
|
|
62
|
+
this.currentIssue = {
|
|
63
|
+
issueNumber,
|
|
64
|
+
title,
|
|
65
|
+
labels,
|
|
66
|
+
phases: [],
|
|
67
|
+
status: "success",
|
|
68
|
+
totalDurationSeconds: 0,
|
|
69
|
+
};
|
|
70
|
+
if (this.verbose) {
|
|
71
|
+
console.log(`📝 Started logging issue #${issueNumber}`);
|
|
72
|
+
}
|
|
73
|
+
}
|
|
74
|
+
/**
|
|
75
|
+
* Log a completed phase
|
|
76
|
+
*
|
|
77
|
+
* @param phaseLog - Complete phase log entry
|
|
78
|
+
*/
|
|
79
|
+
logPhase(phaseLog) {
|
|
80
|
+
if (!this.currentIssue) {
|
|
81
|
+
throw new Error("No current issue. Call startIssue() first.");
|
|
82
|
+
}
|
|
83
|
+
this.currentIssue.phases = [...(this.currentIssue.phases ?? []), phaseLog];
|
|
84
|
+
// Update issue status based on phase result
|
|
85
|
+
if (phaseLog.status === "failure") {
|
|
86
|
+
this.currentIssue.status = "failure";
|
|
87
|
+
}
|
|
88
|
+
else if (phaseLog.status === "timeout" &&
|
|
89
|
+
this.currentIssue.status !== "failure") {
|
|
90
|
+
this.currentIssue.status = "partial";
|
|
91
|
+
}
|
|
92
|
+
if (this.verbose) {
|
|
93
|
+
console.log(`📝 Logged phase: ${phaseLog.phase} (${phaseLog.status}) - ${phaseLog.durationSeconds.toFixed(1)}s`);
|
|
94
|
+
}
|
|
95
|
+
}
|
|
96
|
+
/**
|
|
97
|
+
* Complete the current issue and add it to the run log
|
|
98
|
+
*/
|
|
99
|
+
completeIssue() {
|
|
100
|
+
if (!this.runLog || !this.currentIssue) {
|
|
101
|
+
throw new Error("No current issue to complete.");
|
|
102
|
+
}
|
|
103
|
+
// Calculate total duration from phases
|
|
104
|
+
const totalDurationSeconds = this.currentIssue.phases?.reduce((sum, p) => sum + p.durationSeconds, 0) ?? 0;
|
|
105
|
+
const issueLog = {
|
|
106
|
+
issueNumber: this.currentIssue.issueNumber,
|
|
107
|
+
title: this.currentIssue.title,
|
|
108
|
+
labels: this.currentIssue.labels,
|
|
109
|
+
status: this.currentIssue.status,
|
|
110
|
+
phases: this.currentIssue.phases,
|
|
111
|
+
totalDurationSeconds,
|
|
112
|
+
};
|
|
113
|
+
this.runLog.issues.push(issueLog);
|
|
114
|
+
this.currentIssue = null;
|
|
115
|
+
if (this.verbose) {
|
|
116
|
+
console.log(`📝 Completed issue #${issueLog.issueNumber} (${issueLog.status})`);
|
|
117
|
+
}
|
|
118
|
+
}
|
|
119
|
+
/**
|
|
120
|
+
* Finalize the run log and write to disk
|
|
121
|
+
*
|
|
122
|
+
* @returns Path to the written log file
|
|
123
|
+
*/
|
|
124
|
+
async finalize() {
|
|
125
|
+
if (!this.runLog) {
|
|
126
|
+
throw new Error("LogWriter not initialized.");
|
|
127
|
+
}
|
|
128
|
+
// Complete any pending issue
|
|
129
|
+
if (this.currentIssue) {
|
|
130
|
+
this.completeIssue();
|
|
131
|
+
}
|
|
132
|
+
const finalLog = finalizeRunLog(this.runLog);
|
|
133
|
+
const filename = generateLogFilename(finalLog.runId, new Date(finalLog.startTime));
|
|
134
|
+
// Write to project logs
|
|
135
|
+
const projectPath = path.join(this.resolvePath(this.logPath), filename);
|
|
136
|
+
await this.writeLogFile(projectPath, finalLog);
|
|
137
|
+
// Optionally write to user logs
|
|
138
|
+
if (this.writeToUserLogs) {
|
|
139
|
+
const userPath = path.join(this.resolvePath(LOG_PATHS.user), filename);
|
|
140
|
+
await this.writeLogFile(userPath, finalLog);
|
|
141
|
+
}
|
|
142
|
+
if (this.verbose) {
|
|
143
|
+
console.log(`📝 Log written: ${projectPath}`);
|
|
144
|
+
}
|
|
145
|
+
return projectPath;
|
|
146
|
+
}
|
|
147
|
+
/**
|
|
148
|
+
* Get the current run log (for inspection)
|
|
149
|
+
*/
|
|
150
|
+
getRunLog() {
|
|
151
|
+
return this.runLog;
|
|
152
|
+
}
|
|
153
|
+
/**
|
|
154
|
+
* Get the run ID
|
|
155
|
+
*/
|
|
156
|
+
getRunId() {
|
|
157
|
+
return this.runLog?.runId ?? null;
|
|
158
|
+
}
|
|
159
|
+
resolvePath(logPath) {
|
|
160
|
+
return logPath.replace("~", os.homedir());
|
|
161
|
+
}
|
|
162
|
+
async ensureLogDirectory(logPath) {
|
|
163
|
+
const resolved = this.resolvePath(logPath);
|
|
164
|
+
if (!fs.existsSync(resolved)) {
|
|
165
|
+
fs.mkdirSync(resolved, { recursive: true });
|
|
166
|
+
}
|
|
167
|
+
}
|
|
168
|
+
async writeLogFile(filePath, log) {
|
|
169
|
+
const dir = path.dirname(filePath);
|
|
170
|
+
if (!fs.existsSync(dir)) {
|
|
171
|
+
fs.mkdirSync(dir, { recursive: true });
|
|
172
|
+
}
|
|
173
|
+
fs.writeFileSync(filePath, JSON.stringify(log, null, 2));
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Create a simple phase log from timing data
|
|
178
|
+
*
|
|
179
|
+
* Utility function for creating phase logs when you have start/end times.
|
|
180
|
+
*/
|
|
181
|
+
export function createPhaseLogFromTiming(phase, issueNumber, startTime, endTime, status, options) {
|
|
182
|
+
const durationSeconds = (endTime.getTime() - startTime.getTime()) / 1000;
|
|
183
|
+
return {
|
|
184
|
+
phase,
|
|
185
|
+
issueNumber,
|
|
186
|
+
startTime: startTime.toISOString(),
|
|
187
|
+
endTime: endTime.toISOString(),
|
|
188
|
+
durationSeconds,
|
|
189
|
+
status,
|
|
190
|
+
...options,
|
|
191
|
+
};
|
|
192
|
+
}
|
|
193
|
+
//# sourceMappingURL=log-writer.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"log-writer.js","sourceRoot":"","sources":["../../../../src/lib/workflow/log-writer.ts"],"names":[],"mappings":"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"}
|