@cortexkit/opencode-magic-context 0.41.1 → 0.41.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +9 -3
- package/dist/announcement-3c1vertn.js +14 -0
- package/dist/config/project-security.d.ts.map +1 -1
- package/dist/config/schema/magic-context.d.ts +756 -4
- package/dist/config/schema/magic-context.d.ts.map +1 -1
- package/dist/conflict-warning-hook-z5sd697e.js +16 -0
- package/dist/derive-budgets-901a0pk0.js +11 -0
- package/dist/features/magic-context/compartment-chunk-embedding.d.ts +4 -1
- package/dist/features/magic-context/compartment-chunk-embedding.d.ts.map +1 -1
- package/dist/features/magic-context/compartment-embedding.d.ts.map +1 -1
- package/dist/features/magic-context/compartment-lease.d.ts +6 -0
- package/dist/features/magic-context/compartment-lease.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/curate-memory-safety.d.ts +21 -0
- package/dist/features/magic-context/dreamer/curate-memory-safety.d.ts.map +1 -0
- package/dist/features/magic-context/dreamer/task-executor.d.ts.map +1 -1
- package/dist/features/magic-context/dreamer/task-prompts.d.ts +1 -6
- package/dist/features/magic-context/dreamer/task-prompts.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-failure.d.ts +10 -2
- package/dist/features/magic-context/memory/embedding-failure.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-local.d.ts +7 -0
- package/dist/features/magic-context/memory/embedding-local.d.ts.map +1 -1
- package/dist/features/magic-context/memory/onnxruntime-node-wasm-shim.d.ts +3 -0
- package/dist/features/magic-context/memory/onnxruntime-node-wasm-shim.d.ts.map +1 -0
- package/dist/features/magic-context/memory/sharp-wasm-shim.d.ts +2 -0
- package/dist/features/magic-context/memory/sharp-wasm-shim.d.ts.map +1 -0
- package/dist/features/magic-context/memory/transformers-node-wasm-entry.d.ts +3 -0
- package/dist/features/magic-context/memory/transformers-node-wasm-entry.d.ts.map +1 -0
- package/dist/features/magic-context/message-fts-rowid-map.d.ts +28 -0
- package/dist/features/magic-context/message-fts-rowid-map.d.ts.map +1 -0
- package/dist/features/magic-context/message-index.d.ts.map +1 -1
- package/dist/features/magic-context/migrations.d.ts.map +1 -1
- package/dist/features/magic-context/overflow-detection.d.ts +15 -2
- package/dist/features/magic-context/overflow-detection.d.ts.map +1 -1
- package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
- package/dist/features/magic-context/storage-db.d.ts +20 -2
- package/dist/features/magic-context/storage-db.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-persisted.d.ts +30 -14
- package/dist/features/magic-context/storage-meta-persisted.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta-session.d.ts +3 -2
- package/dist/features/magic-context/storage-meta-session.d.ts.map +1 -1
- package/dist/features/magic-context/storage-meta.d.ts +2 -2
- package/dist/features/magic-context/storage-meta.d.ts.map +1 -1
- package/dist/features/magic-context/storage-schema-helpers.d.ts.map +1 -1
- package/dist/features/magic-context/storage-session-tables.d.ts +9 -1
- package/dist/features/magic-context/storage-session-tables.d.ts.map +1 -1
- package/dist/features/magic-context/storage-subagent-invocations.d.ts +3 -2
- package/dist/features/magic-context/storage-subagent-invocations.d.ts.map +1 -1
- package/dist/features/magic-context/storage-tags.d.ts +19 -0
- package/dist/features/magic-context/storage-tags.d.ts.map +1 -1
- package/dist/features/magic-context/storage.d.ts +2 -2
- package/dist/features/magic-context/storage.d.ts.map +1 -1
- package/dist/features/magic-context/subagent-token-capture.d.ts +2 -1
- package/dist/features/magic-context/subagent-token-capture.d.ts.map +1 -1
- package/dist/hooks/magic-context/compaction-marker-manager.d.ts +6 -1
- package/dist/hooks/magic-context/compaction-marker-manager.d.ts.map +1 -1
- package/dist/hooks/magic-context/compartment-runner.d.ts +2 -1
- package/dist/hooks/magic-context/compartment-runner.d.ts.map +1 -1
- package/dist/hooks/magic-context/event-handler.d.ts +4 -1
- package/dist/hooks/magic-context/event-handler.d.ts.map +1 -1
- package/dist/hooks/magic-context/format-embed-failure.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook-handlers.d.ts +3 -0
- package/dist/hooks/magic-context/hook-handlers.d.ts.map +1 -1
- package/dist/hooks/magic-context/hook.d.ts +4 -1
- package/dist/hooks/magic-context/hook.d.ts.map +1 -1
- package/dist/hooks/magic-context/inject-compartments.d.ts +6 -0
- package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
- package/dist/hooks/magic-context/live-session-state.d.ts +3 -1
- package/dist/hooks/magic-context/live-session-state.d.ts.map +1 -1
- package/dist/hooks/magic-context/module-state-sync.d.ts +2 -1
- package/dist/hooks/magic-context/module-state-sync.d.ts.map +1 -1
- package/dist/hooks/magic-context/module-transport.d.ts +11 -4
- package/dist/hooks/magic-context/module-transport.d.ts.map +1 -1
- package/dist/hooks/magic-context/module-wire.d.ts +6 -1
- package/dist/hooks/magic-context/module-wire.d.ts.map +1 -1
- package/dist/hooks/magic-context/read-session-db.d.ts +15 -0
- package/dist/hooks/magic-context/read-session-db.d.ts.map +1 -1
- package/dist/hooks/magic-context/rust-mode-transform.d.ts +19 -1
- package/dist/hooks/magic-context/rust-mode-transform.d.ts.map +1 -1
- package/dist/hooks/magic-context/send-session-notification.d.ts +6 -0
- package/dist/hooks/magic-context/send-session-notification.d.ts.map +1 -1
- package/dist/hooks/magic-context/sentinel.d.ts +18 -53
- package/dist/hooks/magic-context/sentinel.d.ts.map +1 -1
- package/dist/hooks/magic-context/strip-content.d.ts +12 -5
- package/dist/hooks/magic-context/strip-content.d.ts.map +1 -1
- package/dist/hooks/magic-context/tag-id-fallback.d.ts +3 -1
- package/dist/hooks/magic-context/tag-id-fallback.d.ts.map +1 -1
- package/dist/hooks/magic-context/tag-messages.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +57 -2
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform.d.ts +1 -1
- package/dist/hooks/magic-context/transform.d.ts.map +1 -1
- package/dist/{index-z893kjyt.js → index-0bycg0np.js} +90 -26
- package/dist/{index-1yh8g550.js → index-22jkk6wg.js} +2 -15
- package/dist/{index-dmvy29z0.js → index-3wzdwt6p.js} +11 -15
- package/dist/{index-d1mxrd3p.js → index-7k55qm8a.js} +17 -12
- package/dist/{index-4x691bz5.js → index-dkv2dn46.js} +5 -2
- package/dist/{index-2d4kf2ve.js → index-dn1rwpd8.js} +16 -11
- package/dist/{index-rgdqj8nj.js → index-e7vx3byk.js} +1 -1
- package/dist/{index-szf8w1p5.js → index-fmsr7v69.js} +2 -2
- package/dist/{index-d62ypazr.js → index-jdxxq8cz.js} +6 -11
- package/dist/{index-9j3tx8hy.js → index-may8skc8.js} +6 -25
- package/dist/{index-eq9wr75c.js → index-npx8vhmy.js} +57 -108
- package/dist/{index-zwjhba2r.js → index-q264erdp.js} +122 -41
- package/dist/{index-b9j85d29.js → index-raatkvw5.js} +49 -11
- package/dist/{index-9xexf8s7.js → index-rn7gafjr.js} +1 -9
- package/dist/index-v6t0tg85.js +13 -0
- package/dist/{index-dh0vfghk.js → index-vmmjdpc0.js} +2594 -11271
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3414 -2620
- package/dist/model-resolution-dxatzjde.js +12 -0
- package/dist/{index-dynqfgx1.js → module-asyncify-2EFITU5U-rkqjhjxd.js} +69 -8
- package/dist/plugin/boot-deadline.d.ts +47 -0
- package/dist/plugin/boot-deadline.d.ts.map +1 -0
- package/dist/plugin/conflict-warning-hook.d.ts +10 -0
- package/dist/plugin/conflict-warning-hook.d.ts.map +1 -1
- package/dist/plugin/dream-timer.d.ts +4 -0
- package/dist/plugin/dream-timer.d.ts.map +1 -1
- package/dist/plugin/hooks/create-session-hooks.d.ts +4 -2
- package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
- package/dist/plugin/messages-transform.d.ts.map +1 -1
- package/dist/prompt-context-5y5ms8f9.js +6 -0
- package/dist/recomp-orchestrator-f5m2wk74.js +19 -0
- package/dist/rpc-notifications-4amf6mf4.js +14 -0
- package/dist/{index-vnz6jvdc.js → safe-notification-target-q9z81zt3.js} +4 -3
- package/dist/send-session-notification-hdh02wy9.js +16 -0
- package/dist/shared/conflict-detector.d.ts +3 -1
- package/dist/shared/conflict-detector.d.ts.map +1 -1
- package/dist/shared/harness.d.ts +3 -3
- package/dist/shared/harness.d.ts.map +1 -1
- package/dist/shared/index.d.ts +1 -0
- package/dist/shared/index.d.ts.map +1 -1
- package/dist/shared/model-resolution.d.ts +3 -3
- package/dist/shared/model-resolution.d.ts.map +1 -1
- package/dist/shared/prompt-surface-runtime.d.ts +2 -2
- package/dist/shared/prompt-surface-runtime.d.ts.map +1 -1
- package/dist/shared/rpc-utils.d.ts +3 -1
- package/dist/shared/rpc-utils.d.ts.map +1 -1
- package/dist/shared/summarize-child-stderr.d.ts +2 -0
- package/dist/shared/summarize-child-stderr.d.ts.map +1 -0
- package/dist/shared/tag-transcript.d.ts.map +1 -1
- package/dist/shared/transcript.d.ts +2 -1
- package/dist/shared/transcript.d.ts.map +1 -1
- package/dist/shared/window-geometry.d.ts +2 -0
- package/dist/shared/window-geometry.d.ts.map +1 -1
- package/dist/storage-meta-session-3rxx9ekm.js +20 -0
- package/dist/task-config-hnv93r7p.js +9 -0
- package/dist/tools/ctx-memory/tools.d.ts.map +1 -1
- package/dist/tools/ctx-memory/types.d.ts +2 -0
- package/dist/tools/ctx-memory/types.d.ts.map +1 -1
- package/dist/tools/ctx-reduce/tools.d.ts.map +1 -1
- package/dist/transformers-node-wasm.js +25676 -0
- package/dist/transformers-web.js +72 -72
- package/dist/{transformers.node-b1wa0hgx.js → transformers.node-dpmf3wpx.js} +74 -74
- package/package.json +4 -3
- package/src/config/index.test.ts +69 -0
- package/src/config/latch-permanence-guard.test.ts +5 -0
- package/src/config/project-security.hostile-matrix.test.ts +78 -9
- package/src/config/project-security.ts +4 -3
- package/src/config/schema/magic-context.test.ts +64 -0
- package/src/config/schema/magic-context.ts +100 -6
- package/src/shared/conflict-detector.test.ts +24 -0
- package/src/shared/conflict-detector.ts +25 -7
- package/src/shared/harness.ts +3 -3
- package/src/shared/index.ts +1 -0
- package/src/shared/model-resolution.test.ts +78 -13
- package/src/shared/model-resolution.ts +14 -5
- package/src/shared/prompt-surface-runtime.ts +3 -3
- package/src/shared/rpc-utils.test.ts +246 -5
- package/src/shared/rpc-utils.ts +340 -49
- package/src/shared/summarize-child-stderr.test.ts +55 -0
- package/src/shared/summarize-child-stderr.ts +33 -0
- package/src/shared/tag-transcript.ts +11 -0
- package/src/shared/transcript.ts +3 -1
- package/src/shared/window-geometry.ts +9 -0
- package/dist/announcement-3g9xg433.js +0 -18
- package/dist/conflict-warning-hook-rf17b6et.js +0 -17
- package/dist/derive-budgets-bb7mrpzs.js +0 -14
- package/dist/emscripten-module-49k43zfy.js +0 -507
- package/dist/emscripten-module-ex4v0x4z.js +0 -606
- package/dist/emscripten-module-jfs3d1dq.js +0 -1536
- package/dist/emscripten-module-ss4g4spn.js +0 -4563
- package/dist/ffi-bbm9vkfa.js +0 -92
- package/dist/ffi-kb5r0x1j.js +0 -92
- package/dist/ffi-qnrt0y78.js +0 -80
- package/dist/ffi-yx2hpf4p.js +0 -80
- package/dist/index-8sseka65.js +0 -251
- package/dist/index-ss632za9.js +0 -77
- package/dist/model-resolution-6w6wzw18.js +0 -17
- package/dist/module-ES6BEMUI-1yjdz59c.js +0 -14
- package/dist/module-asyncify-2EFITU5U-fdkx4fhy.js +0 -9
- package/dist/prompt-context-29qkb28f.js +0 -7
- package/dist/recomp-orchestrator-w7xg48e3.js +0 -34
- package/dist/rpc-notifications-1ffm755w.js +0 -17
- package/dist/safe-notification-target-2a8py95v.js +0 -11
- package/dist/send-session-notification-bw7eex6w.js +0 -20
- package/dist/storage-meta-session-gr4zn7sq.js +0 -21
- package/dist/task-config-gv6s04fp.js +0 -18
- /package/dist/{index-37yzyeca.js → index-3fe78beq.js} +0 -0
- /package/dist/{index-8mtsfhyg.js → index-jfpk81yt.js} +0 -0
- /package/dist/{index-2wchnyk6.js → index-kby1sng5.js} +0 -0
package/src/shared/harness.ts
CHANGED
|
@@ -2,7 +2,7 @@
|
|
|
2
2
|
* Identifier for the host harness this plugin is running inside.
|
|
3
3
|
*
|
|
4
4
|
* Magic Context's SQLite database lives at a vendor-scoped path
|
|
5
|
-
* (`~/.local/share/cortexkit/magic-context/`) so OpenCode and
|
|
5
|
+
* (`~/.local/share/cortexkit/magic-context/`) so OpenCode, Pi, and OMP can share
|
|
6
6
|
* project memories, embedding cache, dreamer runs, and other project-scoped
|
|
7
7
|
* state. Session-scoped tables carry a `harness` column populated from this
|
|
8
8
|
* module so we can disambiguate which harness wrote each session row,
|
|
@@ -13,13 +13,13 @@
|
|
|
13
13
|
* happens:
|
|
14
14
|
* - OpenCode plugin: relies on the default ("opencode") — no setHarness call
|
|
15
15
|
* needed
|
|
16
|
-
* - Pi plugin: calls `setHarness("pi")` before opening the database
|
|
16
|
+
* - Pi-compatible plugin: resolves the host and calls `setHarness("pi" | "omp")` before opening the database
|
|
17
17
|
*
|
|
18
18
|
* NEVER read this from configuration or session state — it is a
|
|
19
19
|
* boot-time constant per plugin instance. Cross-harness leakage is a
|
|
20
20
|
* correctness bug, not a feature.
|
|
21
21
|
*/
|
|
22
|
-
export type HarnessId = "opencode" | "pi";
|
|
22
|
+
export type HarnessId = "opencode" | "pi" | "omp";
|
|
23
23
|
|
|
24
24
|
let currentHarness: HarnessId = "opencode";
|
|
25
25
|
let harnessLocked = false;
|
package/src/shared/index.ts
CHANGED
|
@@ -10,21 +10,25 @@ import {
|
|
|
10
10
|
|
|
11
11
|
describe("model-resolution", () => {
|
|
12
12
|
test("keeps historian temperature opt-in while preserving explicit overrides", () => {
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
17
|
-
|
|
18
|
-
|
|
13
|
+
const fixtures = [
|
|
14
|
+
{ temperature: undefined, expected: undefined },
|
|
15
|
+
{ temperature: 0.1, expected: 0.1 },
|
|
16
|
+
{ temperature: 0, expected: 0 },
|
|
17
|
+
] as const;
|
|
18
|
+
for (const fixture of fixtures) {
|
|
19
|
+
const resolved = resolveHistorianAgentOverrides({
|
|
20
|
+
...(fixture.temperature !== undefined ? { temperature: fixture.temperature } : {}),
|
|
19
21
|
maxTokens: 16_000,
|
|
20
22
|
opencode: { model: "google/flash", variant: "low" },
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
23
|
+
pi: { model: "pi/must-not-leak", thinking_level: "high" },
|
|
24
|
+
});
|
|
25
|
+
expect(resolved).toEqual({
|
|
26
|
+
maxTokens: 16_000,
|
|
27
|
+
...(fixture.expected !== undefined ? { temperature: fixture.expected } : {}),
|
|
28
|
+
model: "google/flash",
|
|
29
|
+
variant: "low",
|
|
30
|
+
});
|
|
31
|
+
}
|
|
28
32
|
});
|
|
29
33
|
|
|
30
34
|
test("normalizes string and object entries to the same model identity", () => {
|
|
@@ -126,6 +130,67 @@ describe("model-resolution", () => {
|
|
|
126
130
|
});
|
|
127
131
|
});
|
|
128
132
|
|
|
133
|
+
test("uses OMP blocks first, falls back to Pi blocks, then preserves existing defaults", () => {
|
|
134
|
+
const configured = {
|
|
135
|
+
historian: {
|
|
136
|
+
pi: {
|
|
137
|
+
model: { model: "pi/historian", thinking_level: "high" },
|
|
138
|
+
fallback_models: ["pi/historian-fallback"],
|
|
139
|
+
},
|
|
140
|
+
omp: {
|
|
141
|
+
model: { model: "omp/historian", thinking_level: "auto" },
|
|
142
|
+
fallback_models: [{ model: "omp/historian-fallback", thinking_level: "max" }],
|
|
143
|
+
},
|
|
144
|
+
},
|
|
145
|
+
dreamer: {
|
|
146
|
+
tasks: { verify: { schedule: "0 3 * * *" } },
|
|
147
|
+
pi: {
|
|
148
|
+
model: "pi/dreamer",
|
|
149
|
+
tasks: { verify: { model: "pi/verify" } },
|
|
150
|
+
},
|
|
151
|
+
omp: {
|
|
152
|
+
model: "omp/dreamer",
|
|
153
|
+
tasks: {
|
|
154
|
+
verify: {
|
|
155
|
+
model: { model: "omp/verify", thinking_level: "inherit" },
|
|
156
|
+
},
|
|
157
|
+
},
|
|
158
|
+
},
|
|
159
|
+
},
|
|
160
|
+
};
|
|
161
|
+
|
|
162
|
+
expect(resolveHistorianModel(configured, "omp")).toEqual({
|
|
163
|
+
primary: { model: "omp/historian", qualifier: "auto" },
|
|
164
|
+
fallbacks: [{ model: "omp/historian-fallback", qualifier: "max" }],
|
|
165
|
+
});
|
|
166
|
+
expect(
|
|
167
|
+
resolveDreamerTaskModel({ config: configured, harness: "omp", task: "verify" }),
|
|
168
|
+
).toMatchObject({ primary: { model: "omp/verify", qualifier: "inherit" } });
|
|
169
|
+
|
|
170
|
+
const piFallback = {
|
|
171
|
+
historian: configured.historian,
|
|
172
|
+
dreamer: { ...configured.dreamer, omp: undefined },
|
|
173
|
+
};
|
|
174
|
+
delete (piFallback.historian as { omp?: unknown }).omp;
|
|
175
|
+
expect(resolveHistorianModel(piFallback, "omp")?.primary).toEqual({
|
|
176
|
+
model: "pi/historian",
|
|
177
|
+
qualifier: "high",
|
|
178
|
+
});
|
|
179
|
+
expect(
|
|
180
|
+
resolveDreamerTaskModel({ config: piFallback, harness: "omp", task: "verify" }),
|
|
181
|
+
).toMatchObject({ primary: { model: "pi/verify" } });
|
|
182
|
+
|
|
183
|
+
expect(resolveHistorianModel({}, "omp")).toEqual({ fallbacks: [] });
|
|
184
|
+
const existingDefaults = resolveDreamerTaskModel({
|
|
185
|
+
config: { dreamer: { tasks: { verify: { schedule: "0 3 * * *" } } } },
|
|
186
|
+
harness: "omp",
|
|
187
|
+
task: "verify",
|
|
188
|
+
});
|
|
189
|
+
expect(existingDefaults.primary).toBeUndefined();
|
|
190
|
+
expect(existingDefaults.fallbacks).toEqual([]);
|
|
191
|
+
expect(existingDefaults.schedule).toBe("0 3 * * *");
|
|
192
|
+
});
|
|
193
|
+
|
|
129
194
|
test("resolves ordinary task model and scheduling without crossing harnesses", () => {
|
|
130
195
|
const config = {
|
|
131
196
|
dreamer: {
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
export type ModelHarness = "opencode" | "pi";
|
|
1
|
+
export type ModelHarness = "opencode" | "pi" | "omp";
|
|
2
2
|
|
|
3
3
|
export interface ResolvedModelEntry {
|
|
4
4
|
/** Canonical provider/model reference used for identity and model selection. */
|
|
@@ -27,6 +27,14 @@ function hasOwn(record: ConfigRecord, key: string): boolean {
|
|
|
27
27
|
return Object.hasOwn(record, key);
|
|
28
28
|
}
|
|
29
29
|
|
|
30
|
+
function resolveHarnessBlock(
|
|
31
|
+
container: ConfigRecord | undefined,
|
|
32
|
+
harness: ModelHarness,
|
|
33
|
+
): ConfigRecord | undefined {
|
|
34
|
+
const selected = harness === "omp" ? (container?.omp ?? container?.pi) : container?.[harness];
|
|
35
|
+
return asRecord(selected);
|
|
36
|
+
}
|
|
37
|
+
|
|
30
38
|
/**
|
|
31
39
|
* Collapses the string and object spellings of a harness model entry into the
|
|
32
40
|
* same model identity. Qualifiers stay separate because they alter an attempt,
|
|
@@ -98,15 +106,15 @@ export interface ResolvedHistorianModel {
|
|
|
98
106
|
}
|
|
99
107
|
|
|
100
108
|
/**
|
|
101
|
-
* Resolve historian model attempts from
|
|
102
|
-
* and
|
|
109
|
+
* Resolve historian model attempts from the selected harness block. OMP uses
|
|
110
|
+
* its own block when present and falls back to Pi when it is absent.
|
|
103
111
|
*/
|
|
104
112
|
export function resolveHistorianModel(
|
|
105
113
|
config: unknown,
|
|
106
114
|
harness: ModelHarness,
|
|
107
115
|
): ResolvedHistorianModel {
|
|
108
116
|
const historian = asRecord(asRecord(config)?.historian);
|
|
109
|
-
const block =
|
|
117
|
+
const block = resolveHarnessBlock(historian, harness);
|
|
110
118
|
if (!block) return { fallbacks: [] };
|
|
111
119
|
|
|
112
120
|
return {
|
|
@@ -139,7 +147,7 @@ export function resolveDreamerTaskModel(args: {
|
|
|
139
147
|
muralModel?: unknown;
|
|
140
148
|
}): ResolvedDreamerTaskModel {
|
|
141
149
|
const dreamer = asRecord(asRecord(args.config)?.dreamer);
|
|
142
|
-
const harnessBlock =
|
|
150
|
+
const harnessBlock = resolveHarnessBlock(dreamer, args.harness);
|
|
143
151
|
const taskBlock = asRecord(asRecord(harnessBlock?.tasks)?.[args.task]);
|
|
144
152
|
const schedulingTask = asRecord(asRecord(dreamer?.tasks)?.[args.task]);
|
|
145
153
|
if (!harnessBlock) {
|
|
@@ -211,6 +219,7 @@ export function resolveOpenCodeAgentOverrides(agent: unknown): Record<string, un
|
|
|
211
219
|
thinking_level: _thinking,
|
|
212
220
|
opencode,
|
|
213
221
|
pi,
|
|
222
|
+
omp,
|
|
214
223
|
tasks,
|
|
215
224
|
...rest
|
|
216
225
|
} = source;
|
|
@@ -2,7 +2,6 @@ import { existsSync, readFileSync, statSync } from "node:fs";
|
|
|
2
2
|
import { dirname, isAbsolute, resolve } from "node:path";
|
|
3
3
|
|
|
4
4
|
import {
|
|
5
|
-
type ConfigHarness,
|
|
6
5
|
cortexKitUserConfigBasePath,
|
|
7
6
|
resolveLegacyConfigSourcesForHarness,
|
|
8
7
|
} from "../config/migrate-config-location";
|
|
@@ -13,6 +12,7 @@ import {
|
|
|
13
12
|
CTX_REDUCE_LIGHT_DESCRIPTION,
|
|
14
13
|
CTX_SEARCH_LIGHT_DESCRIPTION,
|
|
15
14
|
} from "../tools/light-descriptions";
|
|
15
|
+
import type { HarnessId } from "./harness";
|
|
16
16
|
import { piModelRefToCanonical } from "./harness-provider-map";
|
|
17
17
|
import { detectConfigFile } from "./jsonc-parser";
|
|
18
18
|
import {
|
|
@@ -88,7 +88,7 @@ export interface PromptSurfaceRuntime {
|
|
|
88
88
|
}
|
|
89
89
|
|
|
90
90
|
export interface CreatePromptSurfaceRuntimeOptions {
|
|
91
|
-
harness?:
|
|
91
|
+
harness?: HarnessId;
|
|
92
92
|
directory?: string;
|
|
93
93
|
/** Explicit test/integration seam; production derives the USER config directory. */
|
|
94
94
|
userConfigDirectory?: string;
|
|
@@ -105,7 +105,7 @@ function resolveUserConfigDirectory(options: CreatePromptSurfaceRuntimeOptions):
|
|
|
105
105
|
if (options.harness) {
|
|
106
106
|
const legacy = resolveLegacyConfigSourcesForHarness(
|
|
107
107
|
options.directory ?? process.cwd(),
|
|
108
|
-
options.harness,
|
|
108
|
+
options.harness === "omp" ? "pi" : options.harness,
|
|
109
109
|
).user.find((source) => existsSync(source.path));
|
|
110
110
|
if (legacy) return dirname(legacy.path);
|
|
111
111
|
}
|
|
@@ -53,6 +53,45 @@ function tasklistOutput(entries: Array<[number, string]>): string {
|
|
|
53
53
|
].join("\r\n");
|
|
54
54
|
}
|
|
55
55
|
|
|
56
|
+
const WINDOWS_LAUNCHER_PID = 42424;
|
|
57
|
+
const WINDOWS_FOREIGN_PID = 41001;
|
|
58
|
+
const PLUGIN_BUILD_MS = 1_700_000_000_000;
|
|
59
|
+
const OLDER_THAN_PLUGIN_MS = PLUGIN_BUILD_MS - 60_000;
|
|
60
|
+
const OMP_PI_ARC_COMMAND =
|
|
61
|
+
"C:\\Users\\qiiks\\.bun\\bin\\omp.exe C:\\Users\\qiiks\\AppData\\Roaming\\npm\\node_modules\\@oh-my-pi\\pi-coding-agent\\dist\\cli.js";
|
|
62
|
+
const BUN_PI_CHILD_COMMAND =
|
|
63
|
+
"C:\\Users\\qiiks\\.bun\\bin\\bun.exe C:\\Users\\qiiks\\AppData\\Roaming\\npm\\node_modules\\@oh-my-pi\\pi-coding-agent\\dist\\cli.js";
|
|
64
|
+
const BARE_OMP_COMMAND = "C:\\Users\\qiiks\\.bun\\bin\\omp.exe";
|
|
65
|
+
|
|
66
|
+
function padWmi(value: number, width = 2): string {
|
|
67
|
+
return String(value).padStart(width, "0");
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
/** Format an epoch millisecond timestamp as a WMI CreationDate string. */
|
|
71
|
+
function wmiCreationDate(ms: number, offsetMinutes = 0): string {
|
|
72
|
+
const shifted = new Date(ms + offsetMinutes * 60_000);
|
|
73
|
+
const sign = offsetMinutes >= 0 ? "+" : "-";
|
|
74
|
+
return `${shifted.getUTCFullYear()}${padWmi(shifted.getUTCMonth() + 1)}${padWmi(shifted.getUTCDate())}${padWmi(shifted.getUTCHours())}${padWmi(shifted.getUTCMinutes())}${padWmi(shifted.getUTCSeconds())}.000000${sign}${padWmi(Math.abs(offsetMinutes), 3)}`;
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
function cimOutput(
|
|
78
|
+
rows: Array<{
|
|
79
|
+
ProcessId: number;
|
|
80
|
+
ParentProcessId: number;
|
|
81
|
+
CommandLine: string | null;
|
|
82
|
+
CreationDate: string;
|
|
83
|
+
}>,
|
|
84
|
+
): string {
|
|
85
|
+
return JSON.stringify(rows.length === 1 ? rows[0] : rows);
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function windowsProcessListExec(
|
|
89
|
+
handler: (file: string, args: readonly string[]) => string,
|
|
90
|
+
): typeof execFileSync {
|
|
91
|
+
return ((file: string | URL, args: readonly string[] = []) =>
|
|
92
|
+
handler(String(file), args)) as typeof execFileSync;
|
|
93
|
+
}
|
|
94
|
+
|
|
56
95
|
afterEach(() => {
|
|
57
96
|
__resetRpcIdentityTestHooks();
|
|
58
97
|
});
|
|
@@ -97,7 +136,12 @@ describe("discoverLivePiProcessIds", () => {
|
|
|
97
136
|
].join("\n")) as typeof execFileSync,
|
|
98
137
|
});
|
|
99
138
|
|
|
100
|
-
expect(
|
|
139
|
+
expect(inspectLivePiProcesses()).toEqual({
|
|
140
|
+
state: "known",
|
|
141
|
+
processIds: [41002, 41003],
|
|
142
|
+
inconclusivePids: [41001, 41007],
|
|
143
|
+
});
|
|
144
|
+
expect(discoverLivePiProcessIds()).toEqual([41002, 41003]);
|
|
101
145
|
});
|
|
102
146
|
|
|
103
147
|
test("reports uncertainty instead of treating an unavailable process list as empty", () => {
|
|
@@ -114,12 +158,13 @@ describe("discoverLivePiProcessIds", () => {
|
|
|
114
158
|
});
|
|
115
159
|
});
|
|
116
160
|
|
|
117
|
-
test("
|
|
161
|
+
test("tries PowerShell CIM before tasklist on Windows", () => {
|
|
118
162
|
const calls: string[] = [];
|
|
119
163
|
__setRpcIdentityTestHooks({
|
|
120
164
|
platform: "win32",
|
|
121
165
|
processListExecFileSync: ((file: string | URL) => {
|
|
122
166
|
calls.push(String(file));
|
|
167
|
+
if (String(file) === "powershell") throw new Error("powershell unavailable");
|
|
123
168
|
return tasklistOutput([
|
|
124
169
|
[process.pid, "pi.exe"],
|
|
125
170
|
[41001, "pi.exe"],
|
|
@@ -129,10 +174,197 @@ describe("discoverLivePiProcessIds", () => {
|
|
|
129
174
|
});
|
|
130
175
|
|
|
131
176
|
expect(inspectLivePiProcesses()).toEqual({
|
|
177
|
+
state: "inconclusive",
|
|
178
|
+
processIds: [],
|
|
179
|
+
inconclusivePids: [41001],
|
|
180
|
+
});
|
|
181
|
+
expect(calls).toEqual(["powershell", "tasklist"]);
|
|
182
|
+
});
|
|
183
|
+
});
|
|
184
|
+
|
|
185
|
+
describe("#411 Windows OMP/Pi live-process scan", () => {
|
|
186
|
+
test("(a) tasklist-only fallback skips a parent omp.exe as an ancestor", () => {
|
|
187
|
+
const calls: string[] = [];
|
|
188
|
+
__setRpcIdentityTestHooks({
|
|
189
|
+
platform: "win32",
|
|
190
|
+
processListExecFileSync: windowsProcessListExec((file) => {
|
|
191
|
+
calls.push(file);
|
|
192
|
+
if (file === "powershell") {
|
|
193
|
+
throw new Error("powershell unavailable");
|
|
194
|
+
}
|
|
195
|
+
return tasklistOutput([
|
|
196
|
+
[process.ppid, "omp.exe"],
|
|
197
|
+
[WINDOWS_FOREIGN_PID, "notepad.exe"],
|
|
198
|
+
]);
|
|
199
|
+
}),
|
|
200
|
+
});
|
|
201
|
+
|
|
202
|
+
const discovery = inspectLivePiProcesses();
|
|
203
|
+
expect(discovery.processIds).not.toContain(process.ppid);
|
|
204
|
+
expect(discovery.skippedAncestorPids).toContain(process.ppid);
|
|
205
|
+
expect(calls[0]).toBe("powershell");
|
|
206
|
+
expect(calls).toContain("tasklist");
|
|
207
|
+
});
|
|
208
|
+
|
|
209
|
+
test("(a) CIM parent omp.exe with a Pi arc is skipped as an ancestor", () => {
|
|
210
|
+
__setRpcIdentityTestHooks({
|
|
211
|
+
platform: "win32",
|
|
212
|
+
nowMs: () => PLUGIN_BUILD_MS,
|
|
213
|
+
processListExecFileSync: windowsProcessListExec((file) => {
|
|
214
|
+
if (file !== "powershell") {
|
|
215
|
+
throw new Error(`${file} must not run when CIM succeeds`);
|
|
216
|
+
}
|
|
217
|
+
return cimOutput([
|
|
218
|
+
{
|
|
219
|
+
ProcessId: process.pid,
|
|
220
|
+
ParentProcessId: WINDOWS_LAUNCHER_PID,
|
|
221
|
+
CommandLine: BUN_PI_CHILD_COMMAND,
|
|
222
|
+
CreationDate: wmiCreationDate(PLUGIN_BUILD_MS),
|
|
223
|
+
},
|
|
224
|
+
{
|
|
225
|
+
ProcessId: WINDOWS_LAUNCHER_PID,
|
|
226
|
+
ParentProcessId: 4,
|
|
227
|
+
CommandLine: OMP_PI_ARC_COMMAND,
|
|
228
|
+
CreationDate: wmiCreationDate(OLDER_THAN_PLUGIN_MS),
|
|
229
|
+
},
|
|
230
|
+
]);
|
|
231
|
+
}),
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
const discovery = inspectLivePiProcesses();
|
|
235
|
+
expect(discovery.processIds).not.toContain(WINDOWS_LAUNCHER_PID);
|
|
236
|
+
expect(discovery.processIds).not.toContain(process.pid);
|
|
237
|
+
expect(discovery.skippedAncestorPids).toContain(WINDOWS_LAUNCHER_PID);
|
|
238
|
+
expect(discovery.state).toBe("known");
|
|
239
|
+
});
|
|
240
|
+
|
|
241
|
+
test("(b) CIM unrelated omp.exe with a Pi arc and older CreationDate is a verified blocker", () => {
|
|
242
|
+
__setRpcIdentityTestHooks({
|
|
243
|
+
platform: "win32",
|
|
244
|
+
nowMs: () => PLUGIN_BUILD_MS,
|
|
245
|
+
processListExecFileSync: windowsProcessListExec((file) => {
|
|
246
|
+
if (file !== "powershell") {
|
|
247
|
+
throw new Error(`${file} must not run when CIM succeeds`);
|
|
248
|
+
}
|
|
249
|
+
return cimOutput([
|
|
250
|
+
{
|
|
251
|
+
ProcessId: process.pid,
|
|
252
|
+
ParentProcessId: process.ppid,
|
|
253
|
+
CommandLine: BUN_PI_CHILD_COMMAND,
|
|
254
|
+
CreationDate: wmiCreationDate(PLUGIN_BUILD_MS),
|
|
255
|
+
},
|
|
256
|
+
{
|
|
257
|
+
ProcessId: WINDOWS_FOREIGN_PID,
|
|
258
|
+
ParentProcessId: 8,
|
|
259
|
+
CommandLine: OMP_PI_ARC_COMMAND,
|
|
260
|
+
CreationDate: wmiCreationDate(OLDER_THAN_PLUGIN_MS, 60),
|
|
261
|
+
},
|
|
262
|
+
]);
|
|
263
|
+
}),
|
|
264
|
+
});
|
|
265
|
+
|
|
266
|
+
const discovery = inspectLivePiProcesses();
|
|
267
|
+
expect(discovery.state).toBe("known");
|
|
268
|
+
expect(discovery.processIds).toEqual([WINDOWS_FOREIGN_PID]);
|
|
269
|
+
expect(readProcessProbeEvidence(WINDOWS_FOREIGN_PID)).toEqual({
|
|
270
|
+
startTime: OLDER_THAN_PLUGIN_MS,
|
|
271
|
+
commandLine: OMP_PI_ARC_COMMAND,
|
|
272
|
+
});
|
|
273
|
+
});
|
|
274
|
+
|
|
275
|
+
test("(c) CIM omp.exe with no Pi arc is inconclusive", () => {
|
|
276
|
+
__setRpcIdentityTestHooks({
|
|
277
|
+
platform: "win32",
|
|
278
|
+
processListExecFileSync: windowsProcessListExec((file) => {
|
|
279
|
+
if (file !== "powershell") {
|
|
280
|
+
throw new Error(`${file} must not run when CIM succeeds`);
|
|
281
|
+
}
|
|
282
|
+
return cimOutput([
|
|
283
|
+
{
|
|
284
|
+
ProcessId: WINDOWS_FOREIGN_PID,
|
|
285
|
+
ParentProcessId: 8,
|
|
286
|
+
CommandLine: BARE_OMP_COMMAND,
|
|
287
|
+
CreationDate: wmiCreationDate(OLDER_THAN_PLUGIN_MS),
|
|
288
|
+
},
|
|
289
|
+
]);
|
|
290
|
+
}),
|
|
291
|
+
});
|
|
292
|
+
|
|
293
|
+
const discovery = inspectLivePiProcesses();
|
|
294
|
+
expect(discovery.state).toBe("inconclusive");
|
|
295
|
+
expect(discovery.processIds).toEqual([]);
|
|
296
|
+
expect(discovery.inconclusivePids).toEqual([WINDOWS_FOREIGN_PID]);
|
|
297
|
+
});
|
|
298
|
+
|
|
299
|
+
test("(d) PowerShell unavailable falls back to tasklist as inconclusive", () => {
|
|
300
|
+
const calls: string[] = [];
|
|
301
|
+
__setRpcIdentityTestHooks({
|
|
302
|
+
platform: "win32",
|
|
303
|
+
processListExecFileSync: windowsProcessListExec((file) => {
|
|
304
|
+
calls.push(file);
|
|
305
|
+
if (file === "powershell") {
|
|
306
|
+
throw new Error("powershell unavailable");
|
|
307
|
+
}
|
|
308
|
+
return tasklistOutput([
|
|
309
|
+
[WINDOWS_FOREIGN_PID, "omp.exe"],
|
|
310
|
+
[41002, "opencode.exe"],
|
|
311
|
+
]);
|
|
312
|
+
}),
|
|
313
|
+
});
|
|
314
|
+
|
|
315
|
+
const discovery = inspectLivePiProcesses();
|
|
316
|
+
expect(discovery.state).toBe("inconclusive");
|
|
317
|
+
expect(discovery.processIds).toEqual([]);
|
|
318
|
+
expect(discovery.inconclusivePids).toEqual([WINDOWS_FOREIGN_PID]);
|
|
319
|
+
expect(calls).toEqual(["powershell", "tasklist"]);
|
|
320
|
+
});
|
|
321
|
+
|
|
322
|
+
test("(e) POSIX ancestor exclusion skips the parent Pi harness", () => {
|
|
323
|
+
__setRpcIdentityTestHooks({
|
|
324
|
+
platform: "darwin",
|
|
325
|
+
processListExecFileSync: windowsProcessListExec((file, args) => {
|
|
326
|
+
if (file === "ps" && args.includes("ppid=")) {
|
|
327
|
+
const pidIndex = args.indexOf("-p");
|
|
328
|
+
const pid = Number(args[pidIndex + 1]);
|
|
329
|
+
if (pid === process.pid) return ` ${process.ppid}\n`;
|
|
330
|
+
if (pid === process.ppid) return " 1\n";
|
|
331
|
+
return " 1\n";
|
|
332
|
+
}
|
|
333
|
+
return [
|
|
334
|
+
` ${process.pid} bun /opt/node_modules/@oh-my-pi/pi-coding-agent/dist/cli.js`,
|
|
335
|
+
` ${process.ppid} bun /opt/node_modules/@oh-my-pi/pi-coding-agent/dist/cli.js`,
|
|
336
|
+
" 41001 bun /opt/node_modules/@oh-my-pi/pi-coding-agent/dist/cli.js",
|
|
337
|
+
].join("\n");
|
|
338
|
+
}),
|
|
339
|
+
});
|
|
340
|
+
|
|
341
|
+
const discovery = inspectLivePiProcesses();
|
|
342
|
+
expect(discovery.processIds).toEqual([41001]);
|
|
343
|
+
expect(discovery.skippedAncestorPids).toContain(process.ppid);
|
|
344
|
+
});
|
|
345
|
+
|
|
346
|
+
test("(f) CIM single-object JSON shape parses", () => {
|
|
347
|
+
__setRpcIdentityTestHooks({
|
|
348
|
+
platform: "win32",
|
|
349
|
+
processListExecFileSync: windowsProcessListExec((file) => {
|
|
350
|
+
if (file !== "powershell") {
|
|
351
|
+
throw new Error(`${file} must not run when CIM succeeds`);
|
|
352
|
+
}
|
|
353
|
+
return cimOutput([
|
|
354
|
+
{
|
|
355
|
+
ProcessId: WINDOWS_FOREIGN_PID,
|
|
356
|
+
ParentProcessId: 8,
|
|
357
|
+
CommandLine: OMP_PI_ARC_COMMAND,
|
|
358
|
+
CreationDate: wmiCreationDate(OLDER_THAN_PLUGIN_MS),
|
|
359
|
+
},
|
|
360
|
+
]);
|
|
361
|
+
}),
|
|
362
|
+
});
|
|
363
|
+
|
|
364
|
+
expect(inspectLivePiProcesses()).toMatchObject({
|
|
132
365
|
state: "known",
|
|
133
|
-
processIds: [
|
|
366
|
+
processIds: [WINDOWS_FOREIGN_PID],
|
|
134
367
|
});
|
|
135
|
-
expect(calls).toEqual(["tasklist"]);
|
|
136
368
|
});
|
|
137
369
|
});
|
|
138
370
|
|
|
@@ -369,6 +601,15 @@ describe("isPidIdentityPlausible", () => {
|
|
|
369
601
|
|
|
370
602
|
calls.length = 0;
|
|
371
603
|
expect(isPidIdentityPlausible(record(NOW_MS))).toBe("inconclusive");
|
|
372
|
-
expect(calls).toEqual([
|
|
604
|
+
expect(calls).toEqual([
|
|
605
|
+
{
|
|
606
|
+
file: "powershell",
|
|
607
|
+
args: [
|
|
608
|
+
"-NoProfile",
|
|
609
|
+
"-Command",
|
|
610
|
+
"Get-CimInstance Win32_Process | Select-Object ProcessId,ParentProcessId,CommandLine,CreationDate | ConvertTo-Json -Compress",
|
|
611
|
+
],
|
|
612
|
+
},
|
|
613
|
+
]);
|
|
373
614
|
});
|
|
374
615
|
});
|