@interf/compiler 0.9.4 → 0.9.5

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 (103) hide show
  1. package/CHANGELOG.md +93 -0
  2. package/README.md +2 -1
  3. package/agent-skills/interf-actions/SKILL.md +17 -11
  4. package/agent-skills/interf-actions/references/cli.md +8 -22
  5. package/dist/cli/commands/action-input-cli.d.ts +25 -0
  6. package/dist/cli/commands/action-input-cli.js +73 -0
  7. package/dist/cli/commands/compile.d.ts +3 -8
  8. package/dist/cli/commands/compile.js +13 -41
  9. package/dist/cli/commands/create-method-wizard.d.ts +0 -12
  10. package/dist/cli/commands/create-method-wizard.js +95 -126
  11. package/dist/cli/commands/create.d.ts +0 -2
  12. package/dist/cli/commands/create.js +16 -22
  13. package/dist/cli/commands/doctor.js +1 -1
  14. package/dist/cli/commands/executor-flow.js +1 -1
  15. package/dist/cli/commands/init.d.ts +16 -1
  16. package/dist/cli/commands/init.js +40 -53
  17. package/dist/cli/commands/list.js +1 -1
  18. package/dist/cli/commands/preparation-action.d.ts +8 -0
  19. package/dist/cli/commands/preparation-action.js +29 -0
  20. package/dist/cli/commands/preparation-picker.d.ts +5 -0
  21. package/dist/cli/commands/preparation-picker.js +36 -0
  22. package/dist/cli/commands/preparation-selection.js +2 -2
  23. package/dist/cli/commands/reset.js +15 -4
  24. package/dist/cli/commands/service-action-flow.d.ts +9 -0
  25. package/dist/cli/commands/service-action-flow.js +19 -0
  26. package/dist/cli/commands/source-config-wizard.d.ts +0 -1
  27. package/dist/cli/commands/source-config-wizard.js +43 -53
  28. package/dist/cli/commands/status.js +7 -123
  29. package/dist/cli/commands/test.d.ts +1 -2
  30. package/dist/cli/commands/test.js +40 -203
  31. package/dist/cli/commands/web.js +8 -262
  32. package/dist/compiler-ui/404.html +1 -1
  33. package/dist/compiler-ui/__next.__PAGE__.txt +2 -2
  34. package/dist/compiler-ui/__next._full.txt +3 -3
  35. package/dist/compiler-ui/__next._head.txt +1 -1
  36. package/dist/compiler-ui/__next._index.txt +2 -2
  37. package/dist/compiler-ui/__next._tree.txt +2 -2
  38. package/dist/compiler-ui/_next/static/chunks/177mvn4rse235.js +89 -0
  39. package/dist/compiler-ui/_next/static/chunks/18a8f2jkv3z.c.css +3 -0
  40. package/dist/compiler-ui/_not-found/__next._full.txt +2 -2
  41. package/dist/compiler-ui/_not-found/__next._head.txt +1 -1
  42. package/dist/compiler-ui/_not-found/__next._index.txt +2 -2
  43. package/dist/compiler-ui/_not-found/__next._not-found.__PAGE__.txt +1 -1
  44. package/dist/compiler-ui/_not-found/__next._not-found.txt +1 -1
  45. package/dist/compiler-ui/_not-found/__next._tree.txt +2 -2
  46. package/dist/compiler-ui/_not-found.html +1 -1
  47. package/dist/compiler-ui/_not-found.txt +2 -2
  48. package/dist/compiler-ui/index.html +1 -1
  49. package/dist/compiler-ui/index.txt +3 -3
  50. package/dist/index.d.ts +0 -23
  51. package/dist/index.js +0 -16
  52. package/dist/packages/agents/lib/shells.js +2 -2
  53. package/dist/packages/compiler/lib/schema.d.ts +1 -1
  54. package/dist/packages/compiler/lib/schema.js +1 -1
  55. package/dist/packages/contracts/lib/schema.d.ts +0 -1
  56. package/dist/packages/contracts/lib/schema.js +0 -1
  57. package/dist/packages/execution/lib/schema.d.ts +0 -7
  58. package/dist/packages/execution/lib/schema.js +0 -1
  59. package/dist/packages/local-service/action-definitions.d.ts +246 -0
  60. package/dist/packages/local-service/action-definitions.js +1148 -0
  61. package/dist/packages/local-service/action-planner.d.ts +9 -0
  62. package/dist/packages/local-service/action-planner.js +134 -0
  63. package/dist/packages/local-service/action-values.d.ts +1 -23
  64. package/dist/packages/local-service/action-values.js +1 -31
  65. package/dist/packages/local-service/client.d.ts +48 -17
  66. package/dist/packages/local-service/client.js +95 -52
  67. package/dist/packages/local-service/index.d.ts +8 -5
  68. package/dist/packages/local-service/index.js +5 -3
  69. package/dist/packages/local-service/lib/schema.d.ts +301 -295
  70. package/dist/packages/local-service/lib/schema.js +114 -39
  71. package/dist/packages/local-service/native-run-handlers.d.ts +23 -0
  72. package/dist/{cli/commands/compile-controller.js → packages/local-service/native-run-handlers.js} +203 -19
  73. package/dist/{cli/commands/check-draft.d.ts → packages/local-service/readiness-check-draft.d.ts} +2 -2
  74. package/dist/packages/local-service/routes.d.ts +6 -1
  75. package/dist/packages/local-service/routes.js +7 -2
  76. package/dist/packages/local-service/run-observability.js +15 -17
  77. package/dist/packages/local-service/runtime.d.ts +10 -7
  78. package/dist/packages/local-service/runtime.js +427 -297
  79. package/dist/packages/local-service/server.js +94 -44
  80. package/dist/packages/method-package/method-review-paths.d.ts +1 -1
  81. package/dist/packages/method-package/method-review-paths.js +5 -5
  82. package/dist/packages/project-model/index.d.ts +1 -0
  83. package/dist/packages/project-model/index.js +1 -0
  84. package/dist/packages/project-model/preparation-entries.d.ts +11 -0
  85. package/dist/packages/project-model/preparation-entries.js +49 -0
  86. package/dist/packages/project-model/source-config.d.ts +1 -0
  87. package/dist/packages/project-model/source-config.js +12 -1
  88. package/dist/packages/testing/lib/schema.d.ts +2 -3
  89. package/dist/packages/testing/lib/schema.js +2 -3
  90. package/dist/packages/testing/readiness-check-run.d.ts +3 -3
  91. package/dist/packages/testing/readiness-check-run.js +12 -17
  92. package/package.json +5 -24
  93. package/dist/cli/commands/compile-controller.d.ts +0 -17
  94. package/dist/cli/commands/compiled-flow.d.ts +0 -25
  95. package/dist/cli/commands/compiled-flow.js +0 -112
  96. package/dist/cli/commands/test-flow.d.ts +0 -58
  97. package/dist/cli/commands/test-flow.js +0 -231
  98. package/dist/compiler-ui/_next/static/chunks/0d~8t0zm6545p.js +0 -118
  99. package/dist/compiler-ui/_next/static/chunks/0xnel.ax9a.2c.css +0 -3
  100. /package/dist/compiler-ui/_next/static/{j7pdoqWrl4YJrJUVnksbl → 84FaeF3EzBF9kKTMjSEVN}/_buildManifest.js +0 -0
  101. /package/dist/compiler-ui/_next/static/{j7pdoqWrl4YJrJUVnksbl → 84FaeF3EzBF9kKTMjSEVN}/_clientMiddlewareManifest.js +0 -0
  102. /package/dist/compiler-ui/_next/static/{j7pdoqWrl4YJrJUVnksbl → 84FaeF3EzBF9kKTMjSEVN}/_ssgManifest.js +0 -0
  103. /package/dist/{cli/commands/check-draft.js → packages/local-service/readiness-check-draft.js} +0 -0
@@ -1,4 +1,4 @@
1
- import { existsSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync, } from "node:fs";
1
+ import { existsSync, mkdirSync, readdirSync, readFileSync, rmSync, statSync, writeFileSync, } from "node:fs";
2
2
  import { dirname, join, resolve } from "node:path";
3
3
  import { CompileRunSchema, } from "../execution/lib/schema.js";
4
4
  import { createRunEventId, createRunEventTimestamp, } from "../execution/events.js";
@@ -7,18 +7,21 @@ import { loadState, } from "../compiler/state.js";
7
7
  import { RuntimeRunSchema, } from "../compiler/lib/schema.js";
8
8
  import { ReadinessStateSchema, } from "../contracts/lib/schema.js";
9
9
  import { discoverSourceFiles, } from "../compiler/discovery.js";
10
+ import { resetCompiledGeneratedState, } from "../compiler/reset.js";
10
11
  import { ensurePortableContextScaffold, readInterfConfig, } from "../project-model/interf.js";
11
- import { findSourcePreparationConfig, fingerprintReadinessChecks, listSourcePreparationConfigs, loadSourceFolderConfig, DEFAULT_METHOD_ID, methodIdForSourcePreparationConfig, resolveConfiguredSourceFolderPath, resolveSourcePreparationPath, syncCompiledInterfConfigFromSourcePreparationConfig, upsertSourcePreparationConfig, } from "../project-model/source-config.js";
12
- import { defaultPreparationNameForPath, listSourceFolderChoices, normalizeSourcePreparationPathForConfig, } from "../project-model/source-folders.js";
12
+ import { findSourcePreparationConfig, fingerprintReadinessChecks, listSourcePreparationConfigs, loadSourceFolderConfig, DEFAULT_METHOD_ID, methodIdForSourcePreparationConfig, resolveConfiguredSourceFolderPath, resolveSourcePreparationPath, removeSourcePreparationConfig, saveSourceFolderConfig, syncCompiledInterfConfigFromSourcePreparationConfig, upsertSourcePreparationConfig, } from "../project-model/source-config.js";
13
+ import { listSourceFolderChoices, } from "../project-model/source-folders.js";
13
14
  import { portableContextPath, } from "../project-model/project-paths.js";
14
15
  import { getCompiledMethod, listCompiledMethodChoices, } from "../method-package/method-definitions.js";
15
- import { resolveMethodPackageSourcePath, } from "../method-package/local-methods.js";
16
+ import { contextInterfaceArtifactPath, } from "../method-package/context-interface.js";
17
+ import { methodDefinitionPath, resolveMethodPackageSourcePath, } from "../method-package/local-methods.js";
18
+ import { seedLocalMethodPackageFromBase, } from "../method-package/interf-method-package.js";
16
19
  import { resolveAgent, detectAgents, supportsAutomatedRuns, } from "../agents/lib/detection.js";
17
20
  import { AGENTS, } from "../agents/lib/constants.js";
18
21
  import { loadUserConfig, saveUserConfig, } from "../agents/lib/user-config.js";
19
22
  import { readSavedReadinessCheckRun, } from "../testing/readiness-check-run.js";
20
23
  import { createCompiledTestTarget, } from "../testing/test-targets.js";
21
- import { ActionProposalApprovalRequestSchema, ActionProposalCreateRequestSchema, ActionProposalPlanSchema, ActionProposalResourceSchema, CompileRunCreateRequestSchema, CompileRunResourceSchema, MethodResourceSchema, LocalExecutorStatusSchema, LocalExecutorSelectRequestSchema, LocalServiceHealthSchema, PreparationReadinessStateSchema, LocalRunHandlerResultSchema, LocalJobEventAppendRequestSchema, LocalJobRunCreateRequestSchema, LocalJobRunResourceSchema, SourceFileResourceSchema, WorkspaceFileResourceSchema, PortableContextResourceSchema, PreparationSetupCreateRequestSchema, PreparationResourceSchema, ReadinessCheckDraftCreateRequestSchema, ReadinessCheckDraftResultSchema, TestRunCreateRequestSchema, TestRunResourceSchema, MethodAuthoringCreateRequestSchema, MethodAuthoringResultSchema, } from "./lib/schema.js";
24
+ import { ActionProposalApprovalRequestSchema, ActionProposalCreateRequestSchema, ActionProposalPlanSchema, ActionProposalResourceSchema, ActionProposalPlanActionTypeSchema, ActionProposalTypeSchema, CompileRunCreateRequestSchema, CompileRunResourceSchema, MethodResourceSchema, LocalExecutorStatusSchema, LocalExecutorSelectRequestSchema, LocalServiceHealthSchema, PreparationReadinessStateSchema, LocalRunHandlerResultSchema, LocalJobEventAppendRequestSchema, LocalJobRunCreateRequestSchema, LocalJobRunResourceSchema, SourceFileResourceSchema, WorkspaceFileResourceSchema, PortableContextResourceSchema, PreparationSetupCreateRequestSchema, PreparationSetupResultSchema, PreparationResourceSchema, MethodChangeCreateRequestSchema, MethodChangeResultSchema, PreparationChangeCreateRequestSchema, PreparationChangeResultSchema, ReadinessCheckDraftCreateRequestSchema, ReadinessCheckDraftResultSchema, ResetRequestSchema, ResetResultSchema, TestRunCreateRequestSchema, TestRunResourceSchema, MethodAuthoringCreateRequestSchema, MethodAuthoringResultSchema, } from "./lib/schema.js";
22
25
  import { buildLocalServiceUrl, } from "./routes.js";
23
26
  import { methodAuthoringTaskPrompt, MethodAuthoringActionValuesSchema, PreparationSetupActionValuesSchema, } from "./action-values.js";
24
27
  import { compileRunToObservability, jobRunToObservability, testRunToObservability, uniqueArtifacts, } from "./run-observability.js";
@@ -317,6 +320,12 @@ function applyEventToCompileRun(run, event) {
317
320
  finished_at: run.finished_at ?? now,
318
321
  events: [...run.events, event],
319
322
  };
323
+ case "readiness.updated":
324
+ return {
325
+ ...run,
326
+ readiness: event.readiness,
327
+ events: [...run.events, event],
328
+ };
320
329
  default:
321
330
  break;
322
331
  }
@@ -409,10 +418,46 @@ function slugFromText(value) {
409
418
  .replace(/-+$/g, "");
410
419
  return slug || "custom";
411
420
  }
421
+ function escapeRegExp(value) {
422
+ return value.replace(/[.*+?^${}()|[\]\\]/g, "\\$&");
423
+ }
412
424
  function stringValue(values, key) {
413
425
  const value = values?.[key];
414
426
  return typeof value === "string" && value.trim().length > 0 ? value.trim() : null;
415
427
  }
428
+ function actionTypeFromValues(values) {
429
+ const explicit = stringValue(values, "action_type") ?? stringValue(values, "service_action");
430
+ if (explicit) {
431
+ const parsed = ActionProposalPlanActionTypeSchema.safeParse(explicit);
432
+ if (parsed.success && parsed.data !== "clarification")
433
+ return parsed.data;
434
+ }
435
+ const action = stringValue(values, "action");
436
+ if (action === "compile" || action === "prepare-run" || action === "run-preparation")
437
+ return "compile";
438
+ if (action === "test" || action === "check-readiness")
439
+ return "test";
440
+ if (action === "draft-readiness-checks" || action === "readiness-check-draft")
441
+ return "readiness-check-draft";
442
+ if (action === "create-method" || action === "method-authoring")
443
+ return "method-authoring";
444
+ if (action === "method-duplicate" || action === "method-remove" || action === "method-change")
445
+ return "method-change";
446
+ if (action === "preparation-remove" || action === "preparation-change")
447
+ return "preparation-change";
448
+ if (action === "improve-preparation" || action === "method-improvement")
449
+ return "method-improvement";
450
+ return null;
451
+ }
452
+ function directServiceEndpointForAction(actionType) {
453
+ if (actionType === "preparation-setup")
454
+ return "/v1/preparation-setups";
455
+ if (actionType === "method-change")
456
+ return "/v1/method-changes";
457
+ if (actionType === "preparation-change")
458
+ return "/v1/preparation-changes";
459
+ return null;
460
+ }
416
461
  function numberValue(values, key) {
417
462
  const value = values?.[key];
418
463
  return typeof value === "number" && Number.isFinite(value) ? value : null;
@@ -438,49 +483,88 @@ function testModeCliTarget(mode) {
438
483
  function methodIdForProposal(message, values) {
439
484
  const explicit = stringValue(values, "method_id") ??
440
485
  stringValue(values, "method");
441
- return explicit ?? `custom-${slugFromText(message)}`;
486
+ const fromMessage = message.match(/\b(?:create|reate|eate|draft|author|build|make)\s+(?:a\s+new\s+)?(?:interf\s+)?method\s+([a-z0-9][a-z0-9-]{0,79})\b/i)?.[1];
487
+ return explicit ?? fromMessage ?? `custom-${slugFromText(message)}`;
442
488
  }
443
489
  function actionValueMethodTaskPrompt(values) {
444
490
  const parsed = MethodAuthoringActionValuesSchema.safeParse(values);
445
491
  return parsed.success ? methodAuthoringTaskPrompt(parsed.data) : null;
446
492
  }
447
- function booleanValue(values, key) {
448
- const value = values?.[key];
449
- if (typeof value === "boolean")
450
- return value;
451
- if (typeof value === "string") {
452
- const normalized = value.trim().toLowerCase();
453
- if (normalized === "true" || normalized === "yes" || normalized === "1")
454
- return true;
455
- if (normalized === "false" || normalized === "no" || normalized === "0")
456
- return false;
457
- }
458
- return null;
493
+ const METHOD_AUTHORING_INTERNAL_INSTRUCTION = /Use the attached values as the Method authoring request before proposing the action\.?/gi;
494
+ const METHOD_AUTHORING_LABELS = [
495
+ "Agent work",
496
+ "Portable-context output",
497
+ "Readiness checks",
498
+ "CLI preview",
499
+ ];
500
+ function normalizeMethodAuthoringText(value) {
501
+ return value
502
+ .replace(/[│]+/g, " ")
503
+ .replace(METHOD_AUTHORING_INTERNAL_INSTRUCTION, " ")
504
+ .replace(/\s+/g, " ")
505
+ .trim();
506
+ }
507
+ function extractMethodAuthoringSection(value, label) {
508
+ const otherLabels = METHOD_AUTHORING_LABELS
509
+ .filter((candidate) => candidate !== label)
510
+ .map(escapeRegExp)
511
+ .join("|");
512
+ const match = value.match(new RegExp(`${escapeRegExp(label)}\\s*:\\s*([\\s\\S]*?)(?=\\s*(?:${otherLabels})\\s*:|$)`, "i"));
513
+ return match?.[1] ? normalizeMethodAuthoringText(match[1]) : null;
514
+ }
515
+ function stripMethodCommandPrefix(value, methodId) {
516
+ const specific = new RegExp(`^(?:create|reate|eate|draft|author|build|make)\\s+(?:a\\s+new\\s+)?(?:interf\\s+)?method\\s+${escapeRegExp(methodId)}\\.?\\s*`, "i");
517
+ const generic = /^(?:create|reate|eate|draft|author|build|make)\s+(?:a\s+new\s+)?(?:interf\s+)?method\b[^.]{0,180}\.\s*/i;
518
+ const stripped = normalizeMethodAuthoringText(value)
519
+ .replace(specific, "")
520
+ .replace(generic, "")
521
+ .trim();
522
+ return stripped || normalizeMethodAuthoringText(value);
459
523
  }
460
- function preparationSetupPathValue(values) {
461
- return stringValue(values, "path") ??
462
- stringValue(values, "source_folder_path") ??
463
- stringValue(values, "source_path") ??
464
- stringValue(values, "source_folder") ??
465
- stringValue(values, "folder");
524
+ function methodAuthoringPromptFallback(message, methodId) {
525
+ const cleaned = message
526
+ .replace(/[│]+/g, " ")
527
+ .replace(METHOD_AUTHORING_INTERNAL_INSTRUCTION, " ")
528
+ .trim();
529
+ const agentWork = extractMethodAuthoringSection(cleaned, "Agent work");
530
+ const portableOutput = extractMethodAuthoringSection(cleaned, "Portable-context output");
531
+ const readinessNotes = extractMethodAuthoringSection(cleaned, "Readiness checks");
532
+ const lines = [
533
+ agentWork ? `Agent work: ${stripMethodCommandPrefix(agentWork, methodId)}` : null,
534
+ portableOutput ? `Portable-context output: ${portableOutput}` : null,
535
+ readinessNotes ? `Readiness checks: ${readinessNotes}` : null,
536
+ ].filter((line) => Boolean(line));
537
+ if (lines.length > 0)
538
+ return lines.join("\n");
539
+ return stripMethodCommandPrefix(cleaned, methodId);
466
540
  }
467
- function preparationSetupNameValue(values) {
468
- const parsed = PreparationSetupActionValuesSchema.safeParse(values);
469
- return parsed.success ? parsed.data.name : stringValue(values, "name") ??
470
- stringValue(values, "preparation") ??
471
- stringValue(values, "preparation_name");
541
+ function methodAuthoringHintFromPrompt(prompt) {
542
+ const plain = normalizeMethodAuthoringText(prompt.replace(/\b(?:Agent work|Portable-context output|Readiness checks)\s*:/gi, " "));
543
+ if (plain.length <= 180)
544
+ return plain || "Custom Method";
545
+ const clipped = plain.slice(0, 177).replace(/\s+\S*$/, "").trim();
546
+ return `${clipped || plain.slice(0, 177)}...`;
547
+ }
548
+ function methodLabelFromId(methodId) {
549
+ return methodId
550
+ .split("-")
551
+ .filter(Boolean)
552
+ .map((part) => `${part.slice(0, 1).toUpperCase()}${part.slice(1)}`)
553
+ .join(" ") || methodId;
554
+ }
555
+ function detachMethodFromPreparation(preparation, methodId) {
556
+ if (methodIdForSourcePreparationConfig(preparation) !== methodId)
557
+ return preparation;
558
+ const { method: _removedMethod, ...detachedPreparation } = preparation;
559
+ return detachedPreparation;
560
+ }
561
+ function requireSelectedMethod(preparation) {
562
+ const methodId = methodIdForSourcePreparationConfig(preparation);
563
+ if (methodId)
564
+ return methodId;
565
+ throw new Error(`Select a Method for Preparation "${preparation.name}" before preparing it.`);
472
566
  }
473
567
  function actionCommandPreview(actionType, preparationName, methodId, values) {
474
- if (actionType === "preparation-setup") {
475
- const preparationPart = preparationName ? ` # Preparation: ${preparationName}` : "";
476
- const pathPart = preparationSetupPathValue(values);
477
- const methodSuffix = methodId ? ` # Method: ${methodId}` : "";
478
- const setupPreview = pathPart ? `interf init # source: ${pathPart}${preparationPart}` : `interf init${preparationPart}`;
479
- if (booleanValue(values, "prepare_after_setup") && preparationName) {
480
- return `${setupPreview}\ninterf compile --preparation ${preparationName}${methodSuffix}`;
481
- }
482
- return setupPreview;
483
- }
484
568
  if (actionType === "compile") {
485
569
  const methodSuffix = methodId ? ` # Method: ${methodId}` : "";
486
570
  return preparationName
@@ -507,14 +591,8 @@ function hasCompiledTestTarget(sourcePath, preparationConfig) {
507
591
  return false;
508
592
  return createCompiledTestTarget(compiledPath, preparationConfig.name, methodIdForSourcePreparationConfig(preparationConfig) ?? DEFAULT_METHOD_ID).eligible;
509
593
  }
510
- function actionAssistantMessage(actionType, preparationName, commandPreview, options = {}) {
594
+ function actionAssistantMessage(actionType, preparationName, commandPreview) {
511
595
  const preparationSuffix = preparationName ? ` for Preparation "${preparationName}"` : "";
512
- if (actionType === "preparation-setup") {
513
- if (options.prepareAfterSetup) {
514
- return `Interf prepared a prepare proposal${preparationSuffix}. Approve to save the Preparation and run the selected Method against the Source Folder. CLI equivalent: ${commandPreview}`;
515
- }
516
- return `Interf prepared a Preparation setup proposal${preparationSuffix}. Approve to save the source folder as a Preparation. Preparing portable context is a separate compile run. CLI equivalent: ${commandPreview}`;
517
- }
518
596
  if (actionType === "compile") {
519
597
  return `Interf prepared a prepare-run proposal${preparationSuffix}. Approve to submit it through the local Interf service and watch the run in Interf. CLI equivalent: ${commandPreview}`;
520
598
  }
@@ -522,7 +600,7 @@ function actionAssistantMessage(actionType, preparationName, commandPreview, opt
522
600
  return `Interf prepared a readiness-check proposal${preparationSuffix}. Approve to run the requested target against saved readiness checks. CLI equivalent: ${commandPreview}`;
523
601
  }
524
602
  if (actionType === "readiness-check-draft") {
525
- return `Interf prepared a readiness-check draft proposal${preparationSuffix}. Approve to ask the configured local executor to draft checks as a visible run. CLI equivalent: ${commandPreview}`;
603
+ return `Interf prepared a proposal to draft readiness checks${preparationSuffix}. Approve to ask the configured local executor to draft saved checks as a visible run. CLI equivalent: ${commandPreview}`;
526
604
  }
527
605
  if (actionType === "method-authoring" || actionType === "method-improvement") {
528
606
  return `Interf prepared a Method draft proposal${preparationSuffix}. Approve to draft a reusable local Method as a visible run. CLI equivalent: ${commandPreview}`;
@@ -534,10 +612,10 @@ function passRate(passed, total) {
534
612
  return null;
535
613
  return Math.round((passed / total) * 100);
536
614
  }
537
- function readinessTargetResult(summary, currentFingerprint, comparisonFingerprint) {
615
+ function readinessTargetResult(summary, currentFingerprint, readinessRunFingerprint) {
538
616
  if (!summary)
539
617
  return null;
540
- const resultFingerprint = comparisonFingerprint ?? null;
618
+ const resultFingerprint = readinessRunFingerprint ?? null;
541
619
  return {
542
620
  passed: summary.passed_cases,
543
621
  total: summary.total_cases,
@@ -610,6 +688,7 @@ function buildMethodResource(resource) {
610
688
  source_kind: resource.source_kind,
611
689
  built_in: resource.built_in,
612
690
  active_for_preparations: resource.active_for_preparations,
691
+ output_paths: resource.output_paths,
613
692
  stages: resource.stages,
614
693
  });
615
694
  }
@@ -678,13 +757,13 @@ export class LocalServiceRuntime {
678
757
  const contextReady = compiledTarget.eligible;
679
758
  const compileRun = this.listCompileRunsForPreparation(preparation.name)[0] ?? null;
680
759
  const testRun = this.listTestRunsForPreparation(preparation.name)[0] ?? null;
681
- const comparison = this.readLatestComparison(preparation.name);
760
+ const readinessRun = this.readLatestReadinessRun(preparation.name);
682
761
  const configuredChecks = preparation.checks.length;
683
762
  const currentFingerprint = configuredChecks > 0 ? fingerprintReadinessChecks(preparation.checks) : null;
684
- const comparisonFingerprint = comparison?.checks_fingerprint ?? null;
685
- const sourceResult = readinessTargetResult(comparison?.raw, currentFingerprint, comparisonFingerprint);
686
- const contextResult = readinessTargetResult(comparison?.compiled, currentFingerprint, comparisonFingerprint);
687
- const checksStale = Boolean(currentFingerprint && comparisonFingerprint && currentFingerprint !== comparisonFingerprint);
763
+ const readinessRunFingerprint = readinessRun?.checks_fingerprint ?? null;
764
+ const sourceResult = readinessTargetResult(readinessRun?.raw, currentFingerprint, readinessRunFingerprint);
765
+ const contextResult = readinessTargetResult(readinessRun?.compiled, currentFingerprint, readinessRunFingerprint);
766
+ const checksStale = Boolean(currentFingerprint && readinessRunFingerprint && currentFingerprint !== readinessRunFingerprint);
688
767
  const compileCheck = (() => {
689
768
  if (!compileRun) {
690
769
  return {
@@ -796,7 +875,6 @@ export class LocalServiceRuntime {
796
875
  fingerprint: currentFingerprint,
797
876
  source_files: sourceResult,
798
877
  portable_context: contextResult,
799
- delta: comparison?.summary.pass_rate_delta ?? null,
800
878
  },
801
879
  checks,
802
880
  });
@@ -859,7 +937,7 @@ export class LocalServiceRuntime {
859
937
  const choices = listCompiledMethodChoices(this.rootPath);
860
938
  return choices.map((method) => {
861
939
  const activeForPreparations = preparations
862
- .filter((preparation) => (methodIdForSourcePreparationConfig(preparation) ?? DEFAULT_METHOD_ID) === method.id)
940
+ .filter((preparation) => methodIdForSourcePreparationConfig(preparation) === method.id)
863
941
  .map((preparation) => preparation.name);
864
942
  return buildMethodResource({
865
943
  id: method.id,
@@ -869,6 +947,10 @@ export class LocalServiceRuntime {
869
947
  source_kind: method.scope === "builtin" ? "builtin" : "local",
870
948
  built_in: method.scope === "builtin",
871
949
  active_for_preparations: activeForPreparations,
950
+ output_paths: (method.contextInterface?.zones ?? [])
951
+ .filter((zone) => zone.role === "output")
952
+ .map((zone) => contextInterfaceArtifactPath(zone))
953
+ .sort(),
872
954
  stages: method.stages.map((stage) => ({
873
955
  id: stage.id,
874
956
  label: stage.label,
@@ -974,7 +1056,10 @@ export class LocalServiceRuntime {
974
1056
  }
975
1057
  async createActionProposal(requestValue) {
976
1058
  const request = ActionProposalCreateRequestSchema.parse(requestValue);
977
- const proposal = await this.buildActionProposal(request);
1059
+ const proposal = ActionProposalResourceSchema.parse({
1060
+ ...(await this.buildActionProposal(request)),
1061
+ client_origin: request.client_origin,
1062
+ });
978
1063
  this.writeActionProposal(proposal);
979
1064
  return proposal;
980
1065
  }
@@ -1134,7 +1219,7 @@ export class LocalServiceRuntime {
1134
1219
  this.appendJobRunEvent(job.run_id, {
1135
1220
  type: "step.completed",
1136
1221
  step_id: "read-source",
1137
- message: "Source folder is ready for readiness-check drafting.",
1222
+ message: "Source folder is ready for drafting readiness checks.",
1138
1223
  output: {
1139
1224
  preparation: request.preparation,
1140
1225
  source_folder_path: request.source_folder_path,
@@ -1152,114 +1237,146 @@ export class LocalServiceRuntime {
1152
1237
  void this.runReadinessCheckDraftInBackground(request, job.run_id);
1153
1238
  return this.getJob(job.run_id) ?? job;
1154
1239
  }
1155
- async createPreparationSetupRun(requestValue) {
1240
+ applyMethodChange(requestValue) {
1241
+ const request = MethodChangeCreateRequestSchema.parse(requestValue);
1242
+ const outputPath = request.operation === "duplicate"
1243
+ ? methodDefinitionPath(this.rootPath, request.new_method_id)
1244
+ : methodDefinitionPath(this.rootPath, request.method);
1245
+ if (request.operation === "duplicate") {
1246
+ if (resolveMethodPackageSourcePath(this.rootPath, request.new_method_id)) {
1247
+ throw new Error(`Method "${request.new_method_id}" already exists.`);
1248
+ }
1249
+ if (!resolveMethodPackageSourcePath(this.rootPath, request.method)) {
1250
+ throw new Error(`Method "${request.method}" does not exist.`);
1251
+ }
1252
+ const label = request.label ?? methodLabelFromId(request.new_method_id);
1253
+ const hint = request.hint ?? `Duplicate of ${request.method}`;
1254
+ const methodPath = seedLocalMethodPackageFromBase({
1255
+ sourcePath: this.rootPath,
1256
+ baseMethodId: request.method,
1257
+ methodId: request.new_method_id,
1258
+ label,
1259
+ hint,
1260
+ });
1261
+ return MethodChangeResultSchema.parse({
1262
+ kind: "interf-method-change-result",
1263
+ version: 1,
1264
+ operation: "duplicate",
1265
+ method: request.method,
1266
+ new_method_id: request.new_method_id,
1267
+ updated_preparations: [],
1268
+ method_path: methodPath,
1269
+ changed: true,
1270
+ message: `Duplicated Method ${request.method} as ${request.new_method_id}.`,
1271
+ });
1272
+ }
1273
+ if (request.confirmation !== request.method) {
1274
+ throw new Error(`Type ${request.method} to confirm Method removal.`);
1275
+ }
1276
+ const localMethodPath = methodDefinitionPath(this.rootPath, request.method);
1277
+ if (request.method === DEFAULT_METHOD_ID || !existsSync(localMethodPath)) {
1278
+ throw new Error(`Method "${request.method}" is not a removable local Method.`);
1279
+ }
1280
+ const preparations = listSourcePreparationConfigs(loadSourceFolderConfig(this.rootPath));
1281
+ const updatedPreparations = preparations
1282
+ .filter((preparation) => methodIdForSourcePreparationConfig(preparation) === request.method);
1283
+ if (updatedPreparations.length > 0) {
1284
+ saveSourceFolderConfig(this.rootPath, {
1285
+ preparations: preparations.map((preparation) => detachMethodFromPreparation(preparation, request.method)),
1286
+ });
1287
+ }
1288
+ rmSync(outputPath, { recursive: true, force: true });
1289
+ return MethodChangeResultSchema.parse({
1290
+ kind: "interf-method-change-result",
1291
+ version: 1,
1292
+ operation: "remove",
1293
+ method: request.method,
1294
+ updated_preparations: updatedPreparations.map((preparation) => preparation.name),
1295
+ method_path: outputPath,
1296
+ changed: true,
1297
+ message: updatedPreparations.length > 0
1298
+ ? `Removed Method ${request.method} and cleared it from ${updatedPreparations.length} Preparation(s).`
1299
+ : `Removed Method ${request.method}.`,
1300
+ });
1301
+ }
1302
+ applyPreparationSetup(requestValue) {
1156
1303
  const request = PreparationSetupCreateRequestSchema.parse(requestValue);
1157
1304
  const preparationConfig = request.preparation;
1158
- const methodId = methodIdForSourcePreparationConfig(preparationConfig) ?? "interf-default";
1305
+ const methodId = methodIdForSourcePreparationConfig(preparationConfig) ?? DEFAULT_METHOD_ID;
1159
1306
  const normalizedPreparationConfig = {
1160
1307
  ...preparationConfig,
1161
1308
  method: methodId,
1162
1309
  };
1163
- const sourceFolderPath = resolveSourcePreparationPath(this.rootPath, preparationConfig);
1164
- const job = this.createJobRun({
1165
- job_type: "preparation-setup",
1166
- title: `Create Preparation ${preparationConfig.name}`,
1167
- preparation: preparationConfig.name,
1310
+ const sourceFolderPath = resolveSourcePreparationPath(this.rootPath, normalizedPreparationConfig);
1311
+ if (!existsSync(sourceFolderPath) || !statSync(sourceFolderPath).isDirectory()) {
1312
+ throw new Error(`Source folder "${preparationConfig.path}" is not available.`);
1313
+ }
1314
+ upsertSourcePreparationConfig(this.rootPath, normalizedPreparationConfig);
1315
+ const operation = request.setup_mode === "select-method" ? "select-method" : "create";
1316
+ return PreparationSetupResultSchema.parse({
1317
+ kind: "interf-preparation-setup-result",
1318
+ version: 1,
1319
+ operation,
1320
+ preparation: normalizedPreparationConfig.name,
1168
1321
  method: methodId,
1169
- source_path: sourceFolderPath,
1170
- agent: this.getExecutorStatus().executor,
1171
- steps: [
1172
- {
1173
- id: "validate-source",
1174
- label: "Validate source folder",
1175
- input: {
1176
- preparation: preparationConfig.name,
1177
- path: preparationConfig.path,
1178
- },
1179
- },
1180
- {
1181
- id: "write-config",
1182
- label: "Save Preparation config",
1183
- input: {
1184
- config_path: join(this.rootPath, "interf", "interf.json"),
1185
- },
1186
- },
1187
- ],
1322
+ source_folder_path: sourceFolderPath,
1323
+ config_path: join(this.rootPath, "interf", "interf.json"),
1324
+ portable_context_path: portableContextPath(this.rootPath, normalizedPreparationConfig.name),
1325
+ changed: true,
1326
+ message: operation === "select-method"
1327
+ ? `Preparation ${normalizedPreparationConfig.name} now uses Method ${methodId}.`
1328
+ : `Preparation ${normalizedPreparationConfig.name} is saved.`,
1188
1329
  });
1189
- let activeStep = "validate-source";
1190
- try {
1191
- this.appendJobRunEvent(job.run_id, {
1192
- type: "step.started",
1193
- step_id: "validate-source",
1194
- message: "Validating source folder.",
1195
- input: {
1196
- path: preparationConfig.path,
1197
- source_folder_path: sourceFolderPath,
1198
- },
1199
- });
1200
- if (!existsSync(sourceFolderPath) || !statSync(sourceFolderPath).isDirectory()) {
1201
- throw new Error(`Source folder "${preparationConfig.path}" is not available.`);
1202
- }
1203
- this.appendJobRunEvent(job.run_id, {
1204
- type: "step.completed",
1205
- step_id: "validate-source",
1206
- message: "Source folder is available.",
1207
- output: {
1208
- source_folder_path: sourceFolderPath,
1209
- },
1210
- });
1211
- activeStep = "write-config";
1212
- this.appendJobRunEvent(job.run_id, {
1213
- type: "step.started",
1214
- step_id: "write-config",
1215
- message: "Saving Preparation in the control plane config.",
1216
- input: {
1217
- preparation: preparationConfig.name,
1218
- path: preparationConfig.path,
1219
- },
1220
- });
1221
- upsertSourcePreparationConfig(this.rootPath, normalizedPreparationConfig);
1222
- this.appendJobRunEvent(job.run_id, {
1223
- type: "step.completed",
1224
- step_id: "write-config",
1225
- message: "Preparation config saved.",
1226
- output: {
1227
- config_path: join(this.rootPath, "interf", "interf.json"),
1228
- preparation: preparationConfig.name,
1229
- },
1230
- });
1231
- this.setJobRunResult(job.run_id, {
1232
- preparation: normalizedPreparationConfig,
1233
- source_folder_path: sourceFolderPath,
1234
- config_path: join(this.rootPath, "interf", "interf.json"),
1235
- });
1236
- this.appendJobRunEvent(job.run_id, {
1237
- type: "job.completed",
1238
- message: `Preparation ${preparationConfig.name} is saved. Run prepare to build portable context.`,
1239
- });
1330
+ }
1331
+ applyPreparationChange(requestValue) {
1332
+ const request = PreparationChangeCreateRequestSchema.parse(requestValue);
1333
+ if (request.confirmation !== request.preparation) {
1334
+ throw new Error(`Type ${request.preparation} to confirm Preparation removal.`);
1240
1335
  }
1241
- catch (error) {
1242
- const message = error instanceof Error ? error.message : String(error);
1243
- this.appendJobRunEvent(job.run_id, {
1244
- type: "step.failed",
1245
- step_id: activeStep,
1246
- message,
1247
- output: {
1248
- error: message,
1249
- },
1250
- });
1251
- this.appendJobRunEvent(job.run_id, {
1252
- type: "job.failed",
1253
- message,
1254
- });
1336
+ const preparation = findSourcePreparationConfig(loadSourceFolderConfig(this.rootPath), request.preparation);
1337
+ if (!preparation) {
1338
+ throw new Error(`Preparation "${request.preparation}" is not saved.`);
1255
1339
  }
1256
- return this.getJob(job.run_id) ?? job;
1340
+ removeSourcePreparationConfig(this.rootPath, request.preparation);
1341
+ return PreparationChangeResultSchema.parse({
1342
+ kind: "interf-preparation-change-result",
1343
+ version: 1,
1344
+ operation: "remove",
1345
+ preparation: request.preparation,
1346
+ config_path: join(this.rootPath, "interf", "interf.json"),
1347
+ portable_context_path: portableContextPath(this.rootPath, request.preparation),
1348
+ portable_context_retained: true,
1349
+ changed: true,
1350
+ message: `Removed Preparation ${request.preparation}. Portable Context files were retained.`,
1351
+ });
1257
1352
  }
1258
- async createMethodAuthoringRun(requestValue) {
1353
+ applyReset(requestValue) {
1354
+ const request = ResetRequestSchema.parse(requestValue);
1355
+ const preparation = findSourcePreparationConfig(loadSourceFolderConfig(this.rootPath), request.preparation);
1356
+ if (!preparation) {
1357
+ throw new Error(`Preparation "${request.preparation}" is not saved.`);
1358
+ }
1359
+ const compiledPath = portableContextPath(this.rootPath, request.preparation);
1360
+ if (!existsSync(compiledPath)) {
1361
+ throw new Error(`Portable Context for Preparation "${request.preparation}" does not exist.`);
1362
+ }
1363
+ resetCompiledGeneratedState(compiledPath, request.scope);
1364
+ return ResetResultSchema.parse({
1365
+ kind: "interf-reset-result",
1366
+ version: 1,
1367
+ preparation: request.preparation,
1368
+ scope: request.scope,
1369
+ portable_context_path: compiledPath,
1370
+ changed: true,
1371
+ message: `Reset ${request.scope} state for Preparation ${request.preparation}.`,
1372
+ });
1373
+ }
1374
+ async createMethodAuthoringRun(requestValue, jobType = "method-authoring") {
1259
1375
  const request = MethodAuthoringCreateRequestSchema.parse(requestValue);
1376
+ const isImprovement = jobType === "method-improvement";
1260
1377
  const job = this.createJobRun({
1261
- job_type: "method-authoring",
1262
- title: `Draft Method ${request.method_id}`,
1378
+ job_type: jobType,
1379
+ title: isImprovement ? `Improve Method ${request.method_id}` : `Draft Method ${request.method_id}`,
1263
1380
  preparation: request.preparation ?? null,
1264
1381
  method: request.method_id,
1265
1382
  source_path: request.source_folder_path,
@@ -1276,7 +1393,7 @@ export class LocalServiceRuntime {
1276
1393
  },
1277
1394
  {
1278
1395
  id: "draft-package",
1279
- label: "Draft Method package",
1396
+ label: isImprovement ? "Improve Method package" : "Draft Method package",
1280
1397
  input: {
1281
1398
  method_id: request.method_id,
1282
1399
  label: request.label,
@@ -1295,7 +1412,7 @@ export class LocalServiceRuntime {
1295
1412
  this.appendJobRunEvent(job.run_id, {
1296
1413
  type: "step.started",
1297
1414
  step_id: "inspect-source",
1298
- message: "Inspecting source files for Method drafting.",
1415
+ message: isImprovement ? "Inspecting source files for Method improvement." : "Inspecting source files for Method drafting.",
1299
1416
  input: {
1300
1417
  preparation: request.preparation ?? null,
1301
1418
  source_folder_path: request.source_folder_path,
@@ -1314,7 +1431,7 @@ export class LocalServiceRuntime {
1314
1431
  this.appendJobRunEvent(job.run_id, {
1315
1432
  type: "step.started",
1316
1433
  step_id: "draft-package",
1317
- message: "Drafting Method package.",
1434
+ message: isImprovement ? "Improving Method package." : "Drafting Method package.",
1318
1435
  input: {
1319
1436
  method_id: request.method_id,
1320
1437
  label: request.label,
@@ -1394,7 +1511,7 @@ export class LocalServiceRuntime {
1394
1511
  const compiledPath = this.ensureCompiledForRun(preparationConfig);
1395
1512
  const runId = createRunId("compile");
1396
1513
  const now = new Date().toISOString();
1397
- const method = getCompiledMethod(methodIdForSourcePreparationConfig(preparationConfig) ?? DEFAULT_METHOD_ID, {
1514
+ const method = getCompiledMethod(requireSelectedMethod(preparationConfig), {
1398
1515
  sourcePath: this.rootPath,
1399
1516
  });
1400
1517
  const stageTotal = method.stages.length;
@@ -1484,7 +1601,7 @@ export class LocalServiceRuntime {
1484
1601
  source_path: this.rootPath,
1485
1602
  portable_context_path: compiledTarget.eligible ? compiledPath : null,
1486
1603
  started_at: now,
1487
- comparison: null,
1604
+ readiness_run: null,
1488
1605
  events: [],
1489
1606
  });
1490
1607
  this.writeTestRun(compiledPath, initial);
@@ -1522,6 +1639,7 @@ export class LocalServiceRuntime {
1522
1639
  summary: "Portable context ready.",
1523
1640
  });
1524
1641
  }
1642
+ await this.recordCompileRunEvent(context.compiledPath, context.runId, this.readinessUpdatedEvent(context.runId, context.preparationConfig.name, this.computePreparationReadiness(context.preparationConfig)));
1525
1643
  }
1526
1644
  catch (error) {
1527
1645
  await this.recordCompileRunEvent(context.compiledPath, context.runId, {
@@ -1531,6 +1649,7 @@ export class LocalServiceRuntime {
1531
1649
  timestamp: createRunEventTimestamp(),
1532
1650
  error: error instanceof Error ? error.message : String(error),
1533
1651
  });
1652
+ await this.recordCompileRunEvent(context.compiledPath, context.runId, this.readinessUpdatedEvent(context.runId, context.preparationConfig.name, this.computePreparationReadiness(context.preparationConfig)));
1534
1653
  }
1535
1654
  }
1536
1655
  async runTestInBackground(request, context, initial) {
@@ -1539,15 +1658,15 @@ export class LocalServiceRuntime {
1539
1658
  throw new Error("No test-run handler is configured for this local service.");
1540
1659
  }
1541
1660
  const result = LocalRunHandlerResultSchema.parse(await this.handlers.createTestRun(request, context));
1542
- const comparison = result.comparison ?? this.readLatestComparison(context.preparationConfig.name);
1543
- const resultEvent = comparison
1544
- ? this.checksEvaluatedEvent(context.runId, comparison)
1661
+ const readinessRun = result.readiness_run ?? this.readLatestReadinessRun(context.preparationConfig.name);
1662
+ const resultEvent = readinessRun
1663
+ ? this.checksEvaluatedEvent(context.runId, readinessRun)
1545
1664
  : null;
1546
1665
  const nextWithoutReadiness = TestRunResourceSchema.parse({
1547
1666
  ...initial,
1548
1667
  status: result.ok ? "succeeded" : "failed",
1549
1668
  finished_at: new Date().toISOString(),
1550
- comparison,
1669
+ readiness_run: readinessRun,
1551
1670
  events: resultEvent ? [resultEvent] : [],
1552
1671
  ...(!result.ok ? { error: result.error ?? "Readiness check failed." } : {}),
1553
1672
  });
@@ -1597,7 +1716,7 @@ export class LocalServiceRuntime {
1597
1716
  this.appendJobRunEvent(runId, {
1598
1717
  type: "step.started",
1599
1718
  step_id: "normalize-checks",
1600
- message: "Normalizing readiness-check draft into saved check records.",
1719
+ message: "Normalizing drafted readiness checks into saved check records.",
1601
1720
  input: {
1602
1721
  checks: result.checks.length,
1603
1722
  },
@@ -1770,60 +1889,84 @@ export class LocalServiceRuntime {
1770
1889
  assistant_message: ACTION_PLANNER_CLARIFICATION_MESSAGE,
1771
1890
  });
1772
1891
  }
1773
- buildPreparationSetupRequest(request, plan, values) {
1774
- const sourceFolderChoices = listSourceFolderChoices(this.rootPath);
1775
- const selectedPath = preparationSetupPathValue(values) ??
1776
- (sourceFolderChoices.length === 1 ? sourceFolderChoices[0].value : null);
1777
- if (!selectedPath) {
1778
- return {
1779
- error: "Tell Interf which source folder to use for the Preparation.",
1780
- };
1781
- }
1782
- let normalizedPath;
1783
- try {
1784
- normalizedPath = normalizeSourcePreparationPathForConfig(this.rootPath, selectedPath);
1785
- }
1786
- catch (error) {
1787
- return {
1788
- error: error instanceof Error ? error.message : String(error),
1789
- };
1790
- }
1791
- const explicitName = preparationSetupNameValue(values) ?? plan.preparation ?? request.preparation;
1792
- const preparationName = explicitName
1793
- ? slugFromText(explicitName)
1794
- : defaultPreparationNameForPath(normalizedPath);
1795
- const requestMethodId = stringValue(request.values, "method");
1796
- const valueMethodId = stringValue(values, "method");
1797
- const methodId = requestMethodId ?? plan.method ?? valueMethodId ?? "interf-default";
1798
- const prepareAfterSetup = booleanValue(values, "prepare_after_setup") ?? false;
1799
- try {
1800
- return {
1801
- preparationName,
1802
- methodId,
1803
- prepareAfterSetup,
1804
- request: PreparationSetupCreateRequestSchema.parse({
1805
- prepare_after_setup: prepareAfterSetup,
1806
- preparation: {
1807
- name: preparationName,
1808
- path: normalizedPath,
1809
- about: stringValue(values, "about") ?? stringValue(values, "task_prompt") ?? request.message,
1810
- method: methodId,
1811
- checks: [],
1812
- },
1813
- }),
1814
- };
1815
- }
1816
- catch (error) {
1817
- return {
1818
- error: error instanceof Error ? error.message : String(error),
1819
- };
1892
+ directServiceActionClarification(options) {
1893
+ const endpoint = directServiceEndpointForAction(options.actionType);
1894
+ if (!endpoint) {
1895
+ throw new Error(`Action "${options.actionType}" is not a direct deterministic service action.`);
1820
1896
  }
1897
+ const label = options.actionType === "preparation-setup"
1898
+ ? "Preparation setup"
1899
+ : options.actionType === "method-change"
1900
+ ? "Method change"
1901
+ : "Preparation change";
1902
+ const now = new Date().toISOString();
1903
+ return ActionProposalResourceSchema.parse({
1904
+ kind: "interf-action-proposal",
1905
+ version: 1,
1906
+ proposal_id: createActionProposalId(),
1907
+ status: "needs_clarification",
1908
+ action_type: "clarification",
1909
+ title: `${label} uses a direct service endpoint`,
1910
+ summary: `${label} is deterministic and is not accepted through action proposals.`,
1911
+ assistant_message: `${label} must be submitted directly to ${endpoint}. Action proposals are only for freeform planning or async local-agent-backed work.`,
1912
+ message: options.message,
1913
+ preparation: options.preparation ?? null,
1914
+ method: options.method ?? null,
1915
+ request: {
1916
+ message: options.message,
1917
+ endpoint,
1918
+ action_type: options.actionType,
1919
+ ...(options.values ? { values: options.values } : {}),
1920
+ },
1921
+ created_at: now,
1922
+ updated_at: now,
1923
+ proposed_by_executor: this.getExecutorStatus().executor,
1924
+ approval: null,
1925
+ submitted_run_id: null,
1926
+ submitted_run_type: null,
1927
+ error: null,
1928
+ });
1821
1929
  }
1822
1930
  async buildActionProposal(request) {
1823
- const plan = await this.planActionProposal(request);
1824
1931
  const structuredPreparationSetup = PreparationSetupActionValuesSchema.safeParse(request.values);
1825
- const actionType = structuredPreparationSetup.success ? "preparation-setup" : plan.action_type;
1826
- const usePlannerText = plan.action_type === actionType;
1932
+ const structuredMethodAuthoring = MethodAuthoringActionValuesSchema.safeParse(request.values);
1933
+ const structuredActionType = actionTypeFromValues(request.values);
1934
+ const structuredDirectActionType = structuredPreparationSetup.success
1935
+ ? "preparation-setup"
1936
+ : structuredActionType && directServiceEndpointForAction(structuredActionType)
1937
+ ? structuredActionType
1938
+ : null;
1939
+ if (structuredDirectActionType) {
1940
+ return this.directServiceActionClarification({
1941
+ actionType: structuredDirectActionType,
1942
+ message: request.message,
1943
+ method: stringValue(request.values, "method") ?? stringValue(request.values, "new_method_id"),
1944
+ preparation: request.preparation ?? stringValue(request.values, "preparation") ?? stringValue(request.values, "name"),
1945
+ values: request.values,
1946
+ });
1947
+ }
1948
+ const structuredPlanActionType = structuredMethodAuthoring.success ? "method-authoring" : structuredActionType;
1949
+ // Typed UI/CLI actions already carry the service contract; only freeform chat needs planner inference.
1950
+ const plan = structuredPlanActionType
1951
+ ? ActionProposalPlanSchema.parse({
1952
+ action_type: structuredPlanActionType,
1953
+ ...(request.preparation ? { preparation: request.preparation } : {}),
1954
+ })
1955
+ : await this.planActionProposal(request);
1956
+ const actionType = structuredPlanActionType ?? plan.action_type;
1957
+ if (directServiceEndpointForAction(actionType)) {
1958
+ return this.directServiceActionClarification({
1959
+ actionType,
1960
+ message: request.message,
1961
+ method: plan.method ?? stringValue(plan.values, "method") ?? stringValue(request.values, "method"),
1962
+ preparation: plan.preparation ?? request.preparation ?? stringValue(plan.values, "preparation") ?? stringValue(request.values, "preparation"),
1963
+ values: {
1964
+ ...(plan.values ?? {}),
1965
+ ...(request.values ?? {}),
1966
+ },
1967
+ });
1968
+ }
1969
+ const usePlannerText = !structuredPlanActionType && plan.action_type === actionType;
1827
1970
  const now = new Date().toISOString();
1828
1971
  if (actionType === "clarification") {
1829
1972
  return ActionProposalResourceSchema.parse({
@@ -1856,61 +1999,55 @@ export class LocalServiceRuntime {
1856
1999
  ...(plan.values ?? {}),
1857
2000
  ...(request.values ?? {}),
1858
2001
  };
1859
- if (actionType === "preparation-setup") {
1860
- const setup = this.buildPreparationSetupRequest(request, plan, proposalValues);
1861
- if ("error" in setup) {
1862
- return ActionProposalResourceSchema.parse({
1863
- kind: "interf-action-proposal",
1864
- version: 1,
1865
- proposal_id: createActionProposalId(),
1866
- status: "needs_clarification",
1867
- action_type: "clarification",
1868
- title: "Clarify Preparation setup",
1869
- summary: "Interf needs a source folder before it can save a Preparation.",
1870
- assistant_message: setup.error,
1871
- message: request.message,
1872
- preparation: plan.preparation ?? request.preparation ?? null,
1873
- method: plan.method ?? null,
1874
- request: {
1875
- message: request.message,
1876
- ...(proposalValues ? { values: proposalValues } : {}),
1877
- },
1878
- created_at: now,
1879
- updated_at: now,
1880
- proposed_by_executor: this.getExecutorStatus().executor,
1881
- approval: null,
1882
- submitted_run_id: null,
1883
- submitted_run_type: null,
1884
- error: null,
1885
- });
1886
- }
1887
- const commandValues = {
1888
- ...proposalValues,
1889
- path: setup.request.preparation.path,
1890
- prepare_after_setup: setup.prepareAfterSetup,
2002
+ if (actionType === "method-authoring" || actionType === "method-improvement") {
2003
+ const requestedPreparationName = plan.preparation ?? request.preparation ?? null;
2004
+ const fallbackPreparation = requestedPreparationName
2005
+ ? null
2006
+ : listSourcePreparationConfigs(loadSourceFolderConfig(this.rootPath))[0] ?? null;
2007
+ const preparationConfig = requestedPreparationName
2008
+ ? this.resolvePreparationConfig(requestedPreparationName)
2009
+ : fallbackPreparation;
2010
+ const preparationPath = preparationConfig
2011
+ ? resolveSourcePreparationPath(this.rootPath, preparationConfig)
2012
+ : resolveConfiguredSourceFolderPath(this.rootPath) ?? this.rootPath;
2013
+ const requestedMethodId = stringValue(request.values, "method_id") ??
2014
+ stringValue(request.values, "method");
2015
+ const plannedMethodId = plan.method ??
2016
+ stringValue(plan.values, "method_id") ??
2017
+ stringValue(plan.values, "method");
2018
+ const methodId = requestedMethodId ?? plannedMethodId ?? methodIdForProposal(request.message, proposalValues);
2019
+ const taskPrompt = actionValueMethodTaskPrompt(proposalValues) ??
2020
+ stringValue(proposalValues, "task_prompt") ??
2021
+ methodAuthoringPromptFallback(request.message, methodId);
2022
+ const hint = stringValue(proposalValues, "hint") ?? methodAuthoringHintFromPrompt(taskPrompt);
2023
+ const actionRequest = {
2024
+ preparation: preparationConfig?.name ?? null,
2025
+ source_folder_path: preparationPath,
2026
+ method_id: methodId,
2027
+ ...(stringValue(proposalValues, "base_method_id") ? { base_method_id: stringValue(proposalValues, "base_method_id") } : {}),
2028
+ ...(stringValue(proposalValues, "reference_method_id") ? { reference_method_id: stringValue(proposalValues, "reference_method_id") } : {}),
2029
+ label: stringValue(proposalValues, "label") ?? methodLabelFromId(methodId),
2030
+ hint,
2031
+ task_prompt: taskPrompt,
2032
+ checks: preparationConfig?.checks ?? [],
1891
2033
  };
1892
2034
  const commandPreview = (usePlannerText ? plan.command_preview : undefined) ??
1893
- actionCommandPreview(actionType, setup.preparationName, setup.methodId, {
1894
- ...commandValues,
1895
- });
2035
+ actionCommandPreview(actionType, preparationConfig?.name ?? null, methodId, proposalValues);
1896
2036
  return ActionProposalResourceSchema.parse({
1897
2037
  kind: "interf-action-proposal",
1898
2038
  version: 1,
1899
2039
  proposal_id: createActionProposalId(),
1900
2040
  status: "awaiting_approval",
1901
2041
  action_type: actionType,
1902
- title: (usePlannerText ? plan.title : undefined) ?? (setup.prepareAfterSetup ? `Prepare ${setup.preparationName}` : `Create Preparation ${setup.preparationName}`),
1903
- summary: (usePlannerText ? plan.summary : undefined) ?? (setup.prepareAfterSetup
1904
- ? "Save this source folder as a Preparation and run the selected Method."
1905
- : "Save this source folder as an Interf Preparation."),
1906
- assistant_message: (usePlannerText ? plan.assistant_message : undefined) ?? actionAssistantMessage(actionType, setup.preparationName, commandPreview, {
1907
- prepareAfterSetup: setup.prepareAfterSetup,
1908
- }),
2042
+ title: (usePlannerText ? plan.title : undefined) ?? `Draft Method ${methodId}`,
2043
+ summary: (usePlannerText ? plan.summary : undefined) ?? "Ask the configured local executor to create a reusable local Method.",
2044
+ assistant_message: (usePlannerText ? plan.assistant_message : undefined) ??
2045
+ actionAssistantMessage(actionType, preparationConfig?.name ?? null, commandPreview),
1909
2046
  command_preview: commandPreview,
1910
2047
  message: request.message,
1911
- preparation: setup.preparationName,
1912
- method: setup.methodId,
1913
- request: setup.request,
2048
+ preparation: preparationConfig?.name ?? null,
2049
+ method: methodId,
2050
+ request: actionRequest,
1914
2051
  created_at: now,
1915
2052
  updated_at: now,
1916
2053
  proposed_by_executor: this.getExecutorStatus().executor,
@@ -1921,15 +2058,14 @@ export class LocalServiceRuntime {
1921
2058
  });
1922
2059
  }
1923
2060
  const preparationConfig = this.resolvePreparationConfig(plan.preparation ?? request.preparation ?? this.defaultPreparationName());
2061
+ const proposalActionType = ActionProposalTypeSchema.parse(actionType);
1924
2062
  const preparationPath = resolveSourcePreparationPath(this.rootPath, preparationConfig);
1925
2063
  const requestedMethodId = stringValue(request.values, "method_id") ??
1926
2064
  stringValue(request.values, "method");
1927
2065
  const plannedMethodId = plan.method ??
1928
2066
  stringValue(plan.values, "method_id") ??
1929
2067
  stringValue(plan.values, "method");
1930
- const methodId = actionType === "method-authoring"
1931
- ? requestedMethodId ?? plannedMethodId ?? methodIdForProposal(request.message, proposalValues)
1932
- : requestedMethodId ?? plannedMethodId ?? methodIdForSourcePreparationConfig(preparationConfig);
2068
+ const methodId = requestedMethodId ?? plannedMethodId ?? methodIdForSourcePreparationConfig(preparationConfig);
1933
2069
  const clarifyResolvedAction = (options) => ActionProposalResourceSchema.parse({
1934
2070
  kind: "interf-action-proposal",
1935
2071
  version: 1,
@@ -1995,51 +2131,58 @@ export class LocalServiceRuntime {
1995
2131
  target_count: Math.max(1, Math.min(8, Math.round(numberValue(proposalValues, "target_count") ?? 4))),
1996
2132
  };
1997
2133
  }
2134
+ const fallbackMethodId = methodId ?? methodIdForProposal(request.message, proposalValues);
2135
+ const taskPrompt = actionValueMethodTaskPrompt(proposalValues) ??
2136
+ stringValue(proposalValues, "task_prompt") ??
2137
+ methodAuthoringPromptFallback(request.message, fallbackMethodId);
2138
+ const hint = stringValue(proposalValues, "hint") ?? methodAuthoringHintFromPrompt(taskPrompt);
1998
2139
  return {
1999
2140
  preparation: preparationConfig.name,
2000
2141
  source_folder_path: preparationPath,
2001
- method_id: methodId,
2002
- label: stringValue(proposalValues, "label") ?? `Custom ${preparationConfig.name}`,
2003
- hint: stringValue(proposalValues, "hint") ?? request.message,
2004
- task_prompt: actionValueMethodTaskPrompt(proposalValues) ?? stringValue(proposalValues, "task_prompt") ?? request.message,
2142
+ method_id: fallbackMethodId,
2143
+ ...(stringValue(proposalValues, "base_method_id") ? { base_method_id: stringValue(proposalValues, "base_method_id") } : {}),
2144
+ ...(stringValue(proposalValues, "reference_method_id") ? { reference_method_id: stringValue(proposalValues, "reference_method_id") } : {}),
2145
+ label: stringValue(proposalValues, "label") ?? methodLabelFromId(fallbackMethodId),
2146
+ hint,
2147
+ task_prompt: taskPrompt,
2005
2148
  checks: preparationConfig.checks ?? [],
2006
2149
  };
2007
2150
  })();
2008
2151
  const title = (() => {
2009
2152
  if (plan.title)
2010
2153
  return plan.title;
2011
- if (actionType === "compile")
2154
+ if (proposalActionType === "compile")
2012
2155
  return `Prepare ${preparationConfig.name}`;
2013
- if (actionType === "test")
2156
+ if (proposalActionType === "test")
2014
2157
  return `Check readiness for ${preparationConfig.name}`;
2015
- if (actionType === "readiness-check-draft")
2158
+ if (proposalActionType === "readiness-check-draft")
2016
2159
  return `Draft readiness checks for ${preparationConfig.name}`;
2017
2160
  return `Draft Method ${methodId}`;
2018
2161
  })();
2019
2162
  const summary = (() => {
2020
2163
  if (plan.summary)
2021
2164
  return plan.summary;
2022
- if (actionType === "compile")
2165
+ if (proposalActionType === "compile")
2023
2166
  return "Build portable context agents can use.";
2024
- if (actionType === "test")
2167
+ if (proposalActionType === "test")
2025
2168
  return "Run readiness checks against source files and portable context.";
2026
- if (actionType === "readiness-check-draft")
2169
+ if (proposalActionType === "readiness-check-draft")
2027
2170
  return "Ask the configured local executor to draft saved readiness checks.";
2028
2171
  return "Ask the configured local executor to create a reusable local Method.";
2029
2172
  })();
2030
- const previewValues = actionType === "test"
2173
+ const previewValues = proposalActionType === "test"
2031
2174
  ? { mode: actionRequest.mode }
2032
2175
  : proposalValues;
2033
- const commandPreview = plan.command_preview ?? actionCommandPreview(actionType, preparationConfig.name, methodId, previewValues);
2176
+ const commandPreview = plan.command_preview ?? actionCommandPreview(proposalActionType, preparationConfig.name, methodId, previewValues);
2034
2177
  return ActionProposalResourceSchema.parse({
2035
2178
  kind: "interf-action-proposal",
2036
2179
  version: 1,
2037
2180
  proposal_id: createActionProposalId(),
2038
2181
  status: "awaiting_approval",
2039
- action_type: actionType,
2182
+ action_type: proposalActionType,
2040
2183
  title,
2041
2184
  summary,
2042
- assistant_message: plan.assistant_message ?? actionAssistantMessage(actionType, preparationConfig.name, commandPreview),
2185
+ assistant_message: plan.assistant_message ?? actionAssistantMessage(proposalActionType, preparationConfig.name, commandPreview),
2043
2186
  command_preview: commandPreview,
2044
2187
  message: request.message,
2045
2188
  preparation: preparationConfig.name,
@@ -2072,23 +2215,6 @@ export class LocalServiceRuntime {
2072
2215
  runType: "test-run",
2073
2216
  };
2074
2217
  }
2075
- if (proposal.action_type === "preparation-setup") {
2076
- const job = await this.createPreparationSetupRun(proposal.request);
2077
- if (proposal.request.prepare_after_setup) {
2078
- const resource = await this.createCompileRun({
2079
- preparation: proposal.request.preparation.name,
2080
- method: methodIdForSourcePreparationConfig(proposal.request.preparation) ?? DEFAULT_METHOD_ID,
2081
- });
2082
- return {
2083
- runId: resource.run.run_id,
2084
- runType: "compile-run",
2085
- };
2086
- }
2087
- return {
2088
- runId: job.run_id,
2089
- runType: "job-run",
2090
- };
2091
- }
2092
2218
  if (proposal.action_type === "readiness-check-draft") {
2093
2219
  const job = await this.createReadinessCheckDraftRun(proposal.request);
2094
2220
  return {
@@ -2096,7 +2222,11 @@ export class LocalServiceRuntime {
2096
2222
  runType: "job-run",
2097
2223
  };
2098
2224
  }
2099
- const job = await this.createMethodAuthoringRun(proposal.request);
2225
+ const directEndpoint = directServiceEndpointForAction(proposal.action_type);
2226
+ if (directEndpoint) {
2227
+ throw new Error(`Action "${proposal.action_type}" must be submitted directly to ${directEndpoint}.`);
2228
+ }
2229
+ const job = await this.createMethodAuthoringRun(proposal.request, proposal.action_type === "method-improvement" ? "method-improvement" : "method-authoring");
2100
2230
  return {
2101
2231
  runId: job.run_id,
2102
2232
  runType: "job-run",
@@ -2116,7 +2246,7 @@ export class LocalServiceRuntime {
2116
2246
  };
2117
2247
  }
2118
2248
  ensureCompiledForRun(preparationConfig) {
2119
- const methodId = methodIdForSourcePreparationConfig(preparationConfig) ?? DEFAULT_METHOD_ID;
2249
+ const methodId = requireSelectedMethod(preparationConfig);
2120
2250
  const compiledPath = ensurePortableContextScaffold(this.rootPath, preparationConfig.name, methodId);
2121
2251
  syncCompiledInterfConfigFromSourcePreparationConfig(compiledPath, preparationConfig);
2122
2252
  return compiledPath;
@@ -2242,11 +2372,11 @@ export class LocalServiceRuntime {
2242
2372
  });
2243
2373
  }
2244
2374
  }
2245
- readLatestComparison(preparationName) {
2375
+ readLatestReadinessRun(preparationName) {
2246
2376
  return readSavedReadinessCheckRun(this.rootPath, preparationName);
2247
2377
  }
2248
- checksEvaluatedEvent(runId, comparison) {
2249
- const target = comparison.compiled ?? comparison.raw;
2378
+ checksEvaluatedEvent(runId, readinessRun) {
2379
+ const target = readinessRun.compiled ?? readinessRun.raw;
2250
2380
  return {
2251
2381
  type: "checks.evaluated",
2252
2382
  event_id: createRunEventId("event"),