open-multi-agent-kit 0.78.1 → 0.78.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/CHANGELOG.md +37 -0
- package/MATURITY.md +4 -0
- package/README.md +70 -1
- package/dist/benchmark/contracts.d.ts +116 -0
- package/dist/benchmark/contracts.js +6 -0
- package/dist/benchmark/fixtures.d.ts +11 -0
- package/dist/benchmark/fixtures.js +121 -0
- package/dist/benchmark/harness.d.ts +13 -0
- package/dist/benchmark/harness.js +191 -0
- package/dist/benchmark/shadow-mode.d.ts +17 -0
- package/dist/benchmark/shadow-mode.js +96 -0
- package/dist/cli/register-spec-agent-goal-commands.js +45 -0
- package/dist/cli/release-promotion-gate.d.ts +14 -0
- package/dist/cli/release-promotion-gate.js +71 -0
- package/dist/cli/v2/release-commands.d.ts +29 -0
- package/dist/cli/v2/release-commands.js +95 -0
- package/dist/commands/chat/native-root-loop.js +14 -1
- package/dist/commands/chat/slash/commands/session.js +19 -1
- package/dist/commands/goal-interview.d.ts +18 -0
- package/dist/commands/goal-interview.js +396 -0
- package/dist/commands/merge.js +102 -56
- package/dist/contracts/interview.d.ts +106 -0
- package/dist/contracts/interview.js +9 -0
- package/dist/contracts/provider-health.d.ts +37 -0
- package/dist/contracts/provider-health.js +49 -1
- package/dist/evidence/evidence-trust-score.d.ts +101 -0
- package/dist/evidence/evidence-trust-score.js +408 -0
- package/dist/evidence/index.d.ts +6 -0
- package/dist/evidence/index.js +3 -0
- package/dist/evidence/proof-trust-cli.d.ts +8 -0
- package/dist/evidence/proof-trust-cli.js +27 -0
- package/dist/evidence/proof-trust.d.ts +14 -0
- package/dist/evidence/proof-trust.js +381 -0
- package/dist/evidence/regression-proof-matrix.d.ts +42 -0
- package/dist/evidence/regression-proof-matrix.js +72 -0
- package/dist/goal/intent-frame.d.ts +6 -0
- package/dist/goal/intent-frame.js +21 -9
- package/dist/goal/interview-assimilation.d.ts +13 -0
- package/dist/goal/interview-assimilation.js +383 -0
- package/dist/goal/interview-question-bank.d.ts +11 -0
- package/dist/goal/interview-question-bank.js +225 -0
- package/dist/goal/interview-scoring.d.ts +31 -0
- package/dist/goal/interview-scoring.js +187 -0
- package/dist/goal/interview-session.d.ts +25 -0
- package/dist/goal/interview-session.js +116 -0
- package/dist/input/input-envelope.d.ts +22 -0
- package/dist/input/input-envelope.js +1 -0
- package/dist/orchestration/merge-arbiter.d.ts +91 -0
- package/dist/orchestration/merge-arbiter.js +376 -0
- package/dist/providers/health.d.ts +3 -0
- package/dist/providers/health.js +46 -0
- package/dist/providers/index.d.ts +1 -0
- package/dist/providers/index.js +1 -0
- package/dist/providers/provider-health.d.ts +8 -1
- package/dist/providers/provider-health.js +39 -0
- package/dist/providers/provider-task-runner.js +31 -0
- package/dist/providers/provider.d.ts +2 -0
- package/dist/providers/router.js +87 -3
- package/dist/providers/types.d.ts +4 -0
- package/dist/runtime/advanced-control-loop.d.ts +60 -0
- package/dist/runtime/advanced-control-loop.js +136 -0
- package/dist/runtime/agent-runtime.d.ts +10 -0
- package/dist/runtime/blast-radius.d.ts +10 -0
- package/dist/runtime/blast-radius.js +14 -0
- package/dist/runtime/contracts/evidence.d.ts +87 -0
- package/dist/runtime/contracts/evidence.js +7 -0
- package/dist/runtime/contracts/router-v2.d.ts +44 -0
- package/dist/runtime/contracts/router-v2.js +4 -0
- package/dist/runtime/contracts/weakness-remediation.d.ts +67 -0
- package/dist/runtime/contracts/weakness-remediation.js +36 -0
- package/dist/runtime/kimi-api-runtime.js +59 -1
- package/dist/runtime/proof-bundle-trust.d.ts +74 -0
- package/dist/runtime/proof-bundle-trust.js +100 -0
- package/dist/runtime/provider-maturity-gate.d.ts +43 -0
- package/dist/runtime/provider-maturity-gate.js +129 -0
- package/dist/runtime/public-surface.d.ts +93 -0
- package/dist/runtime/public-surface.js +146 -0
- package/dist/runtime/router-v2-scoring.d.ts +11 -0
- package/dist/runtime/router-v2-scoring.js +151 -0
- package/dist/runtime/tool-dispatch-contracts.d.ts +24 -3
- package/dist/runtime/tool-dispatch-contracts.js +42 -2
- package/dist/runtime/weakness-remediation-index.d.ts +27 -0
- package/dist/runtime/weakness-remediation-index.js +37 -0
- package/dist/safety/enforcement-engine.d.ts +89 -0
- package/dist/safety/enforcement-engine.js +279 -0
- package/dist/safety/tool-authority-gate.d.ts +40 -0
- package/dist/safety/tool-authority-gate.js +92 -0
- package/dist/schema/evidence.schema.d.ts +2 -2
- package/dist/schema/proof-bundle.schema.d.ts +28 -28
- package/dist/util/clipboard-image.d.ts +49 -0
- package/dist/util/clipboard-image.js +263 -0
- package/docs/2026-06-09/critical-issues.md +20 -0
- package/docs/2026-06-09/improvements.md +14 -0
- package/docs/2026-06-09/init-checklist.md +25 -0
- package/docs/2026-06-09/plan.md +20 -0
- package/docs/benchmark-design.md +122 -0
- package/docs/github-organic-promotion.md +127 -0
- package/docs/native-root-runtime-algorithms.md +301 -0
- package/package.json +8 -4
- package/readmeasset/ASSET_INDEX.md +1 -0
- package/templates/skills/agents/omk-agent-reach-websearch/SKILL.md +55 -0
- package/templates/skills/kimi/omk-agent-reach-websearch/SKILL.md +55 -0
|
@@ -0,0 +1,96 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Shadow Mode Engine — side-by-side router v1/v2 recording.
|
|
3
|
+
*/
|
|
4
|
+
import { createRuntimeRouter } from "../runtime/runtime-router.js";
|
|
5
|
+
import { createRouterV2ScoringEngine, scoreRuntimes } from "../runtime/router-v2-scoring.js";
|
|
6
|
+
export function createShadowModeEngine(options) {
|
|
7
|
+
const v1Router = createRuntimeRouter({ runtimes: options.runtimes });
|
|
8
|
+
const v2Engine = createRouterV2ScoringEngine();
|
|
9
|
+
function computeRegret(scores, selectedId) {
|
|
10
|
+
if (scores.length === 0)
|
|
11
|
+
return 0;
|
|
12
|
+
const best = Math.max(...scores.map((s) => s.composite));
|
|
13
|
+
const selected = scores.find((s) => s.runtimeId === selectedId)?.composite ?? 0;
|
|
14
|
+
return Math.max(0, best - selected);
|
|
15
|
+
}
|
|
16
|
+
function evaluate(taskId, nodeId, capsule) {
|
|
17
|
+
const intent = v1Router.classifyIntent(capsule);
|
|
18
|
+
let v1Decision = null;
|
|
19
|
+
let regretV1 = 0;
|
|
20
|
+
try {
|
|
21
|
+
v1Decision = v1Router.selectByIntent(capsule, options.history);
|
|
22
|
+
const v1Scores = v1Decision.scores.map((s) => ({
|
|
23
|
+
runtimeId: s.runtime,
|
|
24
|
+
composite: 0.35 * s.qualityScore +
|
|
25
|
+
0.25 * s.evidencePassRate +
|
|
26
|
+
0.15 * s.costScore +
|
|
27
|
+
0.1 * s.latencyScore +
|
|
28
|
+
0.15 * (1 - s.recentFailurePenalty),
|
|
29
|
+
}));
|
|
30
|
+
regretV1 = computeRegret(v1Scores, v1Decision.runtime.id);
|
|
31
|
+
}
|
|
32
|
+
catch {
|
|
33
|
+
v1Decision = null;
|
|
34
|
+
regretV1 = 1;
|
|
35
|
+
}
|
|
36
|
+
let v2Decision = null;
|
|
37
|
+
let regretV2 = 0;
|
|
38
|
+
try {
|
|
39
|
+
v2Decision = v2Engine.select(options.runtimes, intent, options.history);
|
|
40
|
+
const v2Scores = v2Decision.scores.map((s) => ({
|
|
41
|
+
runtimeId: s.runtimeId,
|
|
42
|
+
composite: s.composite,
|
|
43
|
+
}));
|
|
44
|
+
regretV2 = computeRegret(v2Scores, v2Decision.runtime.id);
|
|
45
|
+
}
|
|
46
|
+
catch {
|
|
47
|
+
v2Decision = null;
|
|
48
|
+
regretV2 = 1;
|
|
49
|
+
}
|
|
50
|
+
const disagreement = v1Decision?.runtime.id !== v2Decision?.runtime.id;
|
|
51
|
+
return {
|
|
52
|
+
taskId,
|
|
53
|
+
nodeId,
|
|
54
|
+
intent,
|
|
55
|
+
v1Decision,
|
|
56
|
+
v2Decision,
|
|
57
|
+
regretV1,
|
|
58
|
+
regretV2,
|
|
59
|
+
disagreement,
|
|
60
|
+
timestamp: new Date().toISOString(),
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
function toBenchmarkDecision(record) {
|
|
64
|
+
const out = [];
|
|
65
|
+
if (record.v1Decision) {
|
|
66
|
+
out.push({
|
|
67
|
+
component: "runtime-router-v1",
|
|
68
|
+
selectedRuntime: record.v1Decision.runtime.id,
|
|
69
|
+
bestAvailableRuntime: record.v2Decision?.scores[0]?.runtimeId ?? record.v1Decision.runtime.id,
|
|
70
|
+
regret: record.regretV1,
|
|
71
|
+
reason: record.v1Decision.reason,
|
|
72
|
+
});
|
|
73
|
+
}
|
|
74
|
+
if (record.v2Decision) {
|
|
75
|
+
out.push({
|
|
76
|
+
component: "runtime-router-v2",
|
|
77
|
+
selectedRuntime: record.v2Decision.runtime.id,
|
|
78
|
+
bestAvailableRuntime: record.v2Decision.scores[0]?.runtimeId ?? record.v2Decision.runtime.id,
|
|
79
|
+
regret: record.regretV2,
|
|
80
|
+
reason: record.v2Decision.reason,
|
|
81
|
+
scoresV2: record.v2Decision.scores,
|
|
82
|
+
});
|
|
83
|
+
}
|
|
84
|
+
return out;
|
|
85
|
+
}
|
|
86
|
+
return { evaluate, toBenchmarkDecision };
|
|
87
|
+
}
|
|
88
|
+
export function computeRouterRegret(candidates, intent, history, selectedId) {
|
|
89
|
+
const engine = createRouterV2ScoringEngine();
|
|
90
|
+
const scores = scoreRuntimes(candidates, intent, history);
|
|
91
|
+
if (scores.length === 0)
|
|
92
|
+
return 0;
|
|
93
|
+
const best = Math.max(...scores.map((s) => s.composite));
|
|
94
|
+
const selected = scores.find((s) => s.runtimeId === selectedId)?.composite ?? 0;
|
|
95
|
+
return Math.max(0, best - selected);
|
|
96
|
+
}
|
|
@@ -159,6 +159,51 @@ export function registerSpecAgentGoalCommands(program) {
|
|
|
159
159
|
throw err;
|
|
160
160
|
}
|
|
161
161
|
});
|
|
162
|
+
goal
|
|
163
|
+
.command("interview [input]")
|
|
164
|
+
.description("[Alpha] Run a deep interview to reduce goal uncertainty before planning")
|
|
165
|
+
.option("--goal-id <id>", "Existing goal id to refine")
|
|
166
|
+
.option("--mode <create|refine>", "Interview mode (create | refine)", "create")
|
|
167
|
+
.option("--depth <light|standard|deep>", "Interview depth (omit to auto-select by ambiguity)")
|
|
168
|
+
.option("--max-questions <n>", "Maximum number of questions")
|
|
169
|
+
.option("--answers <file>", "Answers JSON file: { \"answers\": [{ \"questionId\", \"answer\" }] }")
|
|
170
|
+
.option("--image <file>", "Attach an image file (screenshot/diagram) to the interview")
|
|
171
|
+
.option("--write-spec", "Create or update the goal spec from interview answers")
|
|
172
|
+
.option("--json", t("cmd.goalJsonOption"))
|
|
173
|
+
.action(async (input, options) => {
|
|
174
|
+
const { goalInterviewCommand } = await import("../commands/goal-interview.js");
|
|
175
|
+
try {
|
|
176
|
+
await goalInterviewCommand(input, options);
|
|
177
|
+
}
|
|
178
|
+
catch (err) {
|
|
179
|
+
if (err instanceof CliError) {
|
|
180
|
+
if (process.exitCode === undefined)
|
|
181
|
+
process.exitCode = err.exitCode;
|
|
182
|
+
return;
|
|
183
|
+
}
|
|
184
|
+
throw err;
|
|
185
|
+
}
|
|
186
|
+
});
|
|
187
|
+
goal
|
|
188
|
+
.command("refine <goal-id>")
|
|
189
|
+
.description("[Alpha] Apply the latest interview spec delta to a goal and optionally replan")
|
|
190
|
+
.option("--from-interview <id>", "Interview session id (default: latest)", "latest")
|
|
191
|
+
.option("--plan", "Rebuild the plan after applying the interview delta")
|
|
192
|
+
.option("--json", t("cmd.goalJsonOption"))
|
|
193
|
+
.action(async (goalId, options) => {
|
|
194
|
+
const { goalRefineCommand } = await import("../commands/goal-interview.js");
|
|
195
|
+
try {
|
|
196
|
+
await goalRefineCommand(goalId, options);
|
|
197
|
+
}
|
|
198
|
+
catch (err) {
|
|
199
|
+
if (err instanceof CliError) {
|
|
200
|
+
if (process.exitCode === undefined)
|
|
201
|
+
process.exitCode = err.exitCode;
|
|
202
|
+
return;
|
|
203
|
+
}
|
|
204
|
+
throw err;
|
|
205
|
+
}
|
|
206
|
+
});
|
|
162
207
|
goal
|
|
163
208
|
.command("list")
|
|
164
209
|
.description(t("cmd.goalListDesc"))
|
|
@@ -0,0 +1,14 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 5 — Release Promotion Gate (Algorithm 8)
|
|
3
|
+
*
|
|
4
|
+
* Computes a release viability score R_v from ten normalized input
|
|
5
|
+
* dimensions and derives a verdict: block, pre-release, or stable.
|
|
6
|
+
*/
|
|
7
|
+
import { type ReleasePromotionInputs, type ReleasePromotionResult } from "../runtime/contracts/weakness-remediation.js";
|
|
8
|
+
/** Gate engine contract. */
|
|
9
|
+
export interface ReleasePromotionGate {
|
|
10
|
+
/** Evaluate inputs and return scored result with verdict. */
|
|
11
|
+
evaluate(inputs: ReleasePromotionInputs): ReleasePromotionResult;
|
|
12
|
+
}
|
|
13
|
+
/** Factory that creates the default release promotion gate. */
|
|
14
|
+
export declare function createReleasePromotionGate(): ReleasePromotionGate;
|
|
@@ -0,0 +1,71 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Phase 5 — Release Promotion Gate (Algorithm 8)
|
|
3
|
+
*
|
|
4
|
+
* Computes a release viability score R_v from ten normalized input
|
|
5
|
+
* dimensions and derives a verdict: block, pre-release, or stable.
|
|
6
|
+
*/
|
|
7
|
+
import { RELEASE_GATE_WEIGHTS, } from "../runtime/contracts/weakness-remediation.js";
|
|
8
|
+
/** Factory that creates the default release promotion gate. */
|
|
9
|
+
export function createReleasePromotionGate() {
|
|
10
|
+
return {
|
|
11
|
+
evaluate(inputs) {
|
|
12
|
+
const w = RELEASE_GATE_WEIGHTS;
|
|
13
|
+
const demoRun = inputs.demoRun ?? false;
|
|
14
|
+
const maturity = inputs.maturity ?? inputs.providerMinimum ?? 0;
|
|
15
|
+
const rawScore = w.ci * inputs.ci +
|
|
16
|
+
w.build * (inputs.build ?? 0) +
|
|
17
|
+
w.types * (inputs.types ?? 0) +
|
|
18
|
+
w.tests * (inputs.tests ?? 0) +
|
|
19
|
+
w.install * inputs.freshInstallSmoke +
|
|
20
|
+
w.demo * (demoRun ? 1 : 0) +
|
|
21
|
+
w.proof * inputs.proofMedian +
|
|
22
|
+
w.maturity * maturity +
|
|
23
|
+
w.docs * inputs.docs -
|
|
24
|
+
w.regression * inputs.regressionSeverity;
|
|
25
|
+
const score = clamp01(rawScore);
|
|
26
|
+
const reasons = [];
|
|
27
|
+
const blocked = inputs.ci === 0 || inputs.freshInstallSmoke === 0 || !demoRun;
|
|
28
|
+
if (blocked) {
|
|
29
|
+
if (inputs.ci === 0) {
|
|
30
|
+
reasons.push("CI score is 0 (blocking)");
|
|
31
|
+
}
|
|
32
|
+
if (inputs.freshInstallSmoke === 0) {
|
|
33
|
+
reasons.push("Fresh install smoke is 0 (blocking)");
|
|
34
|
+
}
|
|
35
|
+
if (!demoRun) {
|
|
36
|
+
reasons.push("Minimal verified demo run failed or missing (blocking)");
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
let verdict;
|
|
40
|
+
if (blocked) {
|
|
41
|
+
verdict = "block";
|
|
42
|
+
}
|
|
43
|
+
else if (score >= 0.90 && inputs.proofMedian >= 0.85 && maturity >= 0.80) {
|
|
44
|
+
verdict = "stable";
|
|
45
|
+
reasons.push(`Score ${formatScore(score)} meets stable threshold (≥0.90) with proof≥0.85 and maturity≥0.80`);
|
|
46
|
+
}
|
|
47
|
+
else if (score >= 0.75 && inputs.proofMedian >= 0.75) {
|
|
48
|
+
verdict = "pre-release";
|
|
49
|
+
reasons.push(`Score ${formatScore(score)} meets pre-release threshold (≥0.75) with proof≥0.75`);
|
|
50
|
+
}
|
|
51
|
+
else {
|
|
52
|
+
verdict = "block";
|
|
53
|
+
reasons.push(`Score ${formatScore(score)} below pre-release threshold (≥0.75) or proof below 0.75`);
|
|
54
|
+
}
|
|
55
|
+
return {
|
|
56
|
+
score,
|
|
57
|
+
verdict,
|
|
58
|
+
blocked,
|
|
59
|
+
reasons,
|
|
60
|
+
};
|
|
61
|
+
},
|
|
62
|
+
};
|
|
63
|
+
}
|
|
64
|
+
function clamp01(n) {
|
|
65
|
+
if (Number.isNaN(n))
|
|
66
|
+
return 0;
|
|
67
|
+
return Math.max(0, Math.min(1, n));
|
|
68
|
+
}
|
|
69
|
+
function formatScore(n) {
|
|
70
|
+
return n.toFixed(4);
|
|
71
|
+
}
|
|
@@ -0,0 +1,29 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Section 21 — CLI v2 Release Commands (Clipanion)
|
|
3
|
+
*
|
|
4
|
+
* `omk release check` — Evaluate release promotion gate
|
|
5
|
+
* `omk release promote` — Promote release if gate passes (stub)
|
|
6
|
+
*/
|
|
7
|
+
import { Command, type Cli } from "clipanion";
|
|
8
|
+
type ClipanionRegistrar = Pick<Cli, "register">;
|
|
9
|
+
export declare class ReleaseCheckCommand extends Command {
|
|
10
|
+
static paths: string[][];
|
|
11
|
+
static usage: import("clipanion").Usage;
|
|
12
|
+
ci: string;
|
|
13
|
+
schema: string;
|
|
14
|
+
docs: string;
|
|
15
|
+
proof: string;
|
|
16
|
+
provider: string;
|
|
17
|
+
regression: string;
|
|
18
|
+
install: string;
|
|
19
|
+
semver: string;
|
|
20
|
+
json: boolean;
|
|
21
|
+
execute(): Promise<number>;
|
|
22
|
+
}
|
|
23
|
+
export declare class ReleasePromoteCommand extends Command {
|
|
24
|
+
static paths: string[][];
|
|
25
|
+
static usage: import("clipanion").Usage;
|
|
26
|
+
execute(): Promise<number>;
|
|
27
|
+
}
|
|
28
|
+
export declare function registerReleaseCommandsV2(cli: ClipanionRegistrar): void;
|
|
29
|
+
export {};
|
|
@@ -0,0 +1,95 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Section 21 — CLI v2 Release Commands (Clipanion)
|
|
3
|
+
*
|
|
4
|
+
* `omk release check` — Evaluate release promotion gate
|
|
5
|
+
* `omk release promote` — Promote release if gate passes (stub)
|
|
6
|
+
*/
|
|
7
|
+
import { Command, Option } from "clipanion";
|
|
8
|
+
import { createReleasePromotionGate } from "../release-promotion-gate.js";
|
|
9
|
+
// ──────────────────────────────────────────────
|
|
10
|
+
// Release Check
|
|
11
|
+
// ──────────────────────────────────────────────
|
|
12
|
+
export class ReleaseCheckCommand extends Command {
|
|
13
|
+
static paths = [["release", "check"]];
|
|
14
|
+
static usage = Command.Usage({
|
|
15
|
+
description: "Evaluate release promotion gate",
|
|
16
|
+
examples: [["Check release readiness", "omk release check"]],
|
|
17
|
+
});
|
|
18
|
+
ci = Option.String("--ci", "1", { description: "CI score (0–1)" });
|
|
19
|
+
schema = Option.String("--schema", "1", { description: "Schema score (0–1)" });
|
|
20
|
+
docs = Option.String("--docs", "1", { description: "Docs score (0–1)" });
|
|
21
|
+
proof = Option.String("--proof", "1", { description: "Proof median (0–1)" });
|
|
22
|
+
provider = Option.String("--provider", "1", { description: "Provider minimum (0–1)" });
|
|
23
|
+
regression = Option.String("--regression", "0", { description: "Regression severity (0–1)" });
|
|
24
|
+
install = Option.String("--install", "1", { description: "Fresh install smoke (0–1)" });
|
|
25
|
+
semver = Option.String("--semver", "1", { description: "Semver score (0–1)" });
|
|
26
|
+
json = Option.Boolean("--json", false, { description: "JSON output" });
|
|
27
|
+
async execute() {
|
|
28
|
+
const gate = createReleasePromotionGate();
|
|
29
|
+
const inputs = {
|
|
30
|
+
ci: Number.parseFloat(this.ci),
|
|
31
|
+
schema: Number.parseFloat(this.schema),
|
|
32
|
+
docs: Number.parseFloat(this.docs),
|
|
33
|
+
proofMedian: Number.parseFloat(this.proof),
|
|
34
|
+
providerMinimum: Number.parseFloat(this.provider),
|
|
35
|
+
regressionSeverity: Number.parseFloat(this.regression),
|
|
36
|
+
freshInstallSmoke: Number.parseFloat(this.install),
|
|
37
|
+
semver: Number.parseFloat(this.semver),
|
|
38
|
+
};
|
|
39
|
+
const result = gate.evaluate(inputs);
|
|
40
|
+
if (this.json) {
|
|
41
|
+
this.context.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
42
|
+
}
|
|
43
|
+
else {
|
|
44
|
+
this.context.stdout.write("Release Promotion Gate\n");
|
|
45
|
+
this.context.stdout.write(`Score: ${result.score.toFixed(4)}\n`);
|
|
46
|
+
this.context.stdout.write(`Verdict: ${result.verdict}\n`);
|
|
47
|
+
this.context.stdout.write(`Blocked: ${result.blocked}\n`);
|
|
48
|
+
if (result.reasons.length > 0) {
|
|
49
|
+
this.context.stdout.write("Reasons:\n");
|
|
50
|
+
for (const reason of result.reasons) {
|
|
51
|
+
this.context.stdout.write(` - ${reason}\n`);
|
|
52
|
+
}
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
return result.verdict === "block" ? 1 : 0;
|
|
56
|
+
}
|
|
57
|
+
}
|
|
58
|
+
// ──────────────────────────────────────────────
|
|
59
|
+
// Release Promote
|
|
60
|
+
// ──────────────────────────────────────────────
|
|
61
|
+
export class ReleasePromoteCommand extends Command {
|
|
62
|
+
static paths = [["release", "promote"]];
|
|
63
|
+
static usage = Command.Usage({
|
|
64
|
+
description: "Promote release if gate passes",
|
|
65
|
+
examples: [["Promote release", "omk release promote"]],
|
|
66
|
+
});
|
|
67
|
+
async execute() {
|
|
68
|
+
const gate = createReleasePromotionGate();
|
|
69
|
+
const inputs = {
|
|
70
|
+
ci: Number.parseFloat(process.env.OMK_RELEASE_CI ?? "1"),
|
|
71
|
+
schema: Number.parseFloat(process.env.OMK_RELEASE_SCHEMA ?? "1"),
|
|
72
|
+
docs: Number.parseFloat(process.env.OMK_RELEASE_DOCS ?? "1"),
|
|
73
|
+
proofMedian: Number.parseFloat(process.env.OMK_RELEASE_PROOF ?? "1"),
|
|
74
|
+
providerMinimum: Number.parseFloat(process.env.OMK_RELEASE_PROVIDER ?? "1"),
|
|
75
|
+
regressionSeverity: Number.parseFloat(process.env.OMK_RELEASE_REGRESSION ?? "0"),
|
|
76
|
+
freshInstallSmoke: Number.parseFloat(process.env.OMK_RELEASE_INSTALL ?? "1"),
|
|
77
|
+
semver: Number.parseFloat(process.env.OMK_RELEASE_SEMVER ?? "1"),
|
|
78
|
+
};
|
|
79
|
+
const result = gate.evaluate(inputs);
|
|
80
|
+
this.context.stdout.write(JSON.stringify(result, null, 2) + "\n");
|
|
81
|
+
if (result.verdict === "block") {
|
|
82
|
+
this.context.stderr.write("Release promotion blocked.\n");
|
|
83
|
+
return 1;
|
|
84
|
+
}
|
|
85
|
+
this.context.stdout.write("Release promotion approved.\n");
|
|
86
|
+
return 0;
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
// ──────────────────────────────────────────────
|
|
90
|
+
// Registration
|
|
91
|
+
// ──────────────────────────────────────────────
|
|
92
|
+
export function registerReleaseCommandsV2(cli) {
|
|
93
|
+
cli.register(ReleaseCheckCommand);
|
|
94
|
+
cli.register(ReleasePromoteCommand);
|
|
95
|
+
}
|
|
@@ -791,6 +791,7 @@ export async function runNativeOmkRootLoop(input) {
|
|
|
791
791
|
let running = true;
|
|
792
792
|
let readlineClosed = false;
|
|
793
793
|
let activeTurnAbort;
|
|
794
|
+
let pendingPastedImageLine;
|
|
794
795
|
const queuedLines = [];
|
|
795
796
|
let pendingLineResolve;
|
|
796
797
|
const resolveNextLine = (value) => {
|
|
@@ -846,7 +847,7 @@ export async function runNativeOmkRootLoop(input) {
|
|
|
846
847
|
const userInput = await readPromptLine();
|
|
847
848
|
if (userInput === undefined)
|
|
848
849
|
break;
|
|
849
|
-
|
|
850
|
+
let line = userInput.trim();
|
|
850
851
|
if (!line)
|
|
851
852
|
continue;
|
|
852
853
|
renderer?.emit({ type: "input:submitted", text: line });
|
|
@@ -855,6 +856,10 @@ export async function runNativeOmkRootLoop(input) {
|
|
|
855
856
|
break;
|
|
856
857
|
}
|
|
857
858
|
const parsedSlash = parseSlashInput(line);
|
|
859
|
+
if (!parsedSlash && pendingPastedImageLine) {
|
|
860
|
+
line = `${pendingPastedImageLine}\n${line}`;
|
|
861
|
+
pendingPastedImageLine = undefined;
|
|
862
|
+
}
|
|
858
863
|
const inputEnvelope = buildNativeInputEnvelope({
|
|
859
864
|
loopInput: input,
|
|
860
865
|
state,
|
|
@@ -896,6 +901,14 @@ export async function runNativeOmkRootLoop(input) {
|
|
|
896
901
|
try {
|
|
897
902
|
await terminalOwner.withChildProcess(rl, async () => {
|
|
898
903
|
const result = await runSlashHandler(handler, parsedSlash, slashContext);
|
|
904
|
+
if (parsedSlash.command === "/paste" && result.ok) {
|
|
905
|
+
const pasteLine = result.text?.trim();
|
|
906
|
+
if (pasteLine) {
|
|
907
|
+
pendingPastedImageLine = pendingPastedImageLine
|
|
908
|
+
? `${pendingPastedImageLine}\n${pasteLine}`
|
|
909
|
+
: pasteLine;
|
|
910
|
+
}
|
|
911
|
+
}
|
|
899
912
|
if (result.exit)
|
|
900
913
|
running = false;
|
|
901
914
|
});
|
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import { style } from "../../../../util/theme.js";
|
|
2
2
|
import { readTodos } from "../../../../util/todo-sync.js";
|
|
3
3
|
import { commandLine, formatScopedNames, section } from "../format.js";
|
|
4
|
-
import { okSlashResult } from "../result.js";
|
|
4
|
+
import { errorSlashResult, okSlashResult } from "../result.js";
|
|
5
5
|
export function buildSessionSlashCommands() {
|
|
6
6
|
return [
|
|
7
7
|
{
|
|
@@ -22,6 +22,23 @@ export function buildSessionSlashCommands() {
|
|
|
22
22
|
examples: ["/help"],
|
|
23
23
|
handler: () => okSlashResult({ text: renderSlashHelp() }),
|
|
24
24
|
},
|
|
25
|
+
{
|
|
26
|
+
name: "/paste",
|
|
27
|
+
aliases: [],
|
|
28
|
+
group: "session",
|
|
29
|
+
summary: "Paste image from clipboard",
|
|
30
|
+
usage: "/paste",
|
|
31
|
+
examples: ["/paste"],
|
|
32
|
+
handler: async (ctx) => {
|
|
33
|
+
const { pasteClipboardImage } = await import("../../../../util/clipboard-image.js");
|
|
34
|
+
const result = pasteClipboardImage(ctx.input.root);
|
|
35
|
+
if (!result.ok)
|
|
36
|
+
return errorSlashResult(result.error ?? "No image in clipboard");
|
|
37
|
+
if (!result.relativePath)
|
|
38
|
+
return errorSlashResult("Clipboard image saved without a relative path");
|
|
39
|
+
return okSlashResult({ text: `Image file: ${result.relativePath}` });
|
|
40
|
+
},
|
|
41
|
+
},
|
|
25
42
|
{
|
|
26
43
|
name: "/status",
|
|
27
44
|
aliases: ["/s"],
|
|
@@ -76,6 +93,7 @@ function renderSlashHelp() {
|
|
|
76
93
|
commandLine("/theme", "<system24|green-rain|neon-grid|rust-forge|plain|high-contrast>", "Set session theme"),
|
|
77
94
|
commandLine("/view", "<summary|graph|evidence|tool-plane|events>", "Set control-plane view"),
|
|
78
95
|
commandLine("/animation", "<off|low|auto|full>", "Set animation policy"),
|
|
96
|
+
commandLine("/paste", "", "Paste image from clipboard"),
|
|
79
97
|
commandLine("/status", "", "Session status"),
|
|
80
98
|
commandLine("/clear", "/cls", "Clear screen"),
|
|
81
99
|
commandLine("/runs", "", "Recent run history"),
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
interface GoalInterviewOptions {
|
|
2
|
+
goalId?: string;
|
|
3
|
+
mode?: string;
|
|
4
|
+
depth?: string;
|
|
5
|
+
maxQuestions?: string;
|
|
6
|
+
answers?: string;
|
|
7
|
+
image?: string;
|
|
8
|
+
writeSpec?: boolean;
|
|
9
|
+
json?: boolean;
|
|
10
|
+
}
|
|
11
|
+
interface GoalRefineOptions {
|
|
12
|
+
fromInterview?: string;
|
|
13
|
+
plan?: boolean;
|
|
14
|
+
json?: boolean;
|
|
15
|
+
}
|
|
16
|
+
export declare function goalInterviewCommand(input: string | undefined, options: GoalInterviewOptions): Promise<void>;
|
|
17
|
+
export declare function goalRefineCommand(goalId: string, options: GoalRefineOptions): Promise<void>;
|
|
18
|
+
export {};
|