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.
Files changed (102) hide show
  1. package/CHANGELOG.md +37 -0
  2. package/MATURITY.md +4 -0
  3. package/README.md +70 -1
  4. package/dist/benchmark/contracts.d.ts +116 -0
  5. package/dist/benchmark/contracts.js +6 -0
  6. package/dist/benchmark/fixtures.d.ts +11 -0
  7. package/dist/benchmark/fixtures.js +121 -0
  8. package/dist/benchmark/harness.d.ts +13 -0
  9. package/dist/benchmark/harness.js +191 -0
  10. package/dist/benchmark/shadow-mode.d.ts +17 -0
  11. package/dist/benchmark/shadow-mode.js +96 -0
  12. package/dist/cli/register-spec-agent-goal-commands.js +45 -0
  13. package/dist/cli/release-promotion-gate.d.ts +14 -0
  14. package/dist/cli/release-promotion-gate.js +71 -0
  15. package/dist/cli/v2/release-commands.d.ts +29 -0
  16. package/dist/cli/v2/release-commands.js +95 -0
  17. package/dist/commands/chat/native-root-loop.js +14 -1
  18. package/dist/commands/chat/slash/commands/session.js +19 -1
  19. package/dist/commands/goal-interview.d.ts +18 -0
  20. package/dist/commands/goal-interview.js +396 -0
  21. package/dist/commands/merge.js +102 -56
  22. package/dist/contracts/interview.d.ts +106 -0
  23. package/dist/contracts/interview.js +9 -0
  24. package/dist/contracts/provider-health.d.ts +37 -0
  25. package/dist/contracts/provider-health.js +49 -1
  26. package/dist/evidence/evidence-trust-score.d.ts +101 -0
  27. package/dist/evidence/evidence-trust-score.js +408 -0
  28. package/dist/evidence/index.d.ts +6 -0
  29. package/dist/evidence/index.js +3 -0
  30. package/dist/evidence/proof-trust-cli.d.ts +8 -0
  31. package/dist/evidence/proof-trust-cli.js +27 -0
  32. package/dist/evidence/proof-trust.d.ts +14 -0
  33. package/dist/evidence/proof-trust.js +381 -0
  34. package/dist/evidence/regression-proof-matrix.d.ts +42 -0
  35. package/dist/evidence/regression-proof-matrix.js +72 -0
  36. package/dist/goal/intent-frame.d.ts +6 -0
  37. package/dist/goal/intent-frame.js +21 -9
  38. package/dist/goal/interview-assimilation.d.ts +13 -0
  39. package/dist/goal/interview-assimilation.js +383 -0
  40. package/dist/goal/interview-question-bank.d.ts +11 -0
  41. package/dist/goal/interview-question-bank.js +225 -0
  42. package/dist/goal/interview-scoring.d.ts +31 -0
  43. package/dist/goal/interview-scoring.js +187 -0
  44. package/dist/goal/interview-session.d.ts +25 -0
  45. package/dist/goal/interview-session.js +116 -0
  46. package/dist/input/input-envelope.d.ts +22 -0
  47. package/dist/input/input-envelope.js +1 -0
  48. package/dist/orchestration/merge-arbiter.d.ts +91 -0
  49. package/dist/orchestration/merge-arbiter.js +376 -0
  50. package/dist/providers/health.d.ts +3 -0
  51. package/dist/providers/health.js +46 -0
  52. package/dist/providers/index.d.ts +1 -0
  53. package/dist/providers/index.js +1 -0
  54. package/dist/providers/provider-health.d.ts +8 -1
  55. package/dist/providers/provider-health.js +39 -0
  56. package/dist/providers/provider-task-runner.js +31 -0
  57. package/dist/providers/provider.d.ts +2 -0
  58. package/dist/providers/router.js +87 -3
  59. package/dist/providers/types.d.ts +4 -0
  60. package/dist/runtime/advanced-control-loop.d.ts +60 -0
  61. package/dist/runtime/advanced-control-loop.js +136 -0
  62. package/dist/runtime/agent-runtime.d.ts +10 -0
  63. package/dist/runtime/blast-radius.d.ts +10 -0
  64. package/dist/runtime/blast-radius.js +14 -0
  65. package/dist/runtime/contracts/evidence.d.ts +87 -0
  66. package/dist/runtime/contracts/evidence.js +7 -0
  67. package/dist/runtime/contracts/router-v2.d.ts +44 -0
  68. package/dist/runtime/contracts/router-v2.js +4 -0
  69. package/dist/runtime/contracts/weakness-remediation.d.ts +67 -0
  70. package/dist/runtime/contracts/weakness-remediation.js +36 -0
  71. package/dist/runtime/kimi-api-runtime.js +59 -1
  72. package/dist/runtime/proof-bundle-trust.d.ts +74 -0
  73. package/dist/runtime/proof-bundle-trust.js +100 -0
  74. package/dist/runtime/provider-maturity-gate.d.ts +43 -0
  75. package/dist/runtime/provider-maturity-gate.js +129 -0
  76. package/dist/runtime/public-surface.d.ts +93 -0
  77. package/dist/runtime/public-surface.js +146 -0
  78. package/dist/runtime/router-v2-scoring.d.ts +11 -0
  79. package/dist/runtime/router-v2-scoring.js +151 -0
  80. package/dist/runtime/tool-dispatch-contracts.d.ts +24 -3
  81. package/dist/runtime/tool-dispatch-contracts.js +42 -2
  82. package/dist/runtime/weakness-remediation-index.d.ts +27 -0
  83. package/dist/runtime/weakness-remediation-index.js +37 -0
  84. package/dist/safety/enforcement-engine.d.ts +89 -0
  85. package/dist/safety/enforcement-engine.js +279 -0
  86. package/dist/safety/tool-authority-gate.d.ts +40 -0
  87. package/dist/safety/tool-authority-gate.js +92 -0
  88. package/dist/schema/evidence.schema.d.ts +2 -2
  89. package/dist/schema/proof-bundle.schema.d.ts +28 -28
  90. package/dist/util/clipboard-image.d.ts +49 -0
  91. package/dist/util/clipboard-image.js +263 -0
  92. package/docs/2026-06-09/critical-issues.md +20 -0
  93. package/docs/2026-06-09/improvements.md +14 -0
  94. package/docs/2026-06-09/init-checklist.md +25 -0
  95. package/docs/2026-06-09/plan.md +20 -0
  96. package/docs/benchmark-design.md +122 -0
  97. package/docs/github-organic-promotion.md +127 -0
  98. package/docs/native-root-runtime-algorithms.md +301 -0
  99. package/package.json +8 -4
  100. package/readmeasset/ASSET_INDEX.md +1 -0
  101. package/templates/skills/agents/omk-agent-reach-websearch/SKILL.md +55 -0
  102. 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
- const line = userInput.trim();
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 {};