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.
@@ -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: RIS (Reset to Initial State) clears ALL protocol
475
- // state kitty keyboard protocol, bracketed paste, mouse tracking,
476
- // modifyOtherKeys, SGR, scroll regions, alternate screen, everything.
477
- // This is what `reset` does internally and has worked since the VT100.
478
- "printf '\\033c' 2>/dev/null",
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 { spawn, execFile } from "node:child_process";
23
- import { registerCleaveProc, deregisterCleaveProc, killCleaveProc, killAllCleaveSubprocesses, cleanupOrphanedProcesses } from "./subprocess-tracker.ts";
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
- import { resolveOmegonSubprocess } from "../lib/omegon-subprocess.ts";
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
- if (isInteractiveAssessContext(ctx)) {
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
- return makeAssessResult({
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
- const runSpecAssessment = overrides?.runSpecAssessment ?? runSpecAssessmentSubprocess;
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,
@@ -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 from themes/alpharius.json by scripts/export-kitty-theme.ts";
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 r, t;
9
- function resume(r, t) {
8
+ var t, n;
9
+ function resume(t, n) {
10
10
  try {
11
- var n = e[r](t),
12
- o = n.value,
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 (t) {
14
+ Promise.resolve(u ? o.v : o).then(function (n) {
15
15
  if (u) {
16
- var i = "return" === r ? "return" : "next";
17
- if (!o.k || t.done) return resume(i, t);
18
- t = e[i](t).value;
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(n.done ? "return" : "normal", t);
20
+ settle(!!r.done, n);
21
21
  }, function (e) {
22
22
  resume("throw", e);
23
23
  });
24
24
  } catch (e) {
25
- settle("throw", e);
25
+ settle(2, e);
26
26
  }
27
27
  }
28
- function settle(e, n) {
29
- switch (e) {
30
- case "return":
31
- r.resolve({
32
- value: n,
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, n) {
34
+ this._invoke = function (e, r) {
48
35
  return new Promise(function (o, u) {
49
36
  var i = {
50
37
  key: e,
51
- arg: n,
38
+ arg: r,
52
39
  resolve: o,
53
40
  reject: u,
54
41
  next: null
55
42
  };
56
- t ? t = t.next = i : (r = t = i, resume(e, n));
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 r, t;
9
- function resume(r, t) {
8
+ var t, n;
9
+ function resume(t, n) {
10
10
  try {
11
- var n = e[r](t),
12
- o = n.value,
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 (t) {
14
+ Promise.resolve(u ? o.v : o).then(function (n) {
15
15
  if (u) {
16
- var i = "return" === r ? "return" : "next";
17
- if (!o.k || t.done) return resume(i, t);
18
- t = e[i](t).value;
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(n.done ? "return" : "normal", t);
20
+ settle(!!r.done, n);
21
21
  }, function (e) {
22
22
  resume("throw", e);
23
23
  });
24
24
  } catch (e) {
25
- settle("throw", e);
25
+ settle(2, e);
26
26
  }
27
27
  }
28
- function settle(e, n) {
29
- switch (e) {
30
- case "return":
31
- r.resolve({
32
- value: n,
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, n) {
34
+ this._invoke = function (e, r) {
48
35
  return new Promise(function (o, u) {
49
36
  var i = {
50
37
  key: e,
51
- arg: n,
38
+ arg: r,
52
39
  resolve: o,
53
40
  reject: u,
54
41
  next: null
55
42
  };
56
- t ? t = t.next = i : (r = t = i, resume(e, n));
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
  }
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@babel/runtime",
3
- "version": "7.28.6",
3
+ "version": "7.29.2",
4
4
  "description": "babel's modular runtime helpers",
5
5
  "license": "MIT",
6
6
  "publishConfig": {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "omegon",
3
- "version": "0.7.6",
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",