lazycodex-ai 4.19.2 → 4.19.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/dist/cli/config-migrate.d.ts +8 -0
- package/dist/cli/doctor/checks/deprecated-reasoning-keys.d.ts +2 -0
- package/dist/cli/doctor/checks/legacy-config-leftovers.d.ts +10 -0
- package/dist/cli/doctor/checks/model-resolution-config.d.ts +1 -1
- package/dist/cli/doctor/checks/tools-lsp.d.ts +1 -1
- package/dist/cli/doctor/framework/constants.d.ts +1 -1
- package/dist/cli/index.js +95684 -92814
- package/dist/cli-node/index.js +95650 -92780
- package/package.json +1 -1
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +21 -3
- package/packages/omo-codex/plugin/components/bootstrap/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/bootstrap/package.json +1 -1
- package/packages/omo-codex/plugin/components/codegraph/AGENTS.md +11 -5
- package/packages/omo-codex/plugin/components/codegraph/NOTICE +1 -1
- package/packages/omo-codex/plugin/components/codegraph/dist/cli.js +10373 -2570
- package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +7502 -574
- package/packages/omo-codex/plugin/components/codegraph/package.json +2 -2
- package/packages/omo-codex/plugin/components/codegraph/src/hook-input.ts +33 -0
- package/packages/omo-codex/plugin/components/codegraph/src/hook-types.ts +36 -10
- package/packages/omo-codex/plugin/components/codegraph/src/hook.ts +164 -159
- package/packages/omo-codex/plugin/components/codegraph/src/post-tool-use-hook.ts +34 -0
- package/packages/omo-codex/plugin/components/codegraph/src/serve.ts +20 -2
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-command.ts +106 -0
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-cooldown.ts +145 -0
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-hook-runtime.ts +21 -0
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-lock.ts +139 -0
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-outcome.ts +15 -0
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-paths.ts +32 -0
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-project.ts +109 -0
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker-result.ts +148 -0
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker.ts +126 -175
- package/packages/omo-codex/plugin/components/codegraph/test/hook-exclusion.test.ts +4 -4
- package/packages/omo-codex/plugin/components/codegraph/test/hook-session-start-guard.test.ts +160 -0
- package/packages/omo-codex/plugin/components/codegraph/test/hook-store-upgrade.test.ts +12 -138
- package/packages/omo-codex/plugin/components/codegraph/test/hook.test.ts +34 -24
- package/packages/omo-codex/plugin/components/codegraph/test/mcp-bridge-fixtures.ts +3 -3
- package/packages/omo-codex/plugin/components/codegraph/test/package-runtime.test.ts +2 -2
- package/packages/omo-codex/plugin/components/codegraph/test/provisioned-node-guard.test.ts +5 -5
- package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-bridge.test.ts +3 -3
- package/packages/omo-codex/plugin/components/codegraph/test/serve-mcp-facade.test.ts +1 -1
- package/packages/omo-codex/plugin/components/codegraph/test/serve-provision.test.ts +45 -0
- package/packages/omo-codex/plugin/components/codegraph/test/serve-unavailable.test.ts +2 -2
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-node-support.test.ts +70 -13
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-project.test.ts +58 -0
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-state.test.ts +104 -0
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-trust-boundary.test.ts +4 -2
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-cooldown.test.ts +116 -0
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-flow.test.ts +58 -57
- package/packages/omo-codex/plugin/components/comment-checker/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/comment-checker/package.json +1 -1
- package/packages/omo-codex/plugin/components/git-bash/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/git-bash/package.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/lazycodex-executor-verify/package.json +1 -1
- package/packages/omo-codex/plugin/components/lsp/dist/.omo-runtime-manifest.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/package.json +1 -1
- package/packages/omo-codex/plugin/components/rules/dist/cli.js +32 -15
- package/packages/omo-codex/plugin/components/rules/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/rules/package.json +1 -1
- package/packages/omo-codex/plugin/components/rules/src/post-compact-budget.ts +1 -1
- package/packages/omo-codex/plugin/components/start-work-continuation/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/start-work-continuation/package.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/teammode/package.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/telemetry/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/package.json +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/SKILL.md +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +4 -4
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/SKILL.md +17 -0
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +1 -1
- package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-guarding-ulw-loop-spawns.json +1 -1
- package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/stop-checking-ulw-loop-resume.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +1 -1
- package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +1 -1
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +1 -1
- package/packages/omo-codex/plugin/package-lock.json +42 -41
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/scripts/sync-skills.mjs +6 -0
- package/packages/omo-codex/plugin/shared/src/config-loader.ts +165 -16
- package/packages/omo-codex/plugin/shared/src/config-migration.ts +162 -0
- package/packages/omo-codex/plugin/shared/test/config-loader.test.ts +186 -9
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/SKILL.md +4 -3
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/references/all-platforms.md +3 -1
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/aside_scanner.py +140 -0
- package/packages/omo-codex/plugin/skills/coding-agent-sessions/scripts/agent_sessions/scanners.py +3 -0
- package/packages/omo-codex/plugin/skills/data-scientist/SKILL.md +243 -0
- package/packages/omo-codex/plugin/skills/data-scientist/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/data-scientist/references/common-scenarios.md +176 -0
- package/packages/omo-codex/plugin/skills/data-scientist/references/execution-templates.md +197 -0
- package/packages/omo-codex/plugin/skills/data-scientist/references/integration-patterns.md +153 -0
- package/packages/omo-codex/plugin/skills/data-scientist/references/performance-benchmarks.md +37 -0
- package/packages/omo-codex/plugin/skills/data-scientist/references/uv-setup.md +78 -0
- package/packages/omo-codex/plugin/skills/data-scientist/scripts/quick-query.py +111 -0
- package/packages/omo-codex/plugin/skills/data-scientist/scripts/setup-uv.ps1 +53 -0
- package/packages/omo-codex/plugin/skills/data-scientist/scripts/setup-uv.sh +60 -0
- package/packages/omo-codex/plugin/skills/debugging/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/frontend/ATTRIBUTION.md +7 -0
- package/packages/omo-codex/plugin/skills/frontend/SKILL.md +4 -1
- package/packages/omo-codex/plugin/skills/frontend/references/design/README.md +8 -0
- package/packages/omo-codex/plugin/skills/frontend/references/design/_INDEX.md +14 -1
- package/packages/omo-codex/plugin/skills/frontend/references/design/interaction-skill.md +144 -0
- package/packages/omo-codex/plugin/skills/programming/SKILL.md +1 -2
- package/packages/omo-codex/plugin/skills/ulw-loop/SKILL.md +17 -0
- package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +1 -1
- package/packages/omo-codex/plugin/skills/ulw-research/SKILL.md +121 -11
- package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +7 -0
- package/packages/omo-codex/plugin/test/sync-skills.test.mjs +12 -0
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +24 -5
- package/packages/shared-skills/skills/coding-agent-sessions/SKILL.md +4 -3
- package/packages/shared-skills/skills/coding-agent-sessions/references/all-platforms.md +3 -1
- package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/aside_scanner.py +140 -0
- package/packages/shared-skills/skills/coding-agent-sessions/scripts/agent_sessions/scanners.py +3 -0
- package/packages/shared-skills/skills/data-scientist/SKILL.md +243 -0
- package/packages/shared-skills/skills/data-scientist/references/common-scenarios.md +176 -0
- package/packages/shared-skills/skills/data-scientist/references/execution-templates.md +197 -0
- package/packages/shared-skills/skills/data-scientist/references/integration-patterns.md +153 -0
- package/packages/shared-skills/skills/data-scientist/references/performance-benchmarks.md +37 -0
- package/packages/shared-skills/skills/data-scientist/references/uv-setup.md +78 -0
- package/packages/shared-skills/skills/data-scientist/scripts/quick-query.py +111 -0
- package/packages/shared-skills/skills/data-scientist/scripts/setup-uv.ps1 +53 -0
- package/packages/shared-skills/skills/data-scientist/scripts/setup-uv.sh +60 -0
- package/packages/shared-skills/skills/debugging/SKILL.md +1 -1
- package/packages/shared-skills/skills/frontend/ATTRIBUTION.md +7 -0
- package/packages/shared-skills/skills/frontend/SKILL.md +4 -1
- package/packages/shared-skills/skills/frontend/references/design/README.md +8 -0
- package/packages/shared-skills/skills/frontend/references/design/_INDEX.md +14 -1
- package/packages/shared-skills/skills/frontend/references/design/interaction-skill.md +144 -0
- package/packages/shared-skills/skills/programming/SKILL.md +1 -2
- package/packages/shared-skills/skills/ulw-plan/SKILL.md +1 -1
- package/packages/shared-skills/skills/ulw-research/SKILL.md +122 -11
|
@@ -1,4 +1,6 @@
|
|
|
1
1
|
import { describe, expect, it } from "bun:test";
|
|
2
|
+
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
2
4
|
import { join } from "node:path";
|
|
3
5
|
|
|
4
6
|
import { runCodegraphServe } from "../src/serve.ts";
|
|
@@ -51,6 +53,49 @@ describe("runCodegraphServe provisioning", () => {
|
|
|
51
53
|
]);
|
|
52
54
|
});
|
|
53
55
|
|
|
56
|
+
it("#given a bundled runtime and a stale managed install #when serving MCP #then it upgrades and uses the managed runtime", async () => {
|
|
57
|
+
// given
|
|
58
|
+
const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-serve-managed-upgrade-"));
|
|
59
|
+
const installDir = join(homeDir, ".omo", "codegraph");
|
|
60
|
+
const binPath = join(installDir, "bin", "codegraph");
|
|
61
|
+
mkdirSync(join(installDir, "bin"), { recursive: true });
|
|
62
|
+
mkdirSync(join(installDir, ".provisioned"), { recursive: true });
|
|
63
|
+
writeFileSync(binPath, "stale codegraph\n");
|
|
64
|
+
writeFileSync(
|
|
65
|
+
join(installDir, ".provisioned", "codegraph-1.4.1.json"),
|
|
66
|
+
`${JSON.stringify({ binPath, version: "1.4.1" })}\n`,
|
|
67
|
+
);
|
|
68
|
+
const provisionCalls: unknown[] = [];
|
|
69
|
+
const processCalls: Array<{ readonly args: readonly string[]; readonly command: string }> = [];
|
|
70
|
+
|
|
71
|
+
try {
|
|
72
|
+
// when
|
|
73
|
+
const exitCode = await runCodegraphServe({
|
|
74
|
+
config: { codegraph: { enabled: true }, sources: [], warnings: [] },
|
|
75
|
+
homeDir,
|
|
76
|
+
managedInstallExists: () => true,
|
|
77
|
+
nodeVersion: "22.14.0",
|
|
78
|
+
resolve: () => ({ argsPrefix: ["codegraph.js"], command: "/opt/node22/bin/node", exists: true, source: "bundled" }),
|
|
79
|
+
resolveManagedBin: () => null,
|
|
80
|
+
ensureProvisioned: (options) => {
|
|
81
|
+
provisionCalls.push(options);
|
|
82
|
+
return Promise.resolve({ binPath, provisioned: true });
|
|
83
|
+
},
|
|
84
|
+
runProcess: (command, args) => {
|
|
85
|
+
processCalls.push({ args, command });
|
|
86
|
+
return Promise.resolve(0);
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
// then
|
|
91
|
+
expect(exitCode).toBe(0);
|
|
92
|
+
expect(provisionCalls).toEqual([{ installDir, lockDir: join(installDir, ".locks"), version: "1.5.0" }]);
|
|
93
|
+
expect(processCalls).toEqual([{ args: ["serve", "--mcp"], command: binPath }]);
|
|
94
|
+
} finally {
|
|
95
|
+
rmSync(homeDir, { force: true, recursive: true });
|
|
96
|
+
}
|
|
97
|
+
});
|
|
98
|
+
|
|
54
99
|
it("#given CodeGraph is unresolved and codegraph.daemon=false #when serving MCP #then provisions CodeGraph with daemon-off", async () => {
|
|
55
100
|
// given
|
|
56
101
|
const binPath = join("/tmp/home/.omo/codegraph", "bin", "codegraph");
|
|
@@ -97,8 +97,8 @@ describe("runCodegraphServe unavailable CodeGraph paths", () => {
|
|
|
97
97
|
try {
|
|
98
98
|
mkdirSync(join(homeDir, ".omo"), { recursive: true });
|
|
99
99
|
mkdirSync(join(workspace, ".omo"), { recursive: true });
|
|
100
|
-
writeFileSync(join(homeDir, ".omo", "
|
|
101
|
-
writeFileSync(join(workspace, ".omo", "
|
|
100
|
+
writeFileSync(join(homeDir, ".omo", "omo.jsonc"), '{ "codegraph": { "enabled": true } }\n');
|
|
101
|
+
writeFileSync(join(workspace, ".omo", "omo.jsonc"), '{ "[codex]": { "codegraph": { "enabled": false } } }\n');
|
|
102
102
|
|
|
103
103
|
// when
|
|
104
104
|
const exitCode = await runCodegraphServe({
|
package/packages/omo-codex/plugin/components/codegraph/test/session-start-node-support.test.ts
CHANGED
|
@@ -1,10 +1,15 @@
|
|
|
1
1
|
import { describe, expect, it } from "bun:test";
|
|
2
|
-
import { existsSync, mkdtempSync, rmSync } from "node:fs";
|
|
2
|
+
import { existsSync, mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
3
3
|
import { tmpdir } from "node:os";
|
|
4
4
|
import { join } from "node:path";
|
|
5
5
|
|
|
6
6
|
import { runCodegraphSessionStartWorker } from "../src/hook.ts";
|
|
7
7
|
|
|
8
|
+
function writeProjectDatabase(workspace: string): void {
|
|
9
|
+
mkdirSync(join(workspace, ".codegraph"), { recursive: true });
|
|
10
|
+
writeFileSync(join(workspace, ".codegraph", "codegraph.db"), "fixture");
|
|
11
|
+
}
|
|
12
|
+
|
|
8
13
|
describe("CodeGraph SessionStart worker Node support", () => {
|
|
9
14
|
it("#given an unsupported local Node and a PATH CodeGraph command with auto provisioning disabled #when worker runs #then it skips without touching the workspace", async () => {
|
|
10
15
|
// given
|
|
@@ -52,7 +57,7 @@ describe("CodeGraph SessionStart worker Node support", () => {
|
|
|
52
57
|
const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-node-provision-home-"));
|
|
53
58
|
const binPath = join(homeDir, ".omo", "codegraph", "bin", "codegraph");
|
|
54
59
|
const calls: Array<{ readonly args: readonly string[]; readonly command: string }> = [];
|
|
55
|
-
const provisionCalls: Array<{ readonly installDir?: string; readonly lockDir: string; readonly version: "1.
|
|
60
|
+
const provisionCalls: Array<{ readonly installDir?: string; readonly lockDir: string; readonly version: "1.5.0" }> = [];
|
|
56
61
|
const outcomes: unknown[] = [];
|
|
57
62
|
|
|
58
63
|
try {
|
|
@@ -78,19 +83,17 @@ describe("CodeGraph SessionStart worker Node support", () => {
|
|
|
78
83
|
resolveCommand: () => ({ argsPrefix: [], command: "/usr/local/bin/codegraph", exists: true, source: "path" }),
|
|
79
84
|
runCommand: (_projectRoot, command, args) => {
|
|
80
85
|
calls.push({ args, command });
|
|
81
|
-
|
|
86
|
+
writeProjectDatabase(workspace);
|
|
87
|
+
return Promise.resolve({ exitCode: 0, stdout: "", timedOut: false });
|
|
82
88
|
},
|
|
83
89
|
},
|
|
84
90
|
});
|
|
85
91
|
|
|
86
92
|
// then
|
|
87
93
|
expect(result).toEqual({ action: "initialized" });
|
|
88
|
-
expect(calls).toEqual([
|
|
89
|
-
{ args: ["status", "--json"], command: binPath },
|
|
90
|
-
{ args: ["init"], command: binPath },
|
|
91
|
-
]);
|
|
94
|
+
expect(calls).toEqual([{ args: ["init"], command: binPath }]);
|
|
92
95
|
expect(provisionCalls).toEqual([
|
|
93
|
-
{ installDir: join(homeDir, ".omo", "codegraph"), lockDir: join(homeDir, ".omo", "codegraph", ".locks"), version: "1.
|
|
96
|
+
{ installDir: join(homeDir, ".omo", "codegraph"), lockDir: join(homeDir, ".omo", "codegraph", ".locks"), version: "1.5.0" },
|
|
94
97
|
]);
|
|
95
98
|
expect(outcomes).toEqual([{ action: "initialized", exitCode: 0, projectRoot: workspace, source: "provisioned", timedOut: false }]);
|
|
96
99
|
} finally {
|
|
@@ -99,6 +102,62 @@ describe("CodeGraph SessionStart worker Node support", () => {
|
|
|
99
102
|
}
|
|
100
103
|
});
|
|
101
104
|
|
|
105
|
+
it("#given bundled CodeGraph and a stale managed install #when the worker runs #then it upgrades and uses the managed runtime", async () => {
|
|
106
|
+
// given
|
|
107
|
+
const workspace = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-managed-upgrade-"));
|
|
108
|
+
const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-managed-upgrade-home-"));
|
|
109
|
+
const installDir = join(homeDir, ".omo", "codegraph");
|
|
110
|
+
const binPath = join(installDir, "bin", "codegraph");
|
|
111
|
+
mkdirSync(join(installDir, "bin"), { recursive: true });
|
|
112
|
+
mkdirSync(join(installDir, ".provisioned"), { recursive: true });
|
|
113
|
+
writeFileSync(binPath, "stale codegraph\n");
|
|
114
|
+
writeFileSync(
|
|
115
|
+
join(installDir, ".provisioned", "codegraph-1.4.1.json"),
|
|
116
|
+
`${JSON.stringify({ binPath, version: "1.4.1" })}\n`,
|
|
117
|
+
);
|
|
118
|
+
const provisionCalls: unknown[] = [];
|
|
119
|
+
const commandCalls: Array<{ readonly args: readonly string[]; readonly command: string }> = [];
|
|
120
|
+
|
|
121
|
+
try {
|
|
122
|
+
// when
|
|
123
|
+
const result = await runCodegraphSessionStartWorker({
|
|
124
|
+
cwd: workspace,
|
|
125
|
+
env: { HOME: homeDir },
|
|
126
|
+
nodeVersion: "22.14.0",
|
|
127
|
+
deps: {
|
|
128
|
+
ensureGitignored: () => true,
|
|
129
|
+
ensureProvisioned: (options) => {
|
|
130
|
+
provisionCalls.push(options);
|
|
131
|
+
return Promise.resolve({ binPath, provisioned: true });
|
|
132
|
+
},
|
|
133
|
+
managedInstallExists: () => true,
|
|
134
|
+
prepareWorkspace: () => ({
|
|
135
|
+
dataDir: join(homeDir, ".omo/codegraph/projects/test"),
|
|
136
|
+
dataRoot: join(homeDir, ".omo/codegraph"),
|
|
137
|
+
linked: true,
|
|
138
|
+
mode: "global-linked",
|
|
139
|
+
projectLink: join(workspace, ".codegraph"),
|
|
140
|
+
}),
|
|
141
|
+
resolveCommand: () => ({ argsPrefix: ["codegraph.js"], command: "/opt/node22/bin/node", exists: true, source: "bundled" }),
|
|
142
|
+
resolveManagedBin: () => null,
|
|
143
|
+
runCommand: (_projectRoot, command, args) => {
|
|
144
|
+
commandCalls.push({ args, command });
|
|
145
|
+
writeProjectDatabase(workspace);
|
|
146
|
+
return Promise.resolve({ exitCode: 0, stdout: "", timedOut: false });
|
|
147
|
+
},
|
|
148
|
+
},
|
|
149
|
+
});
|
|
150
|
+
|
|
151
|
+
// then
|
|
152
|
+
expect(result).toEqual({ action: "initialized" });
|
|
153
|
+
expect(provisionCalls).toEqual([{ installDir, lockDir: join(installDir, ".locks"), version: "1.5.0" }]);
|
|
154
|
+
expect(commandCalls).toEqual([{ args: ["init"], command: binPath }]);
|
|
155
|
+
} finally {
|
|
156
|
+
rmSync(workspace, { recursive: true, force: true });
|
|
157
|
+
rmSync(homeDir, { recursive: true, force: true });
|
|
158
|
+
}
|
|
159
|
+
});
|
|
160
|
+
|
|
102
161
|
it("#given an unsupported local Node but bundled CodeGraph resolves through CODEGRAPH_NODE_BIN #when worker runs #then it bootstraps with the compatible runtime", async () => {
|
|
103
162
|
// given
|
|
104
163
|
const workspace = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-compatible-node-"));
|
|
@@ -129,17 +188,15 @@ describe("CodeGraph SessionStart worker Node support", () => {
|
|
|
129
188
|
resolveCommand: () => ({ argsPrefix: ["codegraph.js"], command: nodeBin, exists: true, source: "bundled" }),
|
|
130
189
|
runCommand: (_projectRoot, command, args) => {
|
|
131
190
|
calls.push({ args, command });
|
|
132
|
-
|
|
191
|
+
writeProjectDatabase(workspace);
|
|
192
|
+
return Promise.resolve({ exitCode: 0, stdout: "", timedOut: false });
|
|
133
193
|
},
|
|
134
194
|
},
|
|
135
195
|
});
|
|
136
196
|
|
|
137
197
|
// then
|
|
138
198
|
expect(result).toEqual({ action: "initialized" });
|
|
139
|
-
expect(calls).toEqual([
|
|
140
|
-
{ args: ["codegraph.js", "status", "--json"], command: nodeBin },
|
|
141
|
-
{ args: ["codegraph.js", "init"], command: nodeBin },
|
|
142
|
-
]);
|
|
199
|
+
expect(calls).toEqual([{ args: ["codegraph.js", "init"], command: nodeBin }]);
|
|
143
200
|
expect(outcomes).toEqual([{ action: "initialized", exitCode: 0, projectRoot: workspace, source: "bundled", timedOut: false }]);
|
|
144
201
|
} finally {
|
|
145
202
|
rmSync(workspace, { recursive: true, force: true });
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
|
+
import { mkdirSync, mkdtempSync, realpathSync, rmSync, writeFileSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
|
|
6
|
+
import { probeCodegraphProject } from "../src/session-start-project.ts";
|
|
7
|
+
|
|
8
|
+
describe("CodeGraph SessionStart project probe", () => {
|
|
9
|
+
it("#given the exact project directory has a CodeGraph database #when probing #then it is initialized", () => {
|
|
10
|
+
// given
|
|
11
|
+
const projectRoot = mkdtempSync(join(tmpdir(), "omo-codegraph-probe-exact-"));
|
|
12
|
+
try {
|
|
13
|
+
mkdirSync(join(projectRoot, ".codegraph"), { recursive: true });
|
|
14
|
+
writeFileSync(join(projectRoot, ".codegraph", "codegraph.db"), "fixture");
|
|
15
|
+
|
|
16
|
+
// when
|
|
17
|
+
const result = probeCodegraphProject(projectRoot);
|
|
18
|
+
|
|
19
|
+
// then
|
|
20
|
+
expect(result).toEqual({ kind: "initialized" });
|
|
21
|
+
} finally {
|
|
22
|
+
rmSync(projectRoot, { recursive: true, force: true });
|
|
23
|
+
}
|
|
24
|
+
});
|
|
25
|
+
|
|
26
|
+
it("#given an ancestor directory has a CodeGraph database #when probing a nested project #then the ancestor covers it", () => {
|
|
27
|
+
// given
|
|
28
|
+
const ancestorRoot = mkdtempSync(join(tmpdir(), "omo-codegraph-probe-ancestor-"));
|
|
29
|
+
const projectRoot = join(ancestorRoot, "apps", "server");
|
|
30
|
+
try {
|
|
31
|
+
mkdirSync(join(ancestorRoot, ".codegraph"), { recursive: true });
|
|
32
|
+
mkdirSync(projectRoot, { recursive: true });
|
|
33
|
+
writeFileSync(join(ancestorRoot, ".codegraph", "codegraph.db"), "fixture");
|
|
34
|
+
|
|
35
|
+
// when
|
|
36
|
+
const result = probeCodegraphProject(projectRoot);
|
|
37
|
+
|
|
38
|
+
// then
|
|
39
|
+
expect(result).toEqual({ ancestorRoot: realpathSync(ancestorRoot), kind: "nested-root" });
|
|
40
|
+
} finally {
|
|
41
|
+
rmSync(ancestorRoot, { recursive: true, force: true });
|
|
42
|
+
}
|
|
43
|
+
});
|
|
44
|
+
|
|
45
|
+
it("#given neither the project nor its ancestors have a CodeGraph database #when probing #then it is definitively uninitialized", () => {
|
|
46
|
+
// given
|
|
47
|
+
const projectRoot = mkdtempSync(join(tmpdir(), "omo-codegraph-probe-missing-"));
|
|
48
|
+
try {
|
|
49
|
+
// when
|
|
50
|
+
const result = probeCodegraphProject(projectRoot);
|
|
51
|
+
|
|
52
|
+
// then
|
|
53
|
+
expect(result).toEqual({ kind: "uninitialized" });
|
|
54
|
+
} finally {
|
|
55
|
+
rmSync(projectRoot, { recursive: true, force: true });
|
|
56
|
+
}
|
|
57
|
+
});
|
|
58
|
+
});
|
|
@@ -0,0 +1,104 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
|
+
import { mkdtempSync, rmSync, utimesSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
clearSessionStartCooldown,
|
|
8
|
+
readSessionStartCooldown,
|
|
9
|
+
recordSessionStartFailure,
|
|
10
|
+
} from "../src/session-start-cooldown.ts";
|
|
11
|
+
import {
|
|
12
|
+
acquireSessionStartLock,
|
|
13
|
+
releaseSessionStartLock,
|
|
14
|
+
} from "../src/session-start-lock.ts";
|
|
15
|
+
|
|
16
|
+
describe("CodeGraph SessionStart lock", () => {
|
|
17
|
+
it("#given a live project lock #when a second hook acquires it #then the second hook is deduplicated", () => {
|
|
18
|
+
// given
|
|
19
|
+
const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-lock-home-"));
|
|
20
|
+
const projectRoot = mkdtempSync(join(tmpdir(), "omo-codegraph-lock-project-"));
|
|
21
|
+
try {
|
|
22
|
+
const first = acquireSessionStartLock({ homeDir, nowMs: 10_000, projectRoot, staleMs: 60_000 });
|
|
23
|
+
expect(first.kind).toBe("acquired");
|
|
24
|
+
|
|
25
|
+
// when
|
|
26
|
+
const second = acquireSessionStartLock({ homeDir, nowMs: 10_001, projectRoot, staleMs: 60_000 });
|
|
27
|
+
|
|
28
|
+
// then
|
|
29
|
+
expect(second).toEqual({ kind: "locked" });
|
|
30
|
+
if (first.kind === "acquired") releaseSessionStartLock(first.lock);
|
|
31
|
+
} finally {
|
|
32
|
+
rmSync(homeDir, { recursive: true, force: true });
|
|
33
|
+
rmSync(projectRoot, { recursive: true, force: true });
|
|
34
|
+
}
|
|
35
|
+
});
|
|
36
|
+
|
|
37
|
+
it("#given a project lock older than the stale threshold #when another hook acquires it #then the stale lock is recovered", () => {
|
|
38
|
+
// given
|
|
39
|
+
const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-stale-home-"));
|
|
40
|
+
const projectRoot = mkdtempSync(join(tmpdir(), "omo-codegraph-stale-project-"));
|
|
41
|
+
try {
|
|
42
|
+
const first = acquireSessionStartLock({ homeDir, nowMs: 1_000, projectRoot, staleMs: 500 });
|
|
43
|
+
expect(first.kind).toBe("acquired");
|
|
44
|
+
if (first.kind !== "acquired") return;
|
|
45
|
+
const staleDate = new Date(1_000);
|
|
46
|
+
utimesSync(first.lock.path, staleDate, staleDate);
|
|
47
|
+
|
|
48
|
+
// when
|
|
49
|
+
const second = acquireSessionStartLock({ homeDir, nowMs: 2_000, projectRoot, staleMs: 500 });
|
|
50
|
+
|
|
51
|
+
// then
|
|
52
|
+
expect(second.kind).toBe("acquired");
|
|
53
|
+
if (second.kind === "acquired") {
|
|
54
|
+
expect(second.recoveredStale).toBe(true);
|
|
55
|
+
releaseSessionStartLock(second.lock);
|
|
56
|
+
}
|
|
57
|
+
} finally {
|
|
58
|
+
rmSync(homeDir, { recursive: true, force: true });
|
|
59
|
+
rmSync(projectRoot, { recursive: true, force: true });
|
|
60
|
+
}
|
|
61
|
+
});
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
describe("CodeGraph SessionStart cooldown", () => {
|
|
65
|
+
it("#given a failed worker outcome #when the cooldown is checked #then retries are suppressed until expiry and the next failure backs off", () => {
|
|
66
|
+
// given
|
|
67
|
+
const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-cooldown-home-"));
|
|
68
|
+
const projectRoot = mkdtempSync(join(tmpdir(), "omo-codegraph-cooldown-project-"));
|
|
69
|
+
try {
|
|
70
|
+
const first = recordSessionStartFailure({
|
|
71
|
+
action: "failed",
|
|
72
|
+
baseCooldownMs: 1_000,
|
|
73
|
+
homeDir,
|
|
74
|
+
nowMs: 1_000,
|
|
75
|
+
projectRoot,
|
|
76
|
+
});
|
|
77
|
+
|
|
78
|
+
// when
|
|
79
|
+
const active = readSessionStartCooldown({ baseCooldownMs: 1_000, homeDir, nowMs: 1_999, projectRoot });
|
|
80
|
+
const expired = readSessionStartCooldown({ baseCooldownMs: 1_000, homeDir, nowMs: 2_000, projectRoot });
|
|
81
|
+
const second = recordSessionStartFailure({
|
|
82
|
+
action: "skipped-status",
|
|
83
|
+
baseCooldownMs: 1_000,
|
|
84
|
+
homeDir,
|
|
85
|
+
nowMs: 2_000,
|
|
86
|
+
projectRoot,
|
|
87
|
+
});
|
|
88
|
+
|
|
89
|
+
// then
|
|
90
|
+
expect(first).toMatchObject({ cooldownUntil: 2_000, failureCount: 1 });
|
|
91
|
+
expect(active).toMatchObject({ cooldownUntil: 2_000, failureCount: 1, kind: "active" });
|
|
92
|
+
expect(expired).toEqual({ failureCount: 1, kind: "inactive" });
|
|
93
|
+
expect(second).toMatchObject({ cooldownUntil: 4_000, failureCount: 2 });
|
|
94
|
+
clearSessionStartCooldown({ homeDir, projectRoot });
|
|
95
|
+
expect(readSessionStartCooldown({ baseCooldownMs: 1_000, homeDir, nowMs: 2_001, projectRoot })).toEqual({
|
|
96
|
+
failureCount: 0,
|
|
97
|
+
kind: "inactive",
|
|
98
|
+
});
|
|
99
|
+
} finally {
|
|
100
|
+
rmSync(homeDir, { recursive: true, force: true });
|
|
101
|
+
rmSync(projectRoot, { recursive: true, force: true });
|
|
102
|
+
}
|
|
103
|
+
});
|
|
104
|
+
});
|
package/packages/omo-codex/plugin/components/codegraph/test/session-start-trust-boundary.test.ts
CHANGED
|
@@ -15,7 +15,7 @@ describe("CodeGraph SessionStart trust boundary", () => {
|
|
|
15
15
|
const calls: Array<{ readonly env: Record<string, string>; readonly installDir?: string; readonly lockDir?: string }> = [];
|
|
16
16
|
try {
|
|
17
17
|
mkdirSync(join(workspace, ".omo"), { recursive: true });
|
|
18
|
-
writeFileSync(join(workspace, ".omo", "
|
|
18
|
+
writeFileSync(join(workspace, ".omo", "omo.jsonc"), JSON.stringify({ codegraph: { enabled: true, install_dir: attackerInstallDir } }));
|
|
19
19
|
|
|
20
20
|
// when
|
|
21
21
|
const result = await runCodegraphSessionStartWorker({
|
|
@@ -45,7 +45,9 @@ describe("CodeGraph SessionStart trust boundary", () => {
|
|
|
45
45
|
},
|
|
46
46
|
runCommand: (_projectRoot, _command, _args, options) => {
|
|
47
47
|
calls.push({ env: options.env });
|
|
48
|
-
|
|
48
|
+
mkdirSync(join(workspace, ".codegraph"), { recursive: true });
|
|
49
|
+
writeFileSync(join(workspace, ".codegraph", "codegraph.db"), "fixture");
|
|
50
|
+
return Promise.resolve({ exitCode: 0, stdout: "", timedOut: false });
|
|
49
51
|
},
|
|
50
52
|
},
|
|
51
53
|
});
|
package/packages/omo-codex/plugin/components/codegraph/test/session-start-worker-cooldown.test.ts
ADDED
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
import { describe, expect, it } from "bun:test";
|
|
2
|
+
import { mkdtempSync, rmSync } from "node:fs";
|
|
3
|
+
import { tmpdir } from "node:os";
|
|
4
|
+
import { join } from "node:path";
|
|
5
|
+
|
|
6
|
+
import type { CodegraphSessionStartOutcome } from "../src/hook.ts";
|
|
7
|
+
import { runCodegraphSessionStartWorker } from "../src/hook.ts";
|
|
8
|
+
import { readSessionStartCooldown } from "../src/session-start-cooldown.ts";
|
|
9
|
+
|
|
10
|
+
describe("CodeGraph SessionStart worker cooldown", () => {
|
|
11
|
+
it("#given codegraph init times out #when the worker finishes #then it records a failed outcome and cooldown", async () => {
|
|
12
|
+
// given
|
|
13
|
+
const workspace = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-timeout-"));
|
|
14
|
+
const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-timeout-home-"));
|
|
15
|
+
const outcomes: CodegraphSessionStartOutcome[] = [];
|
|
16
|
+
try {
|
|
17
|
+
// when
|
|
18
|
+
const result = await runCodegraphSessionStartWorker({
|
|
19
|
+
config: { codegraph: { enabled: true, session_start_cooldown_ms: 60_000 }, sources: [], warnings: [] },
|
|
20
|
+
cwd: workspace,
|
|
21
|
+
env: { HOME: homeDir },
|
|
22
|
+
logOutcome: (outcome) => outcomes.push(outcome),
|
|
23
|
+
nodeVersion: "22.14.0",
|
|
24
|
+
nowMs: 1_000,
|
|
25
|
+
projectProbe: () => ({ kind: "uninitialized" }),
|
|
26
|
+
deps: {
|
|
27
|
+
ensureGitignored: () => true,
|
|
28
|
+
ensureProvisioned: () => Promise.resolve({ binPath: "/tmp/codegraph", provisioned: true }),
|
|
29
|
+
prepareWorkspace: () => ({
|
|
30
|
+
dataDir: join(homeDir, ".omo/codegraph/projects/test"),
|
|
31
|
+
dataRoot: join(homeDir, ".omo/codegraph"),
|
|
32
|
+
linked: true,
|
|
33
|
+
mode: "global-linked",
|
|
34
|
+
projectLink: join(workspace, ".codegraph"),
|
|
35
|
+
}),
|
|
36
|
+
resolveCommand: () => ({ argsPrefix: [], command: "/tmp/codegraph", exists: true, source: "path" }),
|
|
37
|
+
runCommand: () => Promise.resolve({ exitCode: 1, stdout: "", timedOut: true }),
|
|
38
|
+
},
|
|
39
|
+
});
|
|
40
|
+
const cooldown = readSessionStartCooldown({
|
|
41
|
+
baseCooldownMs: 60_000,
|
|
42
|
+
homeDir,
|
|
43
|
+
nowMs: 2_000,
|
|
44
|
+
projectRoot: workspace,
|
|
45
|
+
});
|
|
46
|
+
|
|
47
|
+
// then
|
|
48
|
+
expect(result).toEqual({ action: "failed" });
|
|
49
|
+
expect(outcomes).toEqual([{
|
|
50
|
+
action: "failed",
|
|
51
|
+
error: "codegraph init timed out",
|
|
52
|
+
exitCode: 1,
|
|
53
|
+
projectRoot: workspace,
|
|
54
|
+
source: "path",
|
|
55
|
+
timedOut: true,
|
|
56
|
+
}]);
|
|
57
|
+
expect(cooldown).toEqual({ cooldownUntil: 61_000, failureCount: 1, kind: "active" });
|
|
58
|
+
} finally {
|
|
59
|
+
rmSync(homeDir, { recursive: true, force: true });
|
|
60
|
+
rmSync(workspace, { recursive: true, force: true });
|
|
61
|
+
}
|
|
62
|
+
});
|
|
63
|
+
|
|
64
|
+
it("#given codegraph init exits zero without an exact database #when the worker verifies the result #then it records a failure cooldown", async () => {
|
|
65
|
+
// given
|
|
66
|
+
const workspace = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-no-db-"));
|
|
67
|
+
const homeDir = mkdtempSync(join(tmpdir(), "omo-codegraph-worker-no-db-home-"));
|
|
68
|
+
const outcomes: CodegraphSessionStartOutcome[] = [];
|
|
69
|
+
try {
|
|
70
|
+
// when
|
|
71
|
+
const result = await runCodegraphSessionStartWorker({
|
|
72
|
+
config: { codegraph: { enabled: true, session_start_cooldown_ms: 60_000 }, sources: [], warnings: [] },
|
|
73
|
+
cwd: workspace,
|
|
74
|
+
env: { HOME: homeDir },
|
|
75
|
+
logOutcome: (outcome) => outcomes.push(outcome),
|
|
76
|
+
nodeVersion: "22.14.0",
|
|
77
|
+
nowMs: 1_000,
|
|
78
|
+
projectProbe: () => ({ kind: "uninitialized" }),
|
|
79
|
+
deps: {
|
|
80
|
+
ensureGitignored: () => true,
|
|
81
|
+
ensureProvisioned: () => Promise.resolve({ binPath: "/tmp/codegraph", provisioned: true }),
|
|
82
|
+
prepareWorkspace: () => ({
|
|
83
|
+
dataDir: join(homeDir, ".omo/codegraph/projects/test"),
|
|
84
|
+
dataRoot: join(homeDir, ".omo/codegraph"),
|
|
85
|
+
linked: true,
|
|
86
|
+
mode: "global-linked",
|
|
87
|
+
projectLink: join(workspace, ".codegraph"),
|
|
88
|
+
}),
|
|
89
|
+
resolveCommand: () => ({ argsPrefix: [], command: "/tmp/codegraph", exists: true, source: "path" }),
|
|
90
|
+
runCommand: () => Promise.resolve({ exitCode: 0, stdout: "", timedOut: false }),
|
|
91
|
+
},
|
|
92
|
+
});
|
|
93
|
+
const cooldown = readSessionStartCooldown({
|
|
94
|
+
baseCooldownMs: 60_000,
|
|
95
|
+
homeDir,
|
|
96
|
+
nowMs: 2_000,
|
|
97
|
+
projectRoot: workspace,
|
|
98
|
+
});
|
|
99
|
+
|
|
100
|
+
// then
|
|
101
|
+
expect(result).toEqual({ action: "failed" });
|
|
102
|
+
expect(outcomes).toEqual([{
|
|
103
|
+
action: "failed",
|
|
104
|
+
error: "codegraph init completed without creating an exact project database",
|
|
105
|
+
exitCode: 0,
|
|
106
|
+
projectRoot: workspace,
|
|
107
|
+
source: "path",
|
|
108
|
+
timedOut: false,
|
|
109
|
+
}]);
|
|
110
|
+
expect(cooldown).toEqual({ cooldownUntil: 61_000, failureCount: 1, kind: "active" });
|
|
111
|
+
} finally {
|
|
112
|
+
rmSync(homeDir, { recursive: true, force: true });
|
|
113
|
+
rmSync(workspace, { recursive: true, force: true });
|
|
114
|
+
}
|
|
115
|
+
});
|
|
116
|
+
});
|