omegon 0.7.6 → 0.7.8
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/extensions/bootstrap/index.ts +7 -10
- package/extensions/cleave/index.ts +23 -174
- package/extensions/defaults.ts +1 -1
- package/node_modules/@babel/runtime/helpers/esm/wrapAsyncGenerator.js +18 -31
- package/node_modules/@babel/runtime/helpers/wrapAsyncGenerator.js +18 -31
- package/node_modules/@babel/runtime/package.json +1 -1
- package/package.json +1 -1
|
@@ -471,17 +471,14 @@ function restartOmegon(): never {
|
|
|
471
471
|
"done",
|
|
472
472
|
// Extra grace period for fd/terminal release
|
|
473
473
|
"sleep 0.3",
|
|
474
|
-
// Hard terminal reset
|
|
475
|
-
//
|
|
476
|
-
//
|
|
477
|
-
//
|
|
478
|
-
|
|
474
|
+
// Hard terminal reset via /dev/tty — avoids stdout buffering that
|
|
475
|
+
// bleeds into the exec'd process. RIS clears all protocol state
|
|
476
|
+
// (kitty keyboard protocol, bracketed paste, mouse tracking, etc.).
|
|
477
|
+
// Do NOT use `reset` here — it outputs terminfo init strings to
|
|
478
|
+
// stdout which the new TUI interprets as input (causing stray
|
|
479
|
+
// characters and double renders).
|
|
480
|
+
"printf '\\033c' >/dev/tty 2>/dev/null",
|
|
479
481
|
"stty sane 2>/dev/null",
|
|
480
|
-
// `reset` as belt-and-suspenders — reinitializes terminfo state.
|
|
481
|
-
// Some terminals (Kitty) maintain protocol state that RIS alone
|
|
482
|
-
// doesn't fully clear; reset queries terminfo and sends the full
|
|
483
|
-
// initialization sequence for the current TERM.
|
|
484
|
-
"reset 2>/dev/null",
|
|
485
482
|
// Clean up this script
|
|
486
483
|
`rm -f "${script}"`,
|
|
487
484
|
// Replace this shell with new omegon
|
|
@@ -19,8 +19,8 @@ import { truncateTail, DEFAULT_MAX_BYTES, DEFAULT_MAX_LINES, formatSize } from "
|
|
|
19
19
|
|
|
20
20
|
import { Text } from "@styrene-lab/pi-tui";
|
|
21
21
|
import { Type } from "@sinclair/typebox";
|
|
22
|
-
import {
|
|
23
|
-
import {
|
|
22
|
+
import { execFile } from "node:child_process";
|
|
23
|
+
import { killAllCleaveSubprocesses, cleanupOrphanedProcesses } from "./subprocess-tracker.ts";
|
|
24
24
|
import * as fs from "node:fs";
|
|
25
25
|
import * as path from "node:path";
|
|
26
26
|
import { promisify } from "node:util";
|
|
@@ -32,7 +32,7 @@ import { debug } from "../lib/debug.ts";
|
|
|
32
32
|
import { emitOpenSpecState } from "../openspec/dashboard-state.ts";
|
|
33
33
|
import { getSharedBridge, buildSlashCommandResult, parseBridgedArgs } from "../lib/slash-command-bridge.ts";
|
|
34
34
|
import { buildAssessBridgeResult } from "./bridge.ts";
|
|
35
|
-
|
|
35
|
+
|
|
36
36
|
import { scanDesignDocs, getNodeSections } from "../design-tree/tree.ts";
|
|
37
37
|
import {
|
|
38
38
|
assessDirective,
|
|
@@ -659,29 +659,6 @@ function normalizeSpecAssessment(payload: AssessSpecAgentResult, expectedTotal:
|
|
|
659
659
|
};
|
|
660
660
|
}
|
|
661
661
|
|
|
662
|
-
function extractJsonObject(text: string): string | null {
|
|
663
|
-
const fenced = text.match(/```json\s*([\s\S]*?)```/i);
|
|
664
|
-
if (fenced?.[1]) return fenced[1].trim();
|
|
665
|
-
const firstBrace = text.indexOf("{");
|
|
666
|
-
const lastBrace = text.lastIndexOf("}");
|
|
667
|
-
if (firstBrace === -1 || lastBrace === -1 || lastBrace <= firstBrace) return null;
|
|
668
|
-
return text.slice(firstBrace, lastBrace + 1).trim();
|
|
669
|
-
}
|
|
670
|
-
|
|
671
|
-
function extractAssistantText(content: unknown): string {
|
|
672
|
-
if (typeof content === "string") return content.trim();
|
|
673
|
-
if (!Array.isArray(content)) return "";
|
|
674
|
-
return content
|
|
675
|
-
.map((item) => {
|
|
676
|
-
if (typeof item === "string") return item;
|
|
677
|
-
if (!item || typeof item !== "object") return "";
|
|
678
|
-
return typeof (item as { text?: unknown }).text === "string"
|
|
679
|
-
? (item as { text: string }).text
|
|
680
|
-
: "";
|
|
681
|
-
})
|
|
682
|
-
.join("\n")
|
|
683
|
-
.trim();
|
|
684
|
-
}
|
|
685
662
|
|
|
686
663
|
function formatSpecOutcomeLabel(outcome: AssessLifecycleOutcome): string {
|
|
687
664
|
switch (outcome) {
|
|
@@ -721,151 +698,6 @@ function buildSpecAssessmentHumanText(changeName: string, assessed: AssessSpecAg
|
|
|
721
698
|
return lines.join("\n");
|
|
722
699
|
}
|
|
723
700
|
|
|
724
|
-
async function runSpecAssessmentSubprocess(
|
|
725
|
-
input: SpecAssessmentRunnerInput,
|
|
726
|
-
): Promise<SpecAssessmentRunnerOutput> {
|
|
727
|
-
const prompt = [
|
|
728
|
-
"You are performing a read-only OpenSpec compliance assessment.",
|
|
729
|
-
"Operate in read-only plan mode. Never call edit, write, or any workspace-mutating command.",
|
|
730
|
-
"Inspect the repository and determine whether the implementation satisfies every OpenSpec scenario below.",
|
|
731
|
-
"Return ONLY a JSON object with this exact shape:",
|
|
732
|
-
"{",
|
|
733
|
-
' "summary": { "total": number, "pass": number, "fail": number, "unclear": number },',
|
|
734
|
-
' "scenarios": [',
|
|
735
|
-
' { "domain": string, "requirement": string, "scenario": string, "status": "PASS"|"FAIL"|"UNCLEAR", "evidence": string[], "notes"?: string }',
|
|
736
|
-
" ],",
|
|
737
|
-
' "changedFiles": string[],',
|
|
738
|
-
' "constraints": string[],',
|
|
739
|
-
' "overallNotes"?: string',
|
|
740
|
-
"}",
|
|
741
|
-
"Rules:",
|
|
742
|
-
`- Emit exactly ${input.expectedScenarioCount} scenario entries.`,
|
|
743
|
-
"- Use FAIL when the code clearly contradicts or omits the scenario.",
|
|
744
|
-
"- Use UNCLEAR only when code inspection cannot safely prove PASS or FAIL.",
|
|
745
|
-
"- Evidence must cite concrete files, symbols, or line references when possible.",
|
|
746
|
-
"- changedFiles should list files that would need modification if the result reopens work.",
|
|
747
|
-
"- constraints should list newly discovered implementation constraints.",
|
|
748
|
-
"- Do not wrap the JSON in explanatory prose.",
|
|
749
|
-
"",
|
|
750
|
-
`Change: ${input.changeName}`,
|
|
751
|
-
"",
|
|
752
|
-
"## Acceptance Criteria",
|
|
753
|
-
"",
|
|
754
|
-
input.scenarioText,
|
|
755
|
-
"",
|
|
756
|
-
...input.designContext,
|
|
757
|
-
...input.apiContractContext,
|
|
758
|
-
...(input.diffContent ? ["### Recent Changes", "", "```diff", input.diffContent, "```", ""] : []),
|
|
759
|
-
].join("\n");
|
|
760
|
-
|
|
761
|
-
const omegon = resolveOmegonSubprocess();
|
|
762
|
-
const args = [...omegon.argvPrefix, "--mode", "json", "--plan", "-p", "--no-session"];
|
|
763
|
-
if (input.modelId) args.push("--model", input.modelId);
|
|
764
|
-
|
|
765
|
-
return await new Promise<SpecAssessmentRunnerOutput>((resolve, reject) => {
|
|
766
|
-
const proc = spawn(omegon.command, args, {
|
|
767
|
-
cwd: input.repoPath,
|
|
768
|
-
shell: false,
|
|
769
|
-
stdio: ["pipe", "pipe", "pipe"],
|
|
770
|
-
detached: true,
|
|
771
|
-
env: {
|
|
772
|
-
...process.env,
|
|
773
|
-
PI_CHILD: "1",
|
|
774
|
-
TERM: process.env.TERM ?? "dumb",
|
|
775
|
-
},
|
|
776
|
-
});
|
|
777
|
-
registerCleaveProc(proc);
|
|
778
|
-
let stdout = "";
|
|
779
|
-
let stderr = "";
|
|
780
|
-
let buffer = "";
|
|
781
|
-
let assistantText = "";
|
|
782
|
-
let settled = false;
|
|
783
|
-
const settleReject = (error: Error) => {
|
|
784
|
-
if (settled) return;
|
|
785
|
-
settled = true;
|
|
786
|
-
clearTimeout(timer);
|
|
787
|
-
reject(error);
|
|
788
|
-
};
|
|
789
|
-
const settleResolve = (value: SpecAssessmentRunnerOutput) => {
|
|
790
|
-
if (settled) return;
|
|
791
|
-
settled = true;
|
|
792
|
-
clearTimeout(timer);
|
|
793
|
-
resolve(value);
|
|
794
|
-
};
|
|
795
|
-
let escalationTimer: ReturnType<typeof setTimeout> | undefined;
|
|
796
|
-
const timer = setTimeout(() => {
|
|
797
|
-
killCleaveProc(proc);
|
|
798
|
-
escalationTimer = setTimeout(() => {
|
|
799
|
-
if (!proc.killed) {
|
|
800
|
-
try {
|
|
801
|
-
if (proc.pid) process.kill(-proc.pid, "SIGKILL");
|
|
802
|
-
} catch {
|
|
803
|
-
try { proc.kill("SIGKILL"); } catch { /* already dead */ }
|
|
804
|
-
}
|
|
805
|
-
}
|
|
806
|
-
}, 5_000);
|
|
807
|
-
settleReject(new Error(`Timed out after 120s while assessing ${input.changeName}.`));
|
|
808
|
-
}, 120_000);
|
|
809
|
-
|
|
810
|
-
const processLine = (line: string) => {
|
|
811
|
-
if (!line.trim()) return;
|
|
812
|
-
stdout += line + "\n";
|
|
813
|
-
let event: unknown;
|
|
814
|
-
try {
|
|
815
|
-
event = JSON.parse(line);
|
|
816
|
-
} catch {
|
|
817
|
-
return;
|
|
818
|
-
}
|
|
819
|
-
if (!event || typeof event !== "object") return;
|
|
820
|
-
const typed = event as { type?: string; message?: { role?: string; content?: unknown } };
|
|
821
|
-
if (typed.type === "message_end" && typed.message?.role === "assistant") {
|
|
822
|
-
assistantText = extractAssistantText(typed.message.content);
|
|
823
|
-
}
|
|
824
|
-
};
|
|
825
|
-
|
|
826
|
-
proc.stdout.on("data", (data) => {
|
|
827
|
-
buffer += data.toString();
|
|
828
|
-
const lines = buffer.split("\n");
|
|
829
|
-
buffer = lines.pop() || "";
|
|
830
|
-
for (const line of lines) processLine(line);
|
|
831
|
-
});
|
|
832
|
-
proc.stderr.on("data", (data) => {
|
|
833
|
-
stderr += data.toString();
|
|
834
|
-
});
|
|
835
|
-
proc.on("error", (error) => {
|
|
836
|
-
deregisterCleaveProc(proc);
|
|
837
|
-
clearTimeout(escalationTimer);
|
|
838
|
-
settleReject(error);
|
|
839
|
-
});
|
|
840
|
-
proc.on("close", (code) => {
|
|
841
|
-
deregisterCleaveProc(proc);
|
|
842
|
-
clearTimeout(escalationTimer);
|
|
843
|
-
if (buffer.trim()) processLine(buffer.trim());
|
|
844
|
-
if ((code ?? 1) !== 0) {
|
|
845
|
-
settleReject(new Error(stderr.trim() || `Assessment subprocess exited with code ${code ?? 1}.`));
|
|
846
|
-
return;
|
|
847
|
-
}
|
|
848
|
-
const sourceText = assistantText || stdout;
|
|
849
|
-
const jsonText = extractJsonObject(sourceText);
|
|
850
|
-
if (!jsonText) {
|
|
851
|
-
settleReject(new Error(`Assessment subprocess did not return parseable JSON.\n${stderr || stdout}`));
|
|
852
|
-
return;
|
|
853
|
-
}
|
|
854
|
-
try {
|
|
855
|
-
const parsed = JSON.parse(jsonText) as AssessSpecAgentResult;
|
|
856
|
-
settleResolve({
|
|
857
|
-
assessed: normalizeSpecAssessment(parsed, input.expectedScenarioCount),
|
|
858
|
-
});
|
|
859
|
-
} catch (error) {
|
|
860
|
-
const message = error instanceof Error ? error.message : String(error);
|
|
861
|
-
settleReject(new Error(`Assessment JSON was invalid: ${message}`));
|
|
862
|
-
}
|
|
863
|
-
});
|
|
864
|
-
|
|
865
|
-
proc.stdin.write(prompt);
|
|
866
|
-
proc.stdin.end();
|
|
867
|
-
});
|
|
868
|
-
}
|
|
869
701
|
|
|
870
702
|
function applyAssessEffects(pi: ExtensionAPI, result: AssessStructuredResult): void {
|
|
871
703
|
for (const effect of result.effects) {
|
|
@@ -1313,14 +1145,18 @@ async function executeAssessSpec(
|
|
|
1313
1145
|
...(diffContent ? ["", "### Recent Changes (for context)", "", "```diff", diffContent, "```"] : []),
|
|
1314
1146
|
].join("\n");
|
|
1315
1147
|
|
|
1316
|
-
|
|
1148
|
+
// Use the follow-up pattern for any in-session context: return the prepared
|
|
1149
|
+
// assessment prompt and let the current LLM session evaluate scenarios.
|
|
1150
|
+
// The subprocess path below is retained only for programmatic callers that
|
|
1151
|
+
// inject overrides.runSpecAssessment (e.g. tests).
|
|
1152
|
+
if (isInteractiveAssessContext(ctx) || ctx.bridgeInvocation) {
|
|
1317
1153
|
const lifecycleRecord = await buildLifecycleRecord(pi, ctx.cwd, {
|
|
1318
1154
|
changeName: target.name,
|
|
1319
1155
|
assessmentKind: "spec",
|
|
1320
1156
|
outcome: "ambiguous",
|
|
1321
1157
|
recommendedAction: `Run openspec_manage reconcile_after_assess ${target.name} with outcome pass, reopen, or ambiguous after scenario evaluation completes.`,
|
|
1322
1158
|
});
|
|
1323
|
-
|
|
1159
|
+
const result = makeAssessResult({
|
|
1324
1160
|
subcommand: "spec",
|
|
1325
1161
|
args,
|
|
1326
1162
|
ok: true,
|
|
@@ -1343,9 +1179,22 @@ async function executeAssessSpec(
|
|
|
1343
1179
|
lifecycle,
|
|
1344
1180
|
lifecycleRecord,
|
|
1345
1181
|
});
|
|
1182
|
+
// For bridge invocations, eagerly deliver effects so the follow-up prompt
|
|
1183
|
+
// reaches the LLM even if the caller pipeline doesn't include a handler
|
|
1184
|
+
// that calls applyAssessEffects. Clear effects after to prevent double-
|
|
1185
|
+
// delivery (the agentHandler also calls applyAssessEffects).
|
|
1186
|
+
// Interactive callers leave effects intact for interactiveHandler to apply.
|
|
1187
|
+
if (ctx.bridgeInvocation) {
|
|
1188
|
+
applyAssessEffects(pi, result);
|
|
1189
|
+
result.effects = [];
|
|
1190
|
+
}
|
|
1191
|
+
return result;
|
|
1346
1192
|
}
|
|
1347
1193
|
|
|
1348
|
-
|
|
1194
|
+
if (!overrides?.runSpecAssessment) {
|
|
1195
|
+
throw new Error("[assess spec] Unexpected code path: neither interactive nor bridge context, and no runSpecAssessment override provided.");
|
|
1196
|
+
}
|
|
1197
|
+
const runSpecAssessment = overrides.runSpecAssessment;
|
|
1349
1198
|
const completed = await runSpecAssessment({
|
|
1350
1199
|
repoPath,
|
|
1351
1200
|
changeName: target.name,
|
package/extensions/defaults.ts
CHANGED
|
@@ -77,7 +77,7 @@ function restoreTerminalColors(): void {
|
|
|
77
77
|
}
|
|
78
78
|
|
|
79
79
|
/** Ownership marker written by scripts/export-kitty-theme.ts into alpharius.conf */
|
|
80
|
-
const KITTY_OWNERSHIP_MARKER = "# Generated
|
|
80
|
+
const KITTY_OWNERSHIP_MARKER = "# Generated by scripts/export-kitty-theme.ts";
|
|
81
81
|
|
|
82
82
|
/** Installed location — standard Kitty themes directory */
|
|
83
83
|
const KITTY_CONF_PATH = path.join(
|
|
@@ -5,55 +5,42 @@ function _wrapAsyncGenerator(e) {
|
|
|
5
5
|
};
|
|
6
6
|
}
|
|
7
7
|
function AsyncGenerator(e) {
|
|
8
|
-
var
|
|
9
|
-
function resume(
|
|
8
|
+
var t, n;
|
|
9
|
+
function resume(t, n) {
|
|
10
10
|
try {
|
|
11
|
-
var
|
|
12
|
-
o =
|
|
11
|
+
var r = e[t](n),
|
|
12
|
+
o = r.value,
|
|
13
13
|
u = o instanceof OverloadYield;
|
|
14
|
-
Promise.resolve(u ? o.v : o).then(function (
|
|
14
|
+
Promise.resolve(u ? o.v : o).then(function (n) {
|
|
15
15
|
if (u) {
|
|
16
|
-
var i = "return" ===
|
|
17
|
-
if (!o.k ||
|
|
18
|
-
|
|
16
|
+
var i = "return" === t && o.k ? t : "next";
|
|
17
|
+
if (!o.k || n.done) return resume(i, n);
|
|
18
|
+
n = e[i](n).value;
|
|
19
19
|
}
|
|
20
|
-
settle(
|
|
20
|
+
settle(!!r.done, n);
|
|
21
21
|
}, function (e) {
|
|
22
22
|
resume("throw", e);
|
|
23
23
|
});
|
|
24
24
|
} catch (e) {
|
|
25
|
-
settle(
|
|
25
|
+
settle(2, e);
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
|
-
function settle(e,
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
done: !0
|
|
34
|
-
});
|
|
35
|
-
break;
|
|
36
|
-
case "throw":
|
|
37
|
-
r.reject(n);
|
|
38
|
-
break;
|
|
39
|
-
default:
|
|
40
|
-
r.resolve({
|
|
41
|
-
value: n,
|
|
42
|
-
done: !1
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
(r = r.next) ? resume(r.key, r.arg) : t = null;
|
|
28
|
+
function settle(e, r) {
|
|
29
|
+
2 === e ? t.reject(r) : t.resolve({
|
|
30
|
+
value: r,
|
|
31
|
+
done: e
|
|
32
|
+
}), (t = t.next) ? resume(t.key, t.arg) : n = null;
|
|
46
33
|
}
|
|
47
|
-
this._invoke = function (e,
|
|
34
|
+
this._invoke = function (e, r) {
|
|
48
35
|
return new Promise(function (o, u) {
|
|
49
36
|
var i = {
|
|
50
37
|
key: e,
|
|
51
|
-
arg:
|
|
38
|
+
arg: r,
|
|
52
39
|
resolve: o,
|
|
53
40
|
reject: u,
|
|
54
41
|
next: null
|
|
55
42
|
};
|
|
56
|
-
|
|
43
|
+
n ? n = n.next = i : (t = n = i, resume(e, r));
|
|
57
44
|
});
|
|
58
45
|
}, "function" != typeof e["return"] && (this["return"] = void 0);
|
|
59
46
|
}
|
|
@@ -5,55 +5,42 @@ function _wrapAsyncGenerator(e) {
|
|
|
5
5
|
};
|
|
6
6
|
}
|
|
7
7
|
function AsyncGenerator(e) {
|
|
8
|
-
var
|
|
9
|
-
function resume(
|
|
8
|
+
var t, n;
|
|
9
|
+
function resume(t, n) {
|
|
10
10
|
try {
|
|
11
|
-
var
|
|
12
|
-
o =
|
|
11
|
+
var r = e[t](n),
|
|
12
|
+
o = r.value,
|
|
13
13
|
u = o instanceof OverloadYield;
|
|
14
|
-
Promise.resolve(u ? o.v : o).then(function (
|
|
14
|
+
Promise.resolve(u ? o.v : o).then(function (n) {
|
|
15
15
|
if (u) {
|
|
16
|
-
var i = "return" ===
|
|
17
|
-
if (!o.k ||
|
|
18
|
-
|
|
16
|
+
var i = "return" === t && o.k ? t : "next";
|
|
17
|
+
if (!o.k || n.done) return resume(i, n);
|
|
18
|
+
n = e[i](n).value;
|
|
19
19
|
}
|
|
20
|
-
settle(
|
|
20
|
+
settle(!!r.done, n);
|
|
21
21
|
}, function (e) {
|
|
22
22
|
resume("throw", e);
|
|
23
23
|
});
|
|
24
24
|
} catch (e) {
|
|
25
|
-
settle(
|
|
25
|
+
settle(2, e);
|
|
26
26
|
}
|
|
27
27
|
}
|
|
28
|
-
function settle(e,
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
done: !0
|
|
34
|
-
});
|
|
35
|
-
break;
|
|
36
|
-
case "throw":
|
|
37
|
-
r.reject(n);
|
|
38
|
-
break;
|
|
39
|
-
default:
|
|
40
|
-
r.resolve({
|
|
41
|
-
value: n,
|
|
42
|
-
done: !1
|
|
43
|
-
});
|
|
44
|
-
}
|
|
45
|
-
(r = r.next) ? resume(r.key, r.arg) : t = null;
|
|
28
|
+
function settle(e, r) {
|
|
29
|
+
2 === e ? t.reject(r) : t.resolve({
|
|
30
|
+
value: r,
|
|
31
|
+
done: e
|
|
32
|
+
}), (t = t.next) ? resume(t.key, t.arg) : n = null;
|
|
46
33
|
}
|
|
47
|
-
this._invoke = function (e,
|
|
34
|
+
this._invoke = function (e, r) {
|
|
48
35
|
return new Promise(function (o, u) {
|
|
49
36
|
var i = {
|
|
50
37
|
key: e,
|
|
51
|
-
arg:
|
|
38
|
+
arg: r,
|
|
52
39
|
resolve: o,
|
|
53
40
|
reject: u,
|
|
54
41
|
next: null
|
|
55
42
|
};
|
|
56
|
-
|
|
43
|
+
n ? n = n.next = i : (t = n = i, resume(e, r));
|
|
57
44
|
});
|
|
58
45
|
}, "function" != typeof e["return"] && (this["return"] = void 0);
|
|
59
46
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "omegon",
|
|
3
|
-
"version": "0.7.
|
|
3
|
+
"version": "0.7.8",
|
|
4
4
|
"description": "Omegon — an opinionated distribution of pi (by Mario Zechner) with extensions for lifecycle management, memory, orchestration, and visualization",
|
|
5
5
|
"bin": {
|
|
6
6
|
"omegon": "bin/omegon.mjs",
|