open-multi-agent-kit 0.78.1 → 0.78.2
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 +12 -0
- package/MATURITY.md +4 -0
- package/README.md +70 -1
- 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/contracts/interview.d.ts +106 -0
- package/dist/contracts/interview.js +9 -0
- package/dist/evidence/index.d.ts +4 -0
- package/dist/evidence/index.js +2 -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/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 +41 -0
- package/dist/runtime/provider-maturity-gate.js +101 -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/weakness-remediation-index.d.ts +27 -0
- package/dist/runtime/weakness-remediation-index.js +37 -0
- package/dist/schema/proof-bundle.schema.d.ts +26 -26
- 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/github-organic-promotion.md +127 -0
- package/docs/native-root-runtime-algorithms.md +301 -0
- package/package.json +4 -3
- 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
package/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,17 @@
|
|
|
1
1
|
# Changelog
|
|
2
2
|
|
|
3
|
+
## Unreleased — Deep Interview + Clipboard Image Paste
|
|
4
|
+
|
|
5
|
+
### Added
|
|
6
|
+
|
|
7
|
+
- `omk goal interview [input]` and `omk goal refine <goal-id>` commands under the existing `goal` group, adding an evidence-driven clarification step before planning.
|
|
8
|
+
- Deterministic deep interview that scores goal ambiguity (`0..1`), ranks targeted questions (`informationGain*0.35 + riskReduction*0.25 + dagImpact*0.20 + evidenceImpact*0.15 - userCost*0.05`), and computes a completeness score from assimilated answers.
|
|
9
|
+
- Spec-delta assimilation that folds interview answers into a structured `GoalSpec` with conflict resolution, selectable depth (`light|standard|deep`, auto-selected by ambiguity when omitted), and `--write-spec` persistence.
|
|
10
|
+
- `omk.interview.v1` JSON contract (`schemas/omk.interview.v1.schema.json`) plus the `omk.interview-delta.v1` spec-delta envelope.
|
|
11
|
+
- Per-session interview artifacts (`interview.json`, `spec-delta.json`, `questions.md`, `answers.jsonl`, `interview-report.md`) under `.omk/goals/<goalId>/interviews/<sessionId>/` (or `.omk/interviews/<sessionId>/` before `--write-spec`).
|
|
12
|
+
- GitHub organic growth kit: README first-screen positioning, runnable awesome-list examples, a 1280x640 social preview upload candidate, and reusable Topics/About/awesome-list PR copy in `docs/github-organic-promotion.md`.
|
|
13
|
+
- Clipboard image paste support: `/paste` slash command in chat REPL, `--image` flag on `omk goal interview`, cross-platform clipboard reader (macOS/Linux/Windows), `InputAttachment` type for multimodal image handling.
|
|
14
|
+
|
|
3
15
|
## v0.78.1 — package alignment, JSON contract envelopes, and adaptive runtime algorithms (2026-06-07)
|
|
4
16
|
|
|
5
17
|
### Overview
|
package/MATURITY.md
CHANGED
|
@@ -63,6 +63,10 @@ Current source version: v0.78.1 (`v1.2` runtime contract family)
|
|
|
63
63
|
| `omk research` | Core runtime web research wrapper; depends on Kimi tool availability. |
|
|
64
64
|
| `omk open-design-agent` | Local Open Design CLI bridge. |
|
|
65
65
|
|
|
66
|
+
## Regression Proof Matrix Claim Boundary
|
|
67
|
+
|
|
68
|
+
Regression Proof Matrix is a release-defense gate, not a stable-release claim. Stable promotion still requires full `npm test`, live provider maturity data, and a minimal verified demo pass.
|
|
69
|
+
|
|
66
70
|
## Automation Contract Status
|
|
67
71
|
|
|
68
72
|
| Area | Current state | Next hardening |
|
package/README.md
CHANGED
|
@@ -23,6 +23,7 @@
|
|
|
23
23
|
<p align="center">
|
|
24
24
|
<a href="#install">Install</a> ·
|
|
25
25
|
<a href="#quick-start">Quick start</a> ·
|
|
26
|
+
<a href="#who-is-this-for">Who is this for?</a> ·
|
|
26
27
|
<a href="#current-runtime-algorithm">Runtime algorithm</a> ·
|
|
27
28
|
<a href="docs/getting-started.md">Docs</a> ·
|
|
28
29
|
<a href="readmeasset/ASSET_INDEX.md">Visual assets</a>
|
|
@@ -30,6 +31,14 @@
|
|
|
30
31
|
|
|
31
32
|
`OMK` (`omk`) turns a coding goal into a bounded, evidence-gated agent run.
|
|
32
33
|
|
|
34
|
+
Use OMK when one coding agent is not enough: route Codex, OpenCode, Kimi, DeepSeek, Qwen, OpenRouter, and local runtimes through one evidence-gated control loop.
|
|
35
|
+
|
|
36
|
+
## Who is this for?
|
|
37
|
+
|
|
38
|
+
- Developers running multiple coding agents from the terminal.
|
|
39
|
+
- Teams that need MCP-scoped agent execution instead of unrestricted tool access.
|
|
40
|
+
- Agent builders who want routing, fallback, evidence gates, telemetry, and replay.
|
|
41
|
+
|
|
33
42
|
> Current package source target: `open-multi-agent-kit@0.78.1`.
|
|
34
43
|
> Public package name: `open-multi-agent-kit` (`@omk/cli` is not the active npm package).
|
|
35
44
|
> Runtime contract family: `v1.2` (contract family, not a stable npm `1.x` release).
|
|
@@ -38,7 +47,7 @@
|
|
|
38
47
|
|
|
39
48
|
## Quickstart (3 minutes)
|
|
40
49
|
|
|
41
|
-
A beginner reads this, runs four commands, and
|
|
50
|
+
A beginner reads this, runs four commands, and reaches an initialized OMK chat/doctor flow.
|
|
42
51
|
|
|
43
52
|
```bash
|
|
44
53
|
npm i -g open-multi-agent-kit
|
|
@@ -47,6 +56,11 @@ omk doctor
|
|
|
47
56
|
omk chat
|
|
48
57
|
```
|
|
49
58
|
|
|
59
|
+
## Examples for agent tooling lists
|
|
60
|
+
|
|
61
|
+
- [Codex MCP evidence run](https://github.com/dmae97/open-multi-agent-kit/tree/main/examples/codex-mcp-evidence-run): project-scoped MCP setup plus evidence-gated DAG dry run.
|
|
62
|
+
- [Provider fallback](https://github.com/dmae97/open-multi-agent-kit/tree/main/examples/provider-fallback): `--provider auto` routing with parallel worker planning.
|
|
63
|
+
|
|
50
64
|
## Current release reality
|
|
51
65
|
|
|
52
66
|
- The public npm line is `open-multi-agent-kit@0.78.x`. Published npm `latest` is `0.78.0`;
|
|
@@ -58,6 +72,8 @@ omk chat
|
|
|
58
72
|
lanes are scoped by the provider-maturity contract.
|
|
59
73
|
- Safety and evidence claims apply to the exact adapter, command, and verification gate that
|
|
60
74
|
produced them.
|
|
75
|
+
- Regression Proof Matrix is a release-defense coverage gate, not a stable-release claim.
|
|
76
|
+
Stable promotion still requires full tests, live provider maturity data, and a minimal verified demo pass.
|
|
61
77
|
|
|
62
78
|
## Why OMK
|
|
63
79
|
|
|
@@ -192,6 +208,59 @@ Kimi worker prompts use stdin with `--input-format text` where that adapter path
|
|
|
192
208
|
Goal → DAG plan → parallel lanes → evidence bundle → verify gate → merge / replay / inspect
|
|
193
209
|
```
|
|
194
210
|
|
|
211
|
+
## Goal lifecycle
|
|
212
|
+
|
|
213
|
+
`omk goal` turns a raw goal into a planned, evidence-gated run. The **OMK Deep Interview** is an uncertainty reducer that clarifies the goal before planning, so the DAG is compiled from a structured spec instead of a vague prompt.
|
|
214
|
+
|
|
215
|
+
Recommended flow:
|
|
216
|
+
|
|
217
|
+
```bash
|
|
218
|
+
omk goal interview "<raw goal>" --depth deep --write-spec
|
|
219
|
+
omk goal plan <goal-id>
|
|
220
|
+
omk goal run <goal-id> --provider auto --approval-policy interactive
|
|
221
|
+
omk goal verify <goal-id>
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
### `omk goal interview [input]`
|
|
225
|
+
|
|
226
|
+
Runs a deterministic deep interview that scores goal ambiguity (`0..1`), ranks targeted questions, assimilates answers into a structured spec delta, computes a completeness score, and (with `--write-spec`) creates or updates a `GoalSpec`. Question ranking is deterministic:
|
|
227
|
+
|
|
228
|
+
```text
|
|
229
|
+
score = informationGain*0.35 + riskReduction*0.25 + dagImpact*0.20 + evidenceImpact*0.15 - userCost*0.05
|
|
230
|
+
```
|
|
231
|
+
|
|
232
|
+
| Option | Purpose |
|
|
233
|
+
| -------------------------- | -------------------------------------------------------------- |
|
|
234
|
+
| `--goal-id <id>` | Target an existing goal. |
|
|
235
|
+
| `--mode <create\|refine>` | Create a new spec or refine an existing one. |
|
|
236
|
+
| `--depth <light\|standard\|deep>` | Interview depth; omit to auto-select by ambiguity. |
|
|
237
|
+
| `--max-questions <n>` | Cap the number of ranked questions. |
|
|
238
|
+
| `--answers <file>` | Supply answers non-interactively. |
|
|
239
|
+
| `--write-spec` | Persist the spec delta into a `GoalSpec`. |
|
|
240
|
+
| `--json` | Emit the `omk.interview.v1` JSON contract. |
|
|
241
|
+
|
|
242
|
+
### `omk goal refine <goal-id>`
|
|
243
|
+
|
|
244
|
+
Applies the latest interview spec delta to a goal and optionally replans.
|
|
245
|
+
|
|
246
|
+
| Option | Purpose |
|
|
247
|
+
| ----------------------- | ------------------------------------------------ |
|
|
248
|
+
| `--from-interview <id>` | Source interview session (default: latest). |
|
|
249
|
+
| `--plan` | Replan the goal after applying the delta. |
|
|
250
|
+
| `--json` | Emit machine-readable output. |
|
|
251
|
+
|
|
252
|
+
Answers file format (`--answers answers.json`):
|
|
253
|
+
|
|
254
|
+
```json
|
|
255
|
+
{
|
|
256
|
+
"answers": [
|
|
257
|
+
{ "questionId": "q-success-criteria", "answer": "..." }
|
|
258
|
+
]
|
|
259
|
+
}
|
|
260
|
+
```
|
|
261
|
+
|
|
262
|
+
Session artifacts (`interview.json`, `spec-delta.json`, `questions.md`, `answers.jsonl`, `interview-report.md`) are written under `.omk/goals/<goalId>/interviews/<sessionId>/`, or `.omk/interviews/<sessionId>/` before `--write-spec`.
|
|
263
|
+
|
|
195
264
|
## What OMK controls
|
|
196
265
|
|
|
197
266
|
| Surface | What OMK does |
|
|
@@ -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 {};
|