oh-my-opencode 5.1.3 → 5.1.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/index.js +149 -19
- package/dist/cli-node/index.js +149 -19
- package/dist/index.js +148 -18
- package/dist/skills/browser/runtime/omowright/manifest.json +1 -1
- package/dist/tui.js +148 -18
- package/package.json +14 -14
- package/packages/lsp-core/src/lsp/outside-context-workspace.ts +1 -1
- package/packages/lsp-core/src/missing-dependency-result.test.ts +32 -2
- package/packages/lsp-core/src/missing-dependency-result.ts +3 -0
- package/packages/lsp-core/src/post-edit/file-location.ts +50 -0
- package/packages/lsp-core/src/post-edit/index.ts +2 -0
- package/packages/lsp-core/src/post-edit/not-installed-guidance.ts +36 -0
- package/packages/lsp-core/src/post-edit/not-installed.test.ts +199 -0
- package/packages/lsp-core/src/post-edit/orchestration.ts +26 -5
- package/packages/lsp-daemon/dist/cli.js +2 -1
- package/packages/lsp-daemon/dist/client.js +2 -1
- package/packages/lsp-daemon/dist/index.js +2 -1
- package/packages/lsp-tools-mcp/dist/cli.js +2 -1
- package/packages/lsp-tools-mcp/dist/mcp.js +2 -1
- package/packages/lsp-tools-mcp/dist/tools.js +2 -1
- package/packages/omo-codex/plugin/.codex-plugin/plugin.json +1 -1
- 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/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 +4 -4
- package/packages/omo-codex/plugin/components/lsp/dist/cli.js +141 -107
- package/packages/omo-codex/plugin/components/lsp/dist/lsp-session-state.js +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/lsp/src/lsp-session-state.ts +2 -2
- 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/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/ulw-execute-continuation/hooks/hooks.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-execute-continuation/package.json +1 -1
- package/packages/omo-codex/plugin/components/ulw-loop/hooks/hooks.json +5 -5
- package/packages/omo-codex/plugin/components/ulw-loop/package.json +1 -1
- 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-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/post-tool-use-recording-spawn-admission.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-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-ulw-execute-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-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 +12 -12
- package/packages/omo-codex/plugin/package.json +1 -1
- package/packages/omo-codex/plugin/skills/browser/runtime/omowright/manifest.json +1 -1
- package/packages/omo-codex/scripts/install-dist/install-local.mjs +2 -2
- package/packages/shared-skills/skills/browser/runtime/omowright/manifest.json +1 -1
|
@@ -0,0 +1,36 @@
|
|
|
1
|
+
import type { PostEditFileLocation } from "./file-location.js";
|
|
2
|
+
|
|
3
|
+
export interface PostEditNotInstalledOutcome {
|
|
4
|
+
readonly kind: "not_installed";
|
|
5
|
+
readonly serverId: string;
|
|
6
|
+
readonly installDecisionTool: boolean;
|
|
7
|
+
/** A recorded install decision; absent while the user has not decided. */
|
|
8
|
+
readonly decision?: "declined" | "allowed";
|
|
9
|
+
readonly text: string;
|
|
10
|
+
}
|
|
11
|
+
|
|
12
|
+
export interface NotInstalledGuidanceState {
|
|
13
|
+
readonly notInstalledServers: Set<string>;
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
/**
|
|
17
|
+
* Decides whether a missing-server nudge reaches the model.
|
|
18
|
+
*
|
|
19
|
+
* Recorded decisions keep their own text. Undecided nudges are skipped for files outside a project
|
|
20
|
+
* (no marked root, the agent's config dir, or a temp dir) because a repo-local install there would
|
|
21
|
+
* create a manifest in HOME or a temp dir. Without a decision tool nothing can be recorded, so a
|
|
22
|
+
* server is nudged at most once per session state.
|
|
23
|
+
*/
|
|
24
|
+
export function notInstalledGuidance(
|
|
25
|
+
filePath: string,
|
|
26
|
+
outcome: PostEditNotInstalledOutcome,
|
|
27
|
+
state: NotInstalledGuidanceState,
|
|
28
|
+
locateFile: ((filePath: string) => PostEditFileLocation) | undefined,
|
|
29
|
+
): string | undefined {
|
|
30
|
+
if (outcome.decision !== undefined) return outcome.text;
|
|
31
|
+
if (locateFile !== undefined && locateFile(filePath) !== "project") return undefined;
|
|
32
|
+
if (outcome.installDecisionTool) return outcome.text;
|
|
33
|
+
if (state.notInstalledServers.has(outcome.serverId)) return undefined;
|
|
34
|
+
state.notInstalledServers.add(outcome.serverId);
|
|
35
|
+
return outcome.text;
|
|
36
|
+
}
|
|
@@ -0,0 +1,199 @@
|
|
|
1
|
+
import { mkdirSync, mkdtempSync, rmSync, writeFileSync } from "node:fs";
|
|
2
|
+
import { tmpdir } from "node:os";
|
|
3
|
+
import { join } from "node:path";
|
|
4
|
+
import { afterEach, describe, expect, it } from "bun:test";
|
|
5
|
+
|
|
6
|
+
import {
|
|
7
|
+
classifyPostEditFileLocation,
|
|
8
|
+
collectPostEditDiagnostics,
|
|
9
|
+
createPostEditNotConfiguredCache,
|
|
10
|
+
type PostEditDiagnosticsOutcome,
|
|
11
|
+
type PostEditFileLocation,
|
|
12
|
+
resetPostEditNotConfiguredCache,
|
|
13
|
+
} from "./index.js";
|
|
14
|
+
|
|
15
|
+
const tempDirectories: string[] = [];
|
|
16
|
+
|
|
17
|
+
afterEach(() => {
|
|
18
|
+
for (const directory of tempDirectories.splice(0)) {
|
|
19
|
+
rmSync(directory, { recursive: true, force: true });
|
|
20
|
+
}
|
|
21
|
+
});
|
|
22
|
+
|
|
23
|
+
function tempRoot(prefix: string): string {
|
|
24
|
+
const root = mkdtempSync(join(tmpdir(), prefix));
|
|
25
|
+
tempDirectories.push(root);
|
|
26
|
+
return root;
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function touch(path: string, text = ""): string {
|
|
30
|
+
mkdirSync(join(path, ".."), { recursive: true });
|
|
31
|
+
writeFileSync(path, text);
|
|
32
|
+
return path;
|
|
33
|
+
}
|
|
34
|
+
|
|
35
|
+
const FULL_NUDGE = [
|
|
36
|
+
"LSP server 'typescript' for .ts is NOT INSTALLED.",
|
|
37
|
+
"To install in THIS repository (preferred — no global install needed):",
|
|
38
|
+
"ACTION REQUIRED — ASK THE USER whether to install this LSP server.",
|
|
39
|
+
].join("\n");
|
|
40
|
+
|
|
41
|
+
function notInstalled(
|
|
42
|
+
serverId: string,
|
|
43
|
+
overrides: Partial<Extract<PostEditDiagnosticsOutcome, { kind: "not_installed" }>> = {},
|
|
44
|
+
): PostEditDiagnosticsOutcome {
|
|
45
|
+
return {
|
|
46
|
+
kind: "not_installed",
|
|
47
|
+
serverId,
|
|
48
|
+
installDecisionTool: false,
|
|
49
|
+
text: `${FULL_NUDGE} (${serverId})`,
|
|
50
|
+
...overrides,
|
|
51
|
+
};
|
|
52
|
+
}
|
|
53
|
+
|
|
54
|
+
function at(location: PostEditFileLocation): () => PostEditFileLocation {
|
|
55
|
+
return () => location;
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
describe("classifyPostEditFileLocation", () => {
|
|
59
|
+
it("#given a file with no workspace marker above it #when classified #then it is outside any project", () => {
|
|
60
|
+
const root = tempRoot("lsp-postedit-noproject-");
|
|
61
|
+
const file = touch(join(root, "scratch", "note.mjs"));
|
|
62
|
+
|
|
63
|
+
expect(classifyPostEditFileLocation(file, { cwd: root, agentDirs: [], tempDirs: [] })).toBe("outside_project");
|
|
64
|
+
});
|
|
65
|
+
|
|
66
|
+
it("#given a file under the agent config dir inside a git repository #when classified #then the agent config dir wins", () => {
|
|
67
|
+
const root = tempRoot("lsp-postedit-agentdir-");
|
|
68
|
+
mkdirSync(join(root, ".git"));
|
|
69
|
+
const agentDir = join(root, ".omo", "agent");
|
|
70
|
+
const file = touch(join(agentDir, "models.json"), "{}\n");
|
|
71
|
+
|
|
72
|
+
expect(classifyPostEditFileLocation(file, { cwd: root, agentDirs: [agentDir], tempDirs: [] })).toBe(
|
|
73
|
+
"agent_config",
|
|
74
|
+
);
|
|
75
|
+
});
|
|
76
|
+
|
|
77
|
+
it("#given a temp dir holding a stray package.json #when a scratch file there is classified #then it is a temp file", () => {
|
|
78
|
+
const temp = tempRoot("lsp-postedit-temp-");
|
|
79
|
+
touch(join(temp, "package.json"), "{}\n");
|
|
80
|
+
const file = touch(join(temp, "rules_test.mjs"));
|
|
81
|
+
|
|
82
|
+
expect(classifyPostEditFileLocation(file, { cwd: temp, agentDirs: [], tempDirs: [temp] })).toBe("temp");
|
|
83
|
+
});
|
|
84
|
+
|
|
85
|
+
it("#given the default temp dirs #when an OS temp file is classified #then the canonical temp dir matches", () => {
|
|
86
|
+
const root = tempRoot("lsp-postedit-ostemp-");
|
|
87
|
+
const file = touch(join(root, "scratch.mjs"));
|
|
88
|
+
|
|
89
|
+
expect(classifyPostEditFileLocation(file, { cwd: root, agentDirs: [] })).toBe("temp");
|
|
90
|
+
if (process.platform !== "win32") {
|
|
91
|
+
const slashTmp = join("/tmp", `lsp-postedit-missing-${process.pid}`, "rules_test.mjs");
|
|
92
|
+
expect(classifyPostEditFileLocation(slashTmp, { cwd: root, agentDirs: [] })).toBe("temp");
|
|
93
|
+
}
|
|
94
|
+
});
|
|
95
|
+
|
|
96
|
+
it("#given a project with its own marker inside a temp dir #when classified #then it is a project", () => {
|
|
97
|
+
const temp = tempRoot("lsp-postedit-tempproject-");
|
|
98
|
+
const project = join(temp, "checkout");
|
|
99
|
+
touch(join(project, "package.json"), "{}\n");
|
|
100
|
+
const file = touch(join(project, "src", "a.ts"));
|
|
101
|
+
|
|
102
|
+
expect(classifyPostEditFileLocation(file, { cwd: project, agentDirs: [], tempDirs: [temp] })).toBe("project");
|
|
103
|
+
expect(classifyPostEditFileLocation("src/a.ts", { cwd: project, agentDirs: [], tempDirs: [temp] })).toBe(
|
|
104
|
+
"project",
|
|
105
|
+
);
|
|
106
|
+
});
|
|
107
|
+
});
|
|
108
|
+
|
|
109
|
+
describe("collectPostEditDiagnostics not-installed guidance", () => {
|
|
110
|
+
for (const location of ["outside_project", "agent_config", "temp"] as const) {
|
|
111
|
+
it(`#given a missing server for a ${location} file #when diagnostics run #then the install nudge is skipped`, async () => {
|
|
112
|
+
const result = await collectPostEditDiagnostics({
|
|
113
|
+
filePaths: ["file.ts"],
|
|
114
|
+
runDiagnostics: async () => notInstalled("typescript"),
|
|
115
|
+
locateFile: at(location),
|
|
116
|
+
});
|
|
117
|
+
|
|
118
|
+
expect(result.blocks).toEqual([]);
|
|
119
|
+
expect(result.observations).toEqual([{ filePath: "file.ts", kind: "not_installed" }]);
|
|
120
|
+
});
|
|
121
|
+
}
|
|
122
|
+
|
|
123
|
+
it("#given a missing server for a project file #when diagnostics run #then today's full guidance is kept", async () => {
|
|
124
|
+
const result = await collectPostEditDiagnostics({
|
|
125
|
+
filePaths: ["src/a.ts"],
|
|
126
|
+
runDiagnostics: async () => notInstalled("typescript"),
|
|
127
|
+
locateFile: at("project"),
|
|
128
|
+
});
|
|
129
|
+
|
|
130
|
+
expect(result.blocks).toEqual([{ filePath: "src/a.ts", diagnostics: `${FULL_NUDGE} (typescript)` }]);
|
|
131
|
+
});
|
|
132
|
+
|
|
133
|
+
it("#given no decision tool #when repeated edits hit missing servers #then each server is nudged once per session", async () => {
|
|
134
|
+
const cache = createPostEditNotConfiguredCache();
|
|
135
|
+
const serverFor = (filePath: string): string => (filePath.endsWith(".json") ? "biome" : "typescript");
|
|
136
|
+
const run = (filePaths: readonly string[]) =>
|
|
137
|
+
collectPostEditDiagnostics({
|
|
138
|
+
filePaths,
|
|
139
|
+
cache,
|
|
140
|
+
runDiagnostics: async (filePath) => notInstalled(serverFor(filePath)),
|
|
141
|
+
locateFile: at("project"),
|
|
142
|
+
});
|
|
143
|
+
|
|
144
|
+
const first = await run(["a.ts", "b.ts"]);
|
|
145
|
+
const second = await run(["c.ts", "d.json"]);
|
|
146
|
+
const third = await run(["e.json", "f.ts"]);
|
|
147
|
+
|
|
148
|
+
expect(first.blocks.map((block) => block.filePath)).toEqual(["a.ts"]);
|
|
149
|
+
expect(second.blocks.map((block) => block.filePath)).toEqual(["d.json"]);
|
|
150
|
+
expect(third.blocks).toEqual([]);
|
|
151
|
+
|
|
152
|
+
resetPostEditNotConfiguredCache(cache);
|
|
153
|
+
const afterReset = await run(["g.ts"]);
|
|
154
|
+
expect(afterReset.blocks.map((block) => block.filePath)).toEqual(["g.ts"]);
|
|
155
|
+
});
|
|
156
|
+
|
|
157
|
+
it("#given a decision tool #when repeated edits hit a missing server #then every edit keeps the guidance", async () => {
|
|
158
|
+
const cache = createPostEditNotConfiguredCache();
|
|
159
|
+
const run = (filePath: string) =>
|
|
160
|
+
collectPostEditDiagnostics({
|
|
161
|
+
filePaths: [filePath],
|
|
162
|
+
cache,
|
|
163
|
+
runDiagnostics: async () => notInstalled("typescript", { installDecisionTool: true }),
|
|
164
|
+
locateFile: at("project"),
|
|
165
|
+
});
|
|
166
|
+
|
|
167
|
+
expect((await run("a.ts")).blocks).toHaveLength(1);
|
|
168
|
+
expect((await run("b.ts")).blocks).toHaveLength(1);
|
|
169
|
+
});
|
|
170
|
+
|
|
171
|
+
for (const decision of ["declined", "allowed"] as const) {
|
|
172
|
+
it(`#given a recorded ${decision} decision #when edits repeat anywhere #then that branch's text is unchanged every time`, async () => {
|
|
173
|
+
const cache = createPostEditNotConfiguredCache();
|
|
174
|
+
const text = `LSP server 'typescript' ${decision} branch text`;
|
|
175
|
+
const outcomes: PostEditFileLocation[] = ["project", "outside_project", "project"];
|
|
176
|
+
const blocks: string[] = [];
|
|
177
|
+
for (const location of outcomes) {
|
|
178
|
+
const result = await collectPostEditDiagnostics({
|
|
179
|
+
filePaths: ["a.ts"],
|
|
180
|
+
cache,
|
|
181
|
+
runDiagnostics: async () => notInstalled("typescript", { decision, text }),
|
|
182
|
+
locateFile: at(location),
|
|
183
|
+
});
|
|
184
|
+
blocks.push(...result.blocks.map((block) => block.diagnostics));
|
|
185
|
+
}
|
|
186
|
+
|
|
187
|
+
expect(blocks).toEqual([text, text, text]);
|
|
188
|
+
});
|
|
189
|
+
}
|
|
190
|
+
|
|
191
|
+
it("#given no file locator #when a missing server is reported #then the full guidance is kept", async () => {
|
|
192
|
+
const result = await collectPostEditDiagnostics({
|
|
193
|
+
filePaths: ["a.ts"],
|
|
194
|
+
runDiagnostics: async () => notInstalled("typescript"),
|
|
195
|
+
});
|
|
196
|
+
|
|
197
|
+
expect(result.blocks).toEqual([{ filePath: "a.ts", diagnostics: `${FULL_NUDGE} (typescript)` }]);
|
|
198
|
+
});
|
|
199
|
+
});
|
|
@@ -1,5 +1,8 @@
|
|
|
1
1
|
import { extname } from "node:path";
|
|
2
2
|
|
|
3
|
+
import type { PostEditFileLocation } from "./file-location.js";
|
|
4
|
+
import { notInstalledGuidance, type PostEditNotInstalledOutcome } from "./not-installed-guidance.js";
|
|
5
|
+
|
|
3
6
|
const DEFAULT_MAX_CONCURRENCY = 4;
|
|
4
7
|
const CLEAN_DIAGNOSTICS_TEXT = "No diagnostics found";
|
|
5
8
|
|
|
@@ -8,7 +11,8 @@ export type PostEditDiagnosticsOutcome =
|
|
|
8
11
|
| {
|
|
9
12
|
readonly kind: "not_configured";
|
|
10
13
|
readonly extension: string;
|
|
11
|
-
}
|
|
14
|
+
}
|
|
15
|
+
| PostEditNotInstalledOutcome;
|
|
12
16
|
|
|
13
17
|
export type DiagnosticsRunner = (filePath: string) => Promise<PostEditDiagnosticsOutcome>;
|
|
14
18
|
|
|
@@ -19,7 +23,7 @@ export interface PostEditDiagnosticsBlock {
|
|
|
19
23
|
|
|
20
24
|
export interface PostEditDiagnosticsObservation {
|
|
21
25
|
readonly filePath: string;
|
|
22
|
-
readonly kind: "block" | "clean" | "not_configured";
|
|
26
|
+
readonly kind: "block" | "clean" | "not_configured" | "not_installed";
|
|
23
27
|
}
|
|
24
28
|
|
|
25
29
|
export interface PostEditDiagnosticsResult {
|
|
@@ -29,6 +33,7 @@ export interface PostEditDiagnosticsResult {
|
|
|
29
33
|
|
|
30
34
|
export interface PostEditNotConfiguredCache {
|
|
31
35
|
readonly notConfiguredExtensions: Set<string>;
|
|
36
|
+
readonly notInstalledServers: Set<string>;
|
|
32
37
|
}
|
|
33
38
|
|
|
34
39
|
export interface CollectPostEditDiagnosticsInput {
|
|
@@ -36,6 +41,7 @@ export interface CollectPostEditDiagnosticsInput {
|
|
|
36
41
|
readonly runDiagnostics: DiagnosticsRunner;
|
|
37
42
|
readonly cache?: PostEditNotConfiguredCache;
|
|
38
43
|
readonly maxConcurrency?: number;
|
|
44
|
+
readonly locateFile?: (filePath: string) => PostEditFileLocation;
|
|
39
45
|
}
|
|
40
46
|
|
|
41
47
|
interface IndexedFilePath {
|
|
@@ -50,11 +56,12 @@ interface IndexedDiagnostics {
|
|
|
50
56
|
}
|
|
51
57
|
|
|
52
58
|
export function createPostEditNotConfiguredCache(): PostEditNotConfiguredCache {
|
|
53
|
-
return { notConfiguredExtensions: new Set() };
|
|
59
|
+
return { notConfiguredExtensions: new Set(), notInstalledServers: new Set() };
|
|
54
60
|
}
|
|
55
61
|
|
|
56
62
|
export function resetPostEditNotConfiguredCache(cache: PostEditNotConfiguredCache): void {
|
|
57
63
|
cache.notConfiguredExtensions.clear();
|
|
64
|
+
cache.notInstalledServers.clear();
|
|
58
65
|
}
|
|
59
66
|
|
|
60
67
|
export async function collectPostEditDiagnostics(
|
|
@@ -67,8 +74,15 @@ export async function collectPostEditDiagnostics(
|
|
|
67
74
|
const observations: PostEditDiagnosticsObservation[] = [];
|
|
68
75
|
|
|
69
76
|
for (const result of results) {
|
|
70
|
-
const
|
|
77
|
+
const outcome = result.outcome;
|
|
78
|
+
const classification =
|
|
79
|
+
typeof outcome !== "string" && outcome.kind === "not_installed"
|
|
80
|
+
? classifyNotInstalled(notInstalledGuidance(result.filePath, outcome, cache, input.locateFile))
|
|
81
|
+
: classifyDiagnostics(outcome);
|
|
71
82
|
switch (classification.kind) {
|
|
83
|
+
case "not_installed":
|
|
84
|
+
observations.push({ filePath: result.filePath, kind: "not_installed" });
|
|
85
|
+
break;
|
|
72
86
|
case "clean":
|
|
73
87
|
observations.push({ filePath: result.filePath, kind: "clean" });
|
|
74
88
|
break;
|
|
@@ -146,9 +160,16 @@ async function collectFileDiagnostics(
|
|
|
146
160
|
|
|
147
161
|
function normalizeDiagnosticsOutcome(outcome: PostEditDiagnosticsOutcome): PostEditDiagnosticsOutcome {
|
|
148
162
|
if (typeof outcome === "string") return normalizeDiagnosticsText(outcome);
|
|
163
|
+
if (outcome.kind === "not_installed") return { ...outcome, text: normalizeDiagnosticsText(outcome.text) };
|
|
149
164
|
return outcome;
|
|
150
165
|
}
|
|
151
166
|
|
|
167
|
+
function classifyNotInstalled(
|
|
168
|
+
guidance: string | undefined,
|
|
169
|
+
): { readonly kind: "not_installed" } | { readonly kind: "block"; readonly diagnostics: string } {
|
|
170
|
+
return guidance === undefined ? { kind: "not_installed" } : { kind: "block", diagnostics: guidance };
|
|
171
|
+
}
|
|
172
|
+
|
|
152
173
|
function normalizeDiagnosticsText(text: string): string {
|
|
153
174
|
return text.trim();
|
|
154
175
|
}
|
|
@@ -159,7 +180,7 @@ function formatDiagnosticsError(error: Error): string {
|
|
|
159
180
|
}
|
|
160
181
|
|
|
161
182
|
function classifyDiagnostics(
|
|
162
|
-
outcome: PostEditDiagnosticsOutcome,
|
|
183
|
+
outcome: Exclude<PostEditDiagnosticsOutcome, PostEditNotInstalledOutcome>,
|
|
163
184
|
):
|
|
164
185
|
| { readonly kind: "clean" }
|
|
165
186
|
| { readonly kind: "not_configured"; readonly extension: string }
|
|
@@ -5350,7 +5350,8 @@ function missingDependencyAvailability(error) {
|
|
|
5350
5350
|
extensions: [...error.lookup.server.extensions],
|
|
5351
5351
|
installHint: error.lookup.installHint,
|
|
5352
5352
|
installDecisionTool: context.capabilities.installDecisionTool,
|
|
5353
|
-
installDecisionsPath: context.installDecisionsPath
|
|
5353
|
+
installDecisionsPath: context.installDecisionsPath,
|
|
5354
|
+
decision: loadInstallDecision(error.lookup.server.id)?.decision ?? null
|
|
5354
5355
|
};
|
|
5355
5356
|
default: {
|
|
5356
5357
|
const exhaustive = error.lookup;
|
|
@@ -5586,7 +5586,8 @@ function missingDependencyAvailability(error) {
|
|
|
5586
5586
|
extensions: [...error.lookup.server.extensions],
|
|
5587
5587
|
installHint: error.lookup.installHint,
|
|
5588
5588
|
installDecisionTool: context.capabilities.installDecisionTool,
|
|
5589
|
-
installDecisionsPath: context.installDecisionsPath
|
|
5589
|
+
installDecisionsPath: context.installDecisionsPath,
|
|
5590
|
+
decision: loadInstallDecision(error.lookup.server.id)?.decision ?? null
|
|
5590
5591
|
};
|
|
5591
5592
|
default: {
|
|
5592
5593
|
const exhaustive = error.lookup;
|
|
@@ -5581,7 +5581,8 @@ function missingDependencyAvailability(error) {
|
|
|
5581
5581
|
extensions: [...error.lookup.server.extensions],
|
|
5582
5582
|
installHint: error.lookup.installHint,
|
|
5583
5583
|
installDecisionTool: context.capabilities.installDecisionTool,
|
|
5584
|
-
installDecisionsPath: context.installDecisionsPath
|
|
5584
|
+
installDecisionsPath: context.installDecisionsPath,
|
|
5585
|
+
decision: loadInstallDecision(error.lookup.server.id)?.decision ?? null
|
|
5585
5586
|
};
|
|
5586
5587
|
default: {
|
|
5587
5588
|
const exhaustive = error.lookup;
|
|
@@ -4919,7 +4919,8 @@ function missingDependencyAvailability(error) {
|
|
|
4919
4919
|
extensions: [...error.lookup.server.extensions],
|
|
4920
4920
|
installHint: error.lookup.installHint,
|
|
4921
4921
|
installDecisionTool: context.capabilities.installDecisionTool,
|
|
4922
|
-
installDecisionsPath: context.installDecisionsPath
|
|
4922
|
+
installDecisionsPath: context.installDecisionsPath,
|
|
4923
|
+
decision: loadInstallDecision(error.lookup.server.id)?.decision ?? null
|
|
4923
4924
|
};
|
|
4924
4925
|
default: {
|
|
4925
4926
|
const exhaustive = error.lookup;
|
|
@@ -4915,7 +4915,8 @@ function missingDependencyAvailability(error) {
|
|
|
4915
4915
|
extensions: [...error.lookup.server.extensions],
|
|
4916
4916
|
installHint: error.lookup.installHint,
|
|
4917
4917
|
installDecisionTool: context.capabilities.installDecisionTool,
|
|
4918
|
-
installDecisionsPath: context.installDecisionsPath
|
|
4918
|
+
installDecisionsPath: context.installDecisionsPath,
|
|
4919
|
+
decision: loadInstallDecision(error.lookup.server.id)?.decision ?? null
|
|
4919
4920
|
};
|
|
4920
4921
|
default: {
|
|
4921
4922
|
const exhaustive = error.lookup;
|
|
@@ -4603,7 +4603,8 @@ function missingDependencyAvailability(error) {
|
|
|
4603
4603
|
extensions: [...error.lookup.server.extensions],
|
|
4604
4604
|
installHint: error.lookup.installHint,
|
|
4605
4605
|
installDecisionTool: context.capabilities.installDecisionTool,
|
|
4606
|
-
installDecisionsPath: context.installDecisionsPath
|
|
4606
|
+
installDecisionsPath: context.installDecisionsPath,
|
|
4607
|
+
decision: loadInstallDecision(error.lookup.server.id)?.decision ?? null
|
|
4607
4608
|
};
|
|
4608
4609
|
default: {
|
|
4609
4610
|
const exhaustive = error.lookup;
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"command": "node \"${PLUGIN_ROOT}/components/bootstrap/dist/cli.js\" hook session-start",
|
|
9
9
|
"commandWindows": "powershell -NoProfile -ExecutionPolicy Bypass -File \"${PLUGIN_ROOT}\\components\\bootstrap\\scripts\\bootstrap.ps1\"",
|
|
10
10
|
"timeout": 30,
|
|
11
|
-
"statusMessage": "(OmO 5.1.
|
|
11
|
+
"statusMessage": "(OmO 5.1.4) Checking Bootstrap Provisioning"
|
|
12
12
|
}
|
|
13
13
|
]
|
|
14
14
|
}
|
|
@@ -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": "(OmO 5.1.
|
|
11
|
+
"statusMessage": "(OmO 5.1.4) 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": "(OmO 5.1.
|
|
23
|
+
"statusMessage": "(OmO 5.1.4) 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": "(OmO 5.1.
|
|
11
|
+
"statusMessage": "(OmO 5.1.4) Verifying LazyCodex Executor Evidence"
|
|
12
12
|
}
|
|
13
13
|
]
|
|
14
14
|
}
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"schemaVersion": 1,
|
|
3
|
-
"version": "5.1.
|
|
4
|
-
"inputDigest": "sha256:
|
|
3
|
+
"version": "5.1.4",
|
|
4
|
+
"inputDigest": "sha256:4b9c0202761e8abe92155e627fa7548e4252aadd31dd92f1412d6bf1e357ed23",
|
|
5
5
|
"outputs": [
|
|
6
6
|
{
|
|
7
7
|
"path": "cli.d.ts",
|
|
@@ -9,7 +9,7 @@
|
|
|
9
9
|
},
|
|
10
10
|
{
|
|
11
11
|
"path": "cli.js",
|
|
12
|
-
"sha256": "
|
|
12
|
+
"sha256": "d793d83fb82b1fafe52e619f545c5195398498d1f95f15d84904fe3d0a20befe"
|
|
13
13
|
},
|
|
14
14
|
{
|
|
15
15
|
"path": "codex-hook-cli.d.ts",
|
|
@@ -41,7 +41,7 @@
|
|
|
41
41
|
},
|
|
42
42
|
{
|
|
43
43
|
"path": "lsp-session-state.js",
|
|
44
|
-
"sha256": "
|
|
44
|
+
"sha256": "8c0e4fff28cb9deaca9c1b12ed2b0663a93fdf8532a8028f90a241b0607b8368"
|
|
45
45
|
},
|
|
46
46
|
{
|
|
47
47
|
"path": "mutated-file-paths.d.ts",
|