@cortexkit/opencode-magic-context 0.39.0 → 0.40.0
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 +20 -0
- package/dist/config/index.d.ts.map +1 -1
- package/dist/config/profiles.d.ts +22 -0
- package/dist/config/profiles.d.ts.map +1 -0
- package/dist/config/project-security.d.ts +3 -0
- package/dist/config/project-security.d.ts.map +1 -1
- package/dist/config/schema/magic-context.d.ts +400 -0
- package/dist/config/schema/magic-context.d.ts.map +1 -1
- package/dist/features/magic-context/fail-closed-block.d.ts +11 -1
- package/dist/features/magic-context/fail-closed-block.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-failure.d.ts +11 -0
- package/dist/features/magic-context/memory/embedding-failure.d.ts.map +1 -0
- package/dist/features/magic-context/memory/embedding-openai.d.ts +5 -0
- package/dist/features/magic-context/memory/embedding-openai.d.ts.map +1 -1
- package/dist/features/magic-context/memory/embedding-provider.d.ts +3 -0
- package/dist/features/magic-context/memory/embedding-provider.d.ts.map +1 -1
- package/dist/features/magic-context/project-embedding-registry.d.ts +2 -0
- package/dist/features/magic-context/project-embedding-registry.d.ts.map +1 -1
- package/dist/features/magic-context/storage-db.d.ts +1 -1
- package/dist/features/magic-context/storage-db.d.ts.map +1 -1
- package/dist/features/magic-context/transform-decision-log.d.ts.map +1 -1
- package/dist/hooks/magic-context/format-embed-failure.d.ts +3 -0
- package/dist/hooks/magic-context/format-embed-failure.d.ts.map +1 -0
- package/dist/hooks/magic-context/inject-compartments.d.ts +4 -3
- package/dist/hooks/magic-context/inject-compartments.d.ts.map +1 -1
- package/dist/hooks/magic-context/strip-content.d.ts +6 -0
- package/dist/hooks/magic-context/strip-content.d.ts.map +1 -1
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts +1 -0
- package/dist/hooks/magic-context/transform-postprocess-phase.d.ts.map +1 -1
- package/dist/{index-k2ts0wk1.js → index-axpym70t.js} +395 -66
- package/dist/index.js +119 -163
- package/dist/plugin/hooks/create-session-hooks.d.ts +2 -0
- package/dist/plugin/hooks/create-session-hooks.d.ts.map +1 -1
- package/dist/plugin/rpc-handlers.d.ts.map +1 -1
- package/dist/{recomp-orchestrator-2pncxee7.js → recomp-orchestrator-dmyvqekw.js} +1 -1
- package/dist/shared/rpc-types.d.ts +2 -0
- package/dist/shared/rpc-types.d.ts.map +1 -1
- package/dist/shared/rpc-utils.d.ts +12 -1
- package/dist/shared/rpc-utils.d.ts.map +1 -1
- package/dist/shared/status-detail-text.d.ts.map +1 -1
- package/dist/tui/data/context-db.d.ts.map +1 -1
- package/dist/tui-compiled/data/context-db.d.ts.map +1 -1
- package/package.json +1 -1
- package/src/config/index.test.ts +361 -2
- package/src/config/index.ts +29 -10
- package/src/config/profiles.ts +106 -0
- package/src/config/project-security.hostile-matrix.test.ts +9 -0
- package/src/config/project-security.test.ts +17 -0
- package/src/config/project-security.ts +10 -0
- package/src/config/schema/magic-context.test.ts +128 -0
- package/src/config/schema/magic-context.ts +89 -0
- package/src/shared/rpc-types.ts +2 -0
- package/src/shared/rpc-utils.test.ts +32 -0
- package/src/shared/rpc-utils.ts +38 -13
- package/src/shared/status-detail-text.test.ts +2 -0
- package/src/shared/status-detail-text.ts +1 -0
- package/src/tui/data/context-db.ts +1 -0
- package/src/tui-compiled/data/context-db.ts +1 -0
|
@@ -285,6 +285,134 @@ describe("MagicContextConfigSchema", () => {
|
|
|
285
285
|
});
|
|
286
286
|
});
|
|
287
287
|
|
|
288
|
+
describe("config profiles", () => {
|
|
289
|
+
it("admits model-selection fields and preserves per-entry harness qualifiers", () => {
|
|
290
|
+
const result = MagicContextConfigSchema.parse({
|
|
291
|
+
profile: "work",
|
|
292
|
+
profiles: {
|
|
293
|
+
work: {
|
|
294
|
+
historian: {
|
|
295
|
+
opencode: {
|
|
296
|
+
model: { model: "anthropic/work-historian", variant: "high" },
|
|
297
|
+
fallback_models: [
|
|
298
|
+
{ model: "openai/work-fallback", variant: "low" },
|
|
299
|
+
],
|
|
300
|
+
variant: "high",
|
|
301
|
+
},
|
|
302
|
+
pi: {
|
|
303
|
+
model: {
|
|
304
|
+
model: "github-copilot/work-historian",
|
|
305
|
+
thinking_level: "high",
|
|
306
|
+
},
|
|
307
|
+
thinking_level: "high",
|
|
308
|
+
},
|
|
309
|
+
},
|
|
310
|
+
dreamer: {
|
|
311
|
+
opencode: {
|
|
312
|
+
model: { model: "anthropic/work-dreamer", variant: "medium" },
|
|
313
|
+
fallback_models: [
|
|
314
|
+
{ model: "openai/work-dreamer-fallback", variant: "low" },
|
|
315
|
+
],
|
|
316
|
+
variant: "medium",
|
|
317
|
+
},
|
|
318
|
+
pi: {
|
|
319
|
+
model: {
|
|
320
|
+
model: "github-copilot/work-dreamer",
|
|
321
|
+
thinking_level: "high",
|
|
322
|
+
},
|
|
323
|
+
fallback_models: [
|
|
324
|
+
{
|
|
325
|
+
model: "openai/work-dreamer-fallback",
|
|
326
|
+
thinking_level: "minimal",
|
|
327
|
+
},
|
|
328
|
+
],
|
|
329
|
+
thinking_level: "high",
|
|
330
|
+
},
|
|
331
|
+
},
|
|
332
|
+
sidekick: {
|
|
333
|
+
model: "anthropic/work-sidekick",
|
|
334
|
+
fallback_models: ["openai/work-sidekick-fallback"],
|
|
335
|
+
},
|
|
336
|
+
},
|
|
337
|
+
},
|
|
338
|
+
});
|
|
339
|
+
|
|
340
|
+
expect(result.profiles?.work?.historian?.opencode?.fallback_models).toEqual([
|
|
341
|
+
{ model: "openai/work-fallback", variant: "low" },
|
|
342
|
+
]);
|
|
343
|
+
expect(result.profiles?.work?.dreamer?.opencode).toEqual({
|
|
344
|
+
model: { model: "anthropic/work-dreamer", variant: "medium" },
|
|
345
|
+
fallback_models: [{ model: "openai/work-dreamer-fallback", variant: "low" }],
|
|
346
|
+
variant: "medium",
|
|
347
|
+
});
|
|
348
|
+
expect(result.profiles?.work?.dreamer?.pi?.fallback_models).toEqual([
|
|
349
|
+
{ model: "openai/work-dreamer-fallback", thinking_level: "minimal" },
|
|
350
|
+
]);
|
|
351
|
+
expect(result.profiles?.work?.sidekick?.model).toBe("anthropic/work-sidekick");
|
|
352
|
+
});
|
|
353
|
+
|
|
354
|
+
it("rejects timeout_minutes in a dreamer profile", () => {
|
|
355
|
+
const profiles = {
|
|
356
|
+
work: {
|
|
357
|
+
dreamer: {
|
|
358
|
+
opencode: {
|
|
359
|
+
tasks: { verify: { timeout_minutes: 30 } },
|
|
360
|
+
},
|
|
361
|
+
},
|
|
362
|
+
},
|
|
363
|
+
};
|
|
364
|
+
|
|
365
|
+
expect(MagicContextConfigSchema.safeParse({ profiles }).success).toBe(false);
|
|
366
|
+
});
|
|
367
|
+
|
|
368
|
+
it("rejects task execution and every other non-model field class in profiles", () => {
|
|
369
|
+
const profilesWithExcludedFields = [
|
|
370
|
+
{ work: { embedding: { provider: "off" } } },
|
|
371
|
+
{ work: { historian: { two_pass: true } } },
|
|
372
|
+
{ work: { historian: { opencode: { prompt: "override" } } } },
|
|
373
|
+
{ work: { dreamer: { opencode: { tasks: {} } } } },
|
|
374
|
+
{
|
|
375
|
+
work: {
|
|
376
|
+
dreamer: {
|
|
377
|
+
opencode: {
|
|
378
|
+
tasks: {
|
|
379
|
+
verify: {
|
|
380
|
+
model: "anthropic/task-model",
|
|
381
|
+
fallback_models: ["openai/task-fallback"],
|
|
382
|
+
variant: "high",
|
|
383
|
+
timeout_minutes: 30,
|
|
384
|
+
},
|
|
385
|
+
},
|
|
386
|
+
},
|
|
387
|
+
},
|
|
388
|
+
},
|
|
389
|
+
},
|
|
390
|
+
{
|
|
391
|
+
work: {
|
|
392
|
+
dreamer: {
|
|
393
|
+
pi: {
|
|
394
|
+
tasks: {
|
|
395
|
+
verify: {
|
|
396
|
+
model: "github-copilot/task-model",
|
|
397
|
+
fallback_models: ["openai/task-fallback"],
|
|
398
|
+
thinking_level: "high",
|
|
399
|
+
timeout_minutes: 30,
|
|
400
|
+
},
|
|
401
|
+
},
|
|
402
|
+
},
|
|
403
|
+
},
|
|
404
|
+
},
|
|
405
|
+
},
|
|
406
|
+
{ work: { dreamer: { tasks: { verify: { schedule: "0 3 * * *" } } } } },
|
|
407
|
+
{ work: { sidekick: { timeout_ms: 60_000 } } },
|
|
408
|
+
];
|
|
409
|
+
|
|
410
|
+
for (const profiles of profilesWithExcludedFields) {
|
|
411
|
+
expect(MagicContextConfigSchema.safeParse({ profiles }).success).toBe(false);
|
|
412
|
+
}
|
|
413
|
+
});
|
|
414
|
+
});
|
|
415
|
+
|
|
288
416
|
describe("per-harness model configuration", () => {
|
|
289
417
|
it("keeps the migration inventory exhaustive and field-specific", () => {
|
|
290
418
|
expect(PER_HARNESS_MIGRATION_INVENTORY).toEqual({
|
|
@@ -310,6 +310,80 @@ export const DreamerPiHarnessBlockSchema = z
|
|
|
310
310
|
.describe("Strict Pi dreamer model-resolution block. It accepts no OpenCode vocabulary.");
|
|
311
311
|
export type DreamerPiHarnessBlock = z.infer<typeof DreamerPiHarnessBlockSchema>;
|
|
312
312
|
|
|
313
|
+
/**
|
|
314
|
+
* A profile may select models but must not alter execution policy. Keep this
|
|
315
|
+
* separate from the full harness schemas, whose dreamer blocks also admit task
|
|
316
|
+
* overrides such as timeout_minutes.
|
|
317
|
+
*/
|
|
318
|
+
const ProfileOpenCodeModelBlockSchema = z
|
|
319
|
+
.object({
|
|
320
|
+
model: OcEntrySchema.optional().describe("Primary OpenCode model entry."),
|
|
321
|
+
fallback_models: z
|
|
322
|
+
.array(OcEntrySchema)
|
|
323
|
+
.optional()
|
|
324
|
+
.describe("Ordered fallback OpenCode model entries."),
|
|
325
|
+
variant: z
|
|
326
|
+
.string()
|
|
327
|
+
.optional()
|
|
328
|
+
.describe("OpenCode reasoning variant for the primary model entry."),
|
|
329
|
+
})
|
|
330
|
+
.strict()
|
|
331
|
+
.describe("Strict profile-only OpenCode model-selection block.");
|
|
332
|
+
const ProfilePiModelBlockSchema = z
|
|
333
|
+
.object({
|
|
334
|
+
model: PiEntrySchema.optional().describe("Primary Pi model entry."),
|
|
335
|
+
fallback_models: z
|
|
336
|
+
.array(PiEntrySchema)
|
|
337
|
+
.optional()
|
|
338
|
+
.describe("Ordered fallback Pi model entries."),
|
|
339
|
+
thinking_level: PiThinkingLevelSchema.describe(
|
|
340
|
+
"Pi thinking level for the primary model entry.",
|
|
341
|
+
),
|
|
342
|
+
})
|
|
343
|
+
.strict()
|
|
344
|
+
.describe("Strict profile-only Pi model-selection block.");
|
|
345
|
+
const ProfileHistorianSchema = z
|
|
346
|
+
.object({
|
|
347
|
+
opencode: ProfileOpenCodeModelBlockSchema.optional(),
|
|
348
|
+
pi: ProfilePiModelBlockSchema.optional(),
|
|
349
|
+
})
|
|
350
|
+
.strict();
|
|
351
|
+
const ProfileDreamerSchema = z
|
|
352
|
+
.object({
|
|
353
|
+
opencode: ProfileOpenCodeModelBlockSchema.optional(),
|
|
354
|
+
pi: ProfilePiModelBlockSchema.optional(),
|
|
355
|
+
})
|
|
356
|
+
.strict();
|
|
357
|
+
const ProfileSidekickSchema = AgentOverrideConfigSchema.pick({
|
|
358
|
+
model: true,
|
|
359
|
+
fallback_models: true,
|
|
360
|
+
variant: true,
|
|
361
|
+
})
|
|
362
|
+
.extend({
|
|
363
|
+
thinking_level: PiThinkingLevelSchema.describe(
|
|
364
|
+
"Pi thinking level for the sidekick model selection.",
|
|
365
|
+
),
|
|
366
|
+
})
|
|
367
|
+
.strict();
|
|
368
|
+
|
|
369
|
+
export const ConfigProfileSchema = z
|
|
370
|
+
.object({
|
|
371
|
+
historian: ProfileHistorianSchema.optional(),
|
|
372
|
+
dreamer: ProfileDreamerSchema.optional(),
|
|
373
|
+
sidekick: ProfileSidekickSchema.optional(),
|
|
374
|
+
})
|
|
375
|
+
.strict()
|
|
376
|
+
.describe(
|
|
377
|
+
"User-owned model-selection overlay. Only historian/dreamer harness model blocks and sidekick model-selection fields are allowed.",
|
|
378
|
+
);
|
|
379
|
+
export type ConfigProfile = z.infer<typeof ConfigProfileSchema>;
|
|
380
|
+
|
|
381
|
+
export const ConfigProfilesSchema = z.record(
|
|
382
|
+
z.string().trim().min(1, "Profile names must not be empty or whitespace-only."),
|
|
383
|
+
ConfigProfileSchema,
|
|
384
|
+
);
|
|
385
|
+
export type ConfigProfiles = z.infer<typeof ConfigProfilesSchema>;
|
|
386
|
+
|
|
313
387
|
/** A 5-field cron expression, or "" to disable the task. */
|
|
314
388
|
const CronScheduleSchema = z
|
|
315
389
|
.string()
|
|
@@ -672,6 +746,10 @@ export interface MagicContextConfig {
|
|
|
672
746
|
auto_update?: boolean;
|
|
673
747
|
/** Output language for generated Magic Context prose. USER config only. */
|
|
674
748
|
language?: string;
|
|
749
|
+
/** Active user-owned model profile after user/project resolution. */
|
|
750
|
+
profile?: string;
|
|
751
|
+
/** Named user-owned model profiles. Declarations are consumed during resolution. */
|
|
752
|
+
profiles?: ConfigProfiles;
|
|
675
753
|
historian?: HistorianConfig;
|
|
676
754
|
dreamer?: DreamerConfig;
|
|
677
755
|
smart_notes: {
|
|
@@ -892,6 +970,17 @@ export const MagicContextConfigSchema = z
|
|
|
892
970
|
"triggers one cache re-materialization; existing compartments/memories keep their " +
|
|
893
971
|
"original language until naturally rewritten.",
|
|
894
972
|
),
|
|
973
|
+
profile: z
|
|
974
|
+
.string()
|
|
975
|
+
.trim()
|
|
976
|
+
.min(1)
|
|
977
|
+
.optional()
|
|
978
|
+
.describe(
|
|
979
|
+
"Select a named user-owned model profile. A valid project name overrides this user default; an empty string, null, or other non-string project value is ignored with a warning so the user selection still applies. Unknown names warn and use the base configuration.",
|
|
980
|
+
),
|
|
981
|
+
profiles: ConfigProfilesSchema.optional().describe(
|
|
982
|
+
"User-level named model profiles. A profile may contain only historian/dreamer model, fallback_models, OpenCode variant, and Pi thinking_level fields plus sidekick model-selection fields; task execution policy (including timeout_minutes) is excluded. Project configs may select a name but cannot define profiles.",
|
|
983
|
+
),
|
|
895
984
|
historian: HistorianConfigSchema.describe(
|
|
896
985
|
"Historian metadata plus independent strict OpenCode and Pi execution blocks. Retained metadata stays at historian; model, fallback_models, variant, and thinking_level belong only in historian.opencode or historian.pi.",
|
|
897
986
|
),
|
package/src/shared/rpc-types.ts
CHANGED
|
@@ -141,6 +141,8 @@ export interface SidebarSnapshot {
|
|
|
141
141
|
}
|
|
142
142
|
|
|
143
143
|
export interface StatusDetail extends SidebarSnapshot {
|
|
144
|
+
/** User-owned model profile selected for this project, or null for the base config. */
|
|
145
|
+
activeProfile: string | null;
|
|
144
146
|
tagCounter: number;
|
|
145
147
|
activeTags: number;
|
|
146
148
|
droppedTags: number;
|
|
@@ -3,6 +3,7 @@
|
|
|
3
3
|
import { afterEach, describe, expect, test } from "bun:test";
|
|
4
4
|
import type { execFileSync } from "node:child_process";
|
|
5
5
|
import type { readFileSync } from "node:fs";
|
|
6
|
+
|
|
6
7
|
import {
|
|
7
8
|
__resetRpcIdentityTestHooks,
|
|
8
9
|
__setRpcIdentityTestHooks,
|
|
@@ -12,6 +13,7 @@ import {
|
|
|
12
13
|
isPidAlive,
|
|
13
14
|
isPidIdentityPlausible,
|
|
14
15
|
type RpcPortFileRecord,
|
|
16
|
+
readProcessProbeEvidence,
|
|
15
17
|
} from "./rpc-utils";
|
|
16
18
|
|
|
17
19
|
const PID = 1234;
|
|
@@ -210,6 +212,36 @@ describe("isPidAlive", () => {
|
|
|
210
212
|
});
|
|
211
213
|
});
|
|
212
214
|
|
|
215
|
+
describe("readProcessProbeEvidence", () => {
|
|
216
|
+
test("captures the same Linux start-time and command probes used by the guard", () => {
|
|
217
|
+
__setRpcIdentityTestHooks({
|
|
218
|
+
platform: "linux",
|
|
219
|
+
nowMs: () => NOW_MS,
|
|
220
|
+
readFileSync: linuxFiles({
|
|
221
|
+
[`/proc/${PID}/stat`]: procStat(10_000),
|
|
222
|
+
"/proc/uptime": `${UPTIME_SECONDS}.0 0.0`,
|
|
223
|
+
[`/proc/${PID}/cmdline`]:
|
|
224
|
+
"/usr/local/bin/opencode\u0000--directory\u0000/home/alice/project",
|
|
225
|
+
}),
|
|
226
|
+
});
|
|
227
|
+
|
|
228
|
+
expect(readProcessProbeEvidence(PID)).toEqual({
|
|
229
|
+
startTime: 1_100_000,
|
|
230
|
+
commandLine: "/usr/local/bin/opencode\u0000--directory\u0000/home/alice/project",
|
|
231
|
+
});
|
|
232
|
+
});
|
|
233
|
+
|
|
234
|
+
test("returns unavailable fields instead of throwing when probes fail", () => {
|
|
235
|
+
__setRpcIdentityTestHooks({
|
|
236
|
+
platform: "linux",
|
|
237
|
+
readFileSync: linuxFiles({}),
|
|
238
|
+
});
|
|
239
|
+
|
|
240
|
+
expect(() => readProcessProbeEvidence(PID)).not.toThrow();
|
|
241
|
+
expect(readProcessProbeEvidence(PID)).toEqual({ startTime: null, commandLine: null });
|
|
242
|
+
});
|
|
243
|
+
});
|
|
244
|
+
|
|
213
245
|
describe("isPidIdentityPlausible", () => {
|
|
214
246
|
test("rejects a reused Linux PID when proc start time is substantially newer", () => {
|
|
215
247
|
const readPaths: string[] = [];
|
package/src/shared/rpc-utils.ts
CHANGED
|
@@ -5,6 +5,14 @@ import { join } from "node:path";
|
|
|
5
5
|
|
|
6
6
|
export type ProcessKind = "OpenCode server" | "OpenCode instance (TUI/CLI)" | "Pi" | "process";
|
|
7
7
|
|
|
8
|
+
/** Best-effort process details captured while validating a migration blocker. */
|
|
9
|
+
export interface ProcessProbeEvidence {
|
|
10
|
+
/** Epoch milliseconds, or null when the platform/probe cannot provide it. */
|
|
11
|
+
startTime: number | null;
|
|
12
|
+
/** The raw command line, or null when the platform/probe cannot provide it. */
|
|
13
|
+
commandLine: string | null;
|
|
14
|
+
}
|
|
15
|
+
|
|
8
16
|
export interface RpcPortFileRecord {
|
|
9
17
|
port: number;
|
|
10
18
|
pid: number;
|
|
@@ -143,6 +151,24 @@ function readPsProcessStartTime(pid: number): number | null {
|
|
|
143
151
|
}
|
|
144
152
|
}
|
|
145
153
|
|
|
154
|
+
/** Read a process start time without changing the guard's liveness decision. */
|
|
155
|
+
export function readProcessStartTime(pid: number): number | null {
|
|
156
|
+
if (!Number.isInteger(pid) || pid <= 0) return null;
|
|
157
|
+
return rpcIdentityPlatform === "linux"
|
|
158
|
+
? readLinuxProcessStartTime(pid)
|
|
159
|
+
: rpcIdentityPlatform === "win32"
|
|
160
|
+
? null
|
|
161
|
+
: readPsProcessStartTime(pid);
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
/** Capture the command and start-time probes used to explain a blocker. */
|
|
165
|
+
export function readProcessProbeEvidence(pid: number): ProcessProbeEvidence {
|
|
166
|
+
return {
|
|
167
|
+
startTime: readProcessStartTime(pid),
|
|
168
|
+
commandLine: readProcessCommand(pid),
|
|
169
|
+
};
|
|
170
|
+
}
|
|
171
|
+
|
|
146
172
|
interface ProcessListEntry {
|
|
147
173
|
pid: number;
|
|
148
174
|
command: string;
|
|
@@ -319,28 +345,27 @@ function commandLooksLikeOpenCode(command: string): boolean {
|
|
|
319
345
|
*/
|
|
320
346
|
export type PidIdentityPlausibility = "plausible" | "implausible" | "inconclusive";
|
|
321
347
|
|
|
322
|
-
export function isPidIdentityPlausible(
|
|
348
|
+
export function isPidIdentityPlausible(
|
|
349
|
+
record: RpcPortFileRecord,
|
|
350
|
+
evidence?: ProcessProbeEvidence,
|
|
351
|
+
): PidIdentityPlausibility {
|
|
323
352
|
if (!Number.isInteger(record.pid) || record.pid <= 0) return "implausible";
|
|
324
353
|
|
|
325
354
|
if (Number.isFinite(record.started_at) && record.started_at > 0) {
|
|
326
|
-
const processStartTime =
|
|
327
|
-
rpcIdentityPlatform === "linux"
|
|
328
|
-
? readLinuxProcessStartTime(record.pid)
|
|
329
|
-
: rpcIdentityPlatform === "win32"
|
|
330
|
-
? null
|
|
331
|
-
: readPsProcessStartTime(record.pid);
|
|
355
|
+
const processStartTime = evidence ? evidence.startTime : readProcessStartTime(record.pid);
|
|
332
356
|
if (processStartTime === null) return "inconclusive";
|
|
333
357
|
return processStartTime <= record.started_at + RPC_IDENTITY_SKEW_TOLERANCE_MS
|
|
334
358
|
? "plausible"
|
|
335
359
|
: "implausible";
|
|
336
360
|
}
|
|
337
361
|
|
|
338
|
-
const command =
|
|
339
|
-
|
|
340
|
-
|
|
341
|
-
|
|
342
|
-
|
|
343
|
-
|
|
362
|
+
const command = evidence
|
|
363
|
+
? evidence.commandLine
|
|
364
|
+
: rpcIdentityPlatform === "linux"
|
|
365
|
+
? readLinuxProcessCommand(record.pid)
|
|
366
|
+
: rpcIdentityPlatform === "win32"
|
|
367
|
+
? (readWindowsProcess(record.pid).command ?? null)
|
|
368
|
+
: readPsProcessCommand(record.pid);
|
|
344
369
|
if (command === null) return "inconclusive";
|
|
345
370
|
return commandLooksLikeOpenCode(command) ? "plausible" : "implausible";
|
|
346
371
|
}
|
|
@@ -4,6 +4,7 @@ import { formatStatusDetailMarkdown } from "./status-detail-text";
|
|
|
4
4
|
|
|
5
5
|
const STATUS_FIXTURE: StatusDetail = {
|
|
6
6
|
sessionId: "ses_status",
|
|
7
|
+
activeProfile: "work",
|
|
7
8
|
usagePercentage: 75,
|
|
8
9
|
inputTokens: 96_000,
|
|
9
10
|
contextLimit: 128_000,
|
|
@@ -70,6 +71,7 @@ describe("formatStatusDetailMarkdown", () => {
|
|
|
70
71
|
expect(formatStatusDetailMarkdown(STATUS_FIXTURE)).toBe(`## Magic Context Status
|
|
71
72
|
|
|
72
73
|
- **Mode:** Magic Context compaction
|
|
74
|
+
- **Active profile:** work
|
|
73
75
|
- **Usage:** 75.0% (96,000 / 128,000 usable tokens)
|
|
74
76
|
- **Cache lane:** live (42s remaining); TTL 5m
|
|
75
77
|
- **Historian:** running; boundary present; coverage 12
|
|
@@ -35,6 +35,7 @@ export function formatStatusDetailMarkdown(detail: StatusDetail): string {
|
|
|
35
35
|
"## Magic Context Status",
|
|
36
36
|
"",
|
|
37
37
|
`- **Mode:** ${mode}`,
|
|
38
|
+
`- **Active profile:** ${detail.activeProfile ?? "none"}`,
|
|
38
39
|
`- **Usage:** ${detail.usagePercentage.toFixed(1)}% (${formatCount(detail.inputTokens)} / ${usableLimit})`,
|
|
39
40
|
`- **Cache lane:** ${formatCacheLane(detail)}`,
|
|
40
41
|
`- **Historian:** ${[historianState, ...historianDetails].join("; ")}`,
|