@interf/compiler 0.16.0 → 0.21.0

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 (203) hide show
  1. package/LICENSE.md +1 -0
  2. package/README.md +90 -73
  3. package/TRADEMARKS.md +4 -4
  4. package/dist/cli/commands/mcp.d.ts +0 -34
  5. package/dist/cli/commands/mcp.js +246 -45
  6. package/dist/cli/commands/method.js +261 -15
  7. package/dist/cli/commands/prep.js +116 -15
  8. package/dist/cli/commands/runs.js +103 -9
  9. package/dist/cli/commands/status.js +4 -2
  10. package/dist/cli/commands/test.d.ts +10 -0
  11. package/dist/cli/commands/{verify.js → test.js} +24 -17
  12. package/dist/cli/commands/web.js +82 -8
  13. package/dist/cli/commands/wizard.js +158 -51
  14. package/dist/cli/index.d.ts +2 -2
  15. package/dist/cli/index.js +3 -3
  16. package/dist/compiler-ui/404.html +1 -1
  17. package/dist/compiler-ui/__next.__PAGE__.txt +5 -5
  18. package/dist/compiler-ui/__next._full.txt +13 -12
  19. package/dist/compiler-ui/__next._head.txt +3 -3
  20. package/dist/compiler-ui/__next._index.txt +5 -4
  21. package/dist/compiler-ui/__next._tree.txt +4 -3
  22. package/dist/compiler-ui/_next/static/chunks/01646j7yi.w5a.css +1 -0
  23. package/dist/compiler-ui/_next/static/chunks/{0n51hrfoufc7g.js → 02f_.8.ebn556.js} +1 -1
  24. package/dist/compiler-ui/_next/static/chunks/02r7siaw-_p5w.js +1 -0
  25. package/dist/compiler-ui/_next/static/chunks/{08m7vf5asqlsm.js → 04d0ly-7xb~-j.js} +10 -10
  26. package/dist/compiler-ui/_next/static/chunks/0fhs9psnxqd8s.js +1 -0
  27. package/dist/compiler-ui/_next/static/chunks/0mssmhpbifj15.css +2 -0
  28. package/dist/compiler-ui/_next/static/chunks/0nypu~ddwxari.js +116 -0
  29. package/dist/compiler-ui/_next/static/chunks/0p3s8iyhgcww2.js +31 -0
  30. package/dist/compiler-ui/_next/static/chunks/0tjf-vu_rz8s0.css +1 -0
  31. package/dist/compiler-ui/_next/static/chunks/0u6p3fpbbfgtl.js +1 -0
  32. package/dist/compiler-ui/_next/static/chunks/0wpx5..8dnh0w.js +1 -0
  33. package/dist/compiler-ui/_next/static/chunks/0y0uj160p0ts~.js +1 -0
  34. package/dist/compiler-ui/_next/static/chunks/10t8l~_oenf.c.js +1 -0
  35. package/dist/compiler-ui/_next/static/chunks/13gz9e7z~imx1.js +5 -0
  36. package/dist/compiler-ui/_next/static/chunks/156xed-b6czaw.js +1 -0
  37. package/dist/compiler-ui/_next/static/chunks/{turbopack-0.uq1k8c0j4s..js → turbopack-02-3e_c-yz~5g.js} +1 -1
  38. package/dist/compiler-ui/_next/static/chunks/{turbopack-10e~t1yzi4svj.js → turbopack-0apv8vb-nczuy.js} +1 -1
  39. package/dist/compiler-ui/_not-found/__next._full.txt +10 -9
  40. package/dist/compiler-ui/_not-found/__next._head.txt +3 -3
  41. package/dist/compiler-ui/_not-found/__next._index.txt +5 -4
  42. package/dist/compiler-ui/_not-found/__next._not-found.__PAGE__.txt +2 -2
  43. package/dist/compiler-ui/_not-found/__next._not-found.txt +3 -3
  44. package/dist/compiler-ui/_not-found/__next._tree.txt +3 -2
  45. package/dist/compiler-ui/_not-found.html +1 -1
  46. package/dist/compiler-ui/_not-found.txt +10 -9
  47. package/dist/compiler-ui/index.html +1 -1
  48. package/dist/compiler-ui/index.txt +13 -12
  49. package/dist/packages/contracts/index.d.ts +2 -2
  50. package/dist/packages/contracts/index.js +1 -1
  51. package/dist/packages/contracts/lib/schema.d.ts +275 -72
  52. package/dist/packages/contracts/lib/schema.js +244 -83
  53. package/dist/packages/engine/action-definitions.d.ts +174 -13
  54. package/dist/packages/engine/action-definitions.js +125 -122
  55. package/dist/packages/engine/action-planner.js +4 -11
  56. package/dist/packages/engine/agents/lib/shells.d.ts +15 -5
  57. package/dist/packages/engine/agents/lib/shells.js +134 -123
  58. package/dist/packages/engine/agents/role-executors.js +1 -1
  59. package/dist/packages/engine/cloud-seams.d.ts +115 -0
  60. package/dist/packages/engine/cloud-seams.js +84 -0
  61. package/dist/packages/engine/compile/artifact-counts.d.ts +1 -1
  62. package/dist/packages/engine/compile/artifact-counts.js +3 -3
  63. package/dist/packages/engine/compile/artifact-status.d.ts +41 -0
  64. package/dist/packages/engine/compile/artifact-status.js +166 -0
  65. package/dist/packages/engine/compile/billing-events.d.ts +89 -0
  66. package/dist/packages/engine/compile/billing-events.js +74 -0
  67. package/dist/packages/engine/compile/check-evaluator.d.ts +66 -0
  68. package/dist/packages/engine/compile/check-evaluator.js +298 -0
  69. package/dist/packages/engine/compile/compiled-paths.js +6 -6
  70. package/dist/packages/engine/compile/compiled-schema.d.ts +7 -17
  71. package/dist/packages/engine/compile/compiled-schema.js +55 -70
  72. package/dist/packages/engine/compile/compiled-stage-plan.d.ts +1 -0
  73. package/dist/packages/engine/compile/compiled-stage-plan.js +32 -15
  74. package/dist/packages/engine/compile/compiled-stage-runner.js +1 -1
  75. package/dist/packages/engine/compile/index.d.ts +0 -1
  76. package/dist/packages/engine/compile/index.js +0 -1
  77. package/dist/packages/engine/compile/lib/schema.d.ts +111 -92
  78. package/dist/packages/engine/compile/lib/schema.js +35 -39
  79. package/dist/packages/engine/compile/method-primitives.d.ts +2 -2
  80. package/dist/packages/engine/compile/method-primitives.js +1 -1
  81. package/dist/packages/engine/compile/reset.js +4 -4
  82. package/dist/packages/engine/compile/runtime-contracts.js +2 -1
  83. package/dist/packages/engine/compile/runtime-prompt.js +3 -2
  84. package/dist/packages/engine/compile/runtime-reconcile.js +35 -35
  85. package/dist/packages/engine/compile/runtime-runs.js +0 -1
  86. package/dist/packages/engine/compile/runtime-types.d.ts +7 -8
  87. package/dist/packages/engine/compile/runtime.d.ts +1 -2
  88. package/dist/packages/engine/compile/runtime.js +0 -1
  89. package/dist/packages/engine/compile/state-health.js +6 -6
  90. package/dist/packages/engine/compile/state-view.js +7 -6
  91. package/dist/packages/engine/compile/validate-compiled.js +61 -30
  92. package/dist/packages/engine/compile/validate.js +26 -24
  93. package/dist/packages/engine/connection-config.js +1 -1
  94. package/dist/packages/engine/execution/lib/schema.d.ts +89 -33
  95. package/dist/packages/engine/execution/lib/schema.js +13 -5
  96. package/dist/packages/engine/index.d.ts +2 -2
  97. package/dist/packages/engine/index.js +1 -1
  98. package/dist/packages/engine/instance-paths.d.ts +15 -9
  99. package/dist/packages/engine/instance-paths.js +15 -9
  100. package/dist/packages/engine/lib/schema.d.ts +1316 -351
  101. package/dist/packages/engine/lib/schema.js +99 -36
  102. package/dist/packages/engine/native-run-handlers.js +25 -15
  103. package/dist/packages/engine/preparation-store.d.ts +9 -7
  104. package/dist/packages/engine/preparation-store.js +20 -0
  105. package/dist/packages/engine/requested-artifacts.d.ts +5 -0
  106. package/dist/packages/engine/requested-artifacts.js +36 -0
  107. package/dist/packages/engine/routes.d.ts +7 -1
  108. package/dist/packages/engine/routes.js +7 -1
  109. package/dist/packages/engine/run-observability.js +4 -4
  110. package/dist/packages/engine/runtime-event-applier.js +7 -0
  111. package/dist/packages/engine/runtime-proposal-helpers.d.ts +2 -2
  112. package/dist/packages/engine/runtime-proposal-helpers.js +6 -8
  113. package/dist/packages/engine/runtime-resource-builders.d.ts +11 -6
  114. package/dist/packages/engine/runtime-resource-builders.js +18 -6
  115. package/dist/packages/engine/runtime.d.ts +70 -8
  116. package/dist/packages/engine/runtime.js +304 -49
  117. package/dist/packages/engine/server.d.ts +25 -0
  118. package/dist/packages/engine/server.js +161 -50
  119. package/dist/packages/engine/verify/index.d.ts +10 -10
  120. package/dist/packages/engine/verify/index.js +8 -8
  121. package/dist/packages/engine/verify/readiness-check-run.d.ts +27 -4
  122. package/dist/packages/engine/verify/readiness-check-run.js +92 -24
  123. package/dist/packages/engine/verify/{test-execution.d.ts → verify-execution.d.ts} +2 -2
  124. package/dist/packages/engine/verify/{test-execution.js → verify-execution.js} +3 -3
  125. package/dist/packages/engine/verify/{test-paths.d.ts → verify-paths.d.ts} +1 -1
  126. package/dist/packages/engine/verify/{test-sandbox.d.ts → verify-sandbox.d.ts} +1 -1
  127. package/dist/packages/engine/verify/{test-specs.d.ts → verify-specs.d.ts} +1 -1
  128. package/dist/packages/engine/verify/{test-specs.js → verify-specs.js} +1 -1
  129. package/dist/packages/engine/verify/{test-targets.d.ts → verify-targets.d.ts} +1 -1
  130. package/dist/packages/engine/verify/{test.d.ts → verify.d.ts} +4 -4
  131. package/dist/packages/engine/verify/{test.js → verify.js} +3 -3
  132. package/dist/packages/engine/wire-schemas.d.ts +549 -0
  133. package/dist/packages/engine/wire-schemas.js +59 -0
  134. package/dist/packages/methods/authoring/method-authoring.d.ts +5 -1
  135. package/dist/packages/methods/authoring/method-authoring.js +68 -18
  136. package/dist/packages/methods/authoring/method-edit-session.js +5 -5
  137. package/dist/packages/methods/authoring/method-improvement.js +1 -1
  138. package/dist/packages/methods/package/builtin-compiled-method.d.ts +12 -12
  139. package/dist/packages/methods/package/builtin-compiled-method.js +26 -23
  140. package/dist/packages/methods/package/context-interface.d.ts +39 -26
  141. package/dist/packages/methods/package/context-interface.js +48 -39
  142. package/dist/packages/methods/package/interf-method-package.js +28 -47
  143. package/dist/packages/methods/package/local-methods.d.ts +4 -4
  144. package/dist/packages/methods/package/local-methods.js +53 -66
  145. package/dist/packages/methods/package/method-definitions.d.ts +4 -6
  146. package/dist/packages/methods/package/method-definitions.js +1 -5
  147. package/dist/packages/methods/package/method-helpers.d.ts +0 -2
  148. package/dist/packages/methods/package/method-helpers.js +0 -4
  149. package/dist/packages/project/interf-detect.js +6 -6
  150. package/dist/packages/project/interf-scaffold.js +12 -12
  151. package/dist/packages/project/lib/schema.d.ts +193 -0
  152. package/dist/packages/project/lib/schema.js +46 -1
  153. package/dist/packages/project/source-config.js +6 -1
  154. package/dist/packages/project/source-folders.js +1 -1
  155. package/package.json +12 -23
  156. package/public-repo/CONTRIBUTING.md +47 -0
  157. package/public-repo/LICENSE.md +1 -0
  158. package/public-repo/README.md +325 -0
  159. package/public-repo/SECURITY.md +67 -0
  160. package/public-repo/TRADEMARKS.md +8 -0
  161. package/{builtin-methods → public-repo/methods}/interf-default/README.md +10 -7
  162. package/{builtin-methods → public-repo/methods}/interf-default/compile/stages/shape/SKILL.md +4 -8
  163. package/{builtin-methods → public-repo/methods}/interf-default/method.json +8 -69
  164. package/public-repo/methods/interf-default/method.schema.json +75 -0
  165. package/public-repo/methods/interf-default/use/query/SKILL.md +23 -0
  166. package/public-repo/plugins/README.md +9 -0
  167. package/public-repo/plugins/interf/.claude-plugin/plugin.json +21 -0
  168. package/public-repo/plugins/interf/.mcp.json +12 -0
  169. package/public-repo/plugins/interf/README.md +29 -0
  170. package/public-repo/plugins/interf/skills/interf/SKILL.md +477 -0
  171. package/public-repo/skills/interf/SKILL.md +477 -0
  172. package/agent-skills/interf-actions/SKILL.md +0 -185
  173. package/agent-skills/interf-actions/references/cli.md +0 -243
  174. package/builtin-methods/interf-default/method.schema.json +0 -73
  175. package/builtin-methods/interf-default/use/query/SKILL.md +0 -28
  176. package/dist/cli/commands/verify.d.ts +0 -8
  177. package/dist/compiler-ui/_next/static/chunks/06yhdspx~ca5-.js +0 -5
  178. package/dist/compiler-ui/_next/static/chunks/06z~l3kwb891e.js +0 -1
  179. package/dist/compiler-ui/_next/static/chunks/08g7lvje.te.u.js +0 -1
  180. package/dist/compiler-ui/_next/static/chunks/0_i-3_5l9t2qe.js +0 -1
  181. package/dist/compiler-ui/_next/static/chunks/0b-ywny_j0g~0.js +0 -1
  182. package/dist/compiler-ui/_next/static/chunks/0b52v41o1gixx.js +0 -1
  183. package/dist/compiler-ui/_next/static/chunks/0gpzgsv0w.q~m.js +0 -31
  184. package/dist/compiler-ui/_next/static/chunks/0ilwfezfvu6~-.js +0 -1
  185. package/dist/compiler-ui/_next/static/chunks/0jipmpez3_ehh.js +0 -89
  186. package/dist/compiler-ui/_next/static/chunks/0xxmf45eskdt~.css +0 -1
  187. package/dist/compiler-ui/_next/static/chunks/13awzu4tooflw.css +0 -3
  188. package/dist/compiler-ui/_next/static/chunks/14wtz~vq25~qq.js +0 -1
  189. package/dist/packages/engine/compile/runtime-acceptance.d.ts +0 -9
  190. package/dist/packages/engine/compile/runtime-acceptance.js +0 -265
  191. /package/dist/compiler-ui/_next/static/{a3UiUF0DiMEbfWy_0gihg → tYHMLL9oKds1yDoNYgkPV}/_buildManifest.js +0 -0
  192. /package/dist/compiler-ui/_next/static/{a3UiUF0DiMEbfWy_0gihg → tYHMLL9oKds1yDoNYgkPV}/_clientMiddlewareManifest.js +0 -0
  193. /package/dist/compiler-ui/_next/static/{a3UiUF0DiMEbfWy_0gihg → tYHMLL9oKds1yDoNYgkPV}/_ssgManifest.js +0 -0
  194. /package/dist/packages/engine/verify/{test-paths.js → verify-paths.js} +0 -0
  195. /package/dist/packages/engine/verify/{test-profile-presets.d.ts → verify-profile-presets.d.ts} +0 -0
  196. /package/dist/packages/engine/verify/{test-profile-presets.js → verify-profile-presets.js} +0 -0
  197. /package/dist/packages/engine/verify/{test-sandbox.js → verify-sandbox.js} +0 -0
  198. /package/dist/packages/engine/verify/{test-targets.js → verify-targets.js} +0 -0
  199. /package/dist/packages/engine/verify/{test-types.d.ts → verify-types.d.ts} +0 -0
  200. /package/dist/packages/engine/verify/{test-types.js → verify-types.js} +0 -0
  201. /package/{builtin-methods → public-repo/methods}/interf-default/compile/stages/structure/SKILL.md +0 -0
  202. /package/{builtin-methods → public-repo/methods}/interf-default/compile/stages/summarize/SKILL.md +0 -0
  203. /package/{builtin-methods → public-repo/methods}/interf-default/improve/SKILL.md +0 -0
@@ -64,12 +64,14 @@ export const statusCommand = {
64
64
  console.log();
65
65
  console.log(chalk.bold(` Preparations (${list.length})`));
66
66
  if (list.length === 0) {
67
- console.log(chalk.dim(" No preparations yet. `interf prep create <id> --source <path> --method <id>`."));
67
+ console.log(chalk.dim(" No preparations yet. `interf prep create <id> --source <path>`."));
68
68
  }
69
69
  else {
70
70
  for (const prep of list) {
71
71
  const readiness = prep.readiness?.status ?? "—";
72
- console.log(` ${chalk.bold(prep.id)} ${chalk.dim(`(${prep.method_id} · ${readiness})`)}`);
72
+ const buildPlan = prep.method_id ?? "no Build Plan";
73
+ const requested = prep.requested_artifacts?.length ?? 0;
74
+ console.log(` ${chalk.bold(prep.id)} ${chalk.dim(`(${buildPlan} · ${requested} requested · ${readiness})`)}`);
73
75
  console.log(chalk.dim(` source: ${prep.source.locator}`));
74
76
  }
75
77
  }
@@ -0,0 +1,10 @@
1
+ import type { CommandModule } from "yargs";
2
+ type TestTarget = "compiled" | "source-files";
3
+ interface TestArgs {
4
+ prepId: string;
5
+ target?: TestTarget;
6
+ url?: string;
7
+ token?: string;
8
+ }
9
+ export declare const testCommand: CommandModule<unknown, TestArgs>;
10
+ export {};
@@ -1,10 +1,13 @@
1
1
  /**
2
- * `interf verify <prep-id>` — verify a preparation's claim-checks via a
3
- * judge against the latest compiled portable context. Together with the
4
- * method's structural checks (auto-run on every `interf compile`), this
5
- * feeds the preparation's overall readiness state.
2
+ * `interf test <prep-id>` — run readiness checks for a Preparation via a
3
+ * judge against the latest portable context (default) or against the source
4
+ * baseline (`--target source-files`). The source-files target reveals how
5
+ * much value the Method adds. Together with Method Artifact checks
6
+ * (auto-run on every `interf compile`), this feeds the Preparation's
7
+ * overall readiness state.
6
8
  *
7
- * interf verify bristol
9
+ * interf test bristol
10
+ * interf test bristol --target source-files
8
11
  */
9
12
  import chalk from "chalk";
10
13
  import { CONNECT_OR_ERROR_HINT, readActiveConnection } from "../../packages/engine/connection-config.js";
@@ -38,37 +41,41 @@ async function callJson(url, token, init = {}) {
38
41
  }
39
42
  return { status: response.status, body, raw };
40
43
  }
41
- export const verifyCommand = {
42
- command: "verify <prep-id>",
43
- describe: "Verify a preparation's claim-checks against its portable context",
44
+ export const testCommand = {
45
+ command: "test <prep-id>",
46
+ describe: "Run readiness checks against a Preparation's portable context (or source-files baseline)",
44
47
  builder: (yargs) => yargs
45
48
  .positional("prep-id", { type: "string", demandOption: true, describe: "Preparation id" })
49
+ .option("target", {
50
+ type: "string",
51
+ choices: ["compiled", "source-files"],
52
+ default: "compiled",
53
+ describe: "Judge target: 'compiled' (default) checks the portable context, 'source-files' checks the raw Source baseline",
54
+ })
46
55
  .option("url", { type: "string", describe: "Override the active connection URL" })
47
56
  .option("token", { type: "string", describe: "Override the active bearer token" }),
48
57
  handler: async (args) => {
49
58
  const { url, token } = resolveConnection(args);
50
- // 0.15 hard-error: refuse to start a verify run if the engine has
51
- // zero connected agents — verifier-role stages can't run without
52
- // one.
59
+ // 0.15 hard-error: refuse to start a readiness-check run if the engine
60
+ // has zero connected agents — verifier-role stages can't run without one.
53
61
  const instance = await callJson(`${url}/v1/instance`, token);
54
62
  if (instance.body && instance.body.agent_count === 0) {
55
- console.error(chalk.red(" Cannot verify — no agents available."));
63
+ console.error(chalk.red(" Cannot run readiness checks — no agents available."));
56
64
  console.error(" Install Claude Code, Codex, Gemini, or another agent CLI, or");
57
65
  console.error(" register a custom CLI: `interf agents register <name> --command <cmd>`.");
58
66
  process.exit(1);
59
67
  }
60
- // Verify the user's claims against the compiled portable context.
61
- // The legacy "source-files" / "both" targets (file-as-is judging)
62
- // are gone — claims are evaluated against the compiled output only.
63
- const { status, body, raw } = await callJson(`${url}/v1/preparations/${encodeURIComponent(args.prepId)}/verify-runs`, token, { method: "POST", body: JSON.stringify({ mode: "compiled" }) });
68
+ const target = args.target ?? "compiled";
69
+ const { status, body, raw } = await callJson(`${url}/v1/preparations/${encodeURIComponent(args.prepId)}/verify-runs`, token, { method: "POST", body: JSON.stringify({ target }) });
64
70
  if (status !== 201 && status !== 200) {
65
- console.error(chalk.red(`Failed to start verify run for ${args.prepId} (HTTP ${status}).`));
71
+ console.error(chalk.red(`Failed to start readiness-check run for ${args.prepId} (HTTP ${status}).`));
66
72
  if (raw)
67
73
  console.error(raw);
68
74
  process.exit(1);
69
75
  }
70
76
  console.log();
71
77
  console.log(` Run ${chalk.bold(body?.run_id ?? "(?)")} ${chalk.dim(`(${body?.status ?? "started"})`)}`);
78
+ console.log(` Target: ${target}`);
72
79
  if (body?.readiness?.status)
73
80
  console.log(` Readiness: ${body.readiness.status}`);
74
81
  if (body?.error)
@@ -2,6 +2,7 @@
2
2
  * `interf web` — start the engine in the foreground until Ctrl-C.
3
3
  *
4
4
  * interf web # start on default port; hard error if port busy
5
+ * interf web start # start the engine in the background
5
6
  * interf web stop # send SIGTERM to the running engine
6
7
  * interf web status # print engine info via the connected URL
7
8
  *
@@ -10,11 +11,13 @@
10
11
  * connect without a pointer file.
11
12
  */
12
13
  import chalk from "chalk";
13
- import { readFileSync } from "node:fs";
14
+ import { closeSync, mkdirSync, openSync, readFileSync } from "node:fs";
15
+ import { spawn } from "node:child_process";
16
+ import { dirname } from "node:path";
14
17
  import { LOCAL_SERVICE_DEFAULT_HOST, LOCAL_SERVICE_DEFAULT_PORT, buildLocalServiceUrl, } from "../../packages/engine/routes.js";
15
18
  import { startLocalService } from "../../packages/engine/server.js";
16
19
  import { createNativeLocalServiceRunHandlers } from "../../packages/engine/native-run-handlers.js";
17
- import { CONNECT_OR_ERROR_HINT, clearConnection, readActiveConnection, } from "../../packages/engine/connection-config.js";
20
+ import { CONNECT_OR_ERROR_HINT, clearConnection, readActiveConnection, writeConnection, } from "../../packages/engine/connection-config.js";
18
21
  import { serviceRegistryPath } from "../../packages/engine/instance-paths.js";
19
22
  function packageVersionFromManifest() {
20
23
  try {
@@ -53,12 +56,6 @@ async function runWebForeground(args) {
53
56
  }
54
57
  throw error;
55
58
  }
56
- console.log();
57
- console.log(` Interf engine: ${chalk.bold(service.url)}`);
58
- console.log(` Compiler UI: ${service.url}/`);
59
- console.log(` Health: ${service.url}/health`);
60
- console.log(chalk.dim(" Press Ctrl-C to stop."));
61
- console.log();
62
59
  const shutdown = async () => {
63
60
  try {
64
61
  await service.close();
@@ -68,12 +65,84 @@ async function runWebForeground(args) {
68
65
  }
69
66
  process.exit(0);
70
67
  };
68
+ console.log();
69
+ console.log(` Interf engine: ${chalk.bold(service.url)}`);
70
+ console.log(` Compiler UI: ${service.url}/`);
71
+ console.log(` Health: ${service.url}/health`);
72
+ console.log(chalk.dim(" Press Ctrl-C to stop."));
73
+ console.log();
71
74
  process.on("SIGINT", shutdown);
72
75
  process.on("SIGTERM", shutdown);
73
76
  await new Promise(() => {
74
77
  /* block forever; signals trigger shutdown */
75
78
  });
76
79
  }
80
+ async function isEngineReachable(url) {
81
+ try {
82
+ const response = await fetch(`${url}/health`);
83
+ return response.status === 200;
84
+ }
85
+ catch {
86
+ return false;
87
+ }
88
+ }
89
+ async function waitForEngine(url, timeoutMs) {
90
+ const started = Date.now();
91
+ while (Date.now() - started < timeoutMs) {
92
+ if (await isEngineReachable(url))
93
+ return true;
94
+ await new Promise((resolveWait) => setTimeout(resolveWait, 150));
95
+ }
96
+ return false;
97
+ }
98
+ function managedWebLogPath(port) {
99
+ return `${dirname(serviceRegistryPath())}/interf-web-${port}.log`;
100
+ }
101
+ async function runWebStart(args) {
102
+ const host = args.host ?? LOCAL_SERVICE_DEFAULT_HOST;
103
+ const port = args.port ?? LOCAL_SERVICE_DEFAULT_PORT;
104
+ const url = buildLocalServiceUrl({ host, port });
105
+ if (await isEngineReachable(url)) {
106
+ writeConnection({ url, auth_token: null });
107
+ console.log(chalk.green(`Interf engine already running at ${chalk.bold(url)}.`));
108
+ console.log(`Compiler UI: ${url}/`);
109
+ return;
110
+ }
111
+ const binPath = process.argv[1];
112
+ if (!binPath) {
113
+ console.error(chalk.red("Cannot locate the Interf CLI entrypoint for managed start."));
114
+ console.error(`Try running \`interf web\` in a separate terminal instead.`);
115
+ process.exit(1);
116
+ }
117
+ const logPath = args.log ?? managedWebLogPath(port);
118
+ mkdirSync(dirname(logPath), { recursive: true });
119
+ const stdoutFd = openSync(logPath, "a");
120
+ const stderrFd = openSync(logPath, "a");
121
+ let child;
122
+ try {
123
+ child = spawn(process.execPath, [binPath, "web", "--host", host, "--port", String(port)], {
124
+ detached: true,
125
+ stdio: ["ignore", stdoutFd, stderrFd],
126
+ env: process.env,
127
+ });
128
+ child.unref();
129
+ }
130
+ finally {
131
+ closeSync(stdoutFd);
132
+ closeSync(stderrFd);
133
+ }
134
+ const ready = await waitForEngine(url, args.timeoutMs ?? 5000);
135
+ if (!ready) {
136
+ console.error(chalk.red(`Timed out waiting for Interf engine at ${url}.`));
137
+ console.error(`Log: ${logPath}`);
138
+ process.exit(1);
139
+ }
140
+ writeConnection({ url, auth_token: null });
141
+ console.log(chalk.green(`Started Interf engine at ${chalk.bold(url)}.`));
142
+ console.log(`Compiler UI: ${url}/`);
143
+ console.log(`Log: ${logPath}`);
144
+ console.log(chalk.dim(`Stop it with \`interf web stop\`.`));
145
+ }
77
146
  function findEnginePidByUrl(url) {
78
147
  try {
79
148
  const raw = readFileSync(serviceRegistryPath(), "utf8");
@@ -196,6 +265,11 @@ export const webCommand = {
196
265
  command: "web [subcommand]",
197
266
  describe: "Start / stop / inspect the Interf engine",
198
267
  builder: (yargs) => yargs
268
+ .command("start", "Start the engine in the background", (y) => y
269
+ .option("host", { type: "string", default: LOCAL_SERVICE_DEFAULT_HOST, describe: "Host to bind" })
270
+ .option("port", { type: "number", default: LOCAL_SERVICE_DEFAULT_PORT, describe: "Port to bind" })
271
+ .option("timeout-ms", { type: "number", default: 5000, describe: "How long to wait for startup" })
272
+ .option("log", { type: "string", describe: "Path to write background engine logs" }), runWebStart)
199
273
  .command("stop", "Stop the connected engine", (y) => y
200
274
  .option("url", { type: "string", describe: "Override the active connection URL" })
201
275
  .option("token", { type: "string", describe: "Override the active bearer token" }), runWebStop)
@@ -2,7 +2,8 @@
2
2
  * `interf` (no subcommand) and `interf init` — the wizard.
3
3
  *
4
4
  * Casual-user entry point. End-to-end onboarding:
5
- * - If no connection → offer to start a local engine inline (or connect remote, or quit).
5
+ * - If no connection → connect to an already-running local engine, or ask
6
+ * whether to start the foreground local engine, connect remote, or quit.
6
7
  * - Once connected → action menu (list / create / compile / test / open UI / stop engine / quit).
7
8
  * - Each action loops back to the menu instead of exiting.
8
9
  *
@@ -15,7 +16,7 @@ import { existsSync, statSync } from "node:fs";
15
16
  import { homedir } from "node:os";
16
17
  import { basename, resolve } from "node:path";
17
18
  import { spawn } from "node:child_process";
18
- import { readActiveConnection, writeConnection, } from "../../packages/engine/connection-config.js";
19
+ import { ConnectionRecordSchema, readActiveConnection, writeConnection, } from "../../packages/engine/connection-config.js";
19
20
  import { LOCAL_SERVICE_DEFAULT_HOST, LOCAL_SERVICE_DEFAULT_PORT } from "../../packages/engine/routes.js";
20
21
  async function callJson(url, token) {
21
22
  const headers = new Headers();
@@ -46,6 +47,18 @@ function spawnInterf(args) {
46
47
  });
47
48
  }
48
49
  const DEFAULT_ENGINE_URL = `http://${LOCAL_SERVICE_DEFAULT_HOST}:${LOCAL_SERVICE_DEFAULT_PORT}`;
50
+ function hasInteractiveTerminal() {
51
+ return process.stdin.isTTY === true && process.stdout.isTTY === true;
52
+ }
53
+ function isHttpUrl(value) {
54
+ try {
55
+ const parsed = new URL(value);
56
+ return parsed.protocol === "http:" || parsed.protocol === "https:";
57
+ }
58
+ catch {
59
+ return false;
60
+ }
61
+ }
49
62
  /**
50
63
  * Probe a URL's `/health` endpoint and return whether the engine is up.
51
64
  * Used as a fallback when `connection.json` may be missing (e.g. older
@@ -133,6 +146,69 @@ function exitNoEngineConnected(reason) {
133
146
  console.log();
134
147
  process.exit(1);
135
148
  }
149
+ async function promptForConnection(reason) {
150
+ if (!hasInteractiveTerminal()) {
151
+ exitNoEngineConnected(reason);
152
+ }
153
+ console.log();
154
+ console.log(chalk.yellow(` ${reason}`));
155
+ console.log();
156
+ const choice = await p.select({
157
+ message: "How do you want to continue?",
158
+ options: [
159
+ { value: "start-local", label: "Start local engine (serves Compiler UI)" },
160
+ { value: "connect-remote", label: "Connect to remote engine" },
161
+ { value: "quit", label: chalk.dim("Exit") },
162
+ ],
163
+ initialValue: "start-local",
164
+ });
165
+ if (p.isCancel(choice) || choice === "quit") {
166
+ p.outro("Bye.");
167
+ return null;
168
+ }
169
+ if (choice === "start-local") {
170
+ console.log();
171
+ console.log(chalk.dim(" Starting `interf web` in this terminal. Press Ctrl-C to stop the engine."));
172
+ console.log();
173
+ const code = await spawnInterf(["web"]);
174
+ process.exit(code);
175
+ }
176
+ const urlValue = await p.text({
177
+ message: "Remote engine URL",
178
+ placeholder: "https://api.interf.cloud",
179
+ validate: (value) => {
180
+ const trimmed = String(value ?? "").trim();
181
+ if (!trimmed)
182
+ return "URL is required.";
183
+ const parsed = ConnectionRecordSchema.safeParse({ url: trimmed, auth_token: null });
184
+ return parsed.success && isHttpUrl(trimmed) ? undefined : "Enter a valid http(s) URL.";
185
+ },
186
+ });
187
+ if (p.isCancel(urlValue)) {
188
+ p.outro("Bye.");
189
+ return null;
190
+ }
191
+ const tokenValue = await p.password({
192
+ message: "Bearer token (optional)",
193
+ mask: "*",
194
+ });
195
+ if (p.isCancel(tokenValue)) {
196
+ p.outro("Bye.");
197
+ return null;
198
+ }
199
+ const record = ConnectionRecordSchema.parse({
200
+ url: String(urlValue).trim(),
201
+ auth_token: String(tokenValue ?? "").trim() || null,
202
+ });
203
+ const url = record.url.replace(/\/+$/, "");
204
+ const probe = await callJson(`${url}/health`, record.auth_token);
205
+ if (probe.status === 0) {
206
+ return promptForConnection(`Connection ${url} is unreachable.`);
207
+ }
208
+ writeConnection(record);
209
+ console.log(chalk.green("Connection saved."));
210
+ return { url, token: record.auth_token };
211
+ }
136
212
  /** Validate that a path exists and is a directory. */
137
213
  function validateSourcePath(value) {
138
214
  const abs = resolve(value);
@@ -170,7 +246,7 @@ async function promptSourcePath() {
170
246
  }
171
247
  options.push({ value: "__custom__", label: chalk.dim("Type a custom path…") });
172
248
  const choice = await p.select({
173
- message: "Where's the source folder?",
249
+ message: "Where are the source files?",
174
250
  options,
175
251
  initialValue: resolve(cwd),
176
252
  });
@@ -178,7 +254,7 @@ async function promptSourcePath() {
178
254
  return null;
179
255
  if (choice === "__custom__") {
180
256
  const typed = await p.text({
181
- message: "Custom source folder path",
257
+ message: "Custom source path",
182
258
  placeholder: cwd,
183
259
  initialValue: cwd,
184
260
  validate: validateSourcePath,
@@ -207,23 +283,22 @@ async function flowCreatePreparation(conn) {
207
283
  const sourcePath = await promptSourcePath();
208
284
  if (!sourcePath)
209
285
  return null;
210
- // Offer the methods that the connected instance knows about. Method
211
- // binding is OPTIONAL at create time the agent first creates the
212
- // preparation (the unit of agent work) and may pick or draft a method
213
- // for it later.
286
+ // Offer saved Build Plans, but keep selection optional. The agent-first
287
+ // path usually creates the Preparation from requested Artifacts first,
288
+ // then drafts a custom Build Plan for review.
214
289
  const methodsResp = await callJson(`${conn.url}/v1/methods`, conn.token);
215
290
  const methods = methodsResp.body?.methods ?? [];
216
291
  const methodOptions = methods
217
292
  .map((m) => ({ value: m.method_id ?? m.id ?? "", label: `${m.method_id ?? m.id ?? "(?)"}${m.label ? ` — ${m.label}` : ""}` }))
218
293
  .filter((opt) => opt.value !== "");
219
294
  let methodId = null;
220
- const skipOption = { value: "__skip__", label: chalk.dim("Skip — pick or draft a method later") };
221
- const customOption = { value: "__custom__", label: "Other (type a method id)" };
295
+ const skipOption = { value: "__skip__", label: chalk.dim("Skip — pick or draft a Build Plan later") };
296
+ const customOption = { value: "__custom__", label: "Other (type a Build Plan / Method id)" };
222
297
  if (methodOptions.length > 0) {
223
298
  const chosen = await p.select({
224
- message: "Pick a method (optional — you can do this later)",
225
- options: [...methodOptions, customOption, skipOption],
226
- initialValue: methodOptions.find((o) => o.value === "interf-default")?.value ?? methodOptions[0]?.value,
299
+ message: "Select a Build Plan (optional — you can do this later)",
300
+ options: [skipOption, ...methodOptions, customOption],
301
+ initialValue: skipOption.value,
227
302
  });
228
303
  if (p.isCancel(chosen))
229
304
  return null;
@@ -232,7 +307,7 @@ async function flowCreatePreparation(conn) {
232
307
  }
233
308
  else if (chosen === "__custom__") {
234
309
  const typed = await p.text({
235
- message: "Method id",
310
+ message: "Build Plan / Method id",
236
311
  placeholder: "interf-default",
237
312
  });
238
313
  if (p.isCancel(typed))
@@ -245,17 +320,17 @@ async function flowCreatePreparation(conn) {
245
320
  }
246
321
  else {
247
322
  const choose = await p.select({
248
- message: "No methods registered yet — pick a method id?",
323
+ message: "No saved Build Plans registered yet — pick an id?",
249
324
  options: [
250
- { value: "__type__", label: "Type a method id" },
251
325
  skipOption,
326
+ { value: "__type__", label: "Type a Build Plan / Method id" },
252
327
  ],
253
328
  });
254
329
  if (p.isCancel(choose))
255
330
  return null;
256
331
  if (choose === "__type__") {
257
332
  const typed = await p.text({
258
- message: "Method id",
333
+ message: "Build Plan / Method id",
259
334
  initialValue: "interf-default",
260
335
  });
261
336
  if (p.isCancel(typed))
@@ -287,20 +362,20 @@ async function pickPreparation(conn, message) {
287
362
  message,
288
363
  options: list.map((prep) => ({
289
364
  value: prep.id,
290
- label: `${prep.id} ${chalk.dim(`(${prep.method_id} · ${prep.readiness?.status ?? "—"})`)}`,
365
+ label: `${prep.id} ${chalk.dim(`(${prep.method_id ?? "no Build Plan"} · ${prep.readiness?.status ?? "—"})`)}`,
291
366
  })),
292
367
  });
293
368
  if (p.isCancel(choice))
294
369
  return null;
295
370
  return String(choice);
296
371
  }
297
- async function showActionMenu(conn, options = { allowCompileVerify: true }) {
298
- const compileLabel = options.allowCompileVerify
372
+ async function showActionMenu(conn, options = { allowAgentRuns: true }) {
373
+ const compileLabel = options.allowAgentRuns
299
374
  ? "Compile a preparation"
300
375
  : chalk.dim("Compile a preparation (no agents available)");
301
- const verifyLabel = options.allowCompileVerify
302
- ? "Verify a preparation's claim-checks"
303
- : chalk.dim("Verify (no agents available)");
376
+ const testLabel = options.allowAgentRuns
377
+ ? "Run readiness checks"
378
+ : chalk.dim("Readiness checks (no agents available)");
304
379
  const action = await p.select({
305
380
  message: "What do you want to do?",
306
381
  options: [
@@ -309,7 +384,7 @@ async function showActionMenu(conn, options = { allowCompileVerify: true }) {
309
384
  { value: "create", label: "Create a new preparation" },
310
385
  { value: "agents", label: "Manage agents (list / register / role-map)" },
311
386
  { value: "compile", label: compileLabel },
312
- { value: "verify", label: verifyLabel },
387
+ { value: "test", label: testLabel },
313
388
  { value: "stop", label: "Stop the local engine" },
314
389
  { value: "quit", label: "Quit" },
315
390
  ],
@@ -327,7 +402,7 @@ async function showActionMenu(conn, options = { allowCompileVerify: true }) {
327
402
  if (action === "create") {
328
403
  const newId = await flowCreatePreparation(conn);
329
404
  if (newId) {
330
- if (!options.allowCompileVerify) {
405
+ if (!options.allowAgentRuns) {
331
406
  console.log(chalk.dim(" Skipping compile prompt — no agents available. Install one then run `interf compile " +
332
407
  newId +
333
408
  "`."));
@@ -342,7 +417,7 @@ async function showActionMenu(conn, options = { allowCompileVerify: true }) {
342
417
  return "continue";
343
418
  }
344
419
  if (action === "compile") {
345
- if (!options.allowCompileVerify) {
420
+ if (!options.allowAgentRuns) {
346
421
  console.log(chalk.yellow(" Cannot compile — no agents available."));
347
422
  console.log(" Install Claude Code, Codex, Gemini, or another agent CLI, or");
348
423
  console.log(" register a custom CLI: `interf agents register <name> --command <cmd>`.");
@@ -353,14 +428,14 @@ async function showActionMenu(conn, options = { allowCompileVerify: true }) {
353
428
  await spawnInterf(["compile", id]);
354
429
  return "continue";
355
430
  }
356
- if (action === "verify") {
357
- if (!options.allowCompileVerify) {
358
- console.log(chalk.yellow(" Cannot verify — no agents available."));
431
+ if (action === "test") {
432
+ if (!options.allowAgentRuns) {
433
+ console.log(chalk.yellow(" Cannot run readiness checks — no agents available."));
359
434
  return "continue";
360
435
  }
361
- const id = await pickPreparation(conn, "Which preparation to verify?");
436
+ const id = await pickPreparation(conn, "Which preparation should Interf test?");
362
437
  if (id)
363
- await spawnInterf(["verify", id]);
438
+ await spawnInterf(["test", id]);
364
439
  return "continue";
365
440
  }
366
441
  if (action === "ui") {
@@ -395,14 +470,14 @@ async function showActionMenu(conn, options = { allowCompileVerify: true }) {
395
470
  * Agent install-cards menu shown when the connected engine has zero
396
471
  * detected + registered agents. Returns:
397
472
  * - "rerun" → user installed an agent and wants to retry detection
398
- * - "skip" → continue in UI-only mode (no compile/verify)
473
+ * - "skip" → continue in UI-only mode (no compile/test)
399
474
  * - "quit" → exit
400
475
  */
401
476
  async function showAgentInstallCards() {
402
477
  console.log();
403
478
  console.log(chalk.yellow(" No agents detected."));
404
479
  console.log();
405
- console.log(" Interf needs at least one agent to compile and verify preparations.");
480
+ console.log(" Interf needs at least one agent to compile source files and run readiness checks.");
406
481
  console.log();
407
482
  const choice = await p.select({
408
483
  message: "How do you want to proceed?",
@@ -522,25 +597,57 @@ async function fetchAgentSnapshot(conn) {
522
597
  };
523
598
  }
524
599
  async function runWizard(args) {
525
- // Connect-or-error: the wizard never auto-starts an engine. If
526
- // `~/.interf/connection.json` is missing or unreachable, exit
527
- // non-zero and tell the user to run `interf web` (or
528
- // `interf login`) explicitly. This keeps the engine lifecycle in
529
- // the user's hands — no surprise background processes, no stale
530
- // binaries served by a long-lived auto-spawn.
600
+ // The wizard is the human entry point, so it can ask how to connect.
601
+ // It still never auto-starts an engine: starting `interf web` is an
602
+ // explicit foreground choice, and script/agent commands keep the
603
+ // connect-or-error behavior.
531
604
  const initial = readActiveConnection({
532
605
  urlOverride: args.url,
533
606
  authTokenOverride: args.token,
534
607
  });
608
+ let conn = null;
535
609
  if (!initial) {
536
- exitNoEngineConnected("No Interf engine is connected.");
610
+ if (await probeHealth(DEFAULT_ENGINE_URL)) {
611
+ try {
612
+ writeConnection({ url: DEFAULT_ENGINE_URL, auth_token: null });
613
+ }
614
+ catch {
615
+ // best effort
616
+ }
617
+ console.log();
618
+ console.log(chalk.dim(` Engine already running at ${DEFAULT_ENGINE_URL} — connecting.`));
619
+ conn = { url: DEFAULT_ENGINE_URL, token: null };
620
+ }
621
+ else {
622
+ conn = await promptForConnection("No Interf engine is connected.");
623
+ }
537
624
  }
538
- const url = initial.url.replace(/\/+$/, "");
539
- const probe = await callJson(`${url}/health`, initial.auth_token);
540
- if (probe.status === 0) {
541
- exitNoEngineConnected(`Connection ${url} is unreachable.`);
625
+ else {
626
+ const url = initial.url.replace(/\/+$/, "");
627
+ const probe = await callJson(`${url}/health`, initial.auth_token);
628
+ if (probe.status === 0) {
629
+ if (!args.url && await probeHealth(DEFAULT_ENGINE_URL)) {
630
+ try {
631
+ writeConnection({ url: DEFAULT_ENGINE_URL, auth_token: null });
632
+ }
633
+ catch {
634
+ // best effort
635
+ }
636
+ console.log();
637
+ console.log(chalk.dim(` Saved connection ${url} is unreachable; using local engine at ${DEFAULT_ENGINE_URL}.`));
638
+ conn = { url: DEFAULT_ENGINE_URL, token: null };
639
+ }
640
+ else {
641
+ conn = await promptForConnection(`Connection ${url} is unreachable.`);
642
+ }
643
+ }
644
+ else {
645
+ conn = { url, token: initial.auth_token };
646
+ }
647
+ }
648
+ if (!conn) {
649
+ return;
542
650
  }
543
- let conn = { url, token: initial.auth_token };
544
651
  const instance = await callJson(`${conn.url}/v1/instance`, conn.token);
545
652
  console.log();
546
653
  console.log(chalk.bold(` Connected to ${conn.url}`));
@@ -549,7 +656,7 @@ async function runWizard(args) {
549
656
  }
550
657
  // 0.15 — surface the connected agents up front. When zero are
551
658
  // detected, run the install-cards menu before letting the user
552
- // try to compile / verify.
659
+ // try to compile or run readiness checks.
553
660
  let agents = await fetchAgentSnapshot(conn);
554
661
  if (agents && !agents.engineSupportsAgents) {
555
662
  console.log();
@@ -560,7 +667,7 @@ async function runWizard(args) {
560
667
  message: "Restart the engine now to pick up new features?",
561
668
  options: [
562
669
  { value: "restart", label: "Yes — stop old engine, start new one" },
563
- { value: "continue", label: chalk.dim("No — continue with limited features (no agents UI / compile / verify)") },
670
+ { value: "continue", label: chalk.dim("No — continue with limited features (no agents UI / compile / test)") },
564
671
  { value: "quit", label: "Quit" },
565
672
  ],
566
673
  initialValue: "restart",
@@ -592,7 +699,7 @@ async function runWizard(args) {
592
699
  return 0;
593
700
  return snapshot.agents.filter((agent) => agent.available !== false).length;
594
701
  }
595
- let allowCompileVerify = installedAgentCount(agents) > 0;
702
+ let allowAgentRuns = installedAgentCount(agents) > 0;
596
703
  while (agents &&
597
704
  agents.engineSupportsAgents &&
598
705
  installedAgentCount(agents) === 0) {
@@ -602,12 +709,12 @@ async function runWizard(args) {
602
709
  return;
603
710
  }
604
711
  if (decision === "skip") {
605
- allowCompileVerify = false;
712
+ allowAgentRuns = false;
606
713
  break;
607
714
  }
608
715
  // decision === "rerun"
609
716
  agents = await fetchAgentSnapshot(conn);
610
- allowCompileVerify = installedAgentCount(agents) > 0;
717
+ allowAgentRuns = installedAgentCount(agents) > 0;
611
718
  }
612
719
  if (agents && agents.engineSupportsAgents && installedAgentCount(agents) > 0) {
613
720
  // Always confirm the active agent before the action menu. Pre-select
@@ -664,7 +771,7 @@ async function runWizard(args) {
664
771
  }
665
772
  for (;;) {
666
773
  console.log();
667
- const next = await showActionMenu(conn, { allowCompileVerify });
774
+ const next = await showActionMenu(conn, { allowAgentRuns });
668
775
  if (next === "exit")
669
776
  break;
670
777
  }
@@ -1,6 +1,6 @@
1
1
  import { agentsCommand } from "./commands/agents.js";
2
2
  import { compileCommand } from "./commands/compile.js";
3
- import { verifyCommand } from "./commands/verify.js";
3
+ import { testCommand } from "./commands/test.js";
4
4
  import { doctorCommand } from "./commands/doctor.js";
5
5
  import { methodCommand } from "./commands/method.js";
6
6
  import { mcpCommand } from "./commands/mcp.js";
@@ -22,4 +22,4 @@ export declare function runCli(argv?: string[]): {
22
22
  _: (string | number)[];
23
23
  $0: string;
24
24
  }>;
25
- export { initCommand, compileCommand, verifyCommand, agentsCommand, doctorCommand, methodCommand, mcpCommand, runsCommand, statusCommand, resetCommand, webCommand, prepCommand, loginCommand, logoutCommand, wizardCommand, };
25
+ export { initCommand, compileCommand, testCommand, agentsCommand, doctorCommand, methodCommand, mcpCommand, runsCommand, statusCommand, resetCommand, webCommand, prepCommand, loginCommand, logoutCommand, wizardCommand, };