@interf/compiler 0.9.3 → 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 -22
  64. package/dist/packages/local-service/action-values.js +1 -30
  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 +302 -292
  70. package/dist/packages/local-service/lib/schema.js +115 -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 +430 -286
  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/0c9mu7yldxyyg.css +0 -3
  99. package/dist/compiler-ui/_next/static/chunks/15mks7ry_cupt.js +0 -118
  100. /package/dist/compiler-ui/_next/static/{pIZnDsV3Je6hdC3cOsGdK → 84FaeF3EzBF9kKTMjSEVN}/_buildManifest.js +0 -0
  101. /package/dist/compiler-ui/_next/static/{pIZnDsV3Je6hdC3cOsGdK → 84FaeF3EzBF9kKTMjSEVN}/_clientMiddlewareManifest.js +0 -0
  102. /package/dist/compiler-ui/_next/static/{pIZnDsV3Je6hdC3cOsGdK → 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,31 +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 preparationSetupPathValue(values) {
448
- return stringValue(values, "path") ??
449
- stringValue(values, "source_folder_path") ??
450
- stringValue(values, "source_path") ??
451
- stringValue(values, "source_folder") ??
452
- stringValue(values, "folder");
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);
453
523
  }
454
- function preparationSetupNameValue(values) {
455
- const parsed = PreparationSetupActionValuesSchema.safeParse(values);
456
- return parsed.success ? parsed.data.name : stringValue(values, "name") ??
457
- stringValue(values, "preparation") ??
458
- stringValue(values, "preparation_name");
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);
540
+ }
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.`);
459
566
  }
460
567
  function actionCommandPreview(actionType, preparationName, methodId, values) {
461
- if (actionType === "preparation-setup") {
462
- const preparationPart = preparationName ? ` # Preparation: ${preparationName}` : "";
463
- const pathPart = preparationSetupPathValue(values);
464
- return pathPart ? `interf init # source: ${pathPart}${preparationPart}` : `interf init${preparationPart}`;
465
- }
466
568
  if (actionType === "compile") {
467
569
  const methodSuffix = methodId ? ` # Method: ${methodId}` : "";
468
570
  return preparationName
@@ -491,9 +593,6 @@ function hasCompiledTestTarget(sourcePath, preparationConfig) {
491
593
  }
492
594
  function actionAssistantMessage(actionType, preparationName, commandPreview) {
493
595
  const preparationSuffix = preparationName ? ` for Preparation "${preparationName}"` : "";
494
- if (actionType === "preparation-setup") {
495
- return `Interf prepared a Preparation setup proposal${preparationSuffix}. Approve to save the source folder and create the portable-context scaffold. CLI equivalent: ${commandPreview}`;
496
- }
497
596
  if (actionType === "compile") {
498
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}`;
499
598
  }
@@ -501,7 +600,7 @@ function actionAssistantMessage(actionType, preparationName, commandPreview) {
501
600
  return `Interf prepared a readiness-check proposal${preparationSuffix}. Approve to run the requested target against saved readiness checks. CLI equivalent: ${commandPreview}`;
502
601
  }
503
602
  if (actionType === "readiness-check-draft") {
504
- 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}`;
505
604
  }
506
605
  if (actionType === "method-authoring" || actionType === "method-improvement") {
507
606
  return `Interf prepared a Method draft proposal${preparationSuffix}. Approve to draft a reusable local Method as a visible run. CLI equivalent: ${commandPreview}`;
@@ -513,10 +612,10 @@ function passRate(passed, total) {
513
612
  return null;
514
613
  return Math.round((passed / total) * 100);
515
614
  }
516
- function readinessTargetResult(summary, currentFingerprint, comparisonFingerprint) {
615
+ function readinessTargetResult(summary, currentFingerprint, readinessRunFingerprint) {
517
616
  if (!summary)
518
617
  return null;
519
- const resultFingerprint = comparisonFingerprint ?? null;
618
+ const resultFingerprint = readinessRunFingerprint ?? null;
520
619
  return {
521
620
  passed: summary.passed_cases,
522
621
  total: summary.total_cases,
@@ -589,6 +688,7 @@ function buildMethodResource(resource) {
589
688
  source_kind: resource.source_kind,
590
689
  built_in: resource.built_in,
591
690
  active_for_preparations: resource.active_for_preparations,
691
+ output_paths: resource.output_paths,
592
692
  stages: resource.stages,
593
693
  });
594
694
  }
@@ -657,13 +757,13 @@ export class LocalServiceRuntime {
657
757
  const contextReady = compiledTarget.eligible;
658
758
  const compileRun = this.listCompileRunsForPreparation(preparation.name)[0] ?? null;
659
759
  const testRun = this.listTestRunsForPreparation(preparation.name)[0] ?? null;
660
- const comparison = this.readLatestComparison(preparation.name);
760
+ const readinessRun = this.readLatestReadinessRun(preparation.name);
661
761
  const configuredChecks = preparation.checks.length;
662
762
  const currentFingerprint = configuredChecks > 0 ? fingerprintReadinessChecks(preparation.checks) : null;
663
- const comparisonFingerprint = comparison?.checks_fingerprint ?? null;
664
- const sourceResult = readinessTargetResult(comparison?.raw, currentFingerprint, comparisonFingerprint);
665
- const contextResult = readinessTargetResult(comparison?.compiled, currentFingerprint, comparisonFingerprint);
666
- 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);
667
767
  const compileCheck = (() => {
668
768
  if (!compileRun) {
669
769
  return {
@@ -775,7 +875,6 @@ export class LocalServiceRuntime {
775
875
  fingerprint: currentFingerprint,
776
876
  source_files: sourceResult,
777
877
  portable_context: contextResult,
778
- delta: comparison?.summary.pass_rate_delta ?? null,
779
878
  },
780
879
  checks,
781
880
  });
@@ -838,7 +937,7 @@ export class LocalServiceRuntime {
838
937
  const choices = listCompiledMethodChoices(this.rootPath);
839
938
  return choices.map((method) => {
840
939
  const activeForPreparations = preparations
841
- .filter((preparation) => (methodIdForSourcePreparationConfig(preparation) ?? DEFAULT_METHOD_ID) === method.id)
940
+ .filter((preparation) => methodIdForSourcePreparationConfig(preparation) === method.id)
842
941
  .map((preparation) => preparation.name);
843
942
  return buildMethodResource({
844
943
  id: method.id,
@@ -848,6 +947,10 @@ export class LocalServiceRuntime {
848
947
  source_kind: method.scope === "builtin" ? "builtin" : "local",
849
948
  built_in: method.scope === "builtin",
850
949
  active_for_preparations: activeForPreparations,
950
+ output_paths: (method.contextInterface?.zones ?? [])
951
+ .filter((zone) => zone.role === "output")
952
+ .map((zone) => contextInterfaceArtifactPath(zone))
953
+ .sort(),
851
954
  stages: method.stages.map((stage) => ({
852
955
  id: stage.id,
853
956
  label: stage.label,
@@ -953,7 +1056,10 @@ export class LocalServiceRuntime {
953
1056
  }
954
1057
  async createActionProposal(requestValue) {
955
1058
  const request = ActionProposalCreateRequestSchema.parse(requestValue);
956
- const proposal = await this.buildActionProposal(request);
1059
+ const proposal = ActionProposalResourceSchema.parse({
1060
+ ...(await this.buildActionProposal(request)),
1061
+ client_origin: request.client_origin,
1062
+ });
957
1063
  this.writeActionProposal(proposal);
958
1064
  return proposal;
959
1065
  }
@@ -1113,7 +1219,7 @@ export class LocalServiceRuntime {
1113
1219
  this.appendJobRunEvent(job.run_id, {
1114
1220
  type: "step.completed",
1115
1221
  step_id: "read-source",
1116
- message: "Source folder is ready for readiness-check drafting.",
1222
+ message: "Source folder is ready for drafting readiness checks.",
1117
1223
  output: {
1118
1224
  preparation: request.preparation,
1119
1225
  source_folder_path: request.source_folder_path,
@@ -1131,144 +1237,146 @@ export class LocalServiceRuntime {
1131
1237
  void this.runReadinessCheckDraftInBackground(request, job.run_id);
1132
1238
  return this.getJob(job.run_id) ?? job;
1133
1239
  }
1134
- 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) {
1135
1303
  const request = PreparationSetupCreateRequestSchema.parse(requestValue);
1136
1304
  const preparationConfig = request.preparation;
1137
- const methodId = methodIdForSourcePreparationConfig(preparationConfig) ?? "interf-default";
1305
+ const methodId = methodIdForSourcePreparationConfig(preparationConfig) ?? DEFAULT_METHOD_ID;
1138
1306
  const normalizedPreparationConfig = {
1139
1307
  ...preparationConfig,
1140
1308
  method: methodId,
1141
1309
  };
1142
- const sourceFolderPath = resolveSourcePreparationPath(this.rootPath, preparationConfig);
1143
- const outputPath = portableContextPath(this.rootPath, preparationConfig.name);
1144
- const job = this.createJobRun({
1145
- job_type: "preparation-setup",
1146
- title: `Create Preparation ${preparationConfig.name}`,
1147
- 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,
1148
1321
  method: methodId,
1149
- source_path: sourceFolderPath,
1150
- output_path: outputPath,
1151
- agent: this.getExecutorStatus().executor,
1152
- steps: [
1153
- {
1154
- id: "validate-source",
1155
- label: "Validate source folder",
1156
- input: {
1157
- preparation: preparationConfig.name,
1158
- path: preparationConfig.path,
1159
- },
1160
- },
1161
- {
1162
- id: "write-config",
1163
- label: "Save Preparation config",
1164
- input: {
1165
- config_path: join(this.rootPath, "interf", "interf.json"),
1166
- },
1167
- },
1168
- {
1169
- id: "prepare-scaffold",
1170
- label: "Prepare portable context",
1171
- input: {
1172
- output_path: outputPath,
1173
- method: methodId,
1174
- },
1175
- },
1176
- ],
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.`,
1177
1329
  });
1178
- let activeStep = "validate-source";
1179
- try {
1180
- this.appendJobRunEvent(job.run_id, {
1181
- type: "step.started",
1182
- step_id: "validate-source",
1183
- message: "Validating source folder.",
1184
- input: {
1185
- path: preparationConfig.path,
1186
- source_folder_path: sourceFolderPath,
1187
- },
1188
- });
1189
- if (!existsSync(sourceFolderPath) || !statSync(sourceFolderPath).isDirectory()) {
1190
- throw new Error(`Source folder "${preparationConfig.path}" is not available.`);
1191
- }
1192
- this.appendJobRunEvent(job.run_id, {
1193
- type: "step.completed",
1194
- step_id: "validate-source",
1195
- message: "Source folder is available.",
1196
- output: {
1197
- source_folder_path: sourceFolderPath,
1198
- },
1199
- });
1200
- activeStep = "write-config";
1201
- this.appendJobRunEvent(job.run_id, {
1202
- type: "step.started",
1203
- step_id: "write-config",
1204
- message: "Saving Preparation in the control plane config.",
1205
- input: {
1206
- preparation: preparationConfig.name,
1207
- path: preparationConfig.path,
1208
- },
1209
- });
1210
- upsertSourcePreparationConfig(this.rootPath, normalizedPreparationConfig);
1211
- this.appendJobRunEvent(job.run_id, {
1212
- type: "step.completed",
1213
- step_id: "write-config",
1214
- message: "Preparation config saved.",
1215
- output: {
1216
- config_path: join(this.rootPath, "interf", "interf.json"),
1217
- preparation: preparationConfig.name,
1218
- },
1219
- });
1220
- activeStep = "prepare-scaffold";
1221
- this.appendJobRunEvent(job.run_id, {
1222
- type: "step.started",
1223
- step_id: "prepare-scaffold",
1224
- message: "Preparing portable-context scaffold.",
1225
- input: {
1226
- output_path: outputPath,
1227
- method: methodId,
1228
- },
1229
- });
1230
- const compiledPath = ensurePortableContextScaffold(this.rootPath, normalizedPreparationConfig.name, methodId);
1231
- syncCompiledInterfConfigFromSourcePreparationConfig(compiledPath, normalizedPreparationConfig);
1232
- this.appendJobRunEvent(job.run_id, {
1233
- type: "step.completed",
1234
- step_id: "prepare-scaffold",
1235
- message: "Portable-context scaffold is ready.",
1236
- output: {
1237
- portable_context_path: compiledPath,
1238
- },
1239
- });
1240
- this.setJobRunResult(job.run_id, {
1241
- preparation: normalizedPreparationConfig,
1242
- source_folder_path: sourceFolderPath,
1243
- portable_context_path: compiledPath,
1244
- });
1245
- this.appendJobRunEvent(job.run_id, {
1246
- type: "job.completed",
1247
- message: `Preparation ${preparationConfig.name} is ready for Interf runs.`,
1248
- });
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.`);
1249
1335
  }
1250
- catch (error) {
1251
- const message = error instanceof Error ? error.message : String(error);
1252
- this.appendJobRunEvent(job.run_id, {
1253
- type: "step.failed",
1254
- step_id: activeStep,
1255
- message,
1256
- output: {
1257
- error: message,
1258
- },
1259
- });
1260
- this.appendJobRunEvent(job.run_id, {
1261
- type: "job.failed",
1262
- message,
1263
- });
1336
+ const preparation = findSourcePreparationConfig(loadSourceFolderConfig(this.rootPath), request.preparation);
1337
+ if (!preparation) {
1338
+ throw new Error(`Preparation "${request.preparation}" is not saved.`);
1264
1339
  }
1265
- 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
+ });
1352
+ }
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
+ });
1266
1373
  }
1267
- async createMethodAuthoringRun(requestValue) {
1374
+ async createMethodAuthoringRun(requestValue, jobType = "method-authoring") {
1268
1375
  const request = MethodAuthoringCreateRequestSchema.parse(requestValue);
1376
+ const isImprovement = jobType === "method-improvement";
1269
1377
  const job = this.createJobRun({
1270
- job_type: "method-authoring",
1271
- title: `Draft Method ${request.method_id}`,
1378
+ job_type: jobType,
1379
+ title: isImprovement ? `Improve Method ${request.method_id}` : `Draft Method ${request.method_id}`,
1272
1380
  preparation: request.preparation ?? null,
1273
1381
  method: request.method_id,
1274
1382
  source_path: request.source_folder_path,
@@ -1285,7 +1393,7 @@ export class LocalServiceRuntime {
1285
1393
  },
1286
1394
  {
1287
1395
  id: "draft-package",
1288
- label: "Draft Method package",
1396
+ label: isImprovement ? "Improve Method package" : "Draft Method package",
1289
1397
  input: {
1290
1398
  method_id: request.method_id,
1291
1399
  label: request.label,
@@ -1304,7 +1412,7 @@ export class LocalServiceRuntime {
1304
1412
  this.appendJobRunEvent(job.run_id, {
1305
1413
  type: "step.started",
1306
1414
  step_id: "inspect-source",
1307
- message: "Inspecting source files for Method drafting.",
1415
+ message: isImprovement ? "Inspecting source files for Method improvement." : "Inspecting source files for Method drafting.",
1308
1416
  input: {
1309
1417
  preparation: request.preparation ?? null,
1310
1418
  source_folder_path: request.source_folder_path,
@@ -1323,7 +1431,7 @@ export class LocalServiceRuntime {
1323
1431
  this.appendJobRunEvent(job.run_id, {
1324
1432
  type: "step.started",
1325
1433
  step_id: "draft-package",
1326
- message: "Drafting Method package.",
1434
+ message: isImprovement ? "Improving Method package." : "Drafting Method package.",
1327
1435
  input: {
1328
1436
  method_id: request.method_id,
1329
1437
  label: request.label,
@@ -1403,7 +1511,7 @@ export class LocalServiceRuntime {
1403
1511
  const compiledPath = this.ensureCompiledForRun(preparationConfig);
1404
1512
  const runId = createRunId("compile");
1405
1513
  const now = new Date().toISOString();
1406
- const method = getCompiledMethod(methodIdForSourcePreparationConfig(preparationConfig) ?? DEFAULT_METHOD_ID, {
1514
+ const method = getCompiledMethod(requireSelectedMethod(preparationConfig), {
1407
1515
  sourcePath: this.rootPath,
1408
1516
  });
1409
1517
  const stageTotal = method.stages.length;
@@ -1493,7 +1601,7 @@ export class LocalServiceRuntime {
1493
1601
  source_path: this.rootPath,
1494
1602
  portable_context_path: compiledTarget.eligible ? compiledPath : null,
1495
1603
  started_at: now,
1496
- comparison: null,
1604
+ readiness_run: null,
1497
1605
  events: [],
1498
1606
  });
1499
1607
  this.writeTestRun(compiledPath, initial);
@@ -1531,6 +1639,7 @@ export class LocalServiceRuntime {
1531
1639
  summary: "Portable context ready.",
1532
1640
  });
1533
1641
  }
1642
+ await this.recordCompileRunEvent(context.compiledPath, context.runId, this.readinessUpdatedEvent(context.runId, context.preparationConfig.name, this.computePreparationReadiness(context.preparationConfig)));
1534
1643
  }
1535
1644
  catch (error) {
1536
1645
  await this.recordCompileRunEvent(context.compiledPath, context.runId, {
@@ -1540,6 +1649,7 @@ export class LocalServiceRuntime {
1540
1649
  timestamp: createRunEventTimestamp(),
1541
1650
  error: error instanceof Error ? error.message : String(error),
1542
1651
  });
1652
+ await this.recordCompileRunEvent(context.compiledPath, context.runId, this.readinessUpdatedEvent(context.runId, context.preparationConfig.name, this.computePreparationReadiness(context.preparationConfig)));
1543
1653
  }
1544
1654
  }
1545
1655
  async runTestInBackground(request, context, initial) {
@@ -1548,15 +1658,15 @@ export class LocalServiceRuntime {
1548
1658
  throw new Error("No test-run handler is configured for this local service.");
1549
1659
  }
1550
1660
  const result = LocalRunHandlerResultSchema.parse(await this.handlers.createTestRun(request, context));
1551
- const comparison = result.comparison ?? this.readLatestComparison(context.preparationConfig.name);
1552
- const resultEvent = comparison
1553
- ? 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)
1554
1664
  : null;
1555
1665
  const nextWithoutReadiness = TestRunResourceSchema.parse({
1556
1666
  ...initial,
1557
1667
  status: result.ok ? "succeeded" : "failed",
1558
1668
  finished_at: new Date().toISOString(),
1559
- comparison,
1669
+ readiness_run: readinessRun,
1560
1670
  events: resultEvent ? [resultEvent] : [],
1561
1671
  ...(!result.ok ? { error: result.error ?? "Readiness check failed." } : {}),
1562
1672
  });
@@ -1606,7 +1716,7 @@ export class LocalServiceRuntime {
1606
1716
  this.appendJobRunEvent(runId, {
1607
1717
  type: "step.started",
1608
1718
  step_id: "normalize-checks",
1609
- message: "Normalizing readiness-check draft into saved check records.",
1719
+ message: "Normalizing drafted readiness checks into saved check records.",
1610
1720
  input: {
1611
1721
  checks: result.checks.length,
1612
1722
  },
@@ -1779,55 +1889,84 @@ export class LocalServiceRuntime {
1779
1889
  assistant_message: ACTION_PLANNER_CLARIFICATION_MESSAGE,
1780
1890
  });
1781
1891
  }
1782
- buildPreparationSetupRequest(request, plan, values) {
1783
- const sourceFolderChoices = listSourceFolderChoices(this.rootPath);
1784
- const selectedPath = preparationSetupPathValue(values) ??
1785
- (sourceFolderChoices.length === 1 ? sourceFolderChoices[0].value : null);
1786
- if (!selectedPath) {
1787
- return {
1788
- error: "Tell Interf which source folder to use for the Preparation.",
1789
- };
1790
- }
1791
- let normalizedPath;
1792
- try {
1793
- normalizedPath = normalizeSourcePreparationPathForConfig(this.rootPath, selectedPath);
1794
- }
1795
- catch (error) {
1796
- return {
1797
- error: error instanceof Error ? error.message : String(error),
1798
- };
1799
- }
1800
- const explicitName = preparationSetupNameValue(values) ?? plan.preparation ?? request.preparation;
1801
- const preparationName = explicitName
1802
- ? slugFromText(explicitName)
1803
- : defaultPreparationNameForPath(normalizedPath);
1804
- const requestMethodId = stringValue(request.values, "method");
1805
- const valueMethodId = stringValue(values, "method");
1806
- const methodId = requestMethodId ?? plan.method ?? valueMethodId ?? "interf-default";
1807
- try {
1808
- return {
1809
- preparationName,
1810
- methodId,
1811
- request: PreparationSetupCreateRequestSchema.parse({
1812
- preparation: {
1813
- name: preparationName,
1814
- path: normalizedPath,
1815
- about: stringValue(values, "about") ?? stringValue(values, "task_prompt") ?? request.message,
1816
- method: methodId,
1817
- checks: [],
1818
- },
1819
- }),
1820
- };
1821
- }
1822
- catch (error) {
1823
- return {
1824
- error: error instanceof Error ? error.message : String(error),
1825
- };
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.`);
1826
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
+ });
1827
1929
  }
1828
1930
  async buildActionProposal(request) {
1829
- const plan = await this.planActionProposal(request);
1830
- const actionType = plan.action_type;
1931
+ const structuredPreparationSetup = PreparationSetupActionValuesSchema.safeParse(request.values);
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;
1831
1970
  const now = new Date().toISOString();
1832
1971
  if (actionType === "clarification") {
1833
1972
  return ActionProposalResourceSchema.parse({
@@ -1860,53 +1999,55 @@ export class LocalServiceRuntime {
1860
1999
  ...(plan.values ?? {}),
1861
2000
  ...(request.values ?? {}),
1862
2001
  };
1863
- if (actionType === "preparation-setup") {
1864
- const setup = this.buildPreparationSetupRequest(request, plan, proposalValues);
1865
- if ("error" in setup) {
1866
- return ActionProposalResourceSchema.parse({
1867
- kind: "interf-action-proposal",
1868
- version: 1,
1869
- proposal_id: createActionProposalId(),
1870
- status: "needs_clarification",
1871
- action_type: "clarification",
1872
- title: "Clarify Preparation setup",
1873
- summary: "Interf needs a source folder before it can save a Preparation.",
1874
- assistant_message: setup.error,
1875
- message: request.message,
1876
- preparation: plan.preparation ?? request.preparation ?? null,
1877
- method: plan.method ?? null,
1878
- request: {
1879
- message: request.message,
1880
- ...(proposalValues ? { values: proposalValues } : {}),
1881
- },
1882
- created_at: now,
1883
- updated_at: now,
1884
- proposed_by_executor: this.getExecutorStatus().executor,
1885
- approval: null,
1886
- submitted_run_id: null,
1887
- submitted_run_type: null,
1888
- error: null,
1889
- });
1890
- }
1891
- const commandPreview = plan.command_preview ??
1892
- actionCommandPreview(actionType, setup.preparationName, setup.methodId, {
1893
- ...proposalValues,
1894
- path: setup.request.preparation.path,
1895
- });
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 ?? [],
2033
+ };
2034
+ const commandPreview = (usePlannerText ? plan.command_preview : undefined) ??
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: plan.title ?? `Create Preparation ${setup.preparationName}`,
1903
- summary: plan.summary ?? "Save this source folder as an Interf Preparation.",
1904
- assistant_message: plan.assistant_message ?? actionAssistantMessage(actionType, setup.preparationName, commandPreview),
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),
1905
2046
  command_preview: commandPreview,
1906
2047
  message: request.message,
1907
- preparation: setup.preparationName,
1908
- method: setup.methodId,
1909
- request: setup.request,
2048
+ preparation: preparationConfig?.name ?? null,
2049
+ method: methodId,
2050
+ request: actionRequest,
1910
2051
  created_at: now,
1911
2052
  updated_at: now,
1912
2053
  proposed_by_executor: this.getExecutorStatus().executor,
@@ -1917,15 +2058,14 @@ export class LocalServiceRuntime {
1917
2058
  });
1918
2059
  }
1919
2060
  const preparationConfig = this.resolvePreparationConfig(plan.preparation ?? request.preparation ?? this.defaultPreparationName());
2061
+ const proposalActionType = ActionProposalTypeSchema.parse(actionType);
1920
2062
  const preparationPath = resolveSourcePreparationPath(this.rootPath, preparationConfig);
1921
2063
  const requestedMethodId = stringValue(request.values, "method_id") ??
1922
2064
  stringValue(request.values, "method");
1923
2065
  const plannedMethodId = plan.method ??
1924
2066
  stringValue(plan.values, "method_id") ??
1925
2067
  stringValue(plan.values, "method");
1926
- const methodId = actionType === "method-authoring"
1927
- ? requestedMethodId ?? plannedMethodId ?? methodIdForProposal(request.message, proposalValues)
1928
- : requestedMethodId ?? plannedMethodId ?? methodIdForSourcePreparationConfig(preparationConfig);
2068
+ const methodId = requestedMethodId ?? plannedMethodId ?? methodIdForSourcePreparationConfig(preparationConfig);
1929
2069
  const clarifyResolvedAction = (options) => ActionProposalResourceSchema.parse({
1930
2070
  kind: "interf-action-proposal",
1931
2071
  version: 1,
@@ -1991,51 +2131,58 @@ export class LocalServiceRuntime {
1991
2131
  target_count: Math.max(1, Math.min(8, Math.round(numberValue(proposalValues, "target_count") ?? 4))),
1992
2132
  };
1993
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);
1994
2139
  return {
1995
2140
  preparation: preparationConfig.name,
1996
2141
  source_folder_path: preparationPath,
1997
- method_id: methodId,
1998
- label: stringValue(proposalValues, "label") ?? `Custom ${preparationConfig.name}`,
1999
- hint: stringValue(proposalValues, "hint") ?? request.message,
2000
- 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,
2001
2148
  checks: preparationConfig.checks ?? [],
2002
2149
  };
2003
2150
  })();
2004
2151
  const title = (() => {
2005
2152
  if (plan.title)
2006
2153
  return plan.title;
2007
- if (actionType === "compile")
2154
+ if (proposalActionType === "compile")
2008
2155
  return `Prepare ${preparationConfig.name}`;
2009
- if (actionType === "test")
2156
+ if (proposalActionType === "test")
2010
2157
  return `Check readiness for ${preparationConfig.name}`;
2011
- if (actionType === "readiness-check-draft")
2158
+ if (proposalActionType === "readiness-check-draft")
2012
2159
  return `Draft readiness checks for ${preparationConfig.name}`;
2013
2160
  return `Draft Method ${methodId}`;
2014
2161
  })();
2015
2162
  const summary = (() => {
2016
2163
  if (plan.summary)
2017
2164
  return plan.summary;
2018
- if (actionType === "compile")
2165
+ if (proposalActionType === "compile")
2019
2166
  return "Build portable context agents can use.";
2020
- if (actionType === "test")
2167
+ if (proposalActionType === "test")
2021
2168
  return "Run readiness checks against source files and portable context.";
2022
- if (actionType === "readiness-check-draft")
2169
+ if (proposalActionType === "readiness-check-draft")
2023
2170
  return "Ask the configured local executor to draft saved readiness checks.";
2024
2171
  return "Ask the configured local executor to create a reusable local Method.";
2025
2172
  })();
2026
- const previewValues = actionType === "test"
2173
+ const previewValues = proposalActionType === "test"
2027
2174
  ? { mode: actionRequest.mode }
2028
2175
  : proposalValues;
2029
- const commandPreview = plan.command_preview ?? actionCommandPreview(actionType, preparationConfig.name, methodId, previewValues);
2176
+ const commandPreview = plan.command_preview ?? actionCommandPreview(proposalActionType, preparationConfig.name, methodId, previewValues);
2030
2177
  return ActionProposalResourceSchema.parse({
2031
2178
  kind: "interf-action-proposal",
2032
2179
  version: 1,
2033
2180
  proposal_id: createActionProposalId(),
2034
2181
  status: "awaiting_approval",
2035
- action_type: actionType,
2182
+ action_type: proposalActionType,
2036
2183
  title,
2037
2184
  summary,
2038
- assistant_message: plan.assistant_message ?? actionAssistantMessage(actionType, preparationConfig.name, commandPreview),
2185
+ assistant_message: plan.assistant_message ?? actionAssistantMessage(proposalActionType, preparationConfig.name, commandPreview),
2039
2186
  command_preview: commandPreview,
2040
2187
  message: request.message,
2041
2188
  preparation: preparationConfig.name,
@@ -2068,13 +2215,6 @@ export class LocalServiceRuntime {
2068
2215
  runType: "test-run",
2069
2216
  };
2070
2217
  }
2071
- if (proposal.action_type === "preparation-setup") {
2072
- const job = await this.createPreparationSetupRun(proposal.request);
2073
- return {
2074
- runId: job.run_id,
2075
- runType: "job-run",
2076
- };
2077
- }
2078
2218
  if (proposal.action_type === "readiness-check-draft") {
2079
2219
  const job = await this.createReadinessCheckDraftRun(proposal.request);
2080
2220
  return {
@@ -2082,7 +2222,11 @@ export class LocalServiceRuntime {
2082
2222
  runType: "job-run",
2083
2223
  };
2084
2224
  }
2085
- 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");
2086
2230
  return {
2087
2231
  runId: job.run_id,
2088
2232
  runType: "job-run",
@@ -2102,7 +2246,7 @@ export class LocalServiceRuntime {
2102
2246
  };
2103
2247
  }
2104
2248
  ensureCompiledForRun(preparationConfig) {
2105
- const methodId = methodIdForSourcePreparationConfig(preparationConfig) ?? DEFAULT_METHOD_ID;
2249
+ const methodId = requireSelectedMethod(preparationConfig);
2106
2250
  const compiledPath = ensurePortableContextScaffold(this.rootPath, preparationConfig.name, methodId);
2107
2251
  syncCompiledInterfConfigFromSourcePreparationConfig(compiledPath, preparationConfig);
2108
2252
  return compiledPath;
@@ -2228,11 +2372,11 @@ export class LocalServiceRuntime {
2228
2372
  });
2229
2373
  }
2230
2374
  }
2231
- readLatestComparison(preparationName) {
2375
+ readLatestReadinessRun(preparationName) {
2232
2376
  return readSavedReadinessCheckRun(this.rootPath, preparationName);
2233
2377
  }
2234
- checksEvaluatedEvent(runId, comparison) {
2235
- const target = comparison.compiled ?? comparison.raw;
2378
+ checksEvaluatedEvent(runId, readinessRun) {
2379
+ const target = readinessRun.compiled ?? readinessRun.raw;
2236
2380
  return {
2237
2381
  type: "checks.evaluated",
2238
2382
  event_id: createRunEventId("event"),