superskill 0.2.2 → 0.2.4
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/.claude-plugin/marketplace.json +23 -0
- package/.claude-plugin/plugin.json +12 -0
- package/.mcp.json +9 -0
- package/LICENSE-COMMERCIAL.md +46 -0
- package/dist/setup/configure.js +21 -1
- package/dist/setup/configure.js.map +1 -1
- package/dist/setup/teardown.js +13 -5
- package/dist/setup/teardown.js.map +1 -1
- package/package.json +7 -1
- package/dist/commands/brainstorm.test.d.ts +0 -1
- package/dist/commands/brainstorm.test.js +0 -110
- package/dist/commands/brainstorm.test.js.map +0 -1
- package/dist/commands/context.test.d.ts +0 -1
- package/dist/commands/context.test.js +0 -230
- package/dist/commands/context.test.js.map +0 -1
- package/dist/commands/decide.test.d.ts +0 -1
- package/dist/commands/decide.test.js +0 -109
- package/dist/commands/decide.test.js.map +0 -1
- package/dist/commands/graph.test.d.ts +0 -1
- package/dist/commands/graph.test.js +0 -215
- package/dist/commands/graph.test.js.map +0 -1
- package/dist/commands/learn.test.d.ts +0 -1
- package/dist/commands/learn.test.js +0 -241
- package/dist/commands/learn.test.js.map +0 -1
- package/dist/commands/read.test.d.ts +0 -1
- package/dist/commands/read.test.js +0 -48
- package/dist/commands/read.test.js.map +0 -1
- package/dist/commands/resume.test.d.ts +0 -1
- package/dist/commands/resume.test.js +0 -243
- package/dist/commands/resume.test.js.map +0 -1
- package/dist/commands/search.test.d.ts +0 -1
- package/dist/commands/search.test.js +0 -61
- package/dist/commands/search.test.js.map +0 -1
- package/dist/commands/session.test.d.ts +0 -1
- package/dist/commands/session.test.js +0 -231
- package/dist/commands/session.test.js.map +0 -1
- package/dist/commands/skill/index.test.d.ts +0 -1
- package/dist/commands/skill/index.test.js +0 -137
- package/dist/commands/skill/index.test.js.map +0 -1
- package/dist/commands/skill/install.test.d.ts +0 -1
- package/dist/commands/skill/install.test.js +0 -225
- package/dist/commands/skill/install.test.js.map +0 -1
- package/dist/commands/skill/list.test.d.ts +0 -1
- package/dist/commands/skill/list.test.js +0 -101
- package/dist/commands/skill/list.test.js.map +0 -1
- package/dist/commands/skill/schema.test.d.ts +0 -1
- package/dist/commands/skill/schema.test.js +0 -142
- package/dist/commands/skill/schema.test.js.map +0 -1
- package/dist/commands/skill/validate.test.d.ts +0 -1
- package/dist/commands/skill/validate.test.js +0 -171
- package/dist/commands/skill/validate.test.js.map +0 -1
- package/dist/commands/task.test.d.ts +0 -1
- package/dist/commands/task.test.js +0 -395
- package/dist/commands/task.test.js.map +0 -1
- package/dist/commands/todo.test.d.ts +0 -1
- package/dist/commands/todo.test.js +0 -324
- package/dist/commands/todo.test.js.map +0 -1
- package/dist/commands/write.test.d.ts +0 -1
- package/dist/commands/write.test.js +0 -79
- package/dist/commands/write.test.js.map +0 -1
- package/dist/config.test.d.ts +0 -1
- package/dist/config.test.js +0 -147
- package/dist/config.test.js.map +0 -1
- package/dist/core/executor.test.d.ts +0 -1
- package/dist/core/executor.test.js +0 -206
- package/dist/core/executor.test.js.map +0 -1
- package/dist/core/registry.test.d.ts +0 -1
- package/dist/core/registry.test.js +0 -213
- package/dist/core/registry.test.js.map +0 -1
- package/dist/integration/coordination.test.d.ts +0 -1
- package/dist/integration/coordination.test.js +0 -286
- package/dist/integration/coordination.test.js.map +0 -1
- package/dist/integration/project-artifacts.test.d.ts +0 -1
- package/dist/integration/project-artifacts.test.js +0 -275
- package/dist/integration/project-artifacts.test.js.map +0 -1
- package/dist/integration/registry-graph.test.d.ts +0 -1
- package/dist/integration/registry-graph.test.js +0 -157
- package/dist/integration/registry-graph.test.js.map +0 -1
- package/dist/integration/vault-lifecycle.test.d.ts +0 -1
- package/dist/integration/vault-lifecycle.test.js +0 -183
- package/dist/integration/vault-lifecycle.test.js.map +0 -1
- package/dist/lib/auto-number.test.d.ts +0 -1
- package/dist/lib/auto-number.test.js +0 -88
- package/dist/lib/auto-number.test.js.map +0 -1
- package/dist/lib/auto-profile.test.d.ts +0 -1
- package/dist/lib/auto-profile.test.js +0 -227
- package/dist/lib/auto-profile.test.js.map +0 -1
- package/dist/lib/escape-regex.test.d.ts +0 -1
- package/dist/lib/escape-regex.test.js +0 -27
- package/dist/lib/escape-regex.test.js.map +0 -1
- package/dist/lib/frontmatter.test.d.ts +0 -1
- package/dist/lib/frontmatter.test.js +0 -192
- package/dist/lib/frontmatter.test.js.map +0 -1
- package/dist/lib/project-detector.test.d.ts +0 -1
- package/dist/lib/project-detector.test.js +0 -117
- package/dist/lib/project-detector.test.js.map +0 -1
- package/dist/lib/safe-external-path.test.d.ts +0 -1
- package/dist/lib/safe-external-path.test.js +0 -99
- package/dist/lib/safe-external-path.test.js.map +0 -1
- package/dist/lib/search-engine.test.d.ts +0 -1
- package/dist/lib/search-engine.test.js +0 -120
- package/dist/lib/search-engine.test.js.map +0 -1
- package/dist/lib/session-registry.test.d.ts +0 -1
- package/dist/lib/session-registry.test.js +0 -199
- package/dist/lib/session-registry.test.js.map +0 -1
- package/dist/lib/stack-detector.test.d.ts +0 -1
- package/dist/lib/stack-detector.test.js +0 -110
- package/dist/lib/stack-detector.test.js.map +0 -1
- package/dist/lib/token-estimator.test.d.ts +0 -1
- package/dist/lib/token-estimator.test.js +0 -65
- package/dist/lib/token-estimator.test.js.map +0 -1
- package/dist/lib/tool-detector.test.d.ts +0 -1
- package/dist/lib/tool-detector.test.js +0 -170
- package/dist/lib/tool-detector.test.js.map +0 -1
- package/dist/lib/vault-fs.test.d.ts +0 -1
- package/dist/lib/vault-fs.test.js +0 -210
- package/dist/lib/vault-fs.test.js.map +0 -1
- package/dist/setup/configure.test.d.ts +0 -1
- package/dist/setup/configure.test.js +0 -112
- package/dist/setup/configure.test.js.map +0 -1
- package/dist/setup/detect.test.d.ts +0 -1
- package/dist/setup/detect.test.js +0 -44
- package/dist/setup/detect.test.js.map +0 -1
- package/dist/setup/instructions.test.d.ts +0 -1
- package/dist/setup/instructions.test.js +0 -84
- package/dist/setup/instructions.test.js.map +0 -1
- package/dist/setup/json-config.test.d.ts +0 -1
- package/dist/setup/json-config.test.js +0 -92
- package/dist/setup/json-config.test.js.map +0 -1
- package/dist/setup/setup-integration.test.d.ts +0 -1
- package/dist/setup/setup-integration.test.js +0 -72
- package/dist/setup/setup-integration.test.js.map +0 -1
- package/dist/setup/teardown.test.d.ts +0 -1
- package/dist/setup/teardown.test.js +0 -105
- package/dist/setup/teardown.test.js.map +0 -1
- package/dist/setup/toml-config.test.d.ts +0 -1
- package/dist/setup/toml-config.test.js +0 -49
- package/dist/setup/toml-config.test.js.map +0 -1
- package/dist/test-helpers.test.d.ts +0 -1
- package/dist/test-helpers.test.js +0 -90
- package/dist/test-helpers.test.js.map +0 -1
|
@@ -1,99 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
-
import { mkdir, rm, symlink } from "fs/promises";
|
|
3
|
-
import { tmpdir, homedir } from "os";
|
|
4
|
-
import { join } from "path";
|
|
5
|
-
import { safeExternalPath } from "./safe-external-path.js";
|
|
6
|
-
import { execFile } from "child_process";
|
|
7
|
-
import { promisify } from "util";
|
|
8
|
-
const execFileAsync = promisify(execFile);
|
|
9
|
-
describe("safeExternalPath", () => {
|
|
10
|
-
let testDir;
|
|
11
|
-
const home = homedir();
|
|
12
|
-
beforeEach(async () => {
|
|
13
|
-
testDir = join(tmpdir(), `safe-path-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
14
|
-
await mkdir(testDir, { recursive: true });
|
|
15
|
-
await execFileAsync("git", ["init"], { cwd: testDir });
|
|
16
|
-
});
|
|
17
|
-
afterEach(async () => {
|
|
18
|
-
await rm(testDir, { recursive: true, force: true });
|
|
19
|
-
});
|
|
20
|
-
describe("valid paths", () => {
|
|
21
|
-
it("accepts path under home directory", async () => {
|
|
22
|
-
const homeTestDir = join(home, `.safe-path-test-${Date.now()}`);
|
|
23
|
-
await mkdir(homeTestDir, { recursive: true });
|
|
24
|
-
await execFileAsync("git", ["init"], { cwd: homeTestDir });
|
|
25
|
-
const result = await safeExternalPath(homeTestDir);
|
|
26
|
-
expect(result).toBe(homeTestDir);
|
|
27
|
-
await rm(homeTestDir, { recursive: true, force: true });
|
|
28
|
-
});
|
|
29
|
-
it("accepts path with ~ prefix", async () => {
|
|
30
|
-
const homeTestDir = join(home, `.safe-path-test-tilde-${Date.now()}`);
|
|
31
|
-
await mkdir(homeTestDir, { recursive: true });
|
|
32
|
-
await execFileAsync("git", ["init"], { cwd: homeTestDir });
|
|
33
|
-
const result = await safeExternalPath(homeTestDir.replace(home, "~"));
|
|
34
|
-
expect(result).toBe(homeTestDir);
|
|
35
|
-
await rm(homeTestDir, { recursive: true, force: true });
|
|
36
|
-
});
|
|
37
|
-
it("resolves relative path segments", async () => {
|
|
38
|
-
const homeTestDir = join(home, `.safe-path-test-rel-${Date.now()}`);
|
|
39
|
-
await mkdir(homeTestDir, { recursive: true });
|
|
40
|
-
await execFileAsync("git", ["init"], { cwd: homeTestDir });
|
|
41
|
-
const result = await safeExternalPath(`${homeTestDir}/./subdir/..`);
|
|
42
|
-
expect(result).toBe(homeTestDir);
|
|
43
|
-
await rm(homeTestDir, { recursive: true, force: true });
|
|
44
|
-
});
|
|
45
|
-
});
|
|
46
|
-
describe("traversal attack prevention", () => {
|
|
47
|
-
it("rejects path with .. traversal", async () => {
|
|
48
|
-
await expect(safeExternalPath("/Users/../../../etc/passwd")).rejects.toThrow("Path must be under home directory");
|
|
49
|
-
});
|
|
50
|
-
});
|
|
51
|
-
describe("symlink escape prevention", () => {
|
|
52
|
-
it("rejects symlink escaping home directory", async () => {
|
|
53
|
-
const outsideDir = join(tmpdir(), `outside-safe-${Date.now()}`);
|
|
54
|
-
await mkdir(outsideDir, { recursive: true });
|
|
55
|
-
const linkPath = join(testDir, "escape-link");
|
|
56
|
-
try {
|
|
57
|
-
await symlink(outsideDir, linkPath);
|
|
58
|
-
await expect(safeExternalPath(linkPath)).rejects.toThrow();
|
|
59
|
-
}
|
|
60
|
-
finally {
|
|
61
|
-
await rm(outsideDir, { recursive: true, force: true });
|
|
62
|
-
}
|
|
63
|
-
});
|
|
64
|
-
it("accepts symlink within home directory", async () => {
|
|
65
|
-
const homeTestDir = join(home, `.safe-path-test-link-${Date.now()}`);
|
|
66
|
-
await mkdir(homeTestDir, { recursive: true });
|
|
67
|
-
await execFileAsync("git", ["init"], { cwd: homeTestDir });
|
|
68
|
-
const linkPath = join(home, `.safe-path-link-${Date.now()}`);
|
|
69
|
-
await symlink(homeTestDir, linkPath);
|
|
70
|
-
const result = await safeExternalPath(linkPath);
|
|
71
|
-
expect(result).toBeDefined();
|
|
72
|
-
await rm(linkPath, { force: true });
|
|
73
|
-
await rm(homeTestDir, { recursive: true, force: true });
|
|
74
|
-
});
|
|
75
|
-
});
|
|
76
|
-
describe("non-home directory rejection", () => {
|
|
77
|
-
it("rejects path outside home directory", async () => {
|
|
78
|
-
await expect(safeExternalPath("/etc/passwd")).rejects.toThrow("Path must be under home directory");
|
|
79
|
-
});
|
|
80
|
-
it("rejects /tmp directly (outside home)", async () => {
|
|
81
|
-
await expect(safeExternalPath("/tmp")).rejects.toThrow("Path must be under home directory");
|
|
82
|
-
});
|
|
83
|
-
});
|
|
84
|
-
describe("git repository check", () => {
|
|
85
|
-
it("rejects non-git directory", async () => {
|
|
86
|
-
const homeNonGit = join(home, `.safe-path-non-git-${Date.now()}`);
|
|
87
|
-
await mkdir(homeNonGit, { recursive: true });
|
|
88
|
-
await expect(safeExternalPath(homeNonGit)).rejects.toThrow("Not a git repository");
|
|
89
|
-
await rm(homeNonGit, { recursive: true, force: true });
|
|
90
|
-
});
|
|
91
|
-
});
|
|
92
|
-
describe("nonexistent path handling", () => {
|
|
93
|
-
it("rejects nonexistent path", async () => {
|
|
94
|
-
const nonexistent = join(home, `.nonexistent-path-${Date.now()}`);
|
|
95
|
-
await expect(safeExternalPath(nonexistent)).rejects.toThrow("Path does not exist");
|
|
96
|
-
});
|
|
97
|
-
});
|
|
98
|
-
});
|
|
99
|
-
//# sourceMappingURL=safe-external-path.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"safe-external-path.test.js","sourceRoot":"","sources":["../../src/lib/safe-external-path.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,120 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
-
import { mkdir, writeFile, rm } from "fs/promises";
|
|
3
|
-
import { tmpdir } from "os";
|
|
4
|
-
import { join } from "path";
|
|
5
|
-
import { searchText, searchStructured } from "./search-engine.js";
|
|
6
|
-
describe("search-engine", () => {
|
|
7
|
-
let vaultRoot;
|
|
8
|
-
beforeEach(async () => {
|
|
9
|
-
vaultRoot = join(tmpdir(), `search-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
10
|
-
await mkdir(vaultRoot, { recursive: true });
|
|
11
|
-
});
|
|
12
|
-
afterEach(async () => {
|
|
13
|
-
await rm(vaultRoot, { recursive: true, force: true });
|
|
14
|
-
});
|
|
15
|
-
describe("searchText", () => {
|
|
16
|
-
beforeEach(async () => {
|
|
17
|
-
await writeFile(join(vaultRoot, "doc1.md"), "# Hello World\n\nThis is a test document.");
|
|
18
|
-
await writeFile(join(vaultRoot, "doc2.md"), "# Another Doc\n\nNo matching content here.");
|
|
19
|
-
await mkdir(join(vaultRoot, "subdir"), { recursive: true });
|
|
20
|
-
await writeFile(join(vaultRoot, "subdir/nested.md"), "# Nested Hello\n\nHello from nested path.");
|
|
21
|
-
await mkdir(join(vaultRoot, ".obsidian"), { recursive: true });
|
|
22
|
-
await writeFile(join(vaultRoot, ".obsidian/config"), "hello in hidden");
|
|
23
|
-
});
|
|
24
|
-
it("finds matching documents", async () => {
|
|
25
|
-
const results = await searchText(vaultRoot, "Hello");
|
|
26
|
-
expect(results.length).toBeGreaterThan(0);
|
|
27
|
-
expect(results.some(r => r.path === "doc1.md")).toBe(true);
|
|
28
|
-
});
|
|
29
|
-
it("is case insensitive", async () => {
|
|
30
|
-
const results = await searchText(vaultRoot, "HELLO");
|
|
31
|
-
expect(results.length).toBeGreaterThan(0);
|
|
32
|
-
});
|
|
33
|
-
it("respects limit parameter", async () => {
|
|
34
|
-
const results = await searchText(vaultRoot, "Hello", { limit: 1 });
|
|
35
|
-
expect(results.length).toBeLessThanOrEqual(1);
|
|
36
|
-
});
|
|
37
|
-
it("filters by path", async () => {
|
|
38
|
-
const results = await searchText(vaultRoot, "Hello", { pathFilter: "subdir" });
|
|
39
|
-
expect(results.every(r => r.path.startsWith("subdir"))).toBe(true);
|
|
40
|
-
});
|
|
41
|
-
it("excludes hidden directories", async () => {
|
|
42
|
-
const results = await searchText(vaultRoot, "hello");
|
|
43
|
-
expect(results.every(r => !r.path.startsWith(".obsidian"))).toBe(true);
|
|
44
|
-
});
|
|
45
|
-
it("returns empty array for no matches", async () => {
|
|
46
|
-
const results = await searchText(vaultRoot, "zzzznomatchxxxx");
|
|
47
|
-
expect(results).toEqual([]);
|
|
48
|
-
});
|
|
49
|
-
it("rejects traversal attack in pathFilter", async () => {
|
|
50
|
-
await expect(searchText(vaultRoot, "test", { pathFilter: "../outside" })).rejects.toThrow();
|
|
51
|
-
});
|
|
52
|
-
it("rejects absolute path in pathFilter", async () => {
|
|
53
|
-
await expect(searchText(vaultRoot, "test", { pathFilter: "/etc/passwd" })).rejects.toThrow();
|
|
54
|
-
});
|
|
55
|
-
it("returns path, snippet, and line number", async () => {
|
|
56
|
-
const results = await searchText(vaultRoot, "World");
|
|
57
|
-
expect(results.length).toBeGreaterThan(0);
|
|
58
|
-
expect(results[0].path).toBeDefined();
|
|
59
|
-
expect(results[0].snippet).toBeDefined();
|
|
60
|
-
expect(results[0].line).toBeGreaterThan(0);
|
|
61
|
-
});
|
|
62
|
-
it("handles special regex characters safely", async () => {
|
|
63
|
-
await writeFile(join(vaultRoot, "special.md"), "Content with $pecial ch@rs");
|
|
64
|
-
const results = await searchText(vaultRoot, "$pecial");
|
|
65
|
-
expect(results.length).toBeGreaterThan(0);
|
|
66
|
-
});
|
|
67
|
-
});
|
|
68
|
-
describe("searchStructured", () => {
|
|
69
|
-
beforeEach(async () => {
|
|
70
|
-
await writeFile(join(vaultRoot, "task1.md"), "---\ntype: task\nstatus: in-progress\nproject: test-project\ntags:\n - urgent\n - backend\n---\n\n# Task 1\n\nTask one content.");
|
|
71
|
-
await writeFile(join(vaultRoot, "task2.md"), "---\ntype: task\nstatus: done\nproject: other-project\ntags:\n - frontend\n---\n\n# Task 2\n\nTask two content.");
|
|
72
|
-
await writeFile(join(vaultRoot, "note.md"), "---\ntype: index\n---\n\n# Note\n\nJust a note.");
|
|
73
|
-
});
|
|
74
|
-
it("filters by single frontmatter field", async () => {
|
|
75
|
-
const results = await searchStructured(vaultRoot, { type: "task" });
|
|
76
|
-
expect(results.length).toBe(2);
|
|
77
|
-
});
|
|
78
|
-
it("filters by multiple fields", async () => {
|
|
79
|
-
const results = await searchStructured(vaultRoot, { type: "task", status: "done" });
|
|
80
|
-
expect(results.length).toBe(1);
|
|
81
|
-
expect(results[0].path).toBe("task2.md");
|
|
82
|
-
});
|
|
83
|
-
it("filters by array field value", async () => {
|
|
84
|
-
const results = await searchStructured(vaultRoot, { tags: "urgent" });
|
|
85
|
-
expect(results.length).toBe(1);
|
|
86
|
-
expect(results[0].path).toBe("task1.md");
|
|
87
|
-
});
|
|
88
|
-
it("respects limit parameter", async () => {
|
|
89
|
-
const results = await searchStructured(vaultRoot, { type: "task" }, { limit: 1 });
|
|
90
|
-
expect(results.length).toBeLessThanOrEqual(1);
|
|
91
|
-
});
|
|
92
|
-
it("returns empty array for no matches", async () => {
|
|
93
|
-
const results = await searchStructured(vaultRoot, { type: "nonexistent" });
|
|
94
|
-
expect(results).toEqual([]);
|
|
95
|
-
});
|
|
96
|
-
it("excludes hidden directories", async () => {
|
|
97
|
-
await mkdir(join(vaultRoot, ".hidden"), { recursive: true });
|
|
98
|
-
await writeFile(join(vaultRoot, ".hidden/secret.md"), "---\ntype: secret\n---\n\n# Secret");
|
|
99
|
-
const results = await searchStructured(vaultRoot, { type: "secret" });
|
|
100
|
-
expect(results.every(r => !r.path.startsWith("."))).toBe(true);
|
|
101
|
-
});
|
|
102
|
-
it("returns path and snippet", async () => {
|
|
103
|
-
const results = await searchStructured(vaultRoot, { type: "task" });
|
|
104
|
-
expect(results.length).toBeGreaterThan(0);
|
|
105
|
-
expect(results[0].path).toBeDefined();
|
|
106
|
-
expect(results[0].snippet).toBeDefined();
|
|
107
|
-
});
|
|
108
|
-
it("handles files without frontmatter", async () => {
|
|
109
|
-
await writeFile(join(vaultRoot, "plain.md"), "Just plain text");
|
|
110
|
-
const results = await searchStructured(vaultRoot, { type: "task" });
|
|
111
|
-
expect(results.every(r => r.path !== "plain.md")).toBe(true);
|
|
112
|
-
});
|
|
113
|
-
it("handles malformed YAML gracefully", async () => {
|
|
114
|
-
await writeFile(join(vaultRoot, "bad.md"), "---\ninvalid: yaml: content\n---\n\n# Bad");
|
|
115
|
-
const results = await searchStructured(vaultRoot, { type: "task" });
|
|
116
|
-
expect(results.every(r => r.path !== "bad.md")).toBe(true);
|
|
117
|
-
});
|
|
118
|
-
});
|
|
119
|
-
});
|
|
120
|
-
//# sourceMappingURL=search-engine.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"search-engine.test.js","sourceRoot":"","sources":["../../src/lib/search-engine.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,199 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
-
import { mkdir, writeFile as fspWriteFile, rm, readFile as fspReadFile } from "fs/promises";
|
|
3
|
-
import { tmpdir } from "os";
|
|
4
|
-
import { join } from "path";
|
|
5
|
-
import { SessionRegistryManager } from "./session-registry.js";
|
|
6
|
-
describe("SessionRegistryManager", () => {
|
|
7
|
-
let vaultRoot;
|
|
8
|
-
let manager;
|
|
9
|
-
beforeEach(async () => {
|
|
10
|
-
vaultRoot = join(tmpdir(), `session-test-${Date.now()}-${Math.random().toString(36).slice(2)}`);
|
|
11
|
-
await mkdir(vaultRoot, { recursive: true });
|
|
12
|
-
manager = new SessionRegistryManager(vaultRoot, 1);
|
|
13
|
-
});
|
|
14
|
-
afterEach(async () => {
|
|
15
|
-
await rm(vaultRoot, { recursive: true, force: true });
|
|
16
|
-
});
|
|
17
|
-
describe("register", () => {
|
|
18
|
-
it("creates session with generated ID", async () => {
|
|
19
|
-
const result = await manager.register("claude-code", "test-project");
|
|
20
|
-
expect(result.session_id).toMatch(/^claude-code-[a-f0-9]{8}$/);
|
|
21
|
-
});
|
|
22
|
-
it("creates session with all fields", async () => {
|
|
23
|
-
const result = await manager.register("opencode", "my-project", "Doing work", ["file1.ts", "file2.ts"]);
|
|
24
|
-
expect(result.session_id).toMatch(/^opencode-/);
|
|
25
|
-
});
|
|
26
|
-
it("detects file conflicts", async () => {
|
|
27
|
-
await manager.register("claude-code", "proj", "Task 1", ["a.ts", "b.ts"]);
|
|
28
|
-
const result = await manager.register("opencode", "proj", "Task 2", ["b.ts", "c.ts"]);
|
|
29
|
-
expect(result.conflicts.length).toBe(1);
|
|
30
|
-
expect(result.conflicts[0].overlapping_files).toContain("b.ts");
|
|
31
|
-
});
|
|
32
|
-
it("returns empty conflicts when no overlap", async () => {
|
|
33
|
-
await manager.register("claude-code", "proj", "Task 1", ["a.ts"]);
|
|
34
|
-
const result = await manager.register("opencode", "proj", "Task 2", ["b.ts"]);
|
|
35
|
-
expect(result.conflicts).toEqual([]);
|
|
36
|
-
});
|
|
37
|
-
it("returns empty conflicts when first session has no files", async () => {
|
|
38
|
-
await manager.register("claude-code", "proj", "Task 1", []);
|
|
39
|
-
const result = await manager.register("opencode", "proj", "Task 2", ["b.ts"]);
|
|
40
|
-
expect(result.conflicts).toEqual([]);
|
|
41
|
-
});
|
|
42
|
-
it("cleans stale sessions on register", async () => {
|
|
43
|
-
const oldManager = new SessionRegistryManager(vaultRoot, 0);
|
|
44
|
-
await oldManager.register("claude-code", "proj", "Old session");
|
|
45
|
-
await new Promise(r => setTimeout(r, 10));
|
|
46
|
-
const newManager = new SessionRegistryManager(vaultRoot, 0.000001);
|
|
47
|
-
await newManager.register("opencode", "proj", "New session");
|
|
48
|
-
const active = await newManager.listActive();
|
|
49
|
-
expect(active.every(s => s.status === "active")).toBe(true);
|
|
50
|
-
});
|
|
51
|
-
it("persists session to registry file", async () => {
|
|
52
|
-
await manager.register("claude-code", "test-project");
|
|
53
|
-
const registryPath = join(vaultRoot, "coordination/session-registry.json");
|
|
54
|
-
const raw = await fspReadFile(registryPath, "utf-8");
|
|
55
|
-
const parsed = JSON.parse(raw);
|
|
56
|
-
expect(parsed.sessions.length).toBe(1);
|
|
57
|
-
expect(parsed.sessions[0].tool).toBe("claude-code");
|
|
58
|
-
});
|
|
59
|
-
});
|
|
60
|
-
describe("heartbeat", () => {
|
|
61
|
-
it("updates heartbeat timestamp", async () => {
|
|
62
|
-
const { session_id } = await manager.register("claude-code", "proj");
|
|
63
|
-
await new Promise(r => setTimeout(r, 10));
|
|
64
|
-
const result = await manager.heartbeat(session_id);
|
|
65
|
-
expect(result).toBe(true);
|
|
66
|
-
});
|
|
67
|
-
it("returns false for missing session", async () => {
|
|
68
|
-
const result = await manager.heartbeat("nonexistent-id");
|
|
69
|
-
expect(result).toBe(false);
|
|
70
|
-
});
|
|
71
|
-
it("persists heartbeat to file", async () => {
|
|
72
|
-
const { session_id } = await manager.register("claude-code", "proj");
|
|
73
|
-
await manager.heartbeat(session_id);
|
|
74
|
-
const registryPath = join(vaultRoot, "coordination/session-registry.json");
|
|
75
|
-
const raw = await fspReadFile(registryPath, "utf-8");
|
|
76
|
-
const parsed = JSON.parse(raw);
|
|
77
|
-
const session = parsed.sessions.find((s) => s.id === session_id);
|
|
78
|
-
expect(session.last_heartbeat).toBeDefined();
|
|
79
|
-
});
|
|
80
|
-
});
|
|
81
|
-
describe("complete", () => {
|
|
82
|
-
it("marks session as completed", async () => {
|
|
83
|
-
const { session_id } = await manager.register("claude-code", "proj");
|
|
84
|
-
await manager.complete(session_id);
|
|
85
|
-
const registryPath = join(vaultRoot, "coordination/session-registry.json");
|
|
86
|
-
const raw = await fspReadFile(registryPath, "utf-8");
|
|
87
|
-
const parsed = JSON.parse(raw);
|
|
88
|
-
const session = parsed.sessions.find((s) => s.id === session_id);
|
|
89
|
-
expect(session.status).toBe("completed");
|
|
90
|
-
expect(session.completed_at).toBeDefined();
|
|
91
|
-
});
|
|
92
|
-
it("updates task summary when provided", async () => {
|
|
93
|
-
const { session_id } = await manager.register("claude-code", "proj", "Old summary");
|
|
94
|
-
await manager.complete(session_id, "New summary");
|
|
95
|
-
const registryPath = join(vaultRoot, "coordination/session-registry.json");
|
|
96
|
-
const raw = await fspReadFile(registryPath, "utf-8");
|
|
97
|
-
const parsed = JSON.parse(raw);
|
|
98
|
-
const session = parsed.sessions.find((s) => s.id === session_id);
|
|
99
|
-
expect(session.task_summary).toBe("New summary");
|
|
100
|
-
});
|
|
101
|
-
it("removes old completed sessions", async () => {
|
|
102
|
-
const { session_id } = await manager.register("claude-code", "proj");
|
|
103
|
-
await manager.complete(session_id);
|
|
104
|
-
const registryPath = join(vaultRoot, "coordination/session-registry.json");
|
|
105
|
-
let raw = await fspReadFile(registryPath, "utf-8");
|
|
106
|
-
let parsed = JSON.parse(raw);
|
|
107
|
-
const session = parsed.sessions.find((s) => s.id === session_id);
|
|
108
|
-
session.completed_at = new Date(Date.now() - 25 * 60 * 60 * 1000).toISOString();
|
|
109
|
-
await fspWriteFile(registryPath, JSON.stringify(parsed));
|
|
110
|
-
await manager.register("opencode", "proj");
|
|
111
|
-
raw = await fspReadFile(registryPath, "utf-8");
|
|
112
|
-
parsed = JSON.parse(raw);
|
|
113
|
-
expect(parsed.sessions.find((s) => s.id === session_id)).toBeUndefined();
|
|
114
|
-
});
|
|
115
|
-
});
|
|
116
|
-
describe("listActive", () => {
|
|
117
|
-
it("returns only active sessions", async () => {
|
|
118
|
-
const { session_id } = await manager.register("claude-code", "proj");
|
|
119
|
-
await manager.register("opencode", "proj2");
|
|
120
|
-
await manager.complete(session_id);
|
|
121
|
-
const active = await manager.listActive();
|
|
122
|
-
expect(active.length).toBe(1);
|
|
123
|
-
expect(active[0].tool).toBe("opencode");
|
|
124
|
-
});
|
|
125
|
-
it("returns empty array when no active sessions", async () => {
|
|
126
|
-
const active = await manager.listActive();
|
|
127
|
-
expect(active).toEqual([]);
|
|
128
|
-
});
|
|
129
|
-
it("persists stale status changes", async () => {
|
|
130
|
-
const staleManager = new SessionRegistryManager(vaultRoot, 0.000001);
|
|
131
|
-
await staleManager.register("claude-code", "proj");
|
|
132
|
-
await new Promise(r => setTimeout(r, 20));
|
|
133
|
-
const active = await staleManager.listActive();
|
|
134
|
-
expect(active).toEqual([]);
|
|
135
|
-
const registryPath = join(vaultRoot, "coordination/session-registry.json");
|
|
136
|
-
const raw = await fspReadFile(registryPath, "utf-8");
|
|
137
|
-
const parsed = JSON.parse(raw);
|
|
138
|
-
expect(parsed.sessions[0].status).toBe("stale");
|
|
139
|
-
});
|
|
140
|
-
});
|
|
141
|
-
describe("withLock", () => {
|
|
142
|
-
it("prevents concurrent access", async () => {
|
|
143
|
-
const promises = [];
|
|
144
|
-
for (let i = 0; i < 5; i++) {
|
|
145
|
-
promises.push(manager.register(`tool-${i}`, "proj"));
|
|
146
|
-
}
|
|
147
|
-
const results = await Promise.all(promises);
|
|
148
|
-
expect(results.every(r => r.session_id)).toBe(true);
|
|
149
|
-
const registryPath = join(vaultRoot, "coordination/session-registry.json");
|
|
150
|
-
const raw = await fspReadFile(registryPath, "utf-8");
|
|
151
|
-
const parsed = JSON.parse(raw);
|
|
152
|
-
expect(parsed.sessions.length).toBe(5);
|
|
153
|
-
});
|
|
154
|
-
it("removes stale locks", async () => {
|
|
155
|
-
const locksDir = join(vaultRoot, "coordination/locks");
|
|
156
|
-
await mkdir(locksDir, { recursive: true });
|
|
157
|
-
const lockPath = join(locksDir, "session-registry.lock");
|
|
158
|
-
await fspWriteFile(lockPath, JSON.stringify({ pid: 999999999, timestamp: new Date().toISOString() }));
|
|
159
|
-
const { session_id } = await manager.register("claude-code", "proj");
|
|
160
|
-
expect(session_id).toBeDefined();
|
|
161
|
-
});
|
|
162
|
-
});
|
|
163
|
-
describe("readRegistry validation", () => {
|
|
164
|
-
it("handles malformed session entries", async () => {
|
|
165
|
-
const registryPath = join(vaultRoot, "coordination/session-registry.json");
|
|
166
|
-
await mkdir(join(vaultRoot, "coordination"), { recursive: true });
|
|
167
|
-
const now = new Date().toISOString();
|
|
168
|
-
const malformedData = {
|
|
169
|
-
sessions: [
|
|
170
|
-
{ id: "valid-1", tool: "test", status: "active", started_at: now, last_heartbeat: now, files_touched: [] },
|
|
171
|
-
{ id: 123, tool: "bad" },
|
|
172
|
-
null,
|
|
173
|
-
"string not object",
|
|
174
|
-
{ id: "valid-2", tool: "test", status: "active", started_at: "bad-date", last_heartbeat: "2024-01-01T00:00:00Z", files_touched: [] },
|
|
175
|
-
]
|
|
176
|
-
};
|
|
177
|
-
await fspWriteFile(registryPath, JSON.stringify(malformedData));
|
|
178
|
-
const active = await manager.listActive();
|
|
179
|
-
const validIds = active.map(s => s.id);
|
|
180
|
-
expect(validIds).toContain("valid-1");
|
|
181
|
-
expect(validIds).not.toContain("valid-2");
|
|
182
|
-
});
|
|
183
|
-
it("handles non-array sessions field", async () => {
|
|
184
|
-
const registryPath = join(vaultRoot, "coordination/session-registry.json");
|
|
185
|
-
await mkdir(join(vaultRoot, "coordination"), { recursive: true });
|
|
186
|
-
await fspWriteFile(registryPath, JSON.stringify({ sessions: "not-an-array" }));
|
|
187
|
-
const active = await manager.listActive();
|
|
188
|
-
expect(active).toEqual([]);
|
|
189
|
-
});
|
|
190
|
-
it("handles missing sessions field", async () => {
|
|
191
|
-
const registryPath = join(vaultRoot, "coordination/session-registry.json");
|
|
192
|
-
await mkdir(join(vaultRoot, "coordination"), { recursive: true });
|
|
193
|
-
await fspWriteFile(registryPath, JSON.stringify({}));
|
|
194
|
-
const active = await manager.listActive();
|
|
195
|
-
expect(active).toEqual([]);
|
|
196
|
-
});
|
|
197
|
-
});
|
|
198
|
-
});
|
|
199
|
-
//# sourceMappingURL=session-registry.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"session-registry.test.js","sourceRoot":"","sources":["../../src/lib/session-registry.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|
|
@@ -1,110 +0,0 @@
|
|
|
1
|
-
import { describe, it, expect, beforeEach, afterEach } from "vitest";
|
|
2
|
-
import { mkdtemp, writeFile, rm } from "fs/promises";
|
|
3
|
-
import { join } from "path";
|
|
4
|
-
import { tmpdir } from "os";
|
|
5
|
-
import { detectStack } from "./stack-detector.js";
|
|
6
|
-
async function mkTmp() {
|
|
7
|
-
return mkdtemp(join(tmpdir(), "stack-detector-"));
|
|
8
|
-
}
|
|
9
|
-
describe("detectStack", () => {
|
|
10
|
-
let dir;
|
|
11
|
-
beforeEach(async () => {
|
|
12
|
-
dir = await mkTmp();
|
|
13
|
-
});
|
|
14
|
-
afterEach(async () => {
|
|
15
|
-
await rm(dir, { recursive: true, force: true });
|
|
16
|
-
});
|
|
17
|
-
it("detects Go project with echo framework", async () => {
|
|
18
|
-
await writeFile(join(dir, "go.mod"), `module example.com/app\n\ngo 1.21\n\nrequire github.com/labstack/echo/v4 v4.11.0\n`);
|
|
19
|
-
const stack = await detectStack(dir);
|
|
20
|
-
expect(stack.languages).toContain("go");
|
|
21
|
-
expect(stack.primary).toBe("go");
|
|
22
|
-
expect(stack.frameworks).toContain("echo");
|
|
23
|
-
});
|
|
24
|
-
it("detects Go project without framework", async () => {
|
|
25
|
-
await writeFile(join(dir, "go.mod"), `module example.com/app\n\ngo 1.21\n`);
|
|
26
|
-
const stack = await detectStack(dir);
|
|
27
|
-
expect(stack.languages).toContain("go");
|
|
28
|
-
expect(stack.primary).toBe("go");
|
|
29
|
-
expect(stack.frameworks).toHaveLength(0);
|
|
30
|
-
});
|
|
31
|
-
it("detects TypeScript/React project", async () => {
|
|
32
|
-
await writeFile(join(dir, "package.json"), JSON.stringify({
|
|
33
|
-
name: "my-app",
|
|
34
|
-
dependencies: { react: "^18.0.0", "react-dom": "^18.0.0" },
|
|
35
|
-
devDependencies: { typescript: "^5.0.0" },
|
|
36
|
-
}));
|
|
37
|
-
const stack = await detectStack(dir);
|
|
38
|
-
expect(stack.languages).toContain("typescript");
|
|
39
|
-
expect(stack.frameworks).toContain("react");
|
|
40
|
-
expect(stack.primary).toBe("typescript");
|
|
41
|
-
});
|
|
42
|
-
it("detects Next.js project", async () => {
|
|
43
|
-
await writeFile(join(dir, "package.json"), JSON.stringify({
|
|
44
|
-
name: "my-next-app",
|
|
45
|
-
dependencies: { next: "^14.0.0", react: "^18.0.0" },
|
|
46
|
-
}));
|
|
47
|
-
const stack = await detectStack(dir);
|
|
48
|
-
expect(stack.frameworks).toContain("next");
|
|
49
|
-
expect(stack.frameworks).toContain("react");
|
|
50
|
-
});
|
|
51
|
-
it("detects Python Django project via requirements.txt", async () => {
|
|
52
|
-
await writeFile(join(dir, "requirements.txt"), `Django==4.2.0\npsycopg2-binary==2.9.0\n`);
|
|
53
|
-
const stack = await detectStack(dir);
|
|
54
|
-
expect(stack.languages).toContain("python");
|
|
55
|
-
expect(stack.frameworks).toContain("django");
|
|
56
|
-
expect(stack.primary).toBe("python");
|
|
57
|
-
});
|
|
58
|
-
it("detects Python FastAPI project via pyproject.toml", async () => {
|
|
59
|
-
await writeFile(join(dir, "pyproject.toml"), `[tool.poetry.dependencies]\npython = "^3.11"\nfastapi = "^0.100.0"\n`);
|
|
60
|
-
const stack = await detectStack(dir);
|
|
61
|
-
expect(stack.languages).toContain("python");
|
|
62
|
-
expect(stack.frameworks).toContain("fastapi");
|
|
63
|
-
});
|
|
64
|
-
it("detects Rust project", async () => {
|
|
65
|
-
await writeFile(join(dir, "Cargo.toml"), `[package]\nname = "my-app"\nversion = "0.1.0"\n`);
|
|
66
|
-
const stack = await detectStack(dir);
|
|
67
|
-
expect(stack.languages).toContain("rust");
|
|
68
|
-
expect(stack.primary).toBe("rust");
|
|
69
|
-
});
|
|
70
|
-
it("detects Ruby on Rails project", async () => {
|
|
71
|
-
await writeFile(join(dir, "Gemfile"), `source 'https://rubygems.org'\ngem 'rails', '~> 7.0.0'\n`);
|
|
72
|
-
const stack = await detectStack(dir);
|
|
73
|
-
expect(stack.languages).toContain("ruby");
|
|
74
|
-
expect(stack.frameworks).toContain("rails");
|
|
75
|
-
expect(stack.primary).toBe("ruby");
|
|
76
|
-
});
|
|
77
|
-
it("detects mixed Go + TypeScript project and picks Go as primary", async () => {
|
|
78
|
-
await writeFile(join(dir, "go.mod"), `module example.com/app\n\ngo 1.21\n`);
|
|
79
|
-
await writeFile(join(dir, "package.json"), JSON.stringify({ dependencies: { react: "^18.0.0" } }));
|
|
80
|
-
const stack = await detectStack(dir);
|
|
81
|
-
expect(stack.languages).toContain("go");
|
|
82
|
-
expect(stack.languages).toContain("typescript");
|
|
83
|
-
expect(stack.primary).toBe("go");
|
|
84
|
-
expect(stack.frameworks).toContain("react");
|
|
85
|
-
});
|
|
86
|
-
it("returns empty/unknown for an empty directory", async () => {
|
|
87
|
-
const stack = await detectStack(dir);
|
|
88
|
-
expect(stack.languages).toHaveLength(0);
|
|
89
|
-
expect(stack.frameworks).toHaveLength(0);
|
|
90
|
-
expect(stack.primary).toBe("unknown");
|
|
91
|
-
});
|
|
92
|
-
it("detects Makefile build tool", async () => {
|
|
93
|
-
await writeFile(join(dir, "Makefile"), "build:\n\tgo build ./...\n");
|
|
94
|
-
await writeFile(join(dir, "go.mod"), `module example.com/app\n\ngo 1.21\n`);
|
|
95
|
-
const stack = await detectStack(dir);
|
|
96
|
-
expect(stack.buildTools).toContain("make");
|
|
97
|
-
});
|
|
98
|
-
it("detects bun as build tool from bun.lockb presence", async () => {
|
|
99
|
-
await writeFile(join(dir, "bun.lockb"), "");
|
|
100
|
-
await writeFile(join(dir, "package.json"), JSON.stringify({ dependencies: { react: "^18.0.0" } }));
|
|
101
|
-
const stack = await detectStack(dir);
|
|
102
|
-
expect(stack.buildTools).toContain("bun");
|
|
103
|
-
});
|
|
104
|
-
it("detects gin framework in Go project", async () => {
|
|
105
|
-
await writeFile(join(dir, "go.mod"), `module example.com/app\n\ngo 1.21\n\nrequire github.com/gin-gonic/gin v1.9.0\n`);
|
|
106
|
-
const stack = await detectStack(dir);
|
|
107
|
-
expect(stack.frameworks).toContain("gin");
|
|
108
|
-
});
|
|
109
|
-
});
|
|
110
|
-
//# sourceMappingURL=stack-detector.test.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"stack-detector.test.js","sourceRoot":"","sources":["../../src/lib/stack-detector.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAC;AACrE,OAAO,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,EAAS,MAAM,aAAa,CAAC;AAC5D,OAAO,EAAE,IAAI,EAAO,MAAM,MAAM,CAAC;AACjC,OAAO,EAAE,MAAM,EAAE,MAAM,IAAI,CAAC;AAC5B,OAAO,EAAE,WAAW,EAAE,MAAM,qBAAqB,CAAC;AAElD,KAAK,UAAU,KAAK;IAClB,OAAO,OAAO,CAAC,IAAI,CAAC,MAAM,EAAE,EAAE,iBAAiB,CAAC,CAAC,CAAC;AACpD,CAAC;AAED,QAAQ,CAAC,aAAa,EAAE,GAAG,EAAE;IAC3B,IAAI,GAAW,CAAC;IAEhB,UAAU,CAAC,KAAK,IAAI,EAAE;QACpB,GAAG,GAAG,MAAM,KAAK,EAAE,CAAC;IACtB,CAAC,CAAC,CAAC;IAEH,SAAS,CAAC,KAAK,IAAI,EAAE;QACnB,MAAM,EAAE,CAAC,GAAG,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC,CAAC;IAClD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,wCAAwC,EAAE,KAAK,IAAI,EAAE;QACtD,MAAM,SAAS,CACb,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,EACnB,oFAAoF,CACrF,CAAC;QAEF,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;QAErC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACxC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sCAAsC,EAAE,KAAK,IAAI,EAAE;QACpD,MAAM,SAAS,CACb,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,EACnB,qCAAqC,CACtC,CAAC;QAEF,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;QAErC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACxC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,kCAAkC,EAAE,KAAK,IAAI,EAAE;QAChD,MAAM,SAAS,CACb,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,EACzB,IAAI,CAAC,SAAS,CAAC;YACb,IAAI,EAAE,QAAQ;YACd,YAAY,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,WAAW,EAAE,SAAS,EAAE;YAC1D,eAAe,EAAE,EAAE,UAAU,EAAE,QAAQ,EAAE;SAC1C,CAAC,CACH,CAAC;QAEF,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;QAErC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QAChD,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAC5C,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,YAAY,CAAC,CAAC;IAC3C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,yBAAyB,EAAE,KAAK,IAAI,EAAE;QACvC,MAAM,SAAS,CACb,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,EACzB,IAAI,CAAC,SAAS,CAAC;YACb,IAAI,EAAE,aAAa;YACnB,YAAY,EAAE,EAAE,IAAI,EAAE,SAAS,EAAE,KAAK,EAAE,SAAS,EAAE;SACpD,CAAC,CACH,CAAC;QAEF,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;QAErC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAC3C,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,oDAAoD,EAAE,KAAK,IAAI,EAAE;QAClE,MAAM,SAAS,CACb,IAAI,CAAC,GAAG,EAAE,kBAAkB,CAAC,EAC7B,yCAAyC,CAC1C,CAAC;QAEF,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;QAErC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAC5C,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAC7C,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACvC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;QACjE,MAAM,SAAS,CACb,IAAI,CAAC,GAAG,EAAE,gBAAgB,CAAC,EAC3B,sEAAsE,CACvE,CAAC;QAEF,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;QAErC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,QAAQ,CAAC,CAAC;QAC5C,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,SAAS,CAAC,CAAC;IAChD,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,sBAAsB,EAAE,KAAK,IAAI,EAAE;QACpC,MAAM,SAAS,CACb,IAAI,CAAC,GAAG,EAAE,YAAY,CAAC,EACvB,iDAAiD,CAClD,CAAC;QAEF,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;QAErC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAC1C,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+BAA+B,EAAE,KAAK,IAAI,EAAE;QAC7C,MAAM,SAAS,CACb,IAAI,CAAC,GAAG,EAAE,SAAS,CAAC,EACpB,0DAA0D,CAC3D,CAAC;QAEF,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;QAErC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;QAC1C,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;QAC5C,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,MAAM,CAAC,CAAC;IACrC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,+DAA+D,EAAE,KAAK,IAAI,EAAE;QAC7E,MAAM,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,EAAE,qCAAqC,CAAC,CAAC;QAC5E,MAAM,SAAS,CACb,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,EACzB,IAAI,CAAC,SAAS,CAAC,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,CAAC,CACvD,CAAC;QAEF,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;QAErC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,IAAI,CAAC,CAAC;QACxC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,SAAS,CAAC,YAAY,CAAC,CAAC;QAChD,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,OAAO,CAAC,CAAC;IAC9C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,8CAA8C,EAAE,KAAK,IAAI,EAAE;QAC5D,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;QAErC,MAAM,CAAC,KAAK,CAAC,SAAS,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACxC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,CAAC;QACzC,MAAM,CAAC,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,SAAS,CAAC,CAAC;IACxC,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,6BAA6B,EAAE,KAAK,IAAI,EAAE;QAC3C,MAAM,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,UAAU,CAAC,EAAE,4BAA4B,CAAC,CAAC;QACrE,MAAM,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,EAAE,qCAAqC,CAAC,CAAC;QAE5E,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;QAErC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,MAAM,CAAC,CAAC;IAC7C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,mDAAmD,EAAE,KAAK,IAAI,EAAE;QACjE,MAAM,SAAS,CAAC,IAAI,CAAC,GAAG,EAAE,WAAW,CAAC,EAAE,EAAE,CAAC,CAAC;QAC5C,MAAM,SAAS,CACb,IAAI,CAAC,GAAG,EAAE,cAAc,CAAC,EACzB,IAAI,CAAC,SAAS,CAAC,EAAE,YAAY,EAAE,EAAE,KAAK,EAAE,SAAS,EAAE,EAAE,CAAC,CACvD,CAAC;QAEF,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;QAErC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;IAEH,EAAE,CAAC,qCAAqC,EAAE,KAAK,IAAI,EAAE;QACnD,MAAM,SAAS,CACb,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,EACnB,gFAAgF,CACjF,CAAC;QAEF,MAAM,KAAK,GAAG,MAAM,WAAW,CAAC,GAAG,CAAC,CAAC;QAErC,MAAM,CAAC,KAAK,CAAC,UAAU,CAAC,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC,CAAC,CAAC;AACL,CAAC,CAAC,CAAC"}
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
export {};
|