oh-my-opencode 4.11.1 → 4.12.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/.agents/skills/codex-qa/scripts/lib/app-server-client.mjs +132 -82
- package/.agents/skills/codex-qa/scripts/lib/app-server-client.test.js +48 -0
- package/.agents/skills/opencode-qa/scripts/serve-wake-split-probe.sh +361 -84
- package/.agents/skills/work-with-pr/SKILL.md +19 -5
- package/.opencode/skills/work-with-pr/SKILL.md +19 -5
- package/dist/agents/types.d.ts +7 -6
- package/dist/cli/index.js +460 -309
- package/dist/cli-node/index.js +460 -309
- package/dist/features/background-agent/parent-wake-flush-runner.d.ts +1 -0
- package/dist/features/background-agent/parent-wake-history-state.d.ts +1 -0
- package/dist/features/background-agent/parent-wake-session-history.d.ts +1 -47
- package/dist/features/background-agent/parent-wake-session-message.d.ts +47 -0
- package/dist/index.js +593 -310
- package/dist/plugin/tool-execute-before.d.ts +2 -0
- package/dist/plugin-handlers/plugin-components-loader.d.ts +1 -0
- package/dist/skills/ultraresearch/SKILL.md +11 -2
- package/dist/skills/ulw-plan/SKILL.md +2 -1
- package/dist/skills/ulw-plan/references/full-workflow.md +1 -1
- package/dist/skills/ulw-plan/references/intent-clear.md +2 -2
- package/dist/tools/background-task/constants.d.ts +1 -1
- package/dist/tools/delegate-task/sync-session-poller.d.ts +1 -2
- package/dist/tools/delegate-task/sync-session-turns.d.ts +3 -0
- package/dist/tui.js +25 -10
- package/package.json +13 -13
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +24 -2
- package/packages/omo-codex/plugin/components/bootstrap/dist/cli.js +25 -9
- 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/dist/cli.js +336 -173
- package/packages/omo-codex/plugin/components/codegraph/dist/serve.js +284 -33
- package/packages/omo-codex/plugin/components/codegraph/package.json +1 -1
- package/packages/omo-codex/plugin/components/codegraph/src/cli.ts +11 -0
- package/packages/omo-codex/plugin/components/codegraph/src/hook-types.ts +12 -0
- package/packages/omo-codex/plugin/components/codegraph/src/hook.ts +34 -0
- package/packages/omo-codex/plugin/components/codegraph/src/serve.ts +47 -5
- package/packages/omo-codex/plugin/components/codegraph/src/session-start-worker.ts +7 -5
- package/packages/omo-codex/plugin/components/codegraph/test/hook.test.ts +58 -96
- package/packages/omo-codex/plugin/components/codegraph/test/provisioned-node-guard.test.ts +94 -0
- package/packages/omo-codex/plugin/components/codegraph/test/serve-node-support.test.ts +33 -0
- package/packages/omo-codex/plugin/components/codegraph/test/serve-provision.test.ts +48 -0
- package/packages/omo-codex/plugin/components/codegraph/test/serve.test.ts +1 -0
- package/packages/omo-codex/plugin/components/codegraph/test/session-start-node-support.test.ts +142 -0
- 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/comment-checker/test/package-smoke.test.ts +2 -71
- 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/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/package.json +2 -2
- package/packages/omo-codex/plugin/components/lsp/test/package-smoke.test.ts +26 -104
- 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/test/package-smoke.test.ts +12 -92
- package/packages/omo-codex/plugin/components/start-work-continuation/dist/cli.js +157 -234
- 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 -2
- package/packages/omo-codex/plugin/components/start-work-continuation/src/boulder-reader.ts +227 -15
- package/packages/omo-codex/plugin/components/start-work-continuation/test/boulder-reader.test.ts +62 -2
- package/packages/omo-codex/plugin/components/start-work-continuation/test/cli.test.ts +34 -3
- package/packages/omo-codex/plugin/components/teammode/dist/cli.js +94 -0
- package/packages/omo-codex/plugin/components/teammode/hooks/hooks.json +17 -0
- package/packages/omo-codex/plugin/components/teammode/package.json +26 -0
- package/packages/omo-codex/plugin/components/teammode/skills/teammode/SKILL.md +139 -0
- package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team-guide.mjs +111 -0
- package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team-state.mjs +250 -0
- package/packages/omo-codex/plugin/components/teammode/skills/teammode/scripts/team.mjs +220 -0
- package/packages/omo-codex/plugin/components/teammode/src/cli.ts +12 -0
- package/packages/omo-codex/plugin/components/teammode/src/codex-hook.ts +125 -0
- package/packages/omo-codex/plugin/components/teammode/test/thread-title-hook.test.ts +116 -0
- package/packages/omo-codex/plugin/components/teammode/tsconfig.json +25 -0
- 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/test-support/package-smoke-fixture.ts +158 -0
- 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 +2 -1
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/full-workflow.md +1 -1
- package/packages/omo-codex/plugin/components/ultrawork/skills/ulw-plan/references/intent-clear.md +2 -2
- package/packages/omo-codex/plugin/components/ultrawork/test/package-smoke.test.ts +76 -49
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +2 -2
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/skills/ulw-loop/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/test/package-smoke.test.ts +1 -1
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-git-bash-mcp-reminder.json +17 -0
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-lsp-diagnostics-cache.json +17 -0
- package/packages/omo-codex/plugin/hooks/post-compact-resetting-project-rule-cache.json +17 -0
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-codegraph-init-guidance.json +17 -0
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-comments.json +17 -0
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-lsp-diagnostics.json +17 -0
- package/packages/omo-codex/plugin/hooks/post-tool-use-checking-thread-title-hygiene.json +17 -0
- package/packages/omo-codex/plugin/hooks/post-tool-use-matching-project-rules.json +17 -0
- package/packages/omo-codex/plugin/hooks/pre-tool-use-enforcing-unlimited-goal-budget.json +17 -0
- package/packages/omo-codex/plugin/hooks/pre-tool-use-recommending-git-bash-mcp.json +17 -0
- package/packages/omo-codex/plugin/hooks/session-start-checking-auto-update.json +17 -0
- package/packages/omo-codex/plugin/hooks/session-start-checking-bootstrap-provisioning.json +17 -0
- package/packages/omo-codex/plugin/hooks/session-start-checking-codegraph-bootstrap.json +16 -0
- package/packages/omo-codex/plugin/hooks/session-start-loading-project-rules.json +16 -0
- package/packages/omo-codex/plugin/hooks/session-start-recording-session-telemetry.json +16 -0
- package/packages/omo-codex/plugin/hooks/stop-checking-start-work-continuation.json +16 -0
- package/packages/omo-codex/plugin/hooks/subagent-stop-checking-start-work-continuation.json +16 -0
- package/packages/omo-codex/plugin/hooks/subagent-stop-verifying-lazycodex-executor-evidence.json +17 -0
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ultrawork-trigger.json +16 -0
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-checking-ulw-loop-steering.json +16 -0
- package/packages/omo-codex/plugin/hooks/user-prompt-submit-loading-project-rules.json +16 -0
- package/packages/omo-codex/plugin/package-lock.json +30 -22
- package/packages/omo-codex/plugin/package.json +2 -1
- package/packages/omo-codex/plugin/scripts/hook-status-message.mjs +15 -11
- package/packages/omo-codex/plugin/scripts/sync-hook-status-messages.mjs +15 -4
- package/packages/omo-codex/plugin/scripts/sync-skills.mjs +37 -0
- package/packages/omo-codex/plugin/skills/ast-grep/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/comment-checker/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/debugging/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/frontend/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/git-master/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/skills/init-deep/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/lcx-contribute-bug-fix/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/skills/lcx-doctor/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/skills/lcx-report-bug/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/skills/lsp/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/lsp-setup/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/programming/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/refactor/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/remove-ai-slops/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/review-work/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/rules/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/start-work/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/teammode/SKILL.md +139 -0
- package/packages/omo-codex/plugin/skills/teammode/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/teammode/scripts/team-guide.mjs +111 -0
- package/packages/omo-codex/plugin/skills/teammode/scripts/team-state.mjs +250 -0
- package/packages/omo-codex/plugin/skills/teammode/scripts/team.mjs +220 -0
- package/packages/omo-codex/plugin/skills/ultraresearch/SKILL.md +11 -2
- package/packages/omo-codex/plugin/skills/ultraresearch/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/skills/ulw-loop/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/skills/ulw-plan/SKILL.md +2 -1
- package/packages/omo-codex/plugin/skills/ulw-plan/agents/openai.yaml +1 -1
- package/packages/omo-codex/plugin/skills/ulw-plan/references/full-workflow.md +1 -1
- package/packages/omo-codex/plugin/skills/ulw-plan/references/intent-clear.md +2 -2
- package/packages/omo-codex/plugin/skills/visual-qa/agents/openai.yaml +2 -0
- package/packages/omo-codex/plugin/test/aggregate-hooks.test.mjs +70 -33
- package/packages/omo-codex/plugin/test/aggregate-manifest.test.mjs +6 -2
- package/packages/omo-codex/plugin/test/aggregate-plugin-fixture.mjs +14 -1
- package/packages/omo-codex/plugin/test/bootstrap-binlinks.test.mjs +1 -1
- package/packages/omo-codex/plugin/test/bootstrap-hooks.test.mjs +14 -6
- package/packages/omo-codex/plugin/test/bootstrap-ps-guard.test.mjs +7 -3
- package/packages/omo-codex/plugin/test/component-bundled-cli.test.mjs +4 -3
- package/packages/omo-codex/plugin/test/component-hook-contract-cases.mjs +24 -0
- package/packages/omo-codex/plugin/test/display-metadata.test.mjs +83 -0
- package/packages/omo-codex/plugin/test/hook-status-message.test.mjs +31 -19
- package/packages/omo-codex/plugin/test/lcx-bug-skills.test.mjs +3 -3
- package/packages/omo-codex/plugin/test/sync-hook-status-messages.test.mjs +6 -6
- package/packages/omo-codex/plugin/test/sync-skills-test-support.mjs +2 -0
- package/packages/omo-codex/plugin/test/sync-skills.test.mjs +9 -4
- package/packages/omo-codex/plugin/test/teammode-safety-fixture.mjs +88 -0
- package/packages/omo-codex/plugin/test/teammode-safety.test.mjs +240 -0
- package/packages/omo-codex/plugin/test/ultraresearch-skill-contract.test.mjs +48 -0
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +398 -206
- package/packages/omo-codex/scripts/install-hook-targets.test.mjs +93 -0
- package/packages/omo-codex/scripts/install-lazycodex-version-stamp.test.mjs +2 -2
- package/packages/omo-codex/scripts/install-local-bun-global-update.test.mjs +63 -0
- package/packages/omo-codex/scripts/install-local-entrypoint.test.mjs +109 -1
- package/packages/omo-codex/scripts/install-local.mjs +1 -0
- package/packages/shared-skills/skills/ultraresearch/SKILL.md +11 -2
- package/packages/shared-skills/skills/ulw-plan/SKILL.md +2 -1
- package/packages/shared-skills/skills/ulw-plan/references/full-workflow.md +1 -1
- package/packages/shared-skills/skills/ulw-plan/references/intent-clear.md +2 -2
- package/packages/omo-codex/plugin/hooks/hooks.json +0 -214
|
@@ -1,44 +1,12 @@
|
|
|
1
|
-
import { readFileSync } from "node:fs";
|
|
2
1
|
import { describe, expect, it } from "vitest";
|
|
3
|
-
|
|
4
|
-
type PackageJson = {
|
|
5
|
-
readonly type: string;
|
|
6
|
-
readonly packageManager: string;
|
|
7
|
-
readonly bin: Record<string, string>;
|
|
8
|
-
readonly dependencies?: Record<string, unknown>;
|
|
9
|
-
readonly optionalDependencies: Record<string, string>;
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
type HookCommand = {
|
|
13
|
-
readonly command: string;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
type HookEntry = {
|
|
17
|
-
readonly hooks: readonly HookCommand[];
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
type HooksJson = {
|
|
21
|
-
readonly hooks: Record<string, readonly HookEntry[]>;
|
|
22
|
-
};
|
|
23
|
-
|
|
24
|
-
function readPackageJson(path: string): PackageJson {
|
|
25
|
-
const parsed: unknown = JSON.parse(readFileSync(path, "utf8"));
|
|
26
|
-
if (!isPackageJson(parsed)) throw new TypeError(`Invalid package metadata: ${path}`);
|
|
27
|
-
return parsed;
|
|
28
|
-
}
|
|
29
|
-
|
|
30
|
-
function readHooksJson(path: string): HooksJson {
|
|
31
|
-
const parsed: unknown = JSON.parse(readFileSync(path, "utf8"));
|
|
32
|
-
if (!isHooksJson(parsed)) throw new TypeError(`Invalid hooks metadata: ${path}`);
|
|
33
|
-
return parsed;
|
|
34
|
-
}
|
|
2
|
+
import { readHooksJson, readPackageJson, readTextFile } from "../../test-support/package-smoke-fixture.js";
|
|
35
3
|
|
|
36
4
|
describe("plugin package metadata", () => {
|
|
37
5
|
it("#given packaged plugin files #when validating entrypoints #then hook command uses portable plugin root interpolation", () => {
|
|
38
6
|
// given
|
|
39
7
|
const packageJson = readPackageJson("package.json");
|
|
40
8
|
const hooksJson = readHooksJson("hooks/hooks.json");
|
|
41
|
-
const cliSource =
|
|
9
|
+
const cliSource = readTextFile("src/cli.ts");
|
|
42
10
|
|
|
43
11
|
// when
|
|
44
12
|
const command = hooksJson.hooks["PostToolUse"]?.[0]?.hooks[0]?.command;
|
|
@@ -54,40 +22,3 @@ describe("plugin package metadata", () => {
|
|
|
54
22
|
expect(command).toBe(`node "${pluginRoot}/dist/cli.js" hook post-tool-use`);
|
|
55
23
|
});
|
|
56
24
|
});
|
|
57
|
-
|
|
58
|
-
function isPackageJson(value: unknown): value is PackageJson {
|
|
59
|
-
if (!isRecord(value)) return false;
|
|
60
|
-
const dependencies = value["dependencies"];
|
|
61
|
-
return (
|
|
62
|
-
value["type"] === "module" &&
|
|
63
|
-
value["packageManager"] === "npm@11.12.1" &&
|
|
64
|
-
isStringRecord(value["bin"]) &&
|
|
65
|
-
isStringRecord(value["optionalDependencies"]) &&
|
|
66
|
-
(dependencies === undefined || isRecord(dependencies))
|
|
67
|
-
);
|
|
68
|
-
}
|
|
69
|
-
|
|
70
|
-
function isHooksJson(value: unknown): value is HooksJson {
|
|
71
|
-
if (!isRecord(value) || !isRecord(value["hooks"])) return false;
|
|
72
|
-
return Object.values(value["hooks"]).every(isHookEntries);
|
|
73
|
-
}
|
|
74
|
-
|
|
75
|
-
function isHookEntries(value: unknown): value is readonly HookEntry[] {
|
|
76
|
-
return Array.isArray(value) && value.every(isHookEntry);
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function isHookEntry(value: unknown): value is HookEntry {
|
|
80
|
-
return isRecord(value) && Array.isArray(value["hooks"]) && value["hooks"].every(isHookCommand);
|
|
81
|
-
}
|
|
82
|
-
|
|
83
|
-
function isHookCommand(value: unknown): value is HookCommand {
|
|
84
|
-
return isRecord(value) && typeof value["command"] === "string";
|
|
85
|
-
}
|
|
86
|
-
|
|
87
|
-
function isStringRecord(value: unknown): value is Record<string, string> {
|
|
88
|
-
return isRecord(value) && Object.values(value).every((item) => typeof item === "string");
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
92
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
93
|
-
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"type": "command",
|
|
9
9
|
"command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook pre-tool-use",
|
|
10
10
|
"timeout": 5,
|
|
11
|
-
"statusMessage": "
|
|
11
|
+
"statusMessage": "(OmO) Recommending Git Bash MCP"
|
|
12
12
|
}
|
|
13
13
|
]
|
|
14
14
|
}
|
|
@@ -20,7 +20,7 @@
|
|
|
20
20
|
"type": "command",
|
|
21
21
|
"command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook post-compact",
|
|
22
22
|
"timeout": 5,
|
|
23
|
-
"statusMessage": "
|
|
23
|
+
"statusMessage": "(OmO) Resetting Git Bash MCP Reminder"
|
|
24
24
|
}
|
|
25
25
|
]
|
|
26
26
|
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"type": "command",
|
|
9
9
|
"command": "node \"${PLUGIN_ROOT}/components/lazycodex-executor-verify/dist/cli.js\" hook subagent-stop",
|
|
10
10
|
"timeout": 10,
|
|
11
|
-
"statusMessage": "
|
|
11
|
+
"statusMessage": "(OmO) Verifying LazyCodex Executor Evidence"
|
|
12
12
|
}
|
|
13
13
|
]
|
|
14
14
|
}
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"type": "command",
|
|
9
9
|
"command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook post-tool-use",
|
|
10
10
|
"timeout": 60,
|
|
11
|
-
"statusMessage": "
|
|
11
|
+
"statusMessage": "(OmO) Checking LSP Diagnostics"
|
|
12
12
|
}
|
|
13
13
|
]
|
|
14
14
|
}
|
|
@@ -21,7 +21,7 @@
|
|
|
21
21
|
"type": "command",
|
|
22
22
|
"command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook post-compact",
|
|
23
23
|
"timeout": 5,
|
|
24
|
-
"statusMessage": "
|
|
24
|
+
"statusMessage": "(OmO) Resetting LSP Diagnostics Cache"
|
|
25
25
|
}
|
|
26
26
|
]
|
|
27
27
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@code-yeongyu/codex-lsp",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.12.1",
|
|
4
4
|
"description": "Codex plugin that exposes Language Server Protocol tools and post-edit diagnostics.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"packageManager": "npm@11.12.1",
|
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"bootstrap": "node scripts/build-lsp-tools.mjs && node scripts/build-lsp-daemon.mjs",
|
|
40
40
|
"prebuild": "node scripts/build-lsp-tools.mjs && node scripts/build-lsp-daemon.mjs",
|
|
41
41
|
"build": "node scripts/clean-dist.mjs && tsc -p tsconfig.build.json",
|
|
42
|
-
"pretest": "
|
|
42
|
+
"pretest": "npm run build --silent",
|
|
43
43
|
"test": "node scripts/test.mjs",
|
|
44
44
|
"test:watch": "vitest",
|
|
45
45
|
"pretypecheck": "node scripts/build-lsp-tools.mjs && node scripts/build-lsp-daemon.mjs",
|
|
@@ -1,53 +1,12 @@
|
|
|
1
|
-
import { readdirSync, readFileSync } from "node:fs";
|
|
2
1
|
import { describe, expect, it } from "vitest";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
|
|
11
|
-
};
|
|
12
|
-
|
|
13
|
-
type HookCommand = {
|
|
14
|
-
readonly command: string;
|
|
15
|
-
};
|
|
16
|
-
|
|
17
|
-
type HookEntry = {
|
|
18
|
-
readonly hooks: readonly HookCommand[];
|
|
19
|
-
};
|
|
20
|
-
|
|
21
|
-
type HooksJson = {
|
|
22
|
-
readonly hooks: Record<string, readonly HookEntry[]>;
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
type McpServer = {
|
|
26
|
-
readonly command: string;
|
|
27
|
-
readonly args: readonly string[];
|
|
28
|
-
};
|
|
29
|
-
|
|
30
|
-
type McpJson = {
|
|
31
|
-
readonly mcpServers: Record<string, McpServer>;
|
|
32
|
-
};
|
|
33
|
-
|
|
34
|
-
function readPackageJson(path: string): PackageJson {
|
|
35
|
-
const parsed: unknown = JSON.parse(readFileSync(path, "utf8"));
|
|
36
|
-
if (!isPackageJson(parsed)) throw new TypeError(`Invalid package metadata: ${path}`);
|
|
37
|
-
return parsed;
|
|
38
|
-
}
|
|
39
|
-
|
|
40
|
-
function readHooksJson(path: string): HooksJson {
|
|
41
|
-
const parsed: unknown = JSON.parse(readFileSync(path, "utf8"));
|
|
42
|
-
if (!isHooksJson(parsed)) throw new TypeError(`Invalid hooks metadata: ${path}`);
|
|
43
|
-
return parsed;
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
function readMcpJson(path: string): McpJson {
|
|
47
|
-
const parsed: unknown = JSON.parse(readFileSync(path, "utf8"));
|
|
48
|
-
if (!isMcpJson(parsed)) throw new TypeError(`Invalid MCP metadata: ${path}`);
|
|
49
|
-
return parsed;
|
|
50
|
-
}
|
|
2
|
+
import {
|
|
3
|
+
listDirectoryEntries,
|
|
4
|
+
readHooksJson,
|
|
5
|
+
readMcpJson,
|
|
6
|
+
readPackageJson,
|
|
7
|
+
readTextFile,
|
|
8
|
+
requireScripts,
|
|
9
|
+
} from "../../test-support/package-smoke-fixture.js";
|
|
51
10
|
|
|
52
11
|
describe("plugin package metadata", () => {
|
|
53
12
|
it("#given packaged component files #when validating entrypoints #then hook command stays local and MCP command references the package", () => {
|
|
@@ -55,10 +14,11 @@ describe("plugin package metadata", () => {
|
|
|
55
14
|
const packageJson = readPackageJson("package.json");
|
|
56
15
|
const hooksJson = readHooksJson("hooks/hooks.json");
|
|
57
16
|
const mcpJson = readMcpJson(".mcp.json");
|
|
58
|
-
const cliSource =
|
|
59
|
-
const codexHookCliSource =
|
|
60
|
-
const codexHookSource =
|
|
61
|
-
const sourceFiles =
|
|
17
|
+
const cliSource = readTextFile("src/cli.ts");
|
|
18
|
+
const codexHookCliSource = readTextFile("src/codex-hook-cli.ts");
|
|
19
|
+
const codexHookSource = readTextFile("src/codex-hook.ts");
|
|
20
|
+
const sourceFiles = listDirectoryEntries("src");
|
|
21
|
+
const scripts = requireScripts(packageJson, "package.json");
|
|
62
22
|
|
|
63
23
|
// when
|
|
64
24
|
const postToolUseCommand = hooksJson.hooks["PostToolUse"]?.[0]?.hooks[0]?.command;
|
|
@@ -74,7 +34,8 @@ describe("plugin package metadata", () => {
|
|
|
74
34
|
});
|
|
75
35
|
expect(packageJson.bin["omo-lsp"]).toBe("./dist/cli.js");
|
|
76
36
|
expect(packageJson.bin["codex-lsp"]).toBeUndefined();
|
|
77
|
-
expect(
|
|
37
|
+
expect(scripts["build"]).toBe("node scripts/clean-dist.mjs && tsc -p tsconfig.build.json");
|
|
38
|
+
expect(scripts["pretest"]).toBe("npm run build --silent");
|
|
78
39
|
expect(cliSource.startsWith("#!/usr/bin/env node")).toBe(true);
|
|
79
40
|
expect(cliSource).toContain("Usage: omo-lsp [mcp | hook post-tool-use | hook post-compact]");
|
|
80
41
|
expect(postToolUseCommand).toBe(`node "${pluginRoot}/dist/cli.js" hook post-tool-use`);
|
|
@@ -91,55 +52,16 @@ describe("plugin package metadata", () => {
|
|
|
91
52
|
expect(sourceFiles.filter((name) => name.startsWith("lazy-mcp") || name === "lazy-lsp-mcp.ts")).toEqual([]);
|
|
92
53
|
});
|
|
93
54
|
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
return (
|
|
98
|
-
isRecord(value) &&
|
|
99
|
-
typeof value["version"] === "string" &&
|
|
100
|
-
value["type"] === "module" &&
|
|
101
|
-
value["packageManager"] === "npm@11.12.1" &&
|
|
102
|
-
isStringRecord(value["bin"]) &&
|
|
103
|
-
isStringRecord(value["dependencies"]) &&
|
|
104
|
-
isStringRecord(value["scripts"])
|
|
105
|
-
);
|
|
106
|
-
}
|
|
107
|
-
|
|
108
|
-
function isHooksJson(value: unknown): value is HooksJson {
|
|
109
|
-
if (!isRecord(value) || !isRecord(value["hooks"])) return false;
|
|
110
|
-
return Object.values(value["hooks"]).every(isHookEntries);
|
|
111
|
-
}
|
|
112
|
-
|
|
113
|
-
function isHookEntries(value: unknown): value is readonly HookEntry[] {
|
|
114
|
-
return Array.isArray(value) && value.every(isHookEntry);
|
|
115
|
-
}
|
|
116
|
-
|
|
117
|
-
function isHookEntry(value: unknown): value is HookEntry {
|
|
118
|
-
return isRecord(value) && Array.isArray(value["hooks"]) && value["hooks"].every(isHookCommand);
|
|
119
|
-
}
|
|
120
|
-
|
|
121
|
-
function isHookCommand(value: unknown): value is HookCommand {
|
|
122
|
-
return isRecord(value) && typeof value["command"] === "string";
|
|
123
|
-
}
|
|
124
|
-
|
|
125
|
-
function isMcpJson(value: unknown): value is McpJson {
|
|
126
|
-
if (!isRecord(value) || !isRecord(value["mcpServers"])) return false;
|
|
127
|
-
return Object.values(value["mcpServers"]).every(isMcpServer);
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
function isMcpServer(value: unknown): value is McpServer {
|
|
131
|
-
return (
|
|
132
|
-
isRecord(value) &&
|
|
133
|
-
typeof value["command"] === "string" &&
|
|
134
|
-
Array.isArray(value["args"]) &&
|
|
135
|
-
value["args"].every((item) => typeof item === "string")
|
|
136
|
-
);
|
|
137
|
-
}
|
|
55
|
+
it("#given LSP skill guidance #when validating MCP tool instructions #then tool names are not framed as shell commands", () => {
|
|
56
|
+
// given
|
|
57
|
+
const skill = readTextFile("skills/lsp/SKILL.md");
|
|
138
58
|
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
59
|
+
// when
|
|
60
|
+
const mentionsToolInterface = skill.includes("through the tool interface");
|
|
61
|
+
const rejectsShellExecution = skill.includes("not shell commands");
|
|
142
62
|
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
63
|
+
// then
|
|
64
|
+
expect(mentionsToolInterface).toBe(true);
|
|
65
|
+
expect(rejectsShellExecution).toBe(true);
|
|
66
|
+
});
|
|
67
|
+
});
|
|
@@ -7,7 +7,7 @@
|
|
|
7
7
|
"type": "command",
|
|
8
8
|
"command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook session-start",
|
|
9
9
|
"timeout": 10,
|
|
10
|
-
"statusMessage": "
|
|
10
|
+
"statusMessage": "(OmO) Loading Project Rules"
|
|
11
11
|
}
|
|
12
12
|
]
|
|
13
13
|
}
|
|
@@ -19,7 +19,7 @@
|
|
|
19
19
|
"type": "command",
|
|
20
20
|
"command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook user-prompt-submit",
|
|
21
21
|
"timeout": 10,
|
|
22
|
-
"statusMessage": "
|
|
22
|
+
"statusMessage": "(OmO) Loading Project Rules"
|
|
23
23
|
}
|
|
24
24
|
]
|
|
25
25
|
}
|
|
@@ -32,7 +32,7 @@
|
|
|
32
32
|
"type": "command",
|
|
33
33
|
"command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook post-tool-use",
|
|
34
34
|
"timeout": 10,
|
|
35
|
-
"statusMessage": "
|
|
35
|
+
"statusMessage": "(OmO) Matching Project Rules"
|
|
36
36
|
}
|
|
37
37
|
]
|
|
38
38
|
}
|
|
@@ -45,7 +45,7 @@
|
|
|
45
45
|
"type": "command",
|
|
46
46
|
"command": "node \"${PLUGIN_ROOT}/dist/cli.js\" hook post-compact",
|
|
47
47
|
"timeout": 10,
|
|
48
|
-
"statusMessage": "
|
|
48
|
+
"statusMessage": "(OmO) Resetting Project Rule Cache"
|
|
49
49
|
}
|
|
50
50
|
]
|
|
51
51
|
}
|
|
@@ -1,48 +1,12 @@
|
|
|
1
|
-
import { readdirSync, readFileSync } from "node:fs";
|
|
2
1
|
import { describe, expect, it } from "vitest";
|
|
3
|
-
|
|
4
|
-
|
|
5
|
-
|
|
6
|
-
|
|
7
|
-
|
|
8
|
-
|
|
9
|
-
|
|
10
|
-
};
|
|
11
|
-
|
|
12
|
-
type PluginJson = {
|
|
13
|
-
readonly hooks: string;
|
|
14
|
-
};
|
|
15
|
-
|
|
16
|
-
type HookCommand = {
|
|
17
|
-
readonly command: string;
|
|
18
|
-
};
|
|
19
|
-
|
|
20
|
-
type HookEntry = {
|
|
21
|
-
readonly matcher?: string;
|
|
22
|
-
readonly hooks: readonly HookCommand[];
|
|
23
|
-
};
|
|
24
|
-
|
|
25
|
-
type HooksJson = {
|
|
26
|
-
readonly hooks: Record<string, readonly HookEntry[]>;
|
|
27
|
-
};
|
|
28
|
-
|
|
29
|
-
function readPackageJson(path: string): PackageJson {
|
|
30
|
-
const parsed: unknown = JSON.parse(readFileSync(path, "utf8"));
|
|
31
|
-
if (!isPackageJson(parsed)) throw new TypeError(`Invalid package metadata: ${path}`);
|
|
32
|
-
return parsed;
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
function readPluginJson(path: string): PluginJson {
|
|
36
|
-
const parsed: unknown = JSON.parse(readFileSync(path, "utf8"));
|
|
37
|
-
if (!isPluginJson(parsed)) throw new TypeError(`Invalid plugin metadata: ${path}`);
|
|
38
|
-
return parsed;
|
|
39
|
-
}
|
|
40
|
-
|
|
41
|
-
function readHooksJson(path: string): HooksJson {
|
|
42
|
-
const parsed: unknown = JSON.parse(readFileSync(path, "utf8"));
|
|
43
|
-
if (!isHooksJson(parsed)) throw new TypeError(`Invalid hooks metadata: ${path}`);
|
|
44
|
-
return parsed;
|
|
45
|
-
}
|
|
2
|
+
import {
|
|
3
|
+
listDirectoryEntries,
|
|
4
|
+
readHooksJson,
|
|
5
|
+
readPackageJson,
|
|
6
|
+
readPluginJson,
|
|
7
|
+
readTextFile,
|
|
8
|
+
requireFiles,
|
|
9
|
+
} from "../../test-support/package-smoke-fixture.js";
|
|
46
10
|
|
|
47
11
|
describe("plugin package metadata", () => {
|
|
48
12
|
it("#given packaged plugin files #when validating entrypoints #then hook commands use portable plugin root interpolation", () => {
|
|
@@ -50,8 +14,9 @@ describe("plugin package metadata", () => {
|
|
|
50
14
|
const packageJson = readPackageJson("package.json");
|
|
51
15
|
const pluginJson = readPluginJson(".codex-plugin/plugin.json");
|
|
52
16
|
const hooksJson = readHooksJson("hooks/hooks.json");
|
|
53
|
-
const cliSource =
|
|
54
|
-
const
|
|
17
|
+
const cliSource = readTextFile("src/cli.ts");
|
|
18
|
+
const packageFiles = requireFiles(packageJson, "package.json");
|
|
19
|
+
const bundledRules = [...listDirectoryEntries("bundled-rules")].sort();
|
|
55
20
|
|
|
56
21
|
// when
|
|
57
22
|
const hookConfig = hooksJson.hooks;
|
|
@@ -69,7 +34,7 @@ describe("plugin package metadata", () => {
|
|
|
69
34
|
expect(packageJson.packageManager).toBe("npm@11.12.1");
|
|
70
35
|
expect(packageJson.dependencies ?? {}).toEqual({ picomatch: "^4.0.3" });
|
|
71
36
|
expect(packageJson.bin["omo-rules"]).toBe("./dist/cli.js");
|
|
72
|
-
expect(
|
|
37
|
+
expect(packageFiles).toContain("bundled-rules");
|
|
73
38
|
expect(bundledRules).toContain("windows-git-bash.md");
|
|
74
39
|
expect(pluginJson.hooks).toBe("./hooks/hooks.json");
|
|
75
40
|
expect(cliSource.startsWith("#!/usr/bin/env node")).toBe(true);
|
|
@@ -106,48 +71,3 @@ describe("plugin package metadata", () => {
|
|
|
106
71
|
).toBe(false);
|
|
107
72
|
});
|
|
108
73
|
});
|
|
109
|
-
|
|
110
|
-
function isPackageJson(value: unknown): value is PackageJson {
|
|
111
|
-
if (!isRecord(value)) return false;
|
|
112
|
-
const dependencies = value["dependencies"];
|
|
113
|
-
return (
|
|
114
|
-
value["type"] === "module" &&
|
|
115
|
-
value["packageManager"] === "npm@11.12.1" &&
|
|
116
|
-
isStringRecord(value["bin"]) &&
|
|
117
|
-
isStringArray(value["files"]) &&
|
|
118
|
-
(dependencies === undefined || isRecord(dependencies))
|
|
119
|
-
);
|
|
120
|
-
}
|
|
121
|
-
|
|
122
|
-
function isStringArray(value: unknown): value is readonly string[] {
|
|
123
|
-
return Array.isArray(value) && value.every((item) => typeof item === "string");
|
|
124
|
-
}
|
|
125
|
-
|
|
126
|
-
function isPluginJson(value: unknown): value is PluginJson {
|
|
127
|
-
return isRecord(value) && typeof value["hooks"] === "string";
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
function isHooksJson(value: unknown): value is HooksJson {
|
|
131
|
-
if (!isRecord(value) || !isRecord(value["hooks"])) return false;
|
|
132
|
-
return Object.values(value["hooks"]).every(isHookEntries);
|
|
133
|
-
}
|
|
134
|
-
|
|
135
|
-
function isHookEntries(value: unknown): value is readonly HookEntry[] {
|
|
136
|
-
return Array.isArray(value) && value.every(isHookEntry);
|
|
137
|
-
}
|
|
138
|
-
|
|
139
|
-
function isHookEntry(value: unknown): value is HookEntry {
|
|
140
|
-
return isRecord(value) && Array.isArray(value["hooks"]) && value["hooks"].every(isHookCommand);
|
|
141
|
-
}
|
|
142
|
-
|
|
143
|
-
function isHookCommand(value: unknown): value is HookCommand {
|
|
144
|
-
return isRecord(value) && typeof value["command"] === "string";
|
|
145
|
-
}
|
|
146
|
-
|
|
147
|
-
function isStringRecord(value: unknown): value is Record<string, string> {
|
|
148
|
-
return isRecord(value) && Object.values(value).every((item) => typeof item === "string");
|
|
149
|
-
}
|
|
150
|
-
|
|
151
|
-
function isRecord(value: unknown): value is Record<string, unknown> {
|
|
152
|
-
return typeof value === "object" && value !== null && !Array.isArray(value);
|
|
153
|
-
}
|