copilotkit 4.9.50 → 4.10.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (74) hide show
  1. package/README.md +44 -4
  2. package/cli-build-info.json +7 -7
  3. package/index.js +1810 -354
  4. package/onboarding/index.json +81 -18
  5. package/onboarding/prompts/authenticate/start.md +56 -190
  6. package/onboarding/prompts/conversion/plan.md +3 -3
  7. package/onboarding/prompts/credentials/finalize-plan.md +25 -98
  8. package/onboarding/prompts/credentials/plan.md +20 -20
  9. package/onboarding/prompts/credentials/settle-credentials.md +153 -0
  10. package/onboarding/prompts/credentials/write-plan.md +93 -0
  11. package/onboarding/prompts/fallback/best-effort.md +12 -9
  12. package/onboarding/prompts/feature/a2ui/implement.md +35 -6
  13. package/onboarding/prompts/feature/a2ui/proof.md +30 -6
  14. package/onboarding/prompts/feature/a2ui/start.md +29 -6
  15. package/onboarding/prompts/feature/chat-suggestions/implement.md +36 -6
  16. package/onboarding/prompts/feature/chat-suggestions/proof.md +30 -5
  17. package/onboarding/prompts/feature/chat-suggestions/start.md +29 -6
  18. package/onboarding/prompts/feature/complete.md +11 -0
  19. package/onboarding/prompts/feature/learning/implement.md +102 -11
  20. package/onboarding/prompts/feature/learning/proof.md +53 -9
  21. package/onboarding/prompts/feature/learning/start.md +35 -8
  22. package/onboarding/prompts/feature/open-generative-ui/implement.md +37 -6
  23. package/onboarding/prompts/feature/open-generative-ui/proof.md +30 -5
  24. package/onboarding/prompts/feature/open-generative-ui/start.md +29 -6
  25. package/onboarding/prompts/feature/realtime-sync/implement.md +36 -7
  26. package/onboarding/prompts/feature/realtime-sync/proof.md +29 -5
  27. package/onboarding/prompts/feature/realtime-sync/start.md +28 -5
  28. package/onboarding/prompts/feature/rich-threads/implement.md +37 -8
  29. package/onboarding/prompts/feature/rich-threads/proof.md +31 -5
  30. package/onboarding/prompts/feature/rich-threads/start.md +28 -5
  31. package/onboarding/prompts/feature/stop.md +10 -7
  32. package/onboarding/prompts/feature/voice/implement.md +35 -6
  33. package/onboarding/prompts/feature/voice/proof.md +30 -5
  34. package/onboarding/prompts/feature/voice/start.md +29 -6
  35. package/onboarding/prompts/framework/ag2.md +2 -2
  36. package/onboarding/prompts/framework/agno.md +2 -2
  37. package/onboarding/prompts/framework/built-in.md +2 -2
  38. package/onboarding/prompts/framework/claude-sdk-python.md +2 -2
  39. package/onboarding/prompts/framework/claude-sdk-typescript.md +2 -2
  40. package/onboarding/prompts/framework/crewai-flows.md +2 -2
  41. package/onboarding/prompts/framework/deep-agents.md +2 -2
  42. package/onboarding/prompts/framework/google-adk.md +2 -2
  43. package/onboarding/prompts/framework/langgraph-fastapi.md +2 -2
  44. package/onboarding/prompts/framework/langgraph-python.md +2 -2
  45. package/onboarding/prompts/framework/langgraph-typescript.md +2 -2
  46. package/onboarding/prompts/framework/llamaindex.md +2 -2
  47. package/onboarding/prompts/framework/mastra.md +2 -2
  48. package/onboarding/prompts/framework/ms-agent-dotnet.md +2 -2
  49. package/onboarding/prompts/framework/ms-agent-harness-dotnet.md +2 -2
  50. package/onboarding/prompts/framework/ms-agent-python.md +2 -2
  51. package/onboarding/prompts/framework/pydantic-ai.md +2 -2
  52. package/onboarding/prompts/framework/strands-python.md +2 -2
  53. package/onboarding/prompts/framework/strands-typescript.md +2 -2
  54. package/onboarding/prompts/frontend/angular.md +3 -3
  55. package/onboarding/prompts/frontend/nextjs.md +3 -3
  56. package/onboarding/prompts/frontend/plan.md +6 -6
  57. package/onboarding/prompts/frontend/react-native.md +2 -2
  58. package/onboarding/prompts/frontend/react-spa.md +2 -2
  59. package/onboarding/prompts/frontend/vue.md +2 -2
  60. package/onboarding/prompts/implementation/build-and-validate.md +122 -12
  61. package/onboarding/prompts/proof/complete.md +23 -10
  62. package/onboarding/prompts/proof/oss-baseline.md +17 -7
  63. package/onboarding/prompts/proof/round-trip.md +33 -13
  64. package/onboarding/prompts/research/gather.md +121 -0
  65. package/onboarding/prompts/research/route.md +81 -0
  66. package/onboarding/prompts/starter/clone.md +18 -9
  67. package/onboarding/prompts/stopped/run-failed.md +44 -0
  68. package/onboarding/prompts/subagent/create-plan.md +32 -1
  69. package/onboarding/prompts/subagent/implement-and-validate.md +9 -1
  70. package/onboarding/prompts/subagent/prove-oss-baseline.md +1 -1
  71. package/onboarding/prompts/subagent/prove-round-trip.md +59 -12
  72. package/onboarding/prompts/unsupported/no-validated-path.md +10 -7
  73. package/package.json +1 -1
  74. package/release/release-tool.js +39 -3
package/index.js CHANGED
@@ -96,14 +96,14 @@ function getTelemetryEndpointUrl() {
96
96
  }
97
97
  function getBuildInfo() {
98
98
  return {
99
- version: true ? "4.9.50" : "dev",
100
- buildNumber: true ? "34486444519" : "dev",
101
- commitSha: true ? "1e703c3c476af7d0a52f801e34fbce2997f6a926" : "dev",
99
+ version: true ? "4.10.0" : "dev",
100
+ buildNumber: true ? "35011911410" : "dev",
101
+ commitSha: true ? "c8e38c8634104047e47545c1ed45a21c259a8658" : "dev",
102
102
  copilotKitCommit: getTemplateRef()
103
103
  };
104
104
  }
105
105
  function getTemplateRef() {
106
- return true ? "380ad1220a7bc78104baedc469c4d086c8910494" : "main";
106
+ return true ? "ce490419d046abe697438b070a99ad5d674365cc" : "main";
107
107
  }
108
108
  function getC15tBackendUrl() {
109
109
  return true ? "https://calm-hazelnut-joy-copilotkit.inth.app" : "";
@@ -1033,6 +1033,12 @@ function classifyError(err2, depth = 0) {
1033
1033
  if (err2.name === "AbortError") {
1034
1034
  return "timeout";
1035
1035
  }
1036
+ const apiErrorCode = err2.code;
1037
+ if (apiErrorCode === "LEARNING_NOT_ENABLED")
1038
+ return "learning_not_enabled";
1039
+ if (apiErrorCode === "LEARNING_CONTAINER_NOT_FOUND") {
1040
+ return "learning_container_absent";
1041
+ }
1036
1042
  const status = err2.status;
1037
1043
  if (err2.name === "ApiClientError" && typeof status === "number") {
1038
1044
  if (status === 401 || status === 403)
@@ -1070,7 +1076,7 @@ function classifyError(err2, depth = 0) {
1070
1076
  return "validation";
1071
1077
  if (code === "ONBOARDING_PROMPT_UNREADABLE")
1072
1078
  return "filesystem";
1073
- if (code === "CLI_PRODUCT_BINARY_TOO_LARGE" || code === "LEARNING_CANDIDATE_CONFLICT" || code === "LEARNING_CANDIDATE_SETTLED" || code === "LEARNING_CANDIDATE_ID_INVALID" || code === "LEARNING_CONTAINER_ID_INVALID" || code === "LEARNING_CONTAINER_INPUT_INVALID" || code === "LEARNING_CONTAINER_NOT_FOUND" || code === "LEARNING_CONTAINER_RESPONSE_INVALID" || code === "LEARNING_PROJECT_ID_INVALID" || code === "LEARNING_RESPONSE_INVALID" || code === "LEARNING_SKILLS_BUNDLE_INVALID" || code === "LEARNING_SKILLS_INTEGRITY_FAILED" || code === "LEARNING_SKILLS_OUTPUT_EXISTS") {
1079
+ if (code === "CLI_PRODUCT_BINARY_TOO_LARGE" || code === "LEARNING_CANDIDATE_CONFLICT" || code === "LEARNING_CANDIDATE_SETTLED" || code === "LEARNING_CANDIDATE_ID_INVALID" || code === "LEARNING_CONTAINER_ID_INVALID" || code === "LEARNING_CONTAINER_INPUT_INVALID" || code === "LEARNING_CONTAINER_RESPONSE_INVALID" || code === "LEARNING_PROJECT_ID_INVALID" || code === "LEARNING_RESPONSE_INVALID" || code === "LEARNING_SKILLS_BUNDLE_INVALID" || code === "LEARNING_SKILLS_INTEGRITY_FAILED" || code === "LEARNING_SKILLS_OUTPUT_EXISTS") {
1074
1080
  return "validation";
1075
1081
  }
1076
1082
  if (code === "KEY_PROVISION_FAILED")
@@ -28858,6 +28864,29 @@ function recordServedPrompt(dependencies, runId, promptName) {
28858
28864
  route: [...previous, promptName]
28859
28865
  });
28860
28866
  }
28867
+ function markRunEnded(dependencies, runId) {
28868
+ const key = stateKey("route", resolveAnchoredRoot(dependencies));
28869
+ const stored = readStoredRoute(dependencies.store, key);
28870
+ if (stored === void 0 || stored.runId !== runId)
28871
+ return;
28872
+ dependencies.store.set(key, { ...stored, ended: true });
28873
+ }
28874
+ function readAbandonedRun(dependencies, currentRunId) {
28875
+ const stored = readStoredRoute(
28876
+ dependencies.store,
28877
+ stateKey("route", resolveAnchoredRoot(dependencies))
28878
+ );
28879
+ if (stored === void 0)
28880
+ return void 0;
28881
+ if (stored.runId === currentRunId)
28882
+ return void 0;
28883
+ if (stored.ended === true)
28884
+ return void 0;
28885
+ const lastPrompt = stored.route[stored.route.length - 1];
28886
+ if (lastPrompt === void 0)
28887
+ return void 0;
28888
+ return { runId: stored.runId, lastPrompt, steps: stored.route.length };
28889
+ }
28861
28890
  function readOnboardingRoute(dependencies) {
28862
28891
  const root2 = resolveAnchoredRoot(dependencies);
28863
28892
  const stored = readStoredRoute(dependencies.store, stateKey("route", root2));
@@ -28868,6 +28897,57 @@ function readOnboardingRoute(dependencies) {
28868
28897
  return [];
28869
28898
  return stored.route;
28870
28899
  }
28900
+ function readStoredProofs(store, key) {
28901
+ const stored = store.get(key);
28902
+ if (typeof stored !== "object" || stored === null)
28903
+ return void 0;
28904
+ if (typeof stored.runId !== "string")
28905
+ return void 0;
28906
+ return typeof stored.proofs === "object" && stored.proofs !== null ? stored : void 0;
28907
+ }
28908
+ function recordProofOutcome(dependencies, runId, step, proof) {
28909
+ const key = stateKey("proof", resolveAnchoredRoot(dependencies));
28910
+ const stored = readStoredProofs(dependencies.store, key);
28911
+ const previous = stored?.runId === runId ? stored.proofs : {};
28912
+ dependencies.store.set(key, {
28913
+ runId,
28914
+ proofs: { ...previous, [step]: proof }
28915
+ });
28916
+ }
28917
+ function readProofOutcome(dependencies, step) {
28918
+ const root2 = resolveAnchoredRoot(dependencies);
28919
+ const stored = readStoredProofs(dependencies.store, stateKey("proof", root2));
28920
+ if (stored === void 0)
28921
+ return void 0;
28922
+ const bound = readBoundRun(dependencies.store, root2);
28923
+ if (bound.state === "live" && bound.runId !== stored.runId)
28924
+ return void 0;
28925
+ return stored.proofs[step];
28926
+ }
28927
+ function readStoredCodingAgent(store, key) {
28928
+ const stored = store.get(key);
28929
+ if (typeof stored !== "object" || stored === null)
28930
+ return void 0;
28931
+ if (typeof stored.runId !== "string")
28932
+ return void 0;
28933
+ return typeof stored.codingAgent === "string" ? stored : void 0;
28934
+ }
28935
+ function recordCodingAgent(dependencies, runId, codingAgent) {
28936
+ dependencies.store.set(stateKey("agent", resolveAnchoredRoot(dependencies)), {
28937
+ codingAgent: normalizeCodingAgent(codingAgent),
28938
+ runId
28939
+ });
28940
+ }
28941
+ function readCodingAgent(dependencies) {
28942
+ const root2 = resolveAnchoredRoot(dependencies);
28943
+ const stored = readStoredCodingAgent(dependencies.store, stateKey("agent", root2));
28944
+ if (stored === void 0)
28945
+ return void 0;
28946
+ const bound = readBoundRun(dependencies.store, root2);
28947
+ if (bound.state === "live" && bound.runId !== stored.runId)
28948
+ return void 0;
28949
+ return stored.codingAgent;
28950
+ }
28871
28951
  function readOnboardingRunId(dependencies) {
28872
28952
  try {
28873
28953
  const bound = readBoundRun(
@@ -28890,21 +28970,6 @@ function readOnboardingIntent(dependencies) {
28890
28970
  return void 0;
28891
28971
  }
28892
28972
  }
28893
- function resolveOnboardingRun(dependencies) {
28894
- const root2 = resolveAnchoredRoot(dependencies);
28895
- const bound = readBoundRun(dependencies.store, root2);
28896
- if (bound.state === "live") {
28897
- return {
28898
- runId: bound.runId,
28899
- started: false,
28900
- idOrigin: "minted",
28901
- ...bound.intent === void 0 ? {} : { intent: bound.intent }
28902
- };
28903
- }
28904
- const generatedRun = mintRunId(dependencies);
28905
- dependencies.store.set(stateKey("run", root2), generatedRun);
28906
- return { runId: generatedRun, started: true, idOrigin: "minted" };
28907
- }
28908
28973
  function startOnboardingRun(dependencies, requestedRunId, requestedIntent) {
28909
28974
  if (requestedIntent !== void 0 && !ONBOARDING_INTENT_PATTERN.test(requestedIntent)) {
28910
28975
  throw new Error("Requested onboarding intent is invalid");
@@ -29761,7 +29826,7 @@ var require_redact = __commonJS({
29761
29826
  } = options;
29762
29827
  validatePaths(paths);
29763
29828
  const pathStructure = buildPathStructure(paths);
29764
- return function redact(obj) {
29829
+ return function redact2(obj) {
29765
29830
  if (strict2 && (obj === null || typeof obj !== "object")) {
29766
29831
  if (obj === null || obj === void 0) {
29767
29832
  return serialize3 ? serialize3(obj) : obj;
@@ -33238,7 +33303,7 @@ var require_pino = __commonJS({
33238
33303
  if (opts.level && typeof opts.level === "string" && DEFAULT_LEVELS[opts.level.toLowerCase()] !== void 0)
33239
33304
  opts.level = opts.level.toLowerCase();
33240
33305
  const {
33241
- redact,
33306
+ redact: redact2,
33242
33307
  crlf,
33243
33308
  serializers: serializers2,
33244
33309
  timestamp: timestamp2,
@@ -33272,8 +33337,8 @@ var require_pino = __commonJS({
33272
33337
  const stringifyFn = stringify4.bind({
33273
33338
  [stringifySafeSym]: stringifySafe
33274
33339
  });
33275
- const stringifiers = redact ? redaction(redact, stringifyFn) : {};
33276
- const formatOpts = redact ? { stringify: stringifiers[redactFmtSym] } : { stringify: stringifyFn };
33340
+ const stringifiers = redact2 ? redaction(redact2, stringifyFn) : {};
33341
+ const formatOpts = redact2 ? { stringify: stringifiers[redactFmtSym] } : { stringify: stringifyFn };
33277
33342
  const end = "}" + (crlf ? "\r\n" : "\n");
33278
33343
  const coreChindings = asChindings.bind(null, {
33279
33344
  [chindingsSym]: "",
@@ -91416,6 +91481,19 @@ function describeCredentialWriteDirectory(dir, ceilingDir) {
91416
91481
  return `Wrote the project key to ${envPath}. ${subject} ${named} ${verb} env files from its own directory, so re-run \`copilotkit project select\` from ${target} to put the key where the app process reads it.
91417
91482
  `;
91418
91483
  }
91484
+ function envFileLoaderDeclaredIn(appDir, ceiling) {
91485
+ const filesystemRoot = path11.parse(appDir).root;
91486
+ let candidate = appDir;
91487
+ while (true) {
91488
+ if (readAppManifest(candidate)?.declaresEnvFileLoader === true) {
91489
+ return candidate;
91490
+ }
91491
+ if (candidate === ceiling || candidate === filesystemRoot) {
91492
+ return void 0;
91493
+ }
91494
+ candidate = path11.dirname(candidate);
91495
+ }
91496
+ }
91419
91497
  function resolveCredentialLoad(inputs) {
91420
91498
  if (inputs.variableName === void 0) {
91421
91499
  return { kind: "no-key" };
@@ -91428,8 +91506,12 @@ function resolveCredentialLoad(inputs) {
91428
91506
  return { apps: apps2, kind: "ambiguous" };
91429
91507
  }
91430
91508
  const appDir = apps2[0];
91431
- if (readAppManifest(appDir)?.declaresEnvFileLoader === true) {
91432
- return { appDir, kind: "loader-declared" };
91509
+ const declaredIn = envFileLoaderDeclaredIn(
91510
+ appDir,
91511
+ canonicalizeDir(inputs.ceiling)
91512
+ );
91513
+ if (declaredIn !== void 0) {
91514
+ return { appDir, declaredIn, kind: "loader-declared" };
91433
91515
  }
91434
91516
  if (inputs.source === void 0) {
91435
91517
  return { appDir, kind: "process-environment" };
@@ -91648,7 +91730,7 @@ function formatTelemetryNotice(privacyPolicyUrl) {
91648
91730
  return [
91649
91731
  "The CopilotKit CLI collects usage data to help improve the product.",
91650
91732
  "While you are signed in, that data is linked to your CopilotKit account.",
91651
- "The onboarding feedback command may send up to 2,048 UTF-8 bytes of text.",
91733
+ "The onboarding friction command sends up to 2,048 UTF-8 bytes of text.",
91652
91734
  "",
91653
91735
  " Disable anytime: copilotkit telemetry disable (or set DO_NOT_TRACK=1)",
91654
91736
  ` Privacy policy: ${privacyPolicyUrl}`,
@@ -91695,6 +91777,15 @@ function createTelemetryService(deps) {
91695
91777
  return typeof deps.installationId === "function" ? deps.installationId() : deps.installationId;
91696
91778
  }
91697
91779
  async function sendOne(prepared) {
91780
+ if (prepared.installationId === "") {
91781
+ deps.logger.error({
91782
+ msg: "telemetry.dropped.no_identity",
91783
+ event: prepared.body.event,
91784
+ outcome: prepared.outcome,
91785
+ command: prepared.command
91786
+ });
91787
+ return { status: "no_identity" };
91788
+ }
91698
91789
  const controller = new AbortController();
91699
91790
  const timer = setTimeout(() => controller.abort(), perRequestTimeoutMs);
91700
91791
  timer.unref?.();
@@ -91710,33 +91801,38 @@ function createTelemetryService(deps) {
91710
91801
  signal: controller.signal
91711
91802
  });
91712
91803
  if (!res.ok) {
91804
+ const latencyMs = Date.now() - started;
91713
91805
  deps.logger.warn({
91714
91806
  msg: "telemetry.sink.failed",
91807
+ event: prepared.body.event,
91715
91808
  status: res.status,
91716
- latency_ms: Date.now() - started,
91809
+ latency_ms: latencyMs,
91717
91810
  outcome: prepared.outcome,
91718
91811
  command: prepared.command
91719
91812
  });
91720
- return false;
91813
+ return { status: "http_error", httpStatus: res.status, latencyMs };
91721
91814
  }
91722
91815
  deps.logger.debug({
91723
91816
  msg: "telemetry.sink.succeeded",
91817
+ event: prepared.body.event,
91724
91818
  status: res.status,
91725
91819
  latency_ms: Date.now() - started,
91726
91820
  outcome: prepared.outcome,
91727
91821
  command: prepared.command
91728
91822
  });
91729
- return true;
91823
+ return { status: "sent" };
91730
91824
  } catch (err2) {
91731
91825
  const isAbort = err2 instanceof Error && err2.name === "AbortError";
91826
+ const latencyMs = Date.now() - started;
91732
91827
  deps.logger.warn({
91733
91828
  msg: "telemetry.sink.failed",
91734
- latency_ms: Date.now() - started,
91829
+ event: prepared.body.event,
91830
+ latency_ms: latencyMs,
91735
91831
  outcome: prepared.outcome,
91736
91832
  command: prepared.command,
91737
91833
  error_code: isAbort ? "timeout" : "network"
91738
91834
  });
91739
- return false;
91835
+ return isAbort ? { status: "timeout", timeoutMs: perRequestTimeoutMs, latencyMs } : { status: "network", latencyMs };
91740
91836
  } finally {
91741
91837
  clearTimeout(timer);
91742
91838
  }
@@ -91763,6 +91859,7 @@ function createTelemetryService(deps) {
91763
91859
  if (inFlight.size >= maxInFlight) {
91764
91860
  deps.logger.error({
91765
91861
  msg: "telemetry.dropped.queue_full",
91862
+ event: event.event ?? CLI_TELEMETRY_EVENT_NAME,
91766
91863
  outcome: event.properties.outcome,
91767
91864
  command: event.properties.command
91768
91865
  });
@@ -91778,8 +91875,17 @@ function createTelemetryService(deps) {
91778
91875
  });
91779
91876
  }
91780
91877
  async function submitEvent(event) {
91781
- if (!deps.enabled || inFlight.size >= maxInFlight)
91782
- return false;
91878
+ if (!deps.enabled)
91879
+ return { status: "disabled" };
91880
+ if (inFlight.size >= maxInFlight) {
91881
+ deps.logger.error({
91882
+ msg: "telemetry.dropped.queue_full",
91883
+ event: event.event ?? CLI_TELEMETRY_EVENT_NAME,
91884
+ outcome: event.properties.outcome,
91885
+ command: event.properties.command
91886
+ });
91887
+ return { status: "queue_full", inFlight: inFlight.size };
91888
+ }
91783
91889
  const promise3 = (async () => {
91784
91890
  await new Promise((resolve9) => setImmediate(resolve9));
91785
91891
  return await sendOne(prepareEvent(event));
@@ -91821,8 +91927,10 @@ __export(telemetry_exports, {
91821
91927
  cliLogTelemetryLogger: () => cliLogTelemetryLogger,
91822
91928
  currentAuthIdentity: () => currentAuthIdentity,
91823
91929
  currentCliStateProperties: () => currentCliStateProperties,
91930
+ currentOnboardingCodingAgent: () => currentOnboardingCodingAgent,
91824
91931
  currentOnboardingRunProperties: () => currentOnboardingRunProperties,
91825
91932
  currentProjectIdentity: () => currentProjectIdentity,
91933
+ describeSubmissionError: () => describeSubmissionError,
91826
91934
  exitWithFlush: () => exitWithFlush,
91827
91935
  flushTelemetry: () => flushTelemetry,
91828
91936
  getCliConsentProvider: () => getCliConsentProvider,
@@ -91831,6 +91939,7 @@ __export(telemetry_exports, {
91831
91939
  hasStandaloneTelemetryIdentityConsent: () => hasStandaloneTelemetryIdentityConsent,
91832
91940
  linkConsentSubjectToUser: () => linkConsentSubjectToUser,
91833
91941
  recordTelemetryEvent: () => recordTelemetryEvent,
91942
+ resolveReturnedOutcome: () => resolveReturnedOutcome,
91834
91943
  submitTelemetryEvent: () => submitTelemetryEvent,
91835
91944
  withTelemetry: () => withTelemetry
91836
91945
  });
@@ -91906,6 +92015,9 @@ function currentOnboardingRunProperties() {
91906
92015
  });
91907
92016
  return runId === void 0 ? {} : { onboarding_run_id: runId };
91908
92017
  }
92018
+ function currentOnboardingCodingAgent() {
92019
+ return readCodingAgent({ cwd: process.cwd(), store: configStore });
92020
+ }
91909
92021
  function currentAuthIdentity() {
91910
92022
  return resolveAuthIdentityProperties({
91911
92023
  readStoredAuth: () => authStore.get()
@@ -91956,8 +92068,54 @@ async function submitTelemetryEvent(event) {
91956
92068
  noticeShown: hasShownTelemetryNotice(configStore)
91957
92069
  });
91958
92070
  if (!gate.send)
91959
- return false;
91960
- return await getTelemetry().submitEvent(withProjectIdentity(event));
92071
+ return { status: "declined" };
92072
+ try {
92073
+ const delivery = await getTelemetry().submitEvent(
92074
+ withProjectIdentity(event)
92075
+ );
92076
+ return describeDelivery(delivery);
92077
+ } catch (error98) {
92078
+ return { status: "failed", detail: describeSubmissionError(error98) };
92079
+ }
92080
+ }
92081
+ function describeDelivery(delivery) {
92082
+ switch (delivery.status) {
92083
+ case "sent":
92084
+ return { status: "sent" };
92085
+ case "disabled":
92086
+ return { status: "declined" };
92087
+ case "no_identity":
92088
+ return {
92089
+ status: "failed",
92090
+ detail: "this install has no telemetry id, so nothing was sent"
92091
+ };
92092
+ case "queue_full":
92093
+ return {
92094
+ status: "failed",
92095
+ detail: `the send queue was full at ${delivery.inFlight} requests, so nothing was sent`
92096
+ };
92097
+ case "http_error":
92098
+ return {
92099
+ status: "failed",
92100
+ detail: `the sink refused the event with HTTP ${delivery.httpStatus}`
92101
+ };
92102
+ case "timeout":
92103
+ return {
92104
+ status: "failed",
92105
+ detail: `the send timed out after ${delivery.timeoutMs}ms`
92106
+ };
92107
+ case "network":
92108
+ return {
92109
+ status: "failed",
92110
+ detail: "the network request failed before the sink answered"
92111
+ };
92112
+ }
92113
+ }
92114
+ function describeSubmissionError(error98) {
92115
+ if (error98 instanceof Error && error98.message !== "")
92116
+ return error98.message;
92117
+ const described = String(error98);
92118
+ return described === "" ? "the telemetry transport threw" : described;
91961
92119
  }
91962
92120
  async function flushTelemetry(timeoutMs = DEFAULT_FLUSH_TIMEOUT_MS) {
91963
92121
  if (!instance)
@@ -91968,6 +92126,17 @@ async function exitWithFlush(code) {
91968
92126
  await flushTelemetry();
91969
92127
  process.exit(code);
91970
92128
  }
92129
+ function resolveReturnedOutcome(input) {
92130
+ if (input.declaredFailure !== null) {
92131
+ return {
92132
+ outcome: "failed",
92133
+ ...input.declaredFailure.errorCode === void 0 ? {} : { errorCode: input.declaredFailure.errorCode }
92134
+ };
92135
+ }
92136
+ const { exitCode } = input;
92137
+ const failedByExit = exitCode !== void 0 && exitCode !== 0 && exitCode !== "0";
92138
+ return failedByExit ? { outcome: "failed" } : { outcome: "succeeded" };
92139
+ }
91971
92140
  async function withTelemetry(base, fn) {
91972
92141
  const buildInfo = getBuildInfo();
91973
92142
  const provider = getConsentProvider();
@@ -91988,9 +92157,13 @@ async function withTelemetry(base, fn) {
91988
92157
  }
91989
92158
  const startedAt = Date.now();
91990
92159
  let extra = {};
92160
+ let declaredFailure = null;
91991
92161
  const ctx = {
91992
92162
  setProperties(next) {
91993
92163
  extra = { ...extra, ...next };
92164
+ },
92165
+ reportFailure(input) {
92166
+ declaredFailure = input ?? {};
91994
92167
  }
91995
92168
  };
91996
92169
  recordTelemetryEvent({
@@ -92003,14 +92176,19 @@ async function withTelemetry(base, fn) {
92003
92176
  });
92004
92177
  try {
92005
92178
  const result = await fn(ctx);
92179
+ const verdict = resolveReturnedOutcome({
92180
+ declaredFailure,
92181
+ exitCode: process.exitCode
92182
+ });
92006
92183
  recordTelemetryEvent({
92007
92184
  properties: {
92008
92185
  ...base,
92009
92186
  ...currentCliStateProperties(base.command),
92010
92187
  ...currentOnboardingRunProperties(),
92011
92188
  ...extra,
92012
- outcome: "succeeded",
92013
- duration_ms: Date.now() - startedAt
92189
+ outcome: verdict.outcome,
92190
+ duration_ms: Date.now() - startedAt,
92191
+ ...verdict.errorCode === void 0 ? {} : { error_code: verdict.errorCode }
92014
92192
  }
92015
92193
  });
92016
92194
  return result;
@@ -93755,6 +93933,9 @@ async function login(options = {}) {
93755
93933
  if (options.authHandoff) {
93756
93934
  loginParams.set("source", options.authHandoff.source);
93757
93935
  loginParams.set("mode", options.authHandoff.mode);
93936
+ if (options.authHandoff.agent !== void 0) {
93937
+ loginParams.set("agent", options.authHandoff.agent);
93938
+ }
93758
93939
  }
93759
93940
  const loginUrl = `${getOpsFrontendUrl()}/cli-auth?${loginParams.toString()}`;
93760
93941
  diagnostics.logPhase("login.browser-url-prepared", {
@@ -94804,13 +94985,25 @@ import * as fs18 from "node:fs";
94804
94985
  import * as path14 from "node:path";
94805
94986
  import * as os7 from "node:os";
94806
94987
  import { execFileSync as execFileSync3 } from "node:child_process";
94988
+ function isCredentialEnvFile(entry) {
94989
+ if (!entry.startsWith(".env"))
94990
+ return false;
94991
+ if (ENV_TEMPLATE_SUFFIXES.some((suffix) => entry.endsWith(suffix)))
94992
+ return false;
94993
+ return entry === ".env" || entry.startsWith(".env.");
94994
+ }
94995
+ function entryHoldsProject(entry) {
94996
+ if (isCredentialEnvFile(entry))
94997
+ return true;
94998
+ return PROJECT_DIRECTORY_NAMES.has(entry) || PROJECT_MANIFEST_NAMES.has(entry);
94999
+ }
94807
95000
  function isProjectDirOccupied(projectDir) {
94808
- return fs18.existsSync(projectDir) && fs18.readdirSync(projectDir).length > 0;
95001
+ return fs18.existsSync(projectDir) && fs18.readdirSync(projectDir).some(entryHoldsProject);
94809
95002
  }
94810
95003
  function assertProjectDirAvailable(projectDir) {
94811
95004
  if (isProjectDirOccupied(projectDir)) {
94812
95005
  throw tagError(
94813
- new Error(`${projectDir} already exists and is not empty`),
95006
+ new Error(`${projectDir} already holds a project`),
94814
95007
  TELEMETRY_ERROR_CODES.PREREQUISITE_MISSING
94815
95008
  );
94816
95009
  }
@@ -95060,12 +95253,36 @@ async function initializeProjectGit(projectDir) {
95060
95253
  }
95061
95254
  return { kind: "initialized" };
95062
95255
  }
95063
- var TEST_HARNESS_ARTIFACTS, LICENSE_TOKEN_LINE_RE;
95256
+ var PROJECT_DIRECTORY_NAMES, PROJECT_MANIFEST_NAMES, ENV_TEMPLATE_SUFFIXES, TEST_HARNESS_ARTIFACTS, LICENSE_TOKEN_LINE_RE;
95064
95257
  var init_project_scaffold = __esm({
95065
95258
  "apps/cli/src/services/project-scaffold.ts"() {
95066
95259
  "use strict";
95067
95260
  init_repository_root();
95068
95261
  init_event_properties();
95262
+ PROJECT_DIRECTORY_NAMES = /* @__PURE__ */ new Set([
95263
+ "agent",
95264
+ "api",
95265
+ "app",
95266
+ "components",
95267
+ "lib",
95268
+ "packages",
95269
+ "pages",
95270
+ "server",
95271
+ "src",
95272
+ "web"
95273
+ ]);
95274
+ PROJECT_MANIFEST_NAMES = /* @__PURE__ */ new Set([
95275
+ "Cargo.toml",
95276
+ "Gemfile",
95277
+ "build.gradle",
95278
+ "composer.json",
95279
+ "go.mod",
95280
+ "package.json",
95281
+ "pom.xml",
95282
+ "pyproject.toml",
95283
+ "requirements.txt"
95284
+ ]);
95285
+ ENV_TEMPLATE_SUFFIXES = [".example", ".sample", ".template"];
95069
95286
  TEST_HARNESS_ARTIFACTS = [
95070
95287
  "docker",
95071
95288
  ".dockerignore",
@@ -95890,6 +96107,27 @@ var init_project_list = __esm({
95890
96107
  });
95891
96108
 
95892
96109
  // apps/cli/src/services/hosted-project-name.ts
96110
+ function suggestFreeProjectName(raw2, existing) {
96111
+ const name = raw2.trim();
96112
+ const taken = new Set(
96113
+ existing.map((project) => project.name.trim().toLowerCase())
96114
+ );
96115
+ if (!taken.has(name.toLowerCase())) {
96116
+ return name;
96117
+ }
96118
+ const stripped = name.replace(NUMERIC_SUFFIX, "");
96119
+ const base = stripped === "" ? name : stripped;
96120
+ let candidate = base;
96121
+ for (let counter = 2; counter < SUGGESTION_ATTEMPTS + 2; counter += 1) {
96122
+ const suffix = `-${String(counter)}`;
96123
+ const room = MAX_PROJECT_NAME_LENGTH - suffix.length;
96124
+ candidate = `${base.slice(0, room)}${suffix}`;
96125
+ if (!taken.has(candidate.toLowerCase())) {
96126
+ return candidate;
96127
+ }
96128
+ }
96129
+ return candidate;
96130
+ }
95893
96131
  function validateProjectName(raw2, existing) {
95894
96132
  const name = raw2.trim();
95895
96133
  if (name === "") {
@@ -95914,16 +96152,19 @@ function validateProjectName(raw2, existing) {
95914
96152
  ok: false,
95915
96153
  reason: "duplicate",
95916
96154
  message: `You already have a project named "${duplicate.name}".`,
95917
- duplicate
96155
+ duplicate,
96156
+ suggestion: suggestFreeProjectName(name, existing)
95918
96157
  };
95919
96158
  }
95920
96159
  return { ok: true, name };
95921
96160
  }
95922
- var MAX_PROJECT_NAME_LENGTH;
96161
+ var MAX_PROJECT_NAME_LENGTH, NUMERIC_SUFFIX, SUGGESTION_ATTEMPTS;
95923
96162
  var init_hosted_project_name = __esm({
95924
96163
  "apps/cli/src/services/hosted-project-name.ts"() {
95925
96164
  "use strict";
95926
96165
  MAX_PROJECT_NAME_LENGTH = 100;
96166
+ NUMERIC_SUFFIX = /-\d+$/;
96167
+ SUGGESTION_ATTEMPTS = 1e3;
95927
96168
  }
95928
96169
  });
95929
96170
 
@@ -95953,6 +96194,12 @@ function defer() {
95953
96194
  function ProjectExplainer({ dim = false }) {
95954
96195
  return /* @__PURE__ */ (0, import_jsx_runtime7.jsx)(Text, { dimColor: dim, children: "An Intelligence project is where this app's threads, messages, and analytics are stored." });
95955
96196
  }
96197
+ function describeNameRefusal(validation) {
96198
+ if (validation.suggestion === void 0) {
96199
+ return validation.message;
96200
+ }
96201
+ return `${validation.message} "${validation.suggestion}" is free \u2014 press Enter to use it, type a different name, or cancel (Esc) and select the existing one from the list.`;
96202
+ }
95956
96203
  function HostedProjectSelect({
95957
96204
  apiClient,
95958
96205
  onResolved,
@@ -95967,6 +96214,7 @@ function HostedProjectSelect({
95967
96214
  const nameDirtyRef = (0, import_react37.useRef)(false);
95968
96215
  const [nameDirty, setNameDirty] = (0, import_react37.useState)(false);
95969
96216
  const [nameError, setNameError] = (0, import_react37.useState)("");
96217
+ const offeredNameRef = (0, import_react37.useRef)(null);
95970
96218
  const pickerIndexRef = (0, import_react37.useRef)(0);
95971
96219
  const [pickerIndex, setPickerIndex] = (0, import_react37.useState)(0);
95972
96220
  const choiceRef = (0, import_react37.useRef)(null);
@@ -95998,6 +96246,8 @@ function HostedProjectSelect({
95998
96246
  setNameDisplay(defaultName);
95999
96247
  nameDirtyRef.current = false;
96000
96248
  setNameDirty(false);
96249
+ offeredNameRef.current = null;
96250
+ setNameError("");
96001
96251
  setView({ kind: "name" });
96002
96252
  return deferred.promise;
96003
96253
  }
@@ -96081,22 +96331,30 @@ function HostedProjectSelect({
96081
96331
  nameDirtyRef.current = true;
96082
96332
  setNameDirty(true);
96083
96333
  }
96334
+ const offered = offeredNameRef.current;
96335
+ if (offered !== null && textBeforeNewline === "") {
96336
+ offeredNameRef.current = null;
96337
+ setNameError("");
96338
+ nameRef.current?.resolve(offered);
96339
+ return;
96340
+ }
96084
96341
  const validation = validateProjectName(
96085
96342
  nameBufferRef.current,
96086
96343
  projectsRef.current
96087
96344
  );
96088
96345
  if (!validation.ok) {
96089
- setNameError(
96090
- validation.reason === "duplicate" ? `${validation.message} Choose a different name, or cancel (Esc) and select it from the list.` : validation.message
96091
- );
96346
+ offeredNameRef.current = validation.suggestion ?? null;
96347
+ setNameError(describeNameRefusal(validation));
96092
96348
  telemetry?.onCreateNameRejected?.(validation.reason);
96093
96349
  return;
96094
96350
  }
96351
+ offeredNameRef.current = null;
96095
96352
  setNameError("");
96096
96353
  nameRef.current?.resolve(validation.name);
96097
96354
  return;
96098
96355
  }
96099
96356
  if (key.backspace || key.delete) {
96357
+ offeredNameRef.current = null;
96100
96358
  const updated = nameDirtyRef.current ? nameBufferRef.current.slice(0, -1) : "";
96101
96359
  nameDirtyRef.current = true;
96102
96360
  setNameDirty(true);
@@ -96105,6 +96363,7 @@ function HostedProjectSelect({
96105
96363
  return;
96106
96364
  }
96107
96365
  if (input && !key.ctrl && !key.meta) {
96366
+ offeredNameRef.current = null;
96108
96367
  const base = nameDirtyRef.current ? nameBufferRef.current : "";
96109
96368
  nameDirtyRef.current = true;
96110
96369
  setNameDirty(true);
@@ -96645,7 +96904,8 @@ function createFlagPrompts(request) {
96645
96904
  kind: "name-rejected",
96646
96905
  reason: validation.reason,
96647
96906
  message: validation.message,
96648
- ...validation.duplicate ? { duplicateSlug: validation.duplicate.slug } : {}
96907
+ ...validation.duplicate ? { duplicateSlug: validation.duplicate.slug } : {},
96908
+ ...validation.suggestion === void 0 ? {} : { suggestedName: validation.suggestion }
96649
96909
  };
96650
96910
  return null;
96651
96911
  }
@@ -96688,7 +96948,8 @@ function createFlagPrompts(request) {
96688
96948
  }
96689
96949
  function formatFlagRefusal(refusal, command2 = "project select") {
96690
96950
  if (refusal.kind === "name-rejected") {
96691
- const remedy = refusal.duplicateSlug === void 0 ? "Pass a different --create name." : `Pass a different --create name, or select it with \`copilotkit ${command2} --project ${refusal.duplicateSlug}\`.`;
96951
+ const free = refusal.suggestedName === void 0 ? "Pass a different --create name" : `\`--create "${refusal.suggestedName}"\` is free`;
96952
+ const remedy = refusal.duplicateSlug === void 0 ? `${free}.` : `${free}, or select the existing project with \`copilotkit ${command2} --project ${refusal.duplicateSlug}\`.`;
96692
96953
  return `${refusal.message} ${remedy}
96693
96954
  `;
96694
96955
  }
@@ -96821,9 +97082,19 @@ async function driveFlagSelect(apiClient, request) {
96821
97082
  return withoutSelection({ kind: "canceled" });
96822
97083
  }
96823
97084
  process.stderr.write(formatFlagRefusal(recorded));
96824
- return withoutSelection(
96825
- recorded.kind === "not-found" ? { kind: "not-found", requested: recorded.requested } : { kind: "name-rejected", message: recorded.message }
96826
- );
97085
+ if (recorded.kind === "not-found") {
97086
+ return withoutSelection({
97087
+ kind: "not-found",
97088
+ requested: recorded.requested
97089
+ });
97090
+ }
97091
+ return withoutSelection({
97092
+ kind: "name-rejected",
97093
+ // The refused name and the free one, in the message the payload carries.
97094
+ // A caller reading only `error` still learns which name to retry with.
97095
+ message: recorded.suggestedName === void 0 ? recorded.message : `${recorded.message} "${recorded.suggestedName}" is free.`,
97096
+ ...recorded.suggestedName === void 0 ? {} : { suggestedName: recorded.suggestedName }
97097
+ });
96827
97098
  }
96828
97099
  return await completeSelection(apiClient, result);
96829
97100
  }
@@ -96906,8 +97177,13 @@ async function runProjectSelectJson(options = {}) {
96906
97177
  throw exitError;
96907
97178
  }
96908
97179
  const error98 = exitError ?? new Error("Project selection did not complete.");
97180
+ const suggestedName = outcome.kind === "name-rejected" ? outcome.suggestedName : void 0;
96909
97181
  process.stdout.write(
96910
- `${JSON.stringify({ error: error98.message, type: "failed" })}
97182
+ `${JSON.stringify({
97183
+ error: error98.message,
97184
+ ...suggestedName === void 0 ? {} : { suggested_name: suggestedName },
97185
+ type: "failed"
97186
+ })}
96911
97187
  `
96912
97188
  );
96913
97189
  throw error98;
@@ -99859,13 +100135,115 @@ var init_learning = __esm({
99859
100135
  }
99860
100136
  });
99861
100137
 
100138
+ // libs/app-api-contracts/src/learning-schedule.ts
100139
+ var localTimeSchema, timeZoneSchema, learningScheduleInputSchema, learningScheduleSchema, learningScheduleResponseSchema, projectLearningScheduleSchema, projectLearningScheduleResponseSchema;
100140
+ var init_learning_schedule = __esm({
100141
+ "libs/app-api-contracts/src/learning-schedule.ts"() {
100142
+ "use strict";
100143
+ init_zod();
100144
+ localTimeSchema = external_exports.string().regex(/^(?:[01]\d|2[0-3]):[0-5]\d$/, {
100145
+ message: "Use a local time in HH:mm format."
100146
+ }).length(5);
100147
+ timeZoneSchema = external_exports.string().min(1).max(255).refine(
100148
+ (timeZone) => {
100149
+ if (/^[+-]/.test(timeZone) || timeZone.trim() !== timeZone)
100150
+ return false;
100151
+ try {
100152
+ new Intl.DateTimeFormat("en-US", { timeZone }).format(0);
100153
+ return true;
100154
+ } catch {
100155
+ return false;
100156
+ }
100157
+ },
100158
+ { message: "Use a valid IANA time zone." }
100159
+ );
100160
+ learningScheduleInputSchema = external_exports.object({
100161
+ localTime: localTimeSchema,
100162
+ timeZone: timeZoneSchema
100163
+ }).strict();
100164
+ learningScheduleSchema = learningScheduleInputSchema.extend({
100165
+ organizationId: external_exports.string(),
100166
+ nextRunAt: external_exports.string().datetime(),
100167
+ updatedAt: external_exports.string().datetime()
100168
+ });
100169
+ learningScheduleResponseSchema = external_exports.object({
100170
+ schedule: learningScheduleSchema
100171
+ }).strict();
100172
+ projectLearningScheduleSchema = learningScheduleSchema.extend({
100173
+ projectId: external_exports.number().int().positive(),
100174
+ source: external_exports.enum(["organization", "project"]),
100175
+ automationEnabled: external_exports.boolean().optional()
100176
+ });
100177
+ projectLearningScheduleResponseSchema = external_exports.object({ schedule: projectLearningScheduleSchema }).strict();
100178
+ }
100179
+ });
100180
+
100181
+ // libs/app-api-contracts/src/learning-automation.ts
100182
+ var learningAutomationReadinessSchema, learningAutomationReadinessResponseSchema;
100183
+ var init_learning_automation = __esm({
100184
+ "libs/app-api-contracts/src/learning-automation.ts"() {
100185
+ "use strict";
100186
+ init_zod();
100187
+ learningAutomationReadinessSchema = external_exports.object({
100188
+ containerId: external_exports.string().min(1).max(64),
100189
+ projectId: external_exports.number().int().positive(),
100190
+ enabled: external_exports.boolean(),
100191
+ eligibleThreadCount: external_exports.number().int().nonnegative(),
100192
+ requiredThreadCount: external_exports.number().int().positive(),
100193
+ blocked: external_exports.boolean(),
100194
+ activeRun: external_exports.boolean()
100195
+ });
100196
+ learningAutomationReadinessResponseSchema = external_exports.object({
100197
+ automation: learningAutomationReadinessSchema
100198
+ }).strict();
100199
+ }
100200
+ });
100201
+
99862
100202
  // libs/app-api-contracts/src/threads.ts
99863
- var threadIdSchema;
100203
+ var threadIdSchema, appUserAliasSchema, collapseAppUserAliases, refuseInternalAppUserForms, threadAppUserSchema, threadReadQuerySchema;
99864
100204
  var init_threads = __esm({
99865
100205
  "libs/app-api-contracts/src/threads.ts"() {
99866
100206
  "use strict";
99867
100207
  init_zod();
99868
100208
  threadIdSchema = external_exports.string().uuid();
100209
+ appUserAliasSchema = external_exports.object({
100210
+ endUserId: external_exports.string().trim().min(1).optional(),
100211
+ end_user_id: external_exports.string().trim().min(1).optional(),
100212
+ userId: external_exports.string().trim().min(1).optional(),
100213
+ createdById: external_exports.string().trim().min(1).optional(),
100214
+ created_by_id: external_exports.string().trim().min(1).optional(),
100215
+ appUserId: external_exports.string().trim().min(1).optional(),
100216
+ app_user_id: external_exports.string().trim().min(1).optional()
100217
+ });
100218
+ collapseAppUserAliases = (data) => ({
100219
+ endUserId: data.endUserId ?? data.end_user_id ?? data.userId,
100220
+ createdById: data.createdById ?? data.created_by_id,
100221
+ appUserId: data.appUserId ?? data.app_user_id
100222
+ });
100223
+ refuseInternalAppUserForms = (data, ctx) => {
100224
+ if (data.createdById) {
100225
+ ctx.addIssue({
100226
+ code: external_exports.ZodIssueCode.custom,
100227
+ message: "createdById is internal; pass bare endUserId instead."
100228
+ });
100229
+ }
100230
+ if (data.appUserId) {
100231
+ ctx.addIssue({
100232
+ code: external_exports.ZodIssueCode.custom,
100233
+ message: "appUserId is not accepted; pass endUserId instead."
100234
+ });
100235
+ }
100236
+ };
100237
+ threadAppUserSchema = appUserAliasSchema.transform(collapseAppUserAliases).superRefine((data, ctx) => {
100238
+ if (!data.endUserId) {
100239
+ ctx.addIssue({
100240
+ code: external_exports.ZodIssueCode.custom,
100241
+ message: "endUserId is required."
100242
+ });
100243
+ }
100244
+ refuseInternalAppUserForms(data, ctx);
100245
+ }).transform((data) => ({ endUserId: data.endUserId }));
100246
+ threadReadQuerySchema = appUserAliasSchema.transform(collapseAppUserAliases).superRefine(refuseInternalAppUserForms).transform((data) => ({ endUserId: data.endUserId }));
99869
100247
  }
99870
100248
  });
99871
100249
 
@@ -99932,6 +100310,8 @@ var init_src6 = __esm({
99932
100310
  init_inspector_metadata();
99933
100311
  init_inspector_learning();
99934
100312
  init_learning();
100313
+ init_learning_schedule();
100314
+ init_learning_automation();
99935
100315
  init_threads();
99936
100316
  init_usage();
99937
100317
  }
@@ -100096,7 +100476,7 @@ async function loadLearningCommandContext() {
100096
100476
  productCredential: auth2.productCredential,
100097
100477
  productOrganizationId: auth2.clerkOrgId
100098
100478
  });
100099
- return { client: client2, projectId: project.projectId };
100479
+ return { client: client2, projectId: project.projectId, projectSlug: project.projectSlug };
100100
100480
  }
100101
100481
  var init_learning_command_context = __esm({
100102
100482
  "apps/cli/src/services/learning-command-context.ts"() {
@@ -100435,6 +100815,21 @@ async function runLearningInsightsCommand(command2, dependencies) {
100435
100815
  command2.candidateId,
100436
100816
  command2.action
100437
100817
  );
100818
+ if (command2.yes) {
100819
+ dependencies.telemetry.onReviewViewed({
100820
+ action: command2.action,
100821
+ durationMs: Date.now() - startedAt,
100822
+ operation: review.operation,
100823
+ reviewMode
100824
+ });
100825
+ dependencies.telemetry.onReviewDecided({
100826
+ action: command2.action,
100827
+ decision: "confirmed",
100828
+ durationMs: 0,
100829
+ operation: review.operation,
100830
+ reviewMode
100831
+ });
100832
+ }
100438
100833
  dependencies.telemetry.setProperties({
100439
100834
  candidate_operation: review.operation,
100440
100835
  review_mode: reviewMode,
@@ -100581,11 +100976,27 @@ var init_learning_containers_api = __esm({
100581
100976
  }
100582
100977
  });
100583
100978
 
100979
+ // apps/cli/src/services/learning-default-container.ts
100980
+ function defaultContainerIdFromProjectSlug(projectSlug) {
100981
+ const reshaped = projectSlug.toLowerCase().replace(/[^a-z0-9]+/gu, "-").replace(/^-+|-+$/gu, "");
100982
+ if (reshaped === "")
100983
+ return void 0;
100984
+ const bounded = reshaped.slice(0, MAX_ID_LENGTH).replace(/-+$/u, "");
100985
+ return bounded === "" ? void 0 : bounded;
100986
+ }
100987
+ var MAX_ID_LENGTH;
100988
+ var init_learning_default_container = __esm({
100989
+ "apps/cli/src/services/learning-default-container.ts"() {
100990
+ "use strict";
100991
+ MAX_ID_LENGTH = 64;
100992
+ }
100993
+ });
100994
+
100584
100995
  // apps/cli/src/ui/learning-container-prompts.tsx
100585
100996
  function LearningContainerCreatePrompt(props) {
100586
100997
  const firstStep = props.initial.id === void 0 ? "id" : props.initial.name === void 0 ? "name" : "prompt";
100587
100998
  const [step, setStep] = (0, import_react43.useState)(firstStep);
100588
- const [id, setId] = (0, import_react43.useState)(props.initial.id ?? "");
100999
+ const [id, setId] = (0, import_react43.useState)(props.initial.id ?? props.initial.proposedId ?? "");
100589
101000
  const [name, setName] = (0, import_react43.useState)(props.initial.name ?? "");
100590
101001
  const [promptContext, setPromptContext] = (0, import_react43.useState)(
100591
101002
  props.initial.promptContext ?? ""
@@ -100757,6 +101168,66 @@ function LearningContainerDeletePrompt(props) {
100757
101168
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { children: "(y/N) " })
100758
101169
  ] });
100759
101170
  }
101171
+ function LearningContainerSelectPrompt(props) {
101172
+ const createIndex = props.containers.length;
101173
+ const moreIndex = props.hasMore ? createIndex + 1 : -1;
101174
+ const itemCount = createIndex + (props.hasMore ? 2 : 1);
101175
+ const [index2, setIndex] = (0, import_react43.useState)(0);
101176
+ const indexRef = (0, import_react43.useRef)(0);
101177
+ const finished2 = (0, import_react43.useRef)(false);
101178
+ const move = (delta) => {
101179
+ const next = (indexRef.current + delta + itemCount) % itemCount;
101180
+ indexRef.current = next;
101181
+ setIndex(next);
101182
+ };
101183
+ const finish = (selection) => {
101184
+ if (finished2.current)
101185
+ return;
101186
+ finished2.current = true;
101187
+ props.onComplete(selection);
101188
+ };
101189
+ use_input_default((_input, key) => {
101190
+ if (key.downArrow) {
101191
+ move(1);
101192
+ return;
101193
+ }
101194
+ if (key.upArrow) {
101195
+ move(-1);
101196
+ return;
101197
+ }
101198
+ if (key.escape) {
101199
+ if (finished2.current)
101200
+ return;
101201
+ finished2.current = true;
101202
+ props.onCancel();
101203
+ return;
101204
+ }
101205
+ if (!key.return)
101206
+ return;
101207
+ const position = indexRef.current;
101208
+ if (position === moreIndex) {
101209
+ finish({ kind: "more" });
101210
+ return;
101211
+ }
101212
+ if (position === createIndex) {
101213
+ finish({ kind: "create" });
101214
+ return;
101215
+ }
101216
+ const container = props.containers[position];
101217
+ if (container === void 0)
101218
+ return;
101219
+ finish({ containerId: container.id, kind: "chosen" });
101220
+ });
101221
+ const marker = (position) => position === index2 ? ">" : " ";
101222
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Box_default, { flexDirection: "column", children: [
101223
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { bold: true, children: "Select a Learning Container" }),
101224
+ props.containers.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { dimColor: true, children: "This project has none yet." }) : null,
101225
+ props.containers.map((container, position) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { children: `${marker(position)} ${container.id} ${container.name}` }, container.id)),
101226
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { children: `${marker(createIndex)} Create a new container` }),
101227
+ props.hasMore ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { children: `${marker(moreIndex)} Show more` }) : null,
101228
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { dimColor: true, children: "Up and down move, Enter selects, Esc cancels." })
101229
+ ] });
101230
+ }
100760
101231
  var import_react43, import_jsx_runtime13;
100761
101232
  var init_learning_container_prompts = __esm({
100762
101233
  async "apps/cli/src/ui/learning-container-prompts.tsx"() {
@@ -100806,6 +101277,22 @@ async function promptUpdate(container) {
100806
101277
  await app.waitUntilExit();
100807
101278
  return result;
100808
101279
  }
101280
+ async function promptSelect(input) {
101281
+ let result = null;
101282
+ const app = render_default(
101283
+ (0, import_react44.createElement)(LearningContainerSelectPrompt, {
101284
+ containers: input.containers,
101285
+ hasMore: input.hasMore,
101286
+ onCancel: () => setTimeout(() => app.unmount(), 0),
101287
+ onComplete: (selection) => {
101288
+ result = selection;
101289
+ setTimeout(() => app.unmount(), 0);
101290
+ }
101291
+ })
101292
+ );
101293
+ await app.waitUntilExit();
101294
+ return result;
101295
+ }
100809
101296
  async function confirmDelete(container) {
100810
101297
  let confirmed = false;
100811
101298
  const app = render_default(
@@ -100823,12 +101310,13 @@ async function confirmDelete(container) {
100823
101310
  function createLearningContainersCommandDependencies() {
100824
101311
  return {
100825
101312
  interactive: process.stdin.isTTY === true && process.stdout.isTTY === true,
100826
- interaction: { confirmDelete, promptCreate, promptUpdate },
101313
+ interaction: { confirmDelete, promptCreate, promptSelect, promptUpdate },
100827
101314
  loadContext: async () => {
100828
- const { client: client2, projectId } = await loadLearningCommandContext();
101315
+ const { client: client2, projectId, projectSlug } = await loadLearningCommandContext();
100829
101316
  return {
100830
101317
  api: createLearningContainersApi(client2),
100831
- projectId
101318
+ projectId,
101319
+ projectSlug
100832
101320
  };
100833
101321
  },
100834
101322
  writeStdout: (text2) => {
@@ -100973,6 +101461,59 @@ Created: ${container.createdAt}
100973
101461
  Updated: ${container.updatedAt}
100974
101462
  `;
100975
101463
  }
101464
+ async function selectLearningContainer(dependencies, projectId) {
101465
+ const { api, projectSlug } = await dependencies.loadContext();
101466
+ const proposedId = projectSlug === void 0 ? void 0 : defaultContainerIdFromProjectSlug(projectSlug);
101467
+ const seen = [];
101468
+ let cursor;
101469
+ let exhausted = false;
101470
+ let pagesRead = 0;
101471
+ const reportSurvey = (selection) => {
101472
+ dependencies.telemetry?.setProperties({
101473
+ container_count: seen.length,
101474
+ container_more_pages: !exhausted,
101475
+ container_pages_read: pagesRead,
101476
+ ...selection === void 0 ? {} : { container_selection: selection }
101477
+ });
101478
+ };
101479
+ for (; ; ) {
101480
+ if (!exhausted) {
101481
+ const page = await api.list(projectId, cursor);
101482
+ pagesRead += 1;
101483
+ seen.push(...page.containers);
101484
+ cursor = page.nextCursor ?? void 0;
101485
+ exhausted = cursor === void 0;
101486
+ }
101487
+ const answer = await dependencies.interaction.promptSelect({
101488
+ containers: [...seen],
101489
+ hasMore: !exhausted
101490
+ });
101491
+ if (answer === null) {
101492
+ reportSurvey();
101493
+ dependencies.writeStdout("Canceled.\n");
101494
+ throw userAbortedError2();
101495
+ }
101496
+ if (answer.kind === "more")
101497
+ continue;
101498
+ if (answer.kind === "create") {
101499
+ reportSurvey("created");
101500
+ const input = await dependencies.interaction.promptCreate(
101501
+ proposedId === void 0 ? {} : { proposedId }
101502
+ );
101503
+ if (input === null) {
101504
+ dependencies.writeStdout("Canceled.\n");
101505
+ throw userAbortedError2();
101506
+ }
101507
+ return api.create(projectId, input);
101508
+ }
101509
+ reportSurvey("chosen");
101510
+ const chosen = seen.find((held) => held.id === answer.containerId);
101511
+ if (chosen === void 0) {
101512
+ throw containerNotFoundError(answer.containerId);
101513
+ }
101514
+ return chosen;
101515
+ }
101516
+ }
100976
101517
  async function runLearningContainersCommand(command2, dependencies) {
100977
101518
  try {
100978
101519
  validateLearningContainersCommandFlags(command2);
@@ -100991,9 +101532,19 @@ async function runLearningContainersCommand(command2, dependencies) {
100991
101532
  "Learning Container delete needs --yes when confirmation is unavailable."
100992
101533
  );
100993
101534
  }
101535
+ if (command2.action === "select" && (command2.json || !dependencies.interactive)) {
101536
+ throw nonInteractiveError(
101537
+ "Learning Container select needs a terminal. Read them with `learning containers list --json` and make one with `learning containers create --id <id> --name <name>`."
101538
+ );
101539
+ }
100994
101540
  const { api, projectId } = await dependencies.loadContext();
100995
101541
  if (command2.action === "list") {
100996
101542
  const page = await api.list(projectId, command2.cursor);
101543
+ dependencies.telemetry?.setProperties({
101544
+ container_count: page.containers.length,
101545
+ container_more_pages: page.nextCursor !== null,
101546
+ container_pages_read: 1
101547
+ });
100997
101548
  if (command2.json) {
100998
101549
  writeJson2(dependencies, {
100999
101550
  command: "learning containers list",
@@ -101024,6 +101575,11 @@ async function runLearningContainersCommand(command2, dependencies) {
101024
101575
  }
101025
101576
  return;
101026
101577
  }
101578
+ if (command2.action === "select") {
101579
+ const container2 = await selectLearningContainer(dependencies, projectId);
101580
+ dependencies.writeStdout(renderLearningContainer(container2));
101581
+ return;
101582
+ }
101027
101583
  if (command2.action === "create") {
101028
101584
  let input;
101029
101585
  if (command2.id !== void 0 && command2.name !== void 0) {
@@ -101148,6 +101704,7 @@ var init_learning_containers = __esm({
101148
101704
  init_src6();
101149
101705
  init_learning_containers_api();
101150
101706
  init_learning_command_context();
101707
+ init_learning_default_container();
101151
101708
  await init_build2();
101152
101709
  import_react44 = __toESM(require_react(), 1);
101153
101710
  await init_learning_container_prompts();
@@ -101548,7 +102105,7 @@ function apiKeyPresentCheck(variableName, source, envSearch) {
101548
102105
  title
101549
102106
  };
101550
102107
  }
101551
- function apiKeyLoadableCheck(facts) {
102108
+ function apiKeyLoadableCheck(facts, runtime) {
101552
102109
  const title = "The app can load the project API key";
101553
102110
  const id = "api_key_loadable_by_app";
101554
102111
  switch (facts.kind) {
@@ -101575,7 +102132,7 @@ function apiKeyLoadableCheck(facts) {
101575
102132
  };
101576
102133
  case "loader-declared":
101577
102134
  return {
101578
- detail: `A script in ${facts.appDir} names an env file itself, so which file that app loads is decided there rather than by its framework's default. This check does not read it.`,
102135
+ detail: facts.declaredIn === facts.appDir ? `A script in ${facts.appDir} names an env file itself, so which file that app loads is decided there rather than by its framework's default. This check does not read it.` : `A script in ${facts.declaredIn} names an env file itself and starts the app in ${facts.appDir}, so which file that app loads is decided there rather than by its framework's default. This check does not read it.`,
101579
102136
  id,
101580
102137
  status: "undetermined",
101581
102138
  title
@@ -101594,13 +102151,24 @@ function apiKeyLoadableCheck(facts) {
101594
102151
  status: "pass",
101595
102152
  title
101596
102153
  };
101597
- case "not-loadable":
102154
+ case "not-loadable": {
102155
+ const located = `The key is in ${facts.foundIn}, which this command found by searching upward. The app in ${facts.appDir} loads env files from its own directory only, and nothing there sets ${eitherKeyName()}.`;
102156
+ const remedy = `Write it to ${facts.expectedFile}, or re-run \`copilotkit project select\` from ${facts.appDir}.`;
102157
+ if (runtime.kind === "ok" && reportsIntelligenceClient(runtime.info)) {
102158
+ return {
102159
+ detail: `${located} A runtime answered and reports an Intelligence entitlement, so some process did load a key \u2014 from a mechanism this check does not read, or from a different process than the app in ${facts.appDir}. Which it was is not decidable from here. If the runtime you probed is not that app: ${remedy}`,
102160
+ id,
102161
+ status: "undetermined",
102162
+ title
102163
+ };
102164
+ }
101598
102165
  return {
101599
- detail: `The key is in ${facts.foundIn}, which this command found by searching upward. The app in ${facts.appDir} loads env files from its own directory only, and nothing there sets ${eitherKeyName()}, so the running application never sees it. Write it to ${facts.expectedFile}, or re-run \`copilotkit project select\` from ${facts.appDir}.`,
102166
+ detail: `${located} So the running application never sees it. ${remedy}`,
101600
102167
  id,
101601
102168
  status: "fail",
101602
102169
  title
101603
102170
  };
102171
+ }
101604
102172
  }
101605
102173
  }
101606
102174
  function apiKeyAuthenticatesCheck(probe) {
@@ -101758,12 +102326,59 @@ function intelligenceConsumedCheck(credential, runtime) {
101758
102326
  };
101759
102327
  }
101760
102328
  return {
101761
- detail: `The runtime holds an Intelligence client and ${describeIntelligenceEntitlement(runtime.info)}, so the key is being used.`,
102329
+ detail: `The runtime holds an Intelligence client and ${describeIntelligenceEntitlement(runtime.info)}. That is a declaration, not proof of a successful call \u2014 see the deployment check below for whether it is pointed at the host this key belongs to.`,
101762
102330
  id: "intelligence_consumed",
101763
102331
  status: "pass",
101764
102332
  title
101765
102333
  };
101766
102334
  }
102335
+ function deploymentHost(url4) {
102336
+ let hostname5;
102337
+ try {
102338
+ hostname5 = new URL(url4).hostname.toLowerCase();
102339
+ } catch {
102340
+ return void 0;
102341
+ }
102342
+ return LOOPBACK_HOSTNAMES.has(hostname5) ? "localhost" : hostname5;
102343
+ }
102344
+ function intelligenceHostAgreementChecks(input) {
102345
+ const { credential, intelligenceTarget, runtime } = input;
102346
+ if (runtime.kind !== "ok" || credential.kind !== "ok")
102347
+ return [];
102348
+ if (!reportsIntelligenceClient(runtime.info))
102349
+ return [];
102350
+ const reportedGateway = runtime.info.intelligenceWsUrl;
102351
+ if (reportedGateway === void 0)
102352
+ return [];
102353
+ const observed = deploymentHost(reportedGateway);
102354
+ const verified = deploymentHost(intelligenceTarget.verifiedUrl);
102355
+ if (observed === void 0 || verified === void 0)
102356
+ return [];
102357
+ const accepted = new Set(
102358
+ [verified, ...intelligenceTarget.pairedGatewayUrls.map(deploymentHost)].filter(
102359
+ (host) => host !== void 0
102360
+ )
102361
+ );
102362
+ if (accepted.has(observed)) {
102363
+ return [
102364
+ {
102365
+ detail: `The runtime reports its Intelligence gateway on ${observed}, which belongs to the deployment this command proved the key against (${verified}).`,
102366
+ id: "intelligence_host_agreement",
102367
+ status: "pass",
102368
+ title: HOST_AGREEMENT_TITLE
102369
+ }
102370
+ ];
102371
+ }
102372
+ const unnamed = intelligenceTarget.source === "cli-default" ? ` This project names no INTELLIGENCE_API_URL, so ${verified} is only this CLI's own default and the runtime fell back to its own.` : "";
102373
+ return [
102374
+ {
102375
+ detail: `The key was proven against ${verified}, but the runtime reports its Intelligence gateway on ${observed} \u2014 a different deployment.${unnamed} Every check above tested a host the runtime never calls, so a valid key still gets 401 AUTH_UNAUTHENTICATED on every request. Set INTELLIGENCE_API_URL=${intelligenceTarget.verifiedUrl} in the env file the app loads, and INTELLIGENCE_GATEWAY_WS_URL to that deployment's gateway.`,
102376
+ id: "intelligence_host_agreement",
102377
+ status: "fail",
102378
+ title: HOST_AGREEMENT_TITLE
102379
+ }
102380
+ ];
102381
+ }
101767
102382
  function ossRuntimeModeCheck(runtime) {
101768
102383
  const title = "The runtime uses the expected OSS mode";
101769
102384
  if (runtime.kind !== "ok") {
@@ -101799,7 +102414,11 @@ function intelligenceThreadRoutesCheck(runtime) {
101799
102414
  title
101800
102415
  };
101801
102416
  }
101802
- const { intelligenceWsUrl, threadMutationsEnabled } = runtime.info;
102417
+ const {
102418
+ intelligenceWsUrl,
102419
+ singleRouteResourceOperations,
102420
+ threadMutationsEnabled
102421
+ } = runtime.info;
101803
102422
  if (!reportsIntelligenceClient(runtime.info)) {
101804
102423
  return {
101805
102424
  detail: "Not attempted: the runtime reports no Intelligence entitlement, so it has no Intelligence routes to serve. The check above names that.",
@@ -101808,6 +102427,14 @@ function intelligenceThreadRoutesCheck(runtime) {
101808
102427
  title
101809
102428
  };
101810
102429
  }
102430
+ if (runtime.transport === "single-route" && singleRouteResourceOperations === void 0) {
102431
+ return {
102432
+ detail: "The runtime answers a single-route envelope and reports nothing about what that mount serves. Its top-level `threadEndpoints` describes the `info` call that carried the answer, not the mount, so it cannot be read either way. Upgrade @copilotkit/runtime to 1.70.2 or later: from there a single-route mount serves `threads/*` and `memories/*` over its `resource/request` method and says so.",
102433
+ id: "intelligence_thread_routes",
102434
+ status: "undetermined",
102435
+ title
102436
+ };
102437
+ }
101811
102438
  if (threadMutationsEnabled === void 0) {
101812
102439
  return {
101813
102440
  detail: "The runtime reports no thread-endpoint state. Runtimes that predate the `threadEndpoints` field in /info omit it, so this could not be read either way. Upgrade @copilotkit/runtime to have it reported.",
@@ -101818,14 +102445,14 @@ function intelligenceThreadRoutesCheck(runtime) {
101818
102445
  }
101819
102446
  if (!threadMutationsEnabled) {
101820
102447
  return {
101821
- detail: runtime.transport === "single-route" ? 'The runtime reports a license but serves no thread or memory routes, so saved Threads cannot be listed or written from the browser. That is what `mode: "single-route"` does: its envelope carries no threads/* or memories/* method. Remove `mode: "single-route"` and mount the handler at a catch-all route \u2014 https://docs.copilotkit.ai/backend/runtime-endpoints#enable-rich-threads-routes' : intelligenceWsUrl === void 0 ? "The runtime reports a license but serves no thread routes and no gateway URL, which is an Intelligence runtime built without `identifyUser`. That gates the whole web surface. Pass `identifyUser` where the runtime is constructed." : "The runtime reports a license and a gateway URL but still serves no thread routes, so saved Threads cannot be listed or written from the browser \u2014 https://docs.copilotkit.ai/backend/runtime-endpoints#enable-rich-threads-routes",
102448
+ detail: intelligenceWsUrl === void 0 ? "The runtime reports a license but serves no thread routes and no gateway URL, which is an Intelligence runtime built without `identifyUser`. That gates the whole web surface. Pass `identifyUser` where the runtime is constructed." : "The runtime reports a license and a gateway URL but still serves no thread routes, so saved Threads cannot be listed or written from the browser \u2014 https://docs.copilotkit.ai/backend/runtime-endpoints#enable-rich-threads-routes",
101822
102449
  id: "intelligence_thread_routes",
101823
102450
  status: "fail",
101824
102451
  title
101825
102452
  };
101826
102453
  }
101827
102454
  return {
101828
- detail: "The runtime serves the thread routes, so saved Threads load.",
102455
+ detail: runtime.transport === "single-route" ? "The runtime serves the thread routes over its single-route envelope, as the `resource/request` method rather than as REST paths, so saved Threads load." : "The runtime serves the thread routes, so saved Threads load.",
101829
102456
  id: "intelligence_thread_routes",
101830
102457
  status: "pass",
101831
102458
  title
@@ -102014,11 +102641,12 @@ function runVerifyChecks(input, expectedRuntime = "intelligence") {
102014
102641
  input.apiKeySource,
102015
102642
  input.envSearch
102016
102643
  ),
102017
- apiKeyLoadableCheck(input.credentialLoad),
102644
+ apiKeyLoadableCheck(input.credentialLoad, input.runtime),
102018
102645
  apiKeyAuthenticatesCheck(input.credential),
102019
102646
  runtimeReachableCheck(input.runtime, input.runtimeUrl),
102020
102647
  runtimeAgentsCheck(input.runtime, input.runtimeUrl),
102021
102648
  intelligenceConsumedCheck(input.credential, input.runtime),
102649
+ ...intelligenceHostAgreementChecks(input),
102022
102650
  intelligenceThreadRoutesCheck(input.runtime),
102023
102651
  ...frontendAssetChecks(input),
102024
102652
  ...corsChecks(input),
@@ -102032,7 +102660,7 @@ function runVerifyChecks(input, expectedRuntime = "intelligence") {
102032
102660
  ok: checks.every((check4) => check4.status === "pass")
102033
102661
  };
102034
102662
  }
102035
- var API_KEY_VARIABLE_NAMES, VERSIONS_CHECK_TITLE, CORS_CHECK_TITLE;
102663
+ var API_KEY_VARIABLE_NAMES, LOOPBACK_HOSTNAMES, HOST_AGREEMENT_TITLE, VERSIONS_CHECK_TITLE, CORS_CHECK_TITLE;
102036
102664
  var init_verify_checks = __esm({
102037
102665
  "apps/cli/src/services/verify-checks.ts"() {
102038
102666
  "use strict";
@@ -102043,6 +102671,14 @@ var init_verify_checks = __esm({
102043
102671
  "COPILOTKIT_API_KEY",
102044
102672
  "INTELLIGENCE_API_KEY"
102045
102673
  ];
102674
+ LOOPBACK_HOSTNAMES = /* @__PURE__ */ new Set([
102675
+ "localhost",
102676
+ "127.0.0.1",
102677
+ "[::1]",
102678
+ "::1",
102679
+ "0.0.0.0"
102680
+ ]);
102681
+ HOST_AGREEMENT_TITLE = "The runtime and this command address the same Intelligence deployment";
102046
102682
  VERSIONS_CHECK_TITLE = "The installed packages match the runtime";
102047
102683
  CORS_CHECK_TITLE = "The runtime accepts the frontend origin";
102048
102684
  }
@@ -377720,6 +378356,9 @@ var init_telemetry2 = __esm({
377720
378356
  });
377721
378357
 
377722
378358
  // apps/cli/src/services/round-trip-checks.ts
378359
+ function describeReadVia(readVia) {
378360
+ return readVia === "app-mount" ? "Read back through the app, so the answer belongs to the caller the app identified." : "Read back from app-api, because this mount serves no thread route: the run and its answer are proved, the end user it belonged to is not.";
378361
+ }
377723
378362
  function runRoundTripCheck(agentId, probe, runtimeUrlSource) {
377724
378363
  const check4 = decideRoundTrip(agentId, probe);
377725
378364
  if (runtimeUrlSource !== "default" || probe.kind === "unreachable") {
@@ -377731,10 +378370,11 @@ function decideRoundTrip(agentId, probe) {
377731
378370
  if (probe.kind === "answered") {
377732
378371
  const toolNote = probe.toolCallNames.length > 0 ? ` It called ${probe.toolCallNames.join(", ")}.` : "";
377733
378372
  return {
377734
- detail: `Agent "${agentId}" answered with ${String(probe.text.length)} characters, recorded on thread ${probe.threadId}.${toolNote}`,
378373
+ detail: `Agent "${agentId}" answered with ${String(probe.text.length)} characters, recorded on thread ${probe.threadId}.${toolNote} ${describeReadVia(probe.readVia)}`,
377735
378374
  evidence: {
377736
378375
  agentId,
377737
378376
  answerCharacters: probe.text.length,
378377
+ readVia: probe.readVia,
377738
378378
  threadId: probe.threadId,
377739
378379
  toolCallNames: probe.toolCallNames
377740
378380
  },
@@ -377768,7 +378408,7 @@ function decideRoundTrip(agentId, probe) {
377768
378408
  };
377769
378409
  }
377770
378410
  return {
377771
- detail: `The run started but nothing from agent "${agentId}" was ever recorded on thread ${probe.threadId}. The agent accepted the request and produced no answer \u2014 check its own logs for a failure after start-up.`,
378411
+ detail: `The run started but nothing from agent "${agentId}" was ever recorded on thread ${probe.threadId}. The agent accepted the request and produced no answer \u2014 check its own logs for a failure after start-up. ${describeReadVia(probe.readVia)}`,
377772
378412
  id: "agent_answers",
377773
378413
  status: "fail",
377774
378414
  title: TITLE
@@ -377813,13 +378453,26 @@ async function pollForAnswer(params, threadId) {
377813
378453
  const deadline = now() + (params.timeoutMs ?? DEFAULT_ROUND_TRIP_TIMEOUT_MS);
377814
378454
  for (; ; ) {
377815
378455
  const attempt = await readAnswer(params, threadId);
377816
- if (attempt.kind !== "no-answer")
377817
- return attempt;
377818
- if (now() >= deadline)
377819
- return attempt;
378456
+ if (attempt.kind === "read-refused") {
378457
+ if (!isRetryableRead(attempt.status))
378458
+ return refusedRead(attempt);
378459
+ if (now() >= deadline)
378460
+ return refusedRead(attempt);
378461
+ } else {
378462
+ if (attempt.kind !== "no-answer")
378463
+ return attempt;
378464
+ if (now() >= deadline)
378465
+ return attempt;
378466
+ }
377820
378467
  await sleep3(POLL_INTERVAL_MS);
377821
378468
  }
377822
378469
  }
378470
+ function isRetryableRead(status) {
378471
+ return status === 404 || status >= 500;
378472
+ }
378473
+ function refusedRead(attempt) {
378474
+ return { kind: "unreachable", message: attempt.message };
378475
+ }
377823
378476
  async function startRun(params, sentThreadId) {
377824
378477
  const body = {
377825
378478
  context: [],
@@ -377836,14 +378489,14 @@ async function startRun(params, sentThreadId) {
377836
378489
  threadId: sentThreadId,
377837
378490
  tools: []
377838
378491
  };
377839
- const response = await params.fetchImpl(
377840
- runtimeRouteUrl(params.runtimeUrl, `agent/${params.agentId}/run`),
377841
- {
377842
- body: JSON.stringify(body),
377843
- headers: { "content-type": "application/json", ...params.headers },
377844
- method: "POST"
377845
- }
377846
- );
378492
+ const singleRoute = params.transport === "single-route";
378493
+ const url4 = singleRoute ? params.runtimeUrl.replace(/\/+$/u, "") : runtimeRouteUrl(params.runtimeUrl, `agent/${params.agentId}/run`);
378494
+ const payload = singleRoute ? { body, method: "agent/run", params: { agentId: params.agentId } } : body;
378495
+ const response = await params.fetchImpl(url4, {
378496
+ body: JSON.stringify(payload),
378497
+ headers: { "content-type": "application/json", ...params.headers },
378498
+ method: "POST"
378499
+ });
377847
378500
  if (!response.ok) {
377848
378501
  const message = await refusalMessage(response);
377849
378502
  return isIdentityRefusal(message) ? { kind: "user-not-identified", message } : { kind: "run-error", message };
@@ -377896,13 +378549,49 @@ async function drain(response) {
377896
378549
  }
377897
378550
  }
377898
378551
  async function readAnswer(params, threadId) {
377899
- const response = await params.fetchImpl(
377900
- runtimeRouteUrl(params.runtimeUrl, `threads/${threadId}/messages`),
377901
- params.headers === void 0 ? void 0 : { headers: params.headers }
377902
- );
377903
- const payload = await response.json();
378552
+ const platform4 = params.transport === "single-route" ? params.platform : void 0;
378553
+ const readVia = platform4 === void 0 ? "app-mount" : "app-api";
378554
+ const request = platform4 === void 0 ? {
378555
+ init: params.headers === void 0 ? void 0 : { headers: params.headers },
378556
+ url: runtimeRouteUrl(params.runtimeUrl, `threads/${threadId}/messages`)
378557
+ } : {
378558
+ init: {
378559
+ headers: {
378560
+ accept: "application/json",
378561
+ authorization: `Bearer ${platform4.apiKey}`
378562
+ }
378563
+ },
378564
+ url: `${platform4.appApiUrl.replace(/\/+$/u, "")}/api/threads/${threadId}/messages`
378565
+ };
378566
+ const response = await params.fetchImpl(request.url, request.init);
378567
+ if (!response.ok) {
378568
+ return {
378569
+ kind: "read-refused",
378570
+ message: `${request.url} answered ${String(response.status)}${await refusalDetail(response)}`,
378571
+ status: response.status
378572
+ };
378573
+ }
378574
+ let payload;
378575
+ try {
378576
+ payload = await response.json();
378577
+ } catch {
378578
+ return {
378579
+ kind: "read-refused",
378580
+ message: `${request.url} did not answer JSON`,
378581
+ status: response.status
378582
+ };
378583
+ }
377904
378584
  const answer = lastAssistantAnswer(payload);
377905
- return answer === void 0 ? { kind: "no-answer", threadId } : { kind: "answered", threadId, ...answer };
378585
+ return answer === void 0 ? { kind: "no-answer", readVia, threadId } : { kind: "answered", readVia, threadId, ...answer };
378586
+ }
378587
+ async function refusalDetail(response) {
378588
+ try {
378589
+ const body = await response.json();
378590
+ const code = typeof body === "object" && body !== null && typeof body.error === "object" && body.error !== null && typeof body.error.code === "string" ? body.error.code : void 0;
378591
+ return code === void 0 ? "" : ` (${code})`;
378592
+ } catch {
378593
+ return "";
378594
+ }
377906
378595
  }
377907
378596
  function lastAssistantAnswer(payload) {
377908
378597
  const messages = typeof payload === "object" && payload !== null && "messages" in payload && Array.isArray(payload.messages) ? payload.messages : [];
@@ -377933,6 +378622,68 @@ var init_round_trip_probe = __esm({
377933
378622
  }
377934
378623
  });
377935
378624
 
378625
+ // apps/cli/src/services/learning-container-check.ts
378626
+ function redact(text2, apiKey) {
378627
+ return text2.split(apiKey).join("[redacted]");
378628
+ }
378629
+ async function checkLearningContainer(params) {
378630
+ const { apiKey } = params;
378631
+ if (apiKey === void 0) {
378632
+ return {
378633
+ kind: "not-attempted",
378634
+ message: "Not attempted: no Intelligence API key was resolved, and the thread read needs one."
378635
+ };
378636
+ }
378637
+ const url4 = `${params.appApiUrl.replace(/\/+$/u, "")}/api/threads/${params.threadId}`;
378638
+ let response;
378639
+ try {
378640
+ response = await params.fetchImpl(url4, {
378641
+ headers: { accept: "application/json", authorization: `Bearer ${apiKey}` },
378642
+ method: "GET"
378643
+ });
378644
+ } catch (error98) {
378645
+ const detail = error98 instanceof Error ? error98.message : String(error98);
378646
+ return {
378647
+ kind: "unreachable",
378648
+ message: `could not reach ${url4} (${redact(detail, apiKey)})`
378649
+ };
378650
+ }
378651
+ if (!response.ok) {
378652
+ return {
378653
+ kind: "unreachable",
378654
+ message: `${url4} answered ${String(response.status)}`
378655
+ };
378656
+ }
378657
+ let body;
378658
+ try {
378659
+ body = await response.json();
378660
+ } catch {
378661
+ return { kind: "unreachable", message: `${url4} did not answer JSON` };
378662
+ }
378663
+ const thread = typeof body === "object" && body !== null && typeof body.thread === "object" && body.thread !== null ? body.thread : void 0;
378664
+ if (thread === void 0) {
378665
+ return {
378666
+ kind: "unreachable",
378667
+ message: `${url4} answered 200 without a thread`
378668
+ };
378669
+ }
378670
+ const actual = typeof thread["learningContainerId"] === "string" ? thread["learningContainerId"] : void 0;
378671
+ if (actual === params.expected) {
378672
+ return { containerId: actual, kind: "proved", threadId: params.threadId };
378673
+ }
378674
+ return {
378675
+ actual,
378676
+ expected: params.expected,
378677
+ kind: "mismatch",
378678
+ threadId: params.threadId
378679
+ };
378680
+ }
378681
+ var init_learning_container_check = __esm({
378682
+ "apps/cli/src/services/learning-container-check.ts"() {
378683
+ "use strict";
378684
+ }
378685
+ });
378686
+
377936
378687
  // apps/cli/src/services/installed-packages.ts
377937
378688
  import { readFileSync as readFileSync16 } from "node:fs";
377938
378689
  import { dirname as dirname10, join as join21, sep } from "node:path";
@@ -378088,7 +378839,8 @@ function toRuntimeProbe(body, status, transport) {
378088
378839
  }
378089
378840
  );
378090
378841
  const wsUrl = parsed.data.intelligence?.wsUrl;
378091
- const mutations = parsed.data.threadEndpoints?.mutations;
378842
+ const singleRoute = parsed.data.singleRoute;
378843
+ const mutations = singleRoute === void 0 ? parsed.data.threadEndpoints?.mutations : singleRoute.threadEndpoints?.mutations;
378092
378844
  const info = {
378093
378845
  agents,
378094
378846
  ...parsed.data.audioFileTranscriptionEnabled === void 0 ? {} : {
@@ -378098,6 +378850,7 @@ function toRuntimeProbe(body, status, transport) {
378098
378850
  ...parsed.data.licenseStatus === void 0 ? {} : { licenseStatus: parsed.data.licenseStatus },
378099
378851
  ...parsed.data.runtimeEntitlements === void 0 ? {} : { runtimeEntitlements: parsed.data.runtimeEntitlements },
378100
378852
  openGenerativeUIEnabled: parsed.data.openGenerativeUIEnabled ?? false,
378853
+ ...singleRoute?.resourceOperations === void 0 ? {} : { singleRouteResourceOperations: singleRoute.resourceOperations },
378101
378854
  ...mutations === void 0 ? {} : { threadMutationsEnabled: mutations },
378102
378855
  version: parsed.data.version
378103
378856
  };
@@ -378241,6 +378994,15 @@ var init_verify_probes = __esm({
378241
378994
  licenseStatus: external_exports.string().optional(),
378242
378995
  runtimeEntitlements: external_exports.object({ status: external_exports.string().optional() }).loose().optional(),
378243
378996
  openGenerativeUIEnabled: external_exports.boolean().optional(),
378997
+ /**
378998
+ * Reported only by a single-route mount, from `@copilotkit/runtime` 1.70.2
378999
+ * onward. Its `threadEndpoints` describes the mount; the top-level one
379000
+ * describes the `info` call that carried this payload (OSS-1166).
379001
+ */
379002
+ singleRoute: external_exports.object({
379003
+ resourceOperations: external_exports.boolean().optional(),
379004
+ threadEndpoints: external_exports.object({ mutations: external_exports.boolean().optional() }).loose().optional()
379005
+ }).loose().optional(),
378244
379006
  threadEndpoints: external_exports.object({ mutations: external_exports.boolean().optional() }).loose().optional(),
378245
379007
  version: external_exports.string()
378246
379008
  });
@@ -378325,8 +379087,8 @@ function factRows(facts) {
378325
379087
  }
378326
379088
  return rows;
378327
379089
  }
378328
- function renderSummary(result, roundTrip) {
378329
- const all = [...result.checks, ...roundTrip ? [roundTrip] : []];
379090
+ function renderSummary(result, roundTrip, extra = []) {
379091
+ const all = [...result.checks, ...roundTrip ? [roundTrip] : [], ...extra];
378330
379092
  const passed = all.filter((check4) => check4.status === "pass").length;
378331
379093
  const failed2 = all.filter((check4) => check4.status === "fail").length;
378332
379094
  const unknown3 = all.filter(
@@ -378341,7 +379103,7 @@ function renderSummary(result, roundTrip) {
378341
379103
  }
378342
379104
  return parts.join(", ");
378343
379105
  }
378344
- function renderVerifyReport(result, context3, roundTrip) {
379106
+ function renderVerifyReport(result, context3, roundTrip, extra = []) {
378345
379107
  const urlNote = `Runtime URL: ${context3.runtimeUrl} ${describeRuntimeUrlSource(context3)}`;
378346
379108
  const frontendNote = context3.frontendUrl.url === void 0 ? "Frontend URL: not resolved (nothing in this project named the port its frontend serves; pass --frontend-url)" : `Frontend URL: ${context3.frontendUrl.url} ${describeFrontendUrlSource(context3.frontendUrl)}`;
378347
379109
  const lines = [
@@ -378361,6 +379123,10 @@ function renderVerifyReport(result, context3, roundTrip) {
378361
379123
  );
378362
379124
  lines.push(` ${roundTrip.detail}`);
378363
379125
  }
379126
+ for (const check4 of extra) {
379127
+ lines.push(` ${STATUS_LABELS[check4.status].padEnd(7)} ${check4.title}`);
379128
+ lines.push(` ${check4.detail}`);
379129
+ }
378364
379130
  const rows = factRows(result.facts);
378365
379131
  if (rows.length > 0) {
378366
379132
  const labelWidth = Math.max(...rows.map(([label]) => label.length));
@@ -378369,10 +379135,10 @@ function renderVerifyReport(result, context3, roundTrip) {
378369
379135
  lines.push(` ${label.padEnd(labelWidth)} ${value}`);
378370
379136
  }
378371
379137
  }
378372
- lines.push("", renderSummary(result, roundTrip), "");
379138
+ lines.push("", renderSummary(result, roundTrip, extra), "");
378373
379139
  return lines.join("\n");
378374
379140
  }
378375
- function renderVerifyJson(result, context3, roundTrip) {
379141
+ function renderVerifyJson(result, context3, roundTrip, extra = []) {
378376
379142
  return `${JSON.stringify(
378377
379143
  {
378378
379144
  checks: result.checks,
@@ -378380,8 +379146,9 @@ function renderVerifyJson(result, context3, roundTrip) {
378380
379146
  // `ok` answers "is this project proven", so a requested round trip that
378381
379147
  // did not pass makes it false. Omitting the round trip from the verdict
378382
379148
  // would let the strongest evidence in the report contradict its summary.
378383
- ok: result.ok && (roundTrip === void 0 || roundTrip.status === "pass"),
379149
+ ok: result.ok && (roundTrip === void 0 || roundTrip.status === "pass") && extra.every((check4) => check4.status === "pass"),
378384
379150
  ...roundTrip === void 0 ? {} : { roundTrip },
379151
+ ...extra.length === 0 ? {} : { extraChecks: extra },
378385
379152
  // The origin a caller opens, so it never composes one. Absent rather than
378386
379153
  // guessed when the project named no port (OSS-1126).
378387
379154
  ...context3.frontendUrl.url === void 0 ? {} : { frontendUrl: context3.frontendUrl.url },
@@ -378419,6 +379186,7 @@ function liveDependencies() {
378419
379186
  return {
378420
379187
  appApiUrl: getAppApiUrl(),
378421
379188
  cwd: process.cwd(),
379189
+ hostedGatewayUrl: getHostedGatewayUrl(),
378422
379190
  env: process.env,
378423
379191
  fetchImpl: fetch,
378424
379192
  newId: (prefix) => `${prefix}-${randomUUID8()}`,
@@ -378459,7 +379227,9 @@ async function runVerify(options, overrides = {}) {
378459
379227
  projectEnvValues: projectEnv.values,
378460
379228
  ...options.frontendUrl === void 0 ? {} : { flagUrl: options.frontendUrl }
378461
379229
  });
378462
- const appApiUrl = (mergedEnv["INTELLIGENCE_API_URL"] ?? "").trim() || deps.appApiUrl;
379230
+ const projectApiUrl = (mergedEnv["INTELLIGENCE_API_URL"] ?? "").trim();
379231
+ const appApiUrl = projectApiUrl || deps.appApiUrl;
379232
+ const pairedGatewayUrls = (projectApiUrl === "" ? [deps.hostedGatewayUrl] : [(mergedEnv["INTELLIGENCE_GATEWAY_WS_URL"] ?? "").trim()]).filter((url4) => url4 !== "");
378463
379233
  const corsApplies = options.frontendUrl !== void 0 && frontendUrlResolution.url !== void 0 && new URL(frontendUrlResolution.url).origin !== new URL(runtimeUrl).origin;
378464
379234
  const [credential, runtime, frontendAssets, cors] = await Promise.all([
378465
379235
  probeCredential(appApiUrl, apiKey?.key, deps.fetchImpl),
@@ -378503,6 +379273,11 @@ async function runVerify(options, overrides = {}) {
378503
379273
  frontendAssets,
378504
379274
  frontendUrl: frontendUrlResolution,
378505
379275
  installedPackages,
379276
+ intelligenceTarget: {
379277
+ pairedGatewayUrls,
379278
+ source: projectApiUrl === "" ? "cli-default" : "project-env",
379279
+ verifiedUrl: appApiUrl
379280
+ },
378506
379281
  projectConfig,
378507
379282
  runtime,
378508
379283
  runtimeUrl: runtimeUrlResolution
@@ -378511,24 +379286,89 @@ async function runVerify(options, overrides = {}) {
378511
379286
  );
378512
379287
  const roundTrip = expectedRuntime === "oss" && (options.roundTrip !== true || options.agent === void 0) ? notAttempted(
378513
379288
  "Not attempted: --expect-runtime oss requires --round-trip --agent <id> so the named agent must answer before this command can pass."
378514
- ) : options.roundTrip === true ? await runLiveRoundTrip(options, deps, runtimeUrlResolution, runtime) : void 0;
379289
+ ) : options.roundTrip === true ? await runLiveRoundTrip(
379290
+ options,
379291
+ deps,
379292
+ runtimeUrlResolution,
379293
+ runtime,
379294
+ appApiUrl,
379295
+ apiKey?.key
379296
+ ) : void 0;
378515
379297
  const context3 = {
378516
379298
  frontendUrl: frontendUrlResolution,
378517
379299
  runtimeUrl,
378518
379300
  runtimeUrlSource: runtimeUrlResolution.source,
378519
379301
  ...runtimeUrlResolution.origin === void 0 ? {} : { runtimeUrlOrigin: runtimeUrlResolution.origin }
378520
379302
  };
379303
+ const learningContainer = options.expectLearningContainer === void 0 ? void 0 : await runLearningContainerCheck(
379304
+ options.expectLearningContainer,
379305
+ deps,
379306
+ appApiUrl,
379307
+ apiKey?.key,
379308
+ roundTrip
379309
+ );
379310
+ const extra = learningContainer === void 0 ? [] : [learningContainer];
378521
379311
  deps.stdout(
378522
- options.json ? renderVerifyJson(result, context3, roundTrip) : renderVerifyReport(result, context3, roundTrip)
379312
+ options.json ? renderVerifyJson(result, context3, roundTrip, extra) : renderVerifyReport(result, context3, roundTrip, extra)
378523
379313
  );
378524
- if (!result.ok || roundTrip !== void 0 && roundTrip.status !== "pass") {
379314
+ if (!result.ok || roundTrip !== void 0 && roundTrip.status !== "pass" || extra.some((check4) => check4.status !== "pass")) {
378525
379315
  process.exitCode = 1;
378526
379316
  }
378527
379317
  }
378528
- async function runLiveRoundTrip(options, deps, runtimeUrl, runtime) {
378529
- if (runtime.kind === "ok" && runtime.transport === "single-route") {
379318
+ async function runLearningContainerCheck(expected, deps, appApiUrl, apiKey, roundTrip) {
379319
+ const base = {
379320
+ id: "learning_container_assigned",
379321
+ title: LEARNING_TITLE
379322
+ };
379323
+ const threadId = roundTrip?.evidence?.threadId;
379324
+ if (threadId === void 0) {
379325
+ deps.recordLearningContainerCheck?.({ outcome: "undetermined" });
379326
+ return {
379327
+ ...base,
379328
+ detail: "Not attempted: no thread was created, so there is nothing to read. The assignment is made while a run starts, so this check needs --round-trip --agent <id> to have run one.",
379329
+ status: "undetermined"
379330
+ };
379331
+ }
379332
+ const checked = await checkLearningContainer({
379333
+ apiKey,
379334
+ // The resolved host, not the build-time default. A project that names
379335
+ // `INTELLIGENCE_API_URL` — a self-hosted deployment, or a test standing up
379336
+ // a stub — is the project this check must ask about.
379337
+ appApiUrl,
379338
+ expected,
379339
+ fetchImpl: deps.fetchImpl,
379340
+ threadId
379341
+ });
379342
+ if (checked.kind === "proved") {
379343
+ deps.recordLearningContainerCheck?.({ outcome: "proved" });
379344
+ return {
379345
+ ...base,
379346
+ detail: `Thread ${checked.threadId} came back from app-api carrying Learning Container "${checked.containerId}". Read from the platform, so it holds whichever way the runtime is mounted.`,
379347
+ status: "pass"
379348
+ };
379349
+ }
379350
+ if (checked.kind === "mismatch") {
379351
+ deps.recordLearningContainerCheck?.({
379352
+ outcome: checked.actual === void 0 ? "unassigned" : "other-container"
379353
+ });
379354
+ return {
379355
+ ...base,
379356
+ detail: checked.actual === void 0 ? `Thread ${checked.threadId} carries no Learning Container, so nothing was assigned. The selector returned nothing for this run, or the runtime holds no getLearningContainerId at all. A plan entitlement or an /info flag saying otherwise is not evidence.` : `Thread ${checked.threadId} is assigned to "${checked.actual}", not "${checked.expected}". A thread cannot move between Containers after its first assignment, so start a new thread rather than repairing this one.`,
379357
+ status: "fail"
379358
+ };
379359
+ }
379360
+ deps.recordLearningContainerCheck?.({ outcome: "undetermined" });
379361
+ return {
379362
+ ...base,
379363
+ detail: `Not proven: ${checked.message}`,
379364
+ status: "undetermined"
379365
+ };
379366
+ }
379367
+ async function runLiveRoundTrip(options, deps, runtimeUrl, runtime, appApiUrl, apiKey) {
379368
+ const singleRoute = runtime.kind === "ok" && runtime.transport === "single-route";
379369
+ if (singleRoute && apiKey === void 0) {
378530
379370
  return notAttempted(
378531
- 'Not attempted: this runtime answers a single-route envelope, and the round trip reads its answer back from a thread route that mount does not serve. Remove `mode: "single-route"` from the handler to run it.'
379371
+ "Not attempted: this runtime answers a single-route envelope, so its answer has to be read from the platform, and no Intelligence API key was resolved to read it with. The checks above name the credential this project is missing."
378532
379372
  );
378533
379373
  }
378534
379374
  const declared = runtime.kind === "ok" ? runtime.info.agents : [];
@@ -378553,6 +379393,10 @@ async function runLiveRoundTrip(options, deps, runtimeUrl, runtime) {
378553
379393
  const probe = await probeRoundTrip({
378554
379394
  agentId,
378555
379395
  fetchImpl: deps.fetchImpl,
379396
+ ...singleRoute ? {
379397
+ platform: { apiKey: apiKey ?? "", appApiUrl },
379398
+ transport: "single-route"
379399
+ } : {},
378556
379400
  newId: deps.newId,
378557
379401
  newThreadId: deps.newThreadId,
378558
379402
  runtimeUrl: runtimeUrl.url,
@@ -378570,6 +379414,7 @@ function notAttempted(detail) {
378570
379414
  title: "The agent answers a real request"
378571
379415
  };
378572
379416
  }
379417
+ var LEARNING_TITLE;
378573
379418
  var init_verify = __esm({
378574
379419
  "apps/cli/src/commands/verify.ts"() {
378575
379420
  "use strict";
@@ -378579,6 +379424,7 @@ var init_verify = __esm({
378579
379424
  init_project_env();
378580
379425
  init_round_trip_checks();
378581
379426
  init_round_trip_probe();
379427
+ init_learning_container_check();
378582
379428
  init_verify_checks();
378583
379429
  init_installed_packages();
378584
379430
  init_verify_probes();
@@ -378586,6 +379432,7 @@ var init_verify = __esm({
378586
379432
  init_runtime_url();
378587
379433
  init_frontend_url();
378588
379434
  init_runtime_url();
379435
+ LEARNING_TITLE = "The run is assigned to the Learning Container";
378589
379436
  }
378590
379437
  });
378591
379438
 
@@ -382980,7 +383827,7 @@ function createHostedProjectApiClient(auth2) {
382980
383827
  productOrganizationId: auth2.clerkOrgId
382981
383828
  });
382982
383829
  }
382983
- function buildInitNextSteps(templateDefinition, projectName, result, unsatisfiedKeys, installAlreadyRan = false, mockProvider = void 0) {
383830
+ function buildInitNextSteps(templateDefinition, projectName, result, unsatisfiedKeys, installAlreadyRan = false, mockProvider = void 0, mockAvailable = false) {
382984
383831
  const missingPrerequisites = templateDefinition.prerequisites.filter(
382985
383832
  (prerequisite) => result.missingPrerequisites.includes(prerequisite.command)
382986
383833
  );
@@ -383041,6 +383888,13 @@ function buildInitNextSteps(templateDefinition, projectName, result, unsatisfied
383041
383888
  code: `${requirement.key}=${requirement.example}`
383042
383889
  });
383043
383890
  }
383891
+ if (unsatisfiedKeys.length > 0 && mockProvider === void 0 && mockAvailable) {
383892
+ steps.push({ text: " Or run without a key:" });
383893
+ steps.push({
383894
+ text: ` Start a local mock model${SEP2}`,
383895
+ code: "copilotkit mock"
383896
+ });
383897
+ }
383044
383898
  for (const note of templateDefinition.setupNotes ?? []) {
383045
383899
  steps.push(note.code !== void 0 ? { ...note } : { text: note.text });
383046
383900
  }
@@ -383833,7 +384687,12 @@ function ScaffoldProgress({
383833
384687
  result,
383834
384688
  unsatisfied,
383835
384689
  installAlreadyRan,
383836
- activeMockProvider
384690
+ activeMockProvider,
384691
+ // Gated on the flag as well as on the framework. `copilotkit mock` is
384692
+ // dark in released binaries (`cli.aimock-mock-mode`, prod: false), and a
384693
+ // run told to reach for a command its own CLI does not implement spends
384694
+ // real time discovering that -- which is itself a reported friction.
384695
+ scaffoldedMockProvider !== void 0 && isCliFlagEnabled("cli.aimock-mock-mode")
383837
384696
  )
383838
384697
  );
383839
384698
  setScaffoldWarnings((prev) => mergeScaffoldWarnings(prev, result.warnings));
@@ -384520,6 +385379,7 @@ async function runLoginJson(dependencies = {
384520
385379
  login,
384521
385380
  recordEvent: recordTelemetryEvent,
384522
385381
  readAuthIdentity: currentAuthIdentity,
385382
+ readCodingAgent: currentOnboardingCodingAgent,
384523
385383
  readOnboardingRun: currentOnboardingRunProperties
384524
385384
  }) {
384525
385385
  try {
@@ -384533,8 +385393,13 @@ async function runLoginJson(dependencies = {
384533
385393
  return;
384534
385394
  }
384535
385395
  let loginUrlWritten = false;
385396
+ const codingAgent = dependencies.readCodingAgent();
384536
385397
  await dependencies.login({
384537
- authHandoff: { source: "cli", mode: "agent_onboarding" },
385398
+ authHandoff: {
385399
+ source: "cli",
385400
+ mode: "agent_onboarding",
385401
+ ...codingAgent === void 0 ? {} : { agent: codingAgent }
385402
+ },
384538
385403
  openBrowser: false,
384539
385404
  onLoginUrl: (url4) => {
384540
385405
  if (loginUrlWritten) {
@@ -384799,7 +385664,16 @@ function reviewFrictionReport(input) {
384799
385664
  `--category must be one of: ${FRICTION_CATEGORIES.join(", ")}.`
384800
385665
  );
384801
385666
  }
384802
- if (input.costSeconds === void 0 || !COST_SECONDS_PATTERN.test(input.costSeconds) || Number(input.costSeconds) > MAX_COST_SECONDS_ESTIMATED) {
385667
+ const phase = input.phase === void 0 ? DEFAULT_FRICTION_PHASE : FRICTION_PHASES.find((candidate) => candidate === input.phase);
385668
+ if (phase === void 0) {
385669
+ return refuse(
385670
+ "FRICTION_PHASE_INVALID",
385671
+ `--phase must be one of: ${FRICTION_PHASES.join(", ")}.`
385672
+ );
385673
+ }
385674
+ const costOmitted = input.costSeconds === void 0;
385675
+ const costMalformed = !costOmitted && (!COST_SECONDS_PATTERN.test(input.costSeconds) || Number(input.costSeconds) > MAX_COST_SECONDS_ESTIMATED);
385676
+ if (costMalformed || costOmitted && phase !== "stop") {
384803
385677
  return refuse(
384804
385678
  "FRICTION_COST_INVALID",
384805
385679
  `--cost-seconds must be a whole number of seconds from 0 to ${MAX_COST_SECONDS_ESTIMATED}.`
@@ -384851,7 +385725,10 @@ function reviewFrictionReport(input) {
384851
385725
  ok: true,
384852
385726
  report: {
384853
385727
  category,
384854
- costSecondsEstimated: Number(input.costSeconds),
385728
+ phase,
385729
+ // Spread so a stop report that named no cost leaves the key off rather
385730
+ // than reporting a zero it never estimated.
385731
+ ...costOmitted ? {} : { costSecondsEstimated: Number(input.costSeconds) },
384855
385732
  // Spread so an absent path leaves the key off entirely, matching how the
384856
385733
  // telemetry properties treat every optional dimension.
384857
385734
  ...docsPath === void 0 ? {} : { docsPath },
@@ -384859,7 +385736,7 @@ function reviewFrictionReport(input) {
384859
385736
  }
384860
385737
  };
384861
385738
  }
384862
- var FRICTION_CATEGORIES, MAX_FRICTION_TEXT_CHARS, MAX_FRICTION_TEXT_NEWLINES, MAX_COST_SECONDS_ESTIMATED, MAX_FRICTION_INPUT_BYTES, FRICTION_SIZE_LIMIT, MAX_FRICTION_DOCS_PATH_CHARS, DOCS_PATH_PATTERN, COST_SECONDS_PATTERN;
385739
+ var FRICTION_CATEGORIES, FRICTION_PHASES, DEFAULT_FRICTION_PHASE, MAX_FRICTION_TEXT_CHARS, MAX_FRICTION_TEXT_NEWLINES, MAX_COST_SECONDS_ESTIMATED, MAX_FRICTION_INPUT_BYTES, FRICTION_SIZE_LIMIT, MAX_FRICTION_DOCS_PATH_CHARS, DOCS_PATH_PATTERN, COST_SECONDS_PATTERN;
384863
385740
  var init_onboarding_friction = __esm({
384864
385741
  "apps/cli/src/services/onboarding-friction.ts"() {
384865
385742
  "use strict";
@@ -384876,6 +385753,8 @@ var init_onboarding_friction = __esm({
384876
385753
  "validation-loop",
384877
385754
  "other"
384878
385755
  ];
385756
+ FRICTION_PHASES = ["repair", "stop", "completion"];
385757
+ DEFAULT_FRICTION_PHASE = "completion";
384879
385758
  MAX_FRICTION_TEXT_CHARS = 2e3;
384880
385759
  MAX_FRICTION_TEXT_NEWLINES = 3;
384881
385760
  MAX_COST_SECONDS_ESTIMATED = 86400;
@@ -384890,76 +385769,6 @@ var init_onboarding_friction = __esm({
384890
385769
  }
384891
385770
  });
384892
385771
 
384893
- // apps/cli/src/services/onboarding-feedback.ts
384894
- function refuse2(code, message) {
384895
- return { ok: false, refusal: { code, message } };
384896
- }
384897
- async function readFeedbackInput(stdin) {
384898
- const read = await readBoundedReportText(stdin, MAX_FEEDBACK_INPUT_BYTES);
384899
- if (read.ok)
384900
- return { ok: true, text: read.text };
384901
- if (read.kind === "invalid-utf8") {
384902
- return refuse2(
384903
- "ONBOARDING_FEEDBACK_INVALID_UTF8",
384904
- "Nothing was sent: the report is not valid UTF-8. Send it again as plain UTF-8 text."
384905
- );
384906
- }
384907
- return refuse2(
384908
- "ONBOARDING_FEEDBACK_TOO_LARGE",
384909
- `Nothing was sent: the report is too large to read. Shorten it to at most ${MAX_FEEDBACK_TEXT_BYTES} UTF-8 bytes and send it again.`
384910
- );
384911
- }
384912
- function reviewFeedbackReport(text2) {
384913
- const violation = reviewReportText({
384914
- text: text2,
384915
- size: FEEDBACK_SIZE_LIMIT,
384916
- maxNewlines: MAX_FEEDBACK_TEXT_NEWLINES
384917
- });
384918
- if (violation === void 0)
384919
- return { ok: true, text: text2.trim() };
384920
- switch (violation.kind) {
384921
- case "empty":
384922
- return refuse2(
384923
- "ONBOARDING_FEEDBACK_EMPTY",
384924
- "Nothing was sent: the report was empty. Name the step that failed, in one or two sentences, on standard input."
384925
- );
384926
- case "possible-secret":
384927
- return refuse2(
384928
- "ONBOARDING_FEEDBACK_POSSIBLE_SECRET",
384929
- `Nothing was sent: the report looks like it contains ${violation.shape}. Describe the problem in words and send it again without the value.`
384930
- );
384931
- case "code-block":
384932
- return refuse2(
384933
- "ONBOARDING_FEEDBACK_CODE_BLOCK",
384934
- "Nothing was sent: the report contains a fenced code block. Describe the problem in words, without source code, logs, or command output."
384935
- );
384936
- case "too-many-lines":
384937
- return refuse2(
384938
- "ONBOARDING_FEEDBACK_TOO_MANY_LINES",
384939
- `Nothing was sent: the report has more than ${MAX_FEEDBACK_TEXT_NEWLINES + 1} lines, so it reads as pasted output. Send at most ${MAX_FEEDBACK_TEXT_NEWLINES + 1} lines of plain prose.`
384940
- );
384941
- case "too-long":
384942
- return refuse2(
384943
- "ONBOARDING_FEEDBACK_TOO_LARGE",
384944
- `Nothing was sent: the report is ${violation.measured} UTF-8 bytes. Shorten it to at most ${MAX_FEEDBACK_TEXT_BYTES} and send it again.`
384945
- );
384946
- }
384947
- }
384948
- var MAX_FEEDBACK_TEXT_BYTES, MAX_FEEDBACK_TEXT_NEWLINES, MAX_FEEDBACK_INPUT_BYTES, FEEDBACK_SIZE_LIMIT;
384949
- var init_onboarding_feedback = __esm({
384950
- "apps/cli/src/services/onboarding-feedback.ts"() {
384951
- "use strict";
384952
- init_onboarding_report_text();
384953
- MAX_FEEDBACK_TEXT_BYTES = 2048;
384954
- MAX_FEEDBACK_TEXT_NEWLINES = 3;
384955
- MAX_FEEDBACK_INPUT_BYTES = 2050;
384956
- FEEDBACK_SIZE_LIMIT = {
384957
- unit: "utf8-bytes",
384958
- max: MAX_FEEDBACK_TEXT_BYTES
384959
- };
384960
- }
384961
- });
384962
-
384963
385772
  // apps/cli/src/services/onboarding-checkpoint.ts
384964
385773
  function reviewCheckpoint(input) {
384965
385774
  const phase = CHECKPOINT_PHASES.find((known) => known === input.phase);
@@ -384994,6 +385803,8 @@ var init_onboarding_checkpoint = __esm({
384994
385803
  "research-returned",
384995
385804
  "starter-cloned",
384996
385805
  "plan-written",
385806
+ "container-surveyed",
385807
+ "container-settled",
384997
385808
  "build-validated",
384998
385809
  "journey-attempted",
384999
385810
  "repair-attempted"
@@ -385005,13 +385816,70 @@ var init_onboarding_checkpoint = __esm({
385005
385816
  // apps/cli/src/services/onboarding-protected-paths.ts
385006
385817
  import { execFileSync as execFileSync5 } from "node:child_process";
385007
385818
  import { createHash as createHash7 } from "node:crypto";
385008
- import { existsSync as existsSync24, readFileSync as readFileSync24, statSync as statSync4 } from "node:fs";
385819
+ import { existsSync as existsSync24, readFileSync as readFileSync24, readdirSync as readdirSync4, statSync as statSync4 } from "node:fs";
385009
385820
  import { isAbsolute, join as join31, relative as relative3, resolve as resolve7, sep as sep3 } from "node:path";
385821
+ function deriveProjectFiles(root2) {
385822
+ const found = [];
385823
+ const pending = [root2];
385824
+ while (pending.length > 0) {
385825
+ const directory = pending.pop();
385826
+ if (directory === void 0)
385827
+ break;
385828
+ let entries;
385829
+ try {
385830
+ entries = readdirSync4(directory, { withFileTypes: true });
385831
+ } catch {
385832
+ continue;
385833
+ }
385834
+ for (const entry of entries) {
385835
+ const absolute = join31(directory, entry.name);
385836
+ if (entry.isDirectory()) {
385837
+ if (!SKIPPED_DIRECTORIES3.has(entry.name))
385838
+ pending.push(absolute);
385839
+ continue;
385840
+ }
385841
+ const relativePath = toRepositoryRelative(root2, absolute);
385842
+ if (relativePath !== void 0)
385843
+ found.push(relativePath);
385844
+ }
385845
+ }
385846
+ return found;
385847
+ }
385010
385848
  function isGraphOwned(relativePath) {
385011
385849
  return GRAPH_OWNED_SUFFIXES.some(
385012
385850
  (suffix) => relativePath === suffix || relativePath.endsWith(`/${suffix}`)
385013
385851
  );
385014
385852
  }
385853
+ function isEnvPath(relativePath) {
385854
+ return relativePath === ".env" || relativePath.endsWith("/.env");
385855
+ }
385856
+ function envKeysOf(root2, relativePath) {
385857
+ const absolute = join31(root2, relativePath);
385858
+ try {
385859
+ if (!existsSync24(absolute))
385860
+ return [];
385861
+ const values = readDotEnvValues(readFileSync24(absolute, "utf8"));
385862
+ return Object.entries(values).map(([name, value]) => ({
385863
+ name,
385864
+ hasValue: value.trim() !== ""
385865
+ }));
385866
+ } catch {
385867
+ return "unreadable";
385868
+ }
385869
+ }
385870
+ function lostCredentials(recorded, current) {
385871
+ const now = new Map(current.map((key) => [key.name, key.hasValue]));
385872
+ return recorded.filter((key) => key.hasValue && now.get(key.name) !== true).map((key) => key.name);
385873
+ }
385874
+ function isEnvKeyList(value) {
385875
+ if (value === void 0)
385876
+ return true;
385877
+ if (!Array.isArray(value))
385878
+ return false;
385879
+ return value.every(
385880
+ (key) => typeof key === "object" && key !== null && typeof key.name === "string" && typeof key.hasValue === "boolean"
385881
+ );
385882
+ }
385015
385883
  function isAcceptedDrift(value) {
385016
385884
  if (value === void 0)
385017
385885
  return true;
@@ -385026,7 +385894,7 @@ function isPathAuthorization(value) {
385026
385894
  if (typeof value !== "object" || value === null)
385027
385895
  return false;
385028
385896
  const candidate = value;
385029
- return typeof candidate.reason === "string" && typeof candidate.at === "string";
385897
+ return typeof candidate.reason === "string" && typeof candidate.at === "string" && (candidate.unplanned === void 0 || candidate.unplanned === true);
385030
385898
  }
385031
385899
  function changeBetween(captured, current) {
385032
385900
  if (captured === void 0)
@@ -385059,13 +385927,19 @@ function readManifest(dependencies) {
385059
385927
  return "malformed";
385060
385928
  if (typeof stored.capturedAt !== "string")
385061
385929
  return "malformed";
385930
+ if (stored.implementationStartedAt !== void 0 && typeof stored.implementationStartedAt !== "string") {
385931
+ return "malformed";
385932
+ }
385062
385933
  if (!Array.isArray(stored.entries))
385063
385934
  return "malformed";
385064
385935
  const wellFormed = stored.entries.every(
385065
- (entry) => typeof entry === "object" && entry !== null && typeof entry.path === "string" && (entry.pathClass === "protected" || entry.pathClass === "deferred") && (entry.digest === void 0 || typeof entry.digest === "string") && isAcceptedDrift(entry.acceptedDrift) && isPathAuthorization(entry.authorization)
385936
+ (entry) => typeof entry === "object" && entry !== null && typeof entry.path === "string" && (entry.pathClass === "protected" || entry.pathClass === "deferred") && (entry.digest === void 0 || typeof entry.digest === "string") && isAcceptedDrift(entry.acceptedDrift) && isPathAuthorization(entry.authorization) && isEnvKeyList(entry.envKeys)
385066
385937
  );
385067
385938
  return wellFormed ? stored : "malformed";
385068
385939
  }
385940
+ function startedMark(stored) {
385941
+ return stored?.implementationStartedAt === void 0 ? {} : { implementationStartedAt: stored.implementationStartedAt };
385942
+ }
385069
385943
  function digestOf(root2, relativePath) {
385070
385944
  const absolute = join31(root2, relativePath);
385071
385945
  try {
@@ -385084,8 +385958,8 @@ function byPath(entries) {
385084
385958
  );
385085
385959
  }
385086
385960
  function deriveChangedPaths(root2) {
385087
- if (!existsSync24(join31(root2, ".git")))
385088
- return [];
385961
+ if (findRepositoryRoot(root2) === void 0)
385962
+ return "no-repository";
385089
385963
  let output;
385090
385964
  try {
385091
385965
  output = execFileSync5(
@@ -385128,6 +386002,9 @@ function probeGraphOwned(root2, cwd2) {
385128
386002
  }
385129
386003
  return found;
385130
386004
  }
386005
+ function toRequestedPath(root2, path45) {
386006
+ return isAbsolute(path45) ? path45 : resolve7(root2, path45);
386007
+ }
385131
386008
  function toRepositoryRelative(root2, absolute) {
385132
386009
  const relativePath = relative3(root2, absolute);
385133
386010
  if (relativePath === "" || relativePath.startsWith(".."))
@@ -385140,10 +386017,14 @@ function captureEntry(root2, relativePath, derived) {
385140
386017
  const read = digestOf(root2, relativePath);
385141
386018
  if (read === "unreadable")
385142
386019
  return "unreadable";
386020
+ const envKeys = isEnvPath(relativePath) ? envKeysOf(root2, relativePath) : void 0;
386021
+ if (envKeys === "unreadable")
386022
+ return "unreadable";
385143
386023
  return {
385144
386024
  path: relativePath,
385145
386025
  pathClass: derived && isGraphOwned(relativePath) ? "deferred" : "protected",
385146
- ...read.digest === void 0 ? {} : { digest: read.digest }
386026
+ ...read.digest === void 0 ? {} : { digest: read.digest },
386027
+ ...envKeys === void 0 ? {} : { envKeys }
385147
386028
  };
385148
386029
  }
385149
386030
  function captureProtectedPaths(dependencies, input) {
@@ -385154,7 +386035,7 @@ function captureProtectedPaths(dependencies, input) {
385154
386035
  const existing = ownBaseline?.entries ?? [];
385155
386036
  const requested = [];
385156
386037
  for (const path45 of input.paths) {
385157
- const absolute = isAbsolute(path45) ? path45 : resolve7(dependencies.cwd, path45);
386038
+ const absolute = toRequestedPath(root2, path45);
385158
386039
  const relativePath = toRepositoryRelative(root2, absolute);
385159
386040
  if (relativePath === void 0) {
385160
386041
  return {
@@ -385181,7 +386062,8 @@ function captureProtectedPaths(dependencies, input) {
385181
386062
  if (changed === "failed") {
385182
386063
  return { status: "blocked", reason: "git-failed", detail: root2 };
385183
386064
  }
385184
- for (const path45 of changed)
386065
+ const derived = changed === "no-repository" ? deriveProjectFiles(root2) : changed;
386066
+ for (const path45 of derived)
385185
386067
  candidates.add(path45);
385186
386068
  for (const path45 of probeGraphOwned(root2, dependencies.cwd)) {
385187
386069
  candidates.add(path45);
@@ -385204,6 +386086,7 @@ function captureProtectedPaths(dependencies, input) {
385204
386086
  dependencies.store.set(protectedBaselineKey(dependencies), {
385205
386087
  runId: input.runId,
385206
386088
  capturedAt: ownBaseline?.capturedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
386089
+ ...startedMark(ownBaseline),
385207
386090
  entries
385208
386091
  });
385209
386092
  return {
@@ -385289,7 +386172,7 @@ function rebaselineProtectedPaths(dependencies, input) {
385289
386172
  }
385290
386173
  const targets = [];
385291
386174
  for (const path45 of input.paths) {
385292
- const absolute = isAbsolute(path45) ? path45 : resolve7(dependencies.cwd, path45);
386175
+ const absolute = toRequestedPath(root2, path45);
385293
386176
  const relativePath = toRepositoryRelative(root2, absolute);
385294
386177
  if (relativePath === void 0) {
385295
386178
  return { status: "blocked", reason: "unknown-path", detail: path45 };
@@ -385318,10 +386201,19 @@ function rebaselineProtectedPaths(dependencies, input) {
385318
386201
  detail: entry.path
385319
386202
  };
385320
386203
  }
386204
+ const promotedKeys = isEnvPath(entry.path) ? envKeysOf(root2, entry.path) : void 0;
386205
+ if (promotedKeys === "unreadable") {
386206
+ return {
386207
+ status: "blocked",
386208
+ reason: "unreadable-path",
386209
+ detail: entry.path
386210
+ };
386211
+ }
385321
386212
  const next = {
385322
386213
  path: entry.path,
385323
386214
  pathClass: "protected",
385324
- ...read.digest === void 0 ? {} : { digest: read.digest }
386215
+ ...read.digest === void 0 ? {} : { digest: read.digest },
386216
+ ...promotedKeys === void 0 ? {} : { envKeys: promotedKeys }
385325
386217
  };
385326
386218
  entries.push(next);
385327
386219
  promoted.push(next);
@@ -385329,6 +386221,7 @@ function rebaselineProtectedPaths(dependencies, input) {
385329
386221
  dependencies.store.set(protectedBaselineKey(dependencies), {
385330
386222
  runId: stored.runId,
385331
386223
  capturedAt: stored.capturedAt,
386224
+ ...startedMark(stored),
385332
386225
  entries: byPath(entries)
385333
386226
  });
385334
386227
  return { status: "passed", runId: stored.runId, promoted: byPath(promoted) };
@@ -385369,7 +386262,7 @@ function acceptProtectedPathDrift(dependencies, input) {
385369
386262
  const drift = /* @__PURE__ */ new Map();
385370
386263
  const accepted = [];
385371
386264
  for (const path45 of input.paths) {
385372
- const absolute = isAbsolute(path45) ? path45 : resolve7(dependencies.cwd, path45);
386265
+ const absolute = toRequestedPath(root2, path45);
385373
386266
  const relativePath = toRepositoryRelative(root2, absolute);
385374
386267
  if (relativePath === void 0) {
385375
386268
  return { status: "blocked", reason: "unknown-path", detail: path45 };
@@ -385436,16 +386329,166 @@ function acceptProtectedPathDrift(dependencies, input) {
385436
386329
  path: entry.path,
385437
386330
  pathClass: entry.pathClass,
385438
386331
  ...digest === void 0 ? {} : { digest },
386332
+ // Carried rather than rebuilt. No env path reaches here today, because
386333
+ // every one of them is graph-owned and refused above. That is a guard one
386334
+ // edit away from changing, and dropping the record would leave the
386335
+ // credential route refusing `unrecorded-keys` on a path it should answer.
386336
+ ...entry.envKeys === void 0 ? {} : { envKeys: entry.envKeys },
385439
386337
  acceptedDrift
385440
386338
  });
385441
386339
  }
385442
386340
  dependencies.store.set(protectedBaselineKey(dependencies), {
385443
386341
  runId: stored.runId,
385444
386342
  capturedAt: stored.capturedAt,
386343
+ ...startedMark(stored),
385445
386344
  entries: byPath(entries)
385446
386345
  });
385447
386346
  return { status: "passed", runId: stored.runId, accepted: byPath(accepted) };
385448
386347
  }
386348
+ function acceptCredentialPlacement(dependencies, input) {
386349
+ const root2 = resolveAnchoredRoot(dependencies);
386350
+ const stored = readManifest(dependencies);
386351
+ if (stored === void 0) {
386352
+ return { status: "blocked", reason: "no-baseline", detail: input.runId };
386353
+ }
386354
+ if (stored === "malformed") {
386355
+ return {
386356
+ status: "blocked",
386357
+ reason: "unreadable-baseline",
386358
+ detail: input.runId
386359
+ };
386360
+ }
386361
+ if (stored.runId !== input.runId) {
386362
+ return { status: "blocked", reason: "run-mismatch", detail: stored.runId };
386363
+ }
386364
+ const at = (/* @__PURE__ */ new Date()).toISOString();
386365
+ const placed = /* @__PURE__ */ new Map();
386366
+ const accepted = [];
386367
+ for (const path45 of input.paths) {
386368
+ const absolute = toRequestedPath(root2, path45);
386369
+ const relativePath = toRepositoryRelative(root2, absolute);
386370
+ if (relativePath === void 0) {
386371
+ return { status: "blocked", reason: "unknown-path", detail: path45 };
386372
+ }
386373
+ if (placed.has(relativePath))
386374
+ continue;
386375
+ if (!isEnvPath(relativePath)) {
386376
+ return { status: "blocked", reason: "not-env-path", detail: relativePath };
386377
+ }
386378
+ const entry = stored.entries.find((held) => held.path === relativePath);
386379
+ if (entry === void 0) {
386380
+ return { status: "blocked", reason: "unknown-path", detail: relativePath };
386381
+ }
386382
+ if (entry.pathClass === "deferred") {
386383
+ return {
386384
+ status: "blocked",
386385
+ reason: "deferred-path",
386386
+ detail: relativePath
386387
+ };
386388
+ }
386389
+ const read = digestOf(root2, relativePath);
386390
+ if (read === "unreadable") {
386391
+ return {
386392
+ status: "blocked",
386393
+ reason: "unreadable-path",
386394
+ detail: relativePath
386395
+ };
386396
+ }
386397
+ if (read.digest === entry.digest) {
386398
+ return {
386399
+ status: "blocked",
386400
+ reason: "unchanged-path",
386401
+ detail: relativePath
386402
+ };
386403
+ }
386404
+ const current = envKeysOf(root2, relativePath);
386405
+ if (current === "unreadable") {
386406
+ return {
386407
+ status: "blocked",
386408
+ reason: "unreadable-path",
386409
+ detail: relativePath
386410
+ };
386411
+ }
386412
+ if (entry.envKeys === void 0) {
386413
+ return {
386414
+ status: "blocked",
386415
+ reason: "unrecorded-keys",
386416
+ detail: relativePath
386417
+ };
386418
+ }
386419
+ const lost = lostCredentials(entry.envKeys, current);
386420
+ if (lost.length > 0) {
386421
+ return {
386422
+ status: "blocked",
386423
+ reason: "credential-lost",
386424
+ detail: `${relativePath}: ${lost.join(", ")}`
386425
+ };
386426
+ }
386427
+ const change = changeBetween(entry.digest, read.digest);
386428
+ placed.set(relativePath, {
386429
+ change,
386430
+ at,
386431
+ envKeys: current,
386432
+ ...read.digest === void 0 ? {} : { digest: read.digest }
386433
+ });
386434
+ accepted.push({ path: relativePath, change, at });
386435
+ }
386436
+ const entries = [];
386437
+ for (const entry of stored.entries) {
386438
+ const moved = placed.get(entry.path);
386439
+ if (moved === void 0) {
386440
+ entries.push(entry);
386441
+ continue;
386442
+ }
386443
+ const { digest, envKeys, ...acceptedDrift } = moved;
386444
+ entries.push({
386445
+ path: entry.path,
386446
+ pathClass: entry.pathClass,
386447
+ ...digest === void 0 ? {} : { digest },
386448
+ ...entry.authorization === void 0 ? {} : { authorization: entry.authorization },
386449
+ acceptedDrift,
386450
+ envKeys
386451
+ });
386452
+ }
386453
+ dependencies.store.set(protectedBaselineKey(dependencies), {
386454
+ runId: stored.runId,
386455
+ capturedAt: stored.capturedAt,
386456
+ ...startedMark(stored),
386457
+ entries: byPath(entries)
386458
+ });
386459
+ return { status: "passed", runId: stored.runId, accepted: byPath(accepted) };
386460
+ }
386461
+ function markImplementationStarted(dependencies, input) {
386462
+ const stored = readManifest(dependencies);
386463
+ if (stored === void 0) {
386464
+ return { status: "blocked", reason: "no-baseline", detail: input.runId };
386465
+ }
386466
+ if (stored === "malformed") {
386467
+ return {
386468
+ status: "blocked",
386469
+ reason: "unreadable-baseline",
386470
+ detail: input.runId
386471
+ };
386472
+ }
386473
+ if (stored.runId !== input.runId) {
386474
+ return { status: "blocked", reason: "run-mismatch", detail: stored.runId };
386475
+ }
386476
+ if (stored.implementationStartedAt !== void 0) {
386477
+ return {
386478
+ status: "passed",
386479
+ runId: stored.runId,
386480
+ startedAt: stored.implementationStartedAt
386481
+ };
386482
+ }
386483
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
386484
+ dependencies.store.set(protectedBaselineKey(dependencies), {
386485
+ runId: stored.runId,
386486
+ capturedAt: stored.capturedAt,
386487
+ implementationStartedAt: startedAt,
386488
+ entries: stored.entries
386489
+ });
386490
+ return { status: "passed", runId: stored.runId, startedAt };
386491
+ }
385449
386492
  function authorizeProtectedPathChange(dependencies, input) {
385450
386493
  const root2 = resolveAnchoredRoot(dependencies);
385451
386494
  const stored = readManifest(dependencies);
@@ -385468,9 +386511,10 @@ function authorizeProtectedPathChange(dependencies, input) {
385468
386511
  }
385469
386512
  const at = (/* @__PURE__ */ new Date()).toISOString();
385470
386513
  const granted = /* @__PURE__ */ new Map();
386514
+ const priorDrift = /* @__PURE__ */ new Map();
385471
386515
  const authorized = [];
385472
386516
  for (const path45 of input.paths) {
385473
- const absolute = isAbsolute(path45) ? path45 : resolve7(dependencies.cwd, path45);
386517
+ const absolute = toRequestedPath(root2, path45);
385474
386518
  const relativePath = toRepositoryRelative(root2, absolute);
385475
386519
  if (relativePath === void 0) {
385476
386520
  return { status: "blocked", reason: "unknown-path", detail: path45 };
@@ -385495,6 +386539,24 @@ function authorizeProtectedPathChange(dependencies, input) {
385495
386539
  detail: relativePath
385496
386540
  };
385497
386541
  }
386542
+ const started = stored.implementationStartedAt !== void 0;
386543
+ if (started && input.unplanned !== true) {
386544
+ return {
386545
+ status: "blocked",
386546
+ reason: "unplanned-path",
386547
+ detail: relativePath
386548
+ };
386549
+ }
386550
+ if (!started && input.unplanned === true) {
386551
+ return { status: "blocked", reason: "planned-path", detail: relativePath };
386552
+ }
386553
+ if (started && input.acceptPriorChange === true) {
386554
+ return {
386555
+ status: "blocked",
386556
+ reason: "prior-change-after-start",
386557
+ detail: relativePath
386558
+ };
386559
+ }
385498
386560
  const read = digestOf(root2, relativePath);
385499
386561
  if (read === "unreadable") {
385500
386562
  return {
@@ -385504,18 +386566,45 @@ function authorizeProtectedPathChange(dependencies, input) {
385504
386566
  };
385505
386567
  }
385506
386568
  if (read.digest !== entry.digest) {
385507
- return { status: "blocked", reason: "changed-path", detail: relativePath };
386569
+ if (input.acceptPriorChange !== true) {
386570
+ return {
386571
+ status: "blocked",
386572
+ reason: "changed-path",
386573
+ detail: relativePath
386574
+ };
386575
+ }
386576
+ priorDrift.set(relativePath, {
386577
+ change: changeBetween(entry.digest, read.digest),
386578
+ at,
386579
+ ...read.digest === void 0 ? {} : { digest: read.digest }
386580
+ });
385508
386581
  }
385509
- granted.set(relativePath, { reason, at });
385510
- authorized.push({ path: relativePath, reason, at });
386582
+ const authorization = input.unplanned === true ? { reason, at, unplanned: true } : { reason, at };
386583
+ granted.set(relativePath, authorization);
386584
+ authorized.push({ path: relativePath, ...authorization });
385511
386585
  }
385512
386586
  const entries = stored.entries.map((entry) => {
385513
386587
  const authorization = granted.get(entry.path);
385514
- return authorization === void 0 ? entry : { ...entry, authorization };
386588
+ if (authorization === void 0)
386589
+ return entry;
386590
+ const moved = priorDrift.get(entry.path);
386591
+ if (moved === void 0)
386592
+ return { ...entry, authorization };
386593
+ const { digest, ...acceptedDrift } = moved;
386594
+ return {
386595
+ path: entry.path,
386596
+ pathClass: entry.pathClass,
386597
+ ...digest === void 0 ? {} : { digest },
386598
+ // Carried for the same reason as in the acceptance route above.
386599
+ ...entry.envKeys === void 0 ? {} : { envKeys: entry.envKeys },
386600
+ acceptedDrift,
386601
+ authorization
386602
+ };
385515
386603
  });
385516
386604
  dependencies.store.set(protectedBaselineKey(dependencies), {
385517
386605
  runId: stored.runId,
385518
386606
  capturedAt: stored.capturedAt,
386607
+ ...startedMark(stored),
385519
386608
  entries: byPath(entries)
385520
386609
  });
385521
386610
  return {
@@ -385524,26 +386613,60 @@ function authorizeProtectedPathChange(dependencies, input) {
385524
386613
  authorized: byPath(authorized)
385525
386614
  };
385526
386615
  }
385527
- var GRAPH_OWNED_SUFFIXES;
386616
+ var SKIPPED_DIRECTORIES3, GRAPH_OWNED_SUFFIXES;
385528
386617
  var init_onboarding_protected_paths = __esm({
385529
386618
  "apps/cli/src/services/onboarding-protected-paths.ts"() {
385530
386619
  "use strict";
386620
+ init_dotenv_read();
386621
+ init_repository_root();
385531
386622
  init_onboarding_state();
386623
+ SKIPPED_DIRECTORIES3 = /* @__PURE__ */ new Set([
386624
+ "node_modules",
386625
+ "dist",
386626
+ "build",
386627
+ "out",
386628
+ "coverage",
386629
+ ".next",
386630
+ "venv",
386631
+ "__pycache__"
386632
+ ]);
385532
386633
  GRAPH_OWNED_SUFFIXES = [".env", ".copilotkit/project.json"];
385533
386634
  }
385534
386635
  });
385535
386636
 
385536
386637
  // apps/cli/src/services/onboarding-classification.ts
385537
- function unprovenBaselineRefusal(startingState, route) {
385538
- if (startingState !== "both-oss")
385539
- return void 0;
385540
- if (route.length === 0)
386638
+ function resolveAgentFrameworkAlias(value) {
386639
+ if (value === void 0)
385541
386640
  return void 0;
385542
- if (route.includes(OSS_BASELINE_NODE))
386641
+ return ONBOARDING_AGENT_FRAMEWORK_ALIASES[value] ?? value;
386642
+ }
386643
+ function unprovenBaselineRefusal(startingState, route, proof) {
386644
+ if (startingState !== "both-oss" && startingState !== "both-copilotkit-unproved") {
385543
386645
  return void 0;
385544
- return `--starting-state both-oss records a proved OSS baseline, and this run never served ${OSS_BASELINE_NODE}.
386646
+ }
386647
+ if (route.length > 0 && !route.includes(OSS_BASELINE_NODE)) {
386648
+ return `--starting-state ${startingState} records a project whose CopilotKit integration was reached, and this run never served ${OSS_BASELINE_NODE}.
385545
386649
  Its route is: ${route.join(",")}.
385546
386650
  Read ${OSS_BASELINE_NODE} and record the state its proof returns.`;
386651
+ }
386652
+ if (proof === void 0)
386653
+ return void 0;
386654
+ if (startingState === "both-oss") {
386655
+ return proof.outcome === "passed" ? void 0 : `--starting-state both-oss records a proved OSS baseline, and this run recorded that baseline as ${proof.outcome}.
386656
+ Record --starting-state both-copilotkit-unproved instead: the CopilotKit integration is present and its round trip did not prove.`;
386657
+ }
386658
+ return proof.outcome === "passed" ? `--starting-state both-copilotkit-unproved records a round trip that did not prove, and this run recorded its baseline as passed.
386659
+ Record --starting-state both-oss instead, and keep the proof evidence with the plan.` : void 0;
386660
+ }
386661
+ function contradictedIntegrationRefusal(startingState, route) {
386662
+ if (!ABSENCE_STATES.some((state) => state === startingState)) {
386663
+ return void 0;
386664
+ }
386665
+ if (!route.includes(OSS_BASELINE_NODE))
386666
+ return void 0;
386667
+ return `--starting-state ${startingState} records a project without a CopilotKit integration, and this run was served ${OSS_BASELINE_NODE}, which is reached only when an agent, a frontend and a CopilotKit integration are all proved present.
386668
+ Its route is: ${route.join(",")}.
386669
+ Record --starting-state both-oss for a baseline that proved, or --starting-state both-copilotkit-unproved for one that did not.`;
385547
386670
  }
385548
386671
  function unresearchedBaselineWarning(promptName, route) {
385549
386672
  if (promptName !== OSS_BASELINE_NODE)
@@ -385563,7 +386686,7 @@ function requireOnboardingChoice(flag, value, choices) {
385563
386686
  }
385564
386687
  return selected;
385565
386688
  }
385566
- var ONBOARDING_STARTING_STATES, ONBOARDING_AGENT_FRAMEWORKS, ONBOARDING_FRONTENDS, OSS_BASELINE_NODE, TERMINAL_NODES, REPOSITORY_RESEARCH_NODE;
386689
+ var ONBOARDING_STARTING_STATES, ONBOARDING_AGENT_FRAMEWORKS, ONBOARDING_AGENT_FRAMEWORK_ALIASES, ONBOARDING_FRONTENDS, ONBOARDING_PROOF_STEPS, ONBOARDING_PROOF_OUTCOMES, ABSENCE_STATES, OSS_BASELINE_NODE, TERMINAL_NODES, REPOSITORY_RESEARCH_NODE;
385567
386690
  var init_onboarding_classification = __esm({
385568
386691
  "apps/cli/src/services/onboarding-classification.ts"() {
385569
386692
  "use strict";
@@ -385572,6 +386695,7 @@ var init_onboarding_classification = __esm({
385572
386695
  "agent-only",
385573
386696
  "frontend-only",
385574
386697
  "both",
386698
+ "both-copilotkit-unproved",
385575
386699
  "both-oss"
385576
386700
  ];
385577
386701
  ONBOARDING_AGENT_FRAMEWORKS = [
@@ -385595,6 +386719,9 @@ var init_onboarding_classification = __esm({
385595
386719
  "strands-python",
385596
386720
  "strands-typescript"
385597
386721
  ];
386722
+ ONBOARDING_AGENT_FRAMEWORK_ALIASES = {
386723
+ langgraph: "langgraph-python"
386724
+ };
385598
386725
  ONBOARDING_FRONTENDS = [
385599
386726
  "react-spa",
385600
386727
  "nextjs",
@@ -385602,6 +386729,18 @@ var init_onboarding_classification = __esm({
385602
386729
  "vue",
385603
386730
  "react-native"
385604
386731
  ];
386732
+ ONBOARDING_PROOF_STEPS = ["oss-baseline", "round-trip"];
386733
+ ONBOARDING_PROOF_OUTCOMES = [
386734
+ "passed",
386735
+ "failed",
386736
+ "skipped"
386737
+ ];
386738
+ ABSENCE_STATES = [
386739
+ "empty",
386740
+ "agent-only",
386741
+ "frontend-only",
386742
+ "both"
386743
+ ];
385605
386744
  OSS_BASELINE_NODE = "proof/oss-baseline";
385606
386745
  TERMINAL_NODES = {
385607
386746
  "fallback/best-effort": "best-effort",
@@ -385611,6 +386750,12 @@ var init_onboarding_classification = __esm({
385611
386750
  // feature run must not enter, because a stop reported from inside a route the
385612
386751
  // run never took is a stop that never happened.
385613
386752
  "feature/stop": "feature-blocked",
386753
+ // A run that broke gets its own ending. 52 outside runs ended at
386754
+ // `unsupported/no-validated-path` in the three weeks to 2026-09-13, and 10 of
386755
+ // them had classified as `built-in` with `nextjs` -- a stack this graph serves.
386756
+ // While one terminal absorbs both, "we do not support this" and "this run
386757
+ // broke" are the same row, and neither can be counted.
386758
+ "stopped/run-failed": "run-failed",
385614
386759
  "unsupported/no-validated-path": "unsupported"
385615
386760
  };
385616
386761
  REPOSITORY_RESEARCH_NODE = "subagent/inspect-repository";
@@ -385780,7 +386925,7 @@ async function runOnboard(argv, dependencies) {
385780
386925
  deps,
385781
386926
  () => deps.loadStartPrompt(parsed.values.intent)
385782
386927
  );
385783
- const binding2 = startOnboardingRun(
386928
+ const binding = startOnboardingRun(
385784
386929
  {
385785
386930
  cwd: deps.cwd,
385786
386931
  store: deps.store,
@@ -385791,14 +386936,40 @@ async function runOnboard(argv, dependencies) {
385791
386936
  );
385792
386937
  recordStarted(
385793
386938
  deps,
385794
- binding2.runId,
386939
+ binding.runId,
385795
386940
  "start",
385796
- binding2.idOrigin,
386941
+ binding.idOrigin,
385797
386942
  parsed.values["coding-agent"]
385798
386943
  );
385799
- printRunId(deps, binding2.runId);
386944
+ if (parsed.values["coding-agent"] !== void 0) {
386945
+ recordCodingAgentBestEffort(
386946
+ deps,
386947
+ binding.runId,
386948
+ parsed.values["coding-agent"]
386949
+ );
386950
+ }
386951
+ recordAbandonedRunWhenFound(deps, binding.runId);
386952
+ printRunId(deps, binding.runId);
385800
386953
  await printGraphTree(deps);
385801
- writePrompt(deps, binding2.runId, startPrompt);
386954
+ writePrompt(deps, binding.runId, startPrompt);
386955
+ return;
386956
+ }
386957
+ if (subcommand === "identify") {
386958
+ const parsed = parseIdentify(argv.slice(1));
386959
+ const runId2 = requireBoundRun(deps, IDENTIFY_RUN_NOT_BOUND);
386960
+ recordCodingAgentBestEffort(deps, runId2, parsed.codingAgent);
386961
+ recordBestEffort(deps, {
386962
+ event: "cli.onboarding.identified",
386963
+ properties: {
386964
+ command: "onboard",
386965
+ ...onboardingIntentProperties(deps),
386966
+ onboarding_run_id: runId2,
386967
+ cli_version: deps.cliVersion,
386968
+ coding_agent: normalizeCodingAgent(parsed.codingAgent)
386969
+ }
386970
+ });
386971
+ deps.stdout.write(`Coding agent recorded for run ${runId2}.
386972
+ `);
385802
386973
  return;
385803
386974
  }
385804
386975
  if (subcommand === "route") {
@@ -385812,23 +386983,21 @@ async function runOnboard(argv, dependencies) {
385812
386983
  if (argv.length !== 2 || promptName === void 0) {
385813
386984
  throw new Error("Usage: copilotkit onboard read <prompt-name>");
385814
386985
  }
385815
- await printPrompt(deps, requireBoundRun(deps), promptName);
386986
+ await printPrompt(
386987
+ deps,
386988
+ requireBoundRun(deps, READ_RUN_NOT_BOUND),
386989
+ promptName
386990
+ );
385816
386991
  return;
385817
386992
  }
385818
- const binding = resolveOnboardingRun({
385819
- cwd: deps.cwd,
385820
- store: deps.store,
385821
- randomRunId: deps.randomRunId
385822
- });
385823
- if (binding.started) {
385824
- recordStarted(
385825
- deps,
385826
- binding.runId,
385827
- "another-step",
385828
- binding.idOrigin,
385829
- void 0
386993
+ if (subcommand === void 0 || !ONBOARD_SUBCOMMANDS.includes(subcommand)) {
386994
+ throw new Error(
386995
+ `Usage: copilotkit onboard <${ONBOARD_SUBCOMMANDS.join("|")}>`
385830
386996
  );
385831
386997
  }
386998
+ const runId = readOnboardingRunId({ cwd: deps.cwd, store: deps.store });
386999
+ if (runId === void 0)
387000
+ throw new Error(STEP_RUN_NOT_BOUND);
385832
387001
  if (subcommand === "complete") {
385833
387002
  const opened = parseFrontendUrl(argv.slice(1));
385834
387003
  if (opened === void 0)
@@ -385839,14 +387008,15 @@ async function runOnboard(argv, dependencies) {
385839
387008
  const check4 = parseSurfaceCheck(blocked2.rest);
385840
387009
  if (check4 === void 0)
385841
387010
  throw new Error(SURFACE_CHECK_USAGE);
385842
- const accepted = readAcceptedDriftBestEffort(deps, binding.runId);
385843
- const authorized = readAuthorizationsBestEffort(deps, binding.runId);
387011
+ const accepted = readAcceptedDriftBestEffort(deps, runId);
387012
+ const authorized = readAuthorizationsBestEffort(deps, runId);
387013
+ markRunEndedBestEffort(deps, runId);
385844
387014
  recordBestEffort(deps, {
385845
387015
  event: "cli.onboarding.completed",
385846
387016
  properties: {
385847
387017
  command: "onboard",
385848
387018
  ...onboardingIntentProperties(deps),
385849
- onboarding_run_id: binding.runId,
387019
+ onboarding_run_id: runId,
385850
387020
  cli_version: deps.cliVersion,
385851
387021
  accepted_count: accepted.length,
385852
387022
  authorized_count: authorized.length,
@@ -385882,7 +387052,7 @@ async function runOnboard(argv, dependencies) {
385882
387052
  const requestedFramework = parsed.values["agent-framework"];
385883
387053
  const startingState = reportingRefusal(
385884
387054
  deps,
385885
- binding.runId,
387055
+ runId,
385886
387056
  "starting-state-invalid",
385887
387057
  {},
385888
387058
  () => requireOnboardingChoice(
@@ -385893,18 +387063,18 @@ async function runOnboard(argv, dependencies) {
385893
387063
  );
385894
387064
  const agentFramework = reportingRefusal(
385895
387065
  deps,
385896
- binding.runId,
387066
+ runId,
385897
387067
  "agent-framework-invalid",
385898
387068
  { requested_agent_framework: reportableSlug(requestedFramework) },
385899
387069
  () => requireOnboardingChoice(
385900
387070
  "--agent-framework",
385901
- requestedFramework,
387071
+ resolveAgentFrameworkAlias(requestedFramework),
385902
387072
  ONBOARDING_AGENT_FRAMEWORKS
385903
387073
  )
385904
387074
  );
385905
387075
  const frontend = reportingRefusal(
385906
387076
  deps,
385907
- binding.runId,
387077
+ runId,
385908
387078
  "frontend-invalid",
385909
387079
  {},
385910
387080
  () => requireOnboardingChoice(
@@ -385913,12 +387083,19 @@ async function runOnboard(argv, dependencies) {
385913
387083
  ONBOARDING_FRONTENDS
385914
387084
  )
385915
387085
  );
387086
+ const route = readOnboardingRoute({ cwd: deps.cwd, store: deps.store });
387087
+ const contradiction = contradictedIntegrationRefusal(startingState, route);
387088
+ if (contradiction !== void 0) {
387089
+ recordClassifyRefusal(deps, runId, "integration-contradicted", {});
387090
+ throw new Error(contradiction);
387091
+ }
385916
387092
  const refusal = unprovenBaselineRefusal(
385917
387093
  startingState,
385918
- readOnboardingRoute({ cwd: deps.cwd, store: deps.store })
387094
+ route,
387095
+ readBaselineProofBestEffort(deps)
385919
387096
  );
385920
387097
  if (refusal !== void 0) {
385921
- recordClassifyRefusal(deps, binding.runId, "baseline-unproven", {});
387098
+ recordClassifyRefusal(deps, runId, "baseline-unproven", {});
385922
387099
  throw new Error(refusal);
385923
387100
  }
385924
387101
  recordBestEffort(deps, {
@@ -385926,7 +387103,7 @@ async function runOnboard(argv, dependencies) {
385926
387103
  properties: {
385927
387104
  command: "onboard",
385928
387105
  ...onboardingIntentProperties(deps),
385929
- onboarding_run_id: binding.runId,
387106
+ onboarding_run_id: runId,
385930
387107
  cli_version: deps.cliVersion,
385931
387108
  starting_state: startingState,
385932
387109
  // Mapped at the emit boundary, never at the flag: the graph's own
@@ -385939,15 +387116,8 @@ async function runOnboard(argv, dependencies) {
385939
387116
  deps.stdout.write("Onboarding path included in telemetry when enabled.\n");
385940
387117
  return;
385941
387118
  }
385942
- if (subcommand === "feedback") {
385943
- if (argv.length !== 1) {
385944
- throw new Error("Usage: copilotkit onboard feedback");
385945
- }
385946
- await reportFeedback(deps, binding.runId);
385947
- return;
385948
- }
385949
387119
  if (subcommand === "friction") {
385950
- await reportFriction(deps, binding.runId, argv.slice(1));
387120
+ await reportFriction(deps, runId, argv.slice(1));
385951
387121
  return;
385952
387122
  }
385953
387123
  if (subcommand === "protect") {
@@ -385955,11 +387125,14 @@ async function runOnboard(argv, dependencies) {
385955
387125
  args: [...argv.slice(1)],
385956
387126
  allowPositionals: false,
385957
387127
  options: {
387128
+ "accept-credential": { type: "boolean" },
385958
387129
  "accept-external": { type: "boolean" },
385959
387130
  authorize: { type: "boolean" },
385960
387131
  path: { type: "string", multiple: true },
385961
387132
  reason: { type: "string" },
385962
- rebaseline: { type: "boolean" }
387133
+ rebaseline: { type: "boolean" },
387134
+ unplanned: { type: "boolean" },
387135
+ "with-prior-change": { type: "boolean" }
385963
387136
  },
385964
387137
  strict: true
385965
387138
  });
@@ -385967,21 +387140,52 @@ async function runOnboard(argv, dependencies) {
385967
387140
  const target = { cwd: deps.cwd, store: deps.store };
385968
387141
  const rebaseline = parsed.values.rebaseline === true;
385969
387142
  const acceptExternal = parsed.values["accept-external"] === true;
387143
+ const acceptCredential = parsed.values["accept-credential"] === true;
385970
387144
  const authorize = parsed.values.authorize === true;
385971
- if ([rebaseline, acceptExternal, authorize].filter(Boolean).length > 1) {
387145
+ const withPriorChange = parsed.values["with-prior-change"] === true;
387146
+ const unplanned = parsed.values.unplanned === true;
387147
+ if ([rebaseline, acceptExternal, acceptCredential, authorize].filter(Boolean).length > 1) {
385972
387148
  throw new Error(EXCLUSIVE_MODE_USAGE);
385973
387149
  }
387150
+ if (withPriorChange && !authorize) {
387151
+ throw new Error(PRIOR_CHANGE_USAGE);
387152
+ }
387153
+ if (unplanned && !authorize) {
387154
+ throw new Error(UNPLANNED_USAGE);
387155
+ }
387156
+ if (acceptCredential) {
387157
+ if (paths.length === 0)
387158
+ throw new Error(ACCEPT_CREDENTIAL_USAGE);
387159
+ const placed = acceptCredentialPlacement(target, {
387160
+ runId,
387161
+ paths
387162
+ });
387163
+ recordProtect(
387164
+ deps,
387165
+ runId,
387166
+ "accept-credential",
387167
+ placed,
387168
+ (result) => ({
387169
+ path_count: result.accepted.length,
387170
+ drift_kinds: joinChanges(result.accepted.map((one) => one.change))
387171
+ })
387172
+ );
387173
+ deps.stdout.write(credentialReport(placed));
387174
+ return;
387175
+ }
385974
387176
  if (authorize) {
385975
387177
  const reason = parsed.values.reason ?? "";
385976
387178
  if (paths.length === 0 || reason.trim() === "") {
385977
387179
  throw new Error(AUTHORIZE_USAGE);
385978
387180
  }
385979
387181
  const authorized = authorizeProtectedPathChange(target, {
385980
- runId: binding.runId,
387182
+ runId,
385981
387183
  paths,
385982
- reason
387184
+ reason,
387185
+ acceptPriorChange: withPriorChange,
387186
+ unplanned
385983
387187
  });
385984
- recordProtect(deps, binding.runId, "authorize", authorized, (result) => ({
387188
+ recordProtect(deps, runId, "authorize", authorized, (result) => ({
385985
387189
  path_count: result.authorized.length
385986
387190
  }));
385987
387191
  deps.stdout.write(authorizationReport(authorized));
@@ -385991,10 +387195,10 @@ async function runOnboard(argv, dependencies) {
385991
387195
  if (paths.length === 0)
385992
387196
  throw new Error(ACCEPT_USAGE);
385993
387197
  const accepted = acceptProtectedPathDrift(target, {
385994
- runId: binding.runId,
387198
+ runId,
385995
387199
  paths
385996
387200
  });
385997
- recordProtect(deps, binding.runId, "accept", accepted, (result) => ({
387201
+ recordProtect(deps, runId, "accept", accepted, (result) => ({
385998
387202
  path_count: result.accepted.length,
385999
387203
  drift_kinds: joinChanges(result.accepted.map((one) => one.change))
386000
387204
  }));
@@ -386005,20 +387209,20 @@ async function runOnboard(argv, dependencies) {
386005
387209
  if (paths.length === 0)
386006
387210
  throw new Error(REBASELINE_USAGE);
386007
387211
  const promoted = rebaselineProtectedPaths(target, {
386008
- runId: binding.runId,
387212
+ runId,
386009
387213
  paths
386010
387214
  });
386011
- recordProtect(deps, binding.runId, "rebaseline", promoted, (result) => ({
387215
+ recordProtect(deps, runId, "rebaseline", promoted, (result) => ({
386012
387216
  path_count: result.promoted.length
386013
387217
  }));
386014
387218
  deps.stdout.write(rebaselineReport(promoted));
386015
387219
  return;
386016
387220
  }
386017
387221
  const captured = captureProtectedPaths(target, {
386018
- runId: binding.runId,
387222
+ runId,
386019
387223
  paths
386020
387224
  });
386021
- recordProtect(deps, binding.runId, "capture", captured, (result) => ({
387225
+ recordProtect(deps, runId, "capture", captured, (result) => ({
386022
387226
  path_count: result.added.length,
386023
387227
  protect_derived: result.derived
386024
387228
  }));
@@ -386026,17 +387230,21 @@ async function runOnboard(argv, dependencies) {
386026
387230
  return;
386027
387231
  }
386028
387232
  if (subcommand === "checkpoint") {
386029
- reportCheckpoint(deps, binding.runId, argv.slice(1));
387233
+ reportCheckpoint(deps, runId, argv.slice(1));
386030
387234
  return;
386031
387235
  }
386032
387236
  if (subcommand === "proof") {
386033
387237
  const proof = parseProof(argv.slice(1));
387238
+ recordProofBestEffort(deps, runId, proof.step, {
387239
+ outcome: proof.outcome,
387240
+ ...proof.predicate === void 0 ? {} : { predicate: proof.predicate }
387241
+ });
386034
387242
  recordBestEffort(deps, {
386035
387243
  event: "cli.onboarding.proof_recorded",
386036
387244
  properties: {
386037
387245
  command: "onboard",
386038
387246
  ...onboardingIntentProperties(deps),
386039
- onboarding_run_id: binding.runId,
387247
+ onboarding_run_id: runId,
386040
387248
  cli_version: deps.cliVersion,
386041
387249
  proof_step: proof.step,
386042
387250
  proof_outcome: proof.outcome,
@@ -386053,14 +387261,14 @@ async function runOnboard(argv, dependencies) {
386053
387261
  throw new Error("Usage: copilotkit onboard audit");
386054
387262
  const audit = auditProtectedPaths(
386055
387263
  { cwd: deps.cwd, store: deps.store },
386056
- { runId: binding.runId }
387264
+ { runId }
386057
387265
  );
386058
387266
  recordBestEffort(deps, {
386059
387267
  event: "cli.onboarding.audit_completed",
386060
387268
  properties: {
386061
387269
  command: "onboard",
386062
387270
  ...onboardingIntentProperties(deps),
386063
- onboarding_run_id: binding.runId,
387271
+ onboarding_run_id: runId,
386064
387272
  cli_version: deps.cliVersion,
386065
387273
  ...describeAudit(audit)
386066
387274
  }
@@ -386068,17 +387276,17 @@ async function runOnboard(argv, dependencies) {
386068
387276
  deps.stdout.write(auditReport(audit));
386069
387277
  return;
386070
387278
  }
386071
- throw new Error(
386072
- `Usage: copilotkit onboard <${ONBOARD_SUBCOMMANDS.join("|")}>`
386073
- );
386074
387279
  }
386075
- function requireBoundRun(dependencies) {
387280
+ function runNotBound(reason) {
387281
+ return "No onboarding run is bound to this directory.\n\n" + reason + "\n\nIf this session has not started, run `copilotkit onboard start` here.\nIf it has, run `copilotkit onboard start --run <id>` here with the id the\nfirst start printed, or run this command from the directory you started in.\n\nThis is a missing start, not a failed step: nothing has been proved\nunsupported.";
387282
+ }
387283
+ function requireBoundRun(dependencies, refusal) {
386076
387284
  const runId = readOnboardingRunId({
386077
387285
  cwd: dependencies.cwd,
386078
387286
  store: dependencies.store
386079
387287
  });
386080
387288
  if (runId === void 0)
386081
- throw new Error(RUN_NOT_BOUND);
387289
+ throw new Error(refusal);
386082
387290
  return runId;
386083
387291
  }
386084
387292
  function plural(count, noun) {
@@ -386164,6 +387372,59 @@ ${detail}`;
386164
387372
  ""
386165
387373
  ].join("\n");
386166
387374
  }
387375
+ function credentialReport(result) {
387376
+ if (result.status === "blocked") {
387377
+ const detail = {
387378
+ "no-baseline": `No protected-path baseline was captured for run ${result.detail}.
387379
+ Run \`copilotkit onboard protect\` first.
387380
+ `,
387381
+ "run-mismatch": `The captured baseline belongs to run ${result.detail}, not to this run.
387382
+ A credential can only be accepted against the baseline of the run that
387383
+ asked for it.
387384
+ `,
387385
+ "unreadable-baseline": `The captured baseline for run ${result.detail} could not be read.
387386
+ Capture it again before accepting anything against it.
387387
+ `,
387388
+ "unreadable-path": `The protected path \`${result.detail}\` could not be read, so the credential
387389
+ it now holds could not be checked.
387390
+ `,
387391
+ "unknown-path": `The path \`${result.detail}\` is not in this run\u2019s baseline.
387392
+ Only a captured path can be accepted.
387393
+ `,
387394
+ "deferred-path": `The path \`${result.detail}\` is deferred, not protected.
387395
+ This graph has not finished writing it, so promote it first with
387396
+ \`onboard protect --rebaseline --path <path>\`.
387397
+ `,
387398
+ "not-env-path": `The path \`${result.detail}\` is not an env file.
387399
+ This route reads variable names to prove no credential was lost, which only
387400
+ means something for a file of \`KEY=value\` lines.
387401
+ `,
387402
+ "unchanged-path": `The path \`${result.detail}\` matches the digest captured for it.
387403
+ Nothing was placed in it, so there is no credential to accept.
387404
+ `,
387405
+ "unrecorded-keys": `The baseline holds no variable names for \`${result.detail}\`.
387406
+ This route proves no credential was lost by comparing them, so with none
387407
+ recorded it can prove nothing. Capture the path again with
387408
+ \`onboard protect --path <path>\` before the developer writes to it.
387409
+ `,
387410
+ "credential-lost": `A credential recorded for \`${result.detail}\` is gone.
387411
+ This route accepts a credential the developer added. It refuses a change
387412
+ that drops one, which is the failure the baseline exists to catch. Do not
387413
+ repair or rewrite the file. Report the missing variable and route out.
387414
+ `
387415
+ }[result.reason];
387416
+ return `Status: blocked
387417
+ ${detail}${NOTHING_ACCEPTED}`;
387418
+ }
387419
+ return [
387420
+ "Status: passed",
387421
+ `Accepted the placed credential in ${plural(result.accepted.length, "env file")} for run ${result.runId}.`,
387422
+ ...result.accepted.map(changeLine),
387423
+ "Every credential the baseline recorded is still there.",
387424
+ "Report each accepted path in the summary.",
387425
+ ""
387426
+ ].join("\n");
387427
+ }
386167
387428
  function acceptanceReport(result) {
386168
387429
  if (result.status === "blocked") {
386169
387430
  const detail = {
@@ -386217,7 +387478,8 @@ ${detail}${NOTHING_ACCEPTED}`;
386217
387478
  ].join("\n");
386218
387479
  }
386219
387480
  function authorizationLine(granted) {
386220
- return ` ${granted.path} \u2014 ${granted.reason}`;
387481
+ const source = granted.unplanned === true ? " (outside the approved plan)" : "";
387482
+ return ` ${granted.path} \u2014 ${granted.reason}${source}`;
386221
387483
  }
386222
387484
  function authorizedLines(authorized) {
386223
387485
  return authorized.length === 0 ? [] : ["Authorized to change:", ...authorized.map(authorizationLine)];
@@ -386249,11 +387511,31 @@ Nothing outside the run writes it, so consent here would only license the
386249
387511
  run against its own credential output.
386250
387512
  `,
386251
387513
  "missing-reason": "No reason was given.\nConsent is recorded so the closing report can tell the developer what their\nfile was changed for. A blank reason records permission and no answer.\n",
387514
+ "unplanned-path": `The path \`${result.detail}\` is not one the approved plan asked for.
387515
+ This run has already reported its plan, so the developer has approved every
387516
+ path they are going to approve. They did not approve this one. Ask them
387517
+ to allow the change, and record the answer they give with
387518
+ \`onboard protect --authorize --unplanned --path <path> --reason "<their
387519
+ answer>"\`. If you cannot ask, route out. Do not repair the path.
387520
+ `,
387521
+ "prior-change-after-start": `The path \`${result.detail}\` cannot carry a prior-change claim any more.
387522
+ That claim says the developer changed the file before this run implemented
387523
+ anything, and this run has already reported its plan. A protected path that
387524
+ changed after that is this run\u2019s own work. Route out rather than record
387525
+ consent over it.
387526
+ `,
387527
+ "planned-path": `The path \`${result.detail}\` can still be authorized by the plan itself.
387528
+ This run has not reported its plan yet, so --unplanned describes nothing:
387529
+ consent here is the developer approving the plan. Record it without the
387530
+ flag, or add the path to the plan and have the developer approve that.
387531
+ `,
386252
387532
  "changed-path": `The path \`${result.detail}\` has already changed since it was captured.
386253
387533
  Consent has to be recorded before the change, or it cannot be told apart from
386254
387534
  a run clearing a failure it caused. Run \`onboard audit\`: if a Files changed
386255
- section from this run names the path, route out; if none does, accept it with
386256
- \`onboard protect --accept-external --path <path>\` instead.
387535
+ section from this run names the path, route out. If none does, the developer
387536
+ changed it, and either accept it with \`onboard protect --accept-external
387537
+ --path <path>\` or, when this run must change the same file, record consent
387538
+ over their change by adding --with-prior-change.
386257
387539
  `
386258
387540
  }[result.reason];
386259
387541
  return `Status: blocked
@@ -386385,6 +387667,24 @@ function parseProof(args) {
386385
387667
  }
386386
387668
  return { step, outcome, predicate };
386387
387669
  }
387670
+ function parseIdentify(args) {
387671
+ let parsed;
387672
+ try {
387673
+ parsed = parseArgs2({
387674
+ args: [...args],
387675
+ allowPositionals: false,
387676
+ options: { "coding-agent": { type: "string" } },
387677
+ strict: true
387678
+ });
387679
+ } catch {
387680
+ throw new Error(IDENTIFY_USAGE);
387681
+ }
387682
+ const codingAgent = parsed.values["coding-agent"];
387683
+ if (codingAgent === void 0 || codingAgent.trim().length === 0) {
387684
+ throw new Error(IDENTIFY_USAGE);
387685
+ }
387686
+ return { codingAgent };
387687
+ }
386388
387688
  function reportCheckpoint(dependencies, runId, args) {
386389
387689
  let parsed;
386390
387690
  try {
@@ -386410,6 +387710,12 @@ function reportCheckpoint(dependencies, runId, args) {
386410
387710
  if (!reviewed.ok) {
386411
387711
  return printCheckpointRefusal(dependencies, runId, reviewed.refusal);
386412
387712
  }
387713
+ if (reviewed.checkpoint.phase === "plan-written") {
387714
+ markImplementationStarted(
387715
+ { cwd: dependencies.cwd, store: dependencies.store },
387716
+ { runId }
387717
+ );
387718
+ }
386413
387719
  recordBestEffort(dependencies, {
386414
387720
  event: "cli.onboarding.checkpoint",
386415
387721
  properties: {
@@ -386477,6 +387783,7 @@ function recordTerminalWhenReached(dependencies, runId, promptName) {
386477
387783
  const terminal = TERMINAL_NODES[promptName];
386478
387784
  if (terminal === void 0)
386479
387785
  return;
387786
+ markRunEndedBestEffort(dependencies, runId);
386480
387787
  recordBestEffort(dependencies, {
386481
387788
  event: "cli.onboarding.terminal_reached",
386482
387789
  properties: {
@@ -386488,6 +387795,40 @@ function recordTerminalWhenReached(dependencies, runId, promptName) {
386488
387795
  }
386489
387796
  });
386490
387797
  }
387798
+ function recordAbandonedRunWhenFound(dependencies, currentRunId) {
387799
+ let abandoned;
387800
+ try {
387801
+ abandoned = readAbandonedRun(
387802
+ { cwd: dependencies.cwd, store: dependencies.store },
387803
+ currentRunId
387804
+ );
387805
+ } catch {
387806
+ return;
387807
+ }
387808
+ if (abandoned === void 0)
387809
+ return;
387810
+ recordBestEffort(dependencies, {
387811
+ event: "cli.onboarding.run_abandoned",
387812
+ properties: {
387813
+ command: "onboard",
387814
+ ...onboardingIntentProperties(dependencies),
387815
+ // The run that is reporting, the way every other event binds. The run
387816
+ // being reported cannot emit anything: it is over, and reporting it is
387817
+ // the whole point. It rides as its own property instead.
387818
+ onboarding_run_id: currentRunId,
387819
+ cli_version: dependencies.cliVersion,
387820
+ abandoned_run_id: abandoned.runId,
387821
+ abandoned_at_prompt: abandoned.lastPrompt,
387822
+ abandoned_after_steps: abandoned.steps
387823
+ }
387824
+ });
387825
+ }
387826
+ function markRunEndedBestEffort(dependencies, runId) {
387827
+ try {
387828
+ markRunEnded({ cwd: dependencies.cwd, store: dependencies.store }, runId);
387829
+ } catch {
387830
+ }
387831
+ }
386491
387832
  function joinChanges(changes) {
386492
387833
  return [...new Set(changes)].sort().join(",");
386493
387834
  }
@@ -386615,42 +387956,15 @@ function completionReport(input) {
386615
387956
  }
386616
387957
  return input.blocker === void 0 ? "CopilotKit onboarding marked complete.\n" : blockedAfterProof(input.blocker);
386617
387958
  }
386618
- async function reportFeedback(dependencies, runId) {
386619
- const input = await readFeedbackInput(dependencies.stdin);
386620
- if (!input.ok)
386621
- return printFeedbackRefusal(dependencies, runId, input.refusal);
386622
- const reviewed = reviewFeedbackReport(input.text);
386623
- if (!reviewed.ok)
386624
- return printFeedbackRefusal(dependencies, runId, reviewed.refusal);
386625
- const feedbackText = reviewed.text;
386626
- let sent = false;
386627
- try {
386628
- sent = await dependencies.submitFeedbackEvent({
386629
- event: "cli.onboarding.feedback_submitted",
386630
- properties: {
386631
- command: "onboard",
386632
- ...onboardingIntentProperties(dependencies),
386633
- onboarding_run_id: runId,
386634
- cli_version: dependencies.cliVersion,
386635
- feedback_text: feedbackText
386636
- }
386637
- });
386638
- } catch {
386639
- sent = false;
387959
+ function describeSubmission(subject, submission) {
387960
+ switch (submission.status) {
387961
+ case "sent":
387962
+ return "Friction reported.";
387963
+ case "declined":
387964
+ return `${subject} was not sent because telemetry is off.`;
387965
+ default:
387966
+ return `${subject} was not sent because the telemetry send failed: ${submission.detail}`;
386640
387967
  }
386641
- dependencies.stdout.write(
386642
- `${sent ? "Feedback sent." : "Feedback was not sent because telemetry is disabled or unavailable."}
386643
- report: ${feedbackText}
386644
- `
386645
- );
386646
- }
386647
- function printFeedbackRefusal(dependencies, runId, refusal) {
386648
- recordReportRefused(dependencies, runId, "feedback", refusal.code);
386649
- dependencies.stdout.write(
386650
- `Feedback refused, and nothing was sent.
386651
- ${refusal.code}: ${refusal.message}
386652
- `
386653
- );
386654
387968
  }
386655
387969
  async function reportFriction(dependencies, runId, args) {
386656
387970
  const parsed = parseFrictionArguments(args);
@@ -386663,14 +387977,15 @@ async function reportFriction(dependencies, runId, args) {
386663
387977
  category: parsed.category,
386664
387978
  costSeconds: parsed.costSeconds,
386665
387979
  docsPath: parsed.docsPath,
387980
+ phase: parsed.phase,
386666
387981
  text: input.text
386667
387982
  });
386668
387983
  if (!reviewed.ok)
386669
387984
  return printFrictionRefusal(dependencies, runId, reviewed.refusal);
386670
387985
  const report = reviewed.report;
386671
- let sent = false;
387986
+ let submission;
386672
387987
  try {
386673
- sent = await dependencies.submitFeedbackEvent({
387988
+ submission = await dependencies.submitFeedbackEvent({
386674
387989
  event: "cli.onboarding.friction_reported",
386675
387990
  properties: {
386676
387991
  command: "onboard",
@@ -386678,17 +387993,20 @@ async function reportFriction(dependencies, runId, args) {
386678
387993
  onboarding_run_id: runId,
386679
387994
  cli_version: dependencies.cliVersion,
386680
387995
  friction_category: report.category,
386681
- cost_seconds_estimated: report.costSecondsEstimated,
387996
+ friction_phase: report.phase,
387997
+ // Spread so a stop report that named no cost leaves the key off rather
387998
+ // than sending an undefined the sink stores as a value.
387999
+ ...report.costSecondsEstimated === void 0 ? {} : { cost_seconds_estimated: report.costSecondsEstimated },
386682
388000
  // Spread so a report about no particular page leaves the key off
386683
388001
  // rather than joining to an empty one.
386684
388002
  ...report.docsPath === void 0 ? {} : { friction_docs_path: report.docsPath },
386685
388003
  friction_text: report.text
386686
388004
  }
386687
388005
  });
386688
- } catch {
386689
- sent = false;
388006
+ } catch (error98) {
388007
+ submission = { status: "failed", detail: describeSubmissionError(error98) };
386690
388008
  }
386691
- printFrictionReport(dependencies, report, sent);
388009
+ printFrictionReport(dependencies, report, submission);
386692
388010
  }
386693
388011
  function parseFrictionArguments(args) {
386694
388012
  try {
@@ -386698,7 +388016,8 @@ function parseFrictionArguments(args) {
386698
388016
  options: {
386699
388017
  category: { type: "string" },
386700
388018
  "cost-seconds": { type: "string" },
386701
- "docs-path": { type: "string" }
388019
+ "docs-path": { type: "string" },
388020
+ phase: { type: "string" }
386702
388021
  },
386703
388022
  strict: true
386704
388023
  });
@@ -386706,14 +388025,15 @@ function parseFrictionArguments(args) {
386706
388025
  ok: true,
386707
388026
  category: parsed.values.category,
386708
388027
  costSeconds: parsed.values["cost-seconds"],
386709
- docsPath: parsed.values["docs-path"]
388028
+ docsPath: parsed.values["docs-path"],
388029
+ phase: parsed.values.phase
386710
388030
  };
386711
388031
  } catch {
386712
388032
  return {
386713
388033
  ok: false,
386714
388034
  refusal: {
386715
388035
  code: "FRICTION_ARGUMENTS_INVALID",
386716
- message: `Usage: copilotkit onboard friction --category <${FRICTION_CATEGORIES.join("|")}> --cost-seconds <seconds> [--docs-path <page path or URL>]`
388036
+ message: `Usage: copilotkit onboard friction --category <${FRICTION_CATEGORIES.join("|")}> --cost-seconds <seconds> [--phase <${FRICTION_PHASES.join("|")}>] [--docs-path <page path or URL>]`
386717
388037
  }
386718
388038
  };
386719
388039
  }
@@ -386726,12 +388046,13 @@ ${refusal.code}: ${refusal.message}
386726
388046
  `
386727
388047
  );
386728
388048
  }
386729
- function printFrictionReport(dependencies, report, sent) {
388049
+ function printFrictionReport(dependencies, report, submission) {
386730
388050
  dependencies.stdout.write(
386731
- `${sent ? "Friction reported." : "Friction was not sent because telemetry is disabled or unavailable."}
388051
+ `${describeSubmission("Friction", submission)}
386732
388052
  category: ${report.category}
386733
- cost_seconds_estimated: ${report.costSecondsEstimated}
386734
- ` + (report.docsPath === void 0 ? "" : `docs_path: ${report.docsPath}
388053
+ phase: ${report.phase}
388054
+ ` + (report.costSecondsEstimated === void 0 ? "" : `cost_seconds_estimated: ${report.costSecondsEstimated}
388055
+ `) + (report.docsPath === void 0 ? "" : `docs_path: ${report.docsPath}
386735
388056
  `) + `report: ${report.text}
386736
388057
  `
386737
388058
  );
@@ -386896,6 +388217,37 @@ function readRouteBestEffort(dependencies) {
386896
388217
  return [];
386897
388218
  }
386898
388219
  }
388220
+ function recordProofBestEffort(dependencies, runId, step, proof) {
388221
+ try {
388222
+ recordProofOutcome(
388223
+ { cwd: dependencies.cwd, store: dependencies.store },
388224
+ runId,
388225
+ step,
388226
+ proof
388227
+ );
388228
+ } catch {
388229
+ }
388230
+ }
388231
+ function recordCodingAgentBestEffort(dependencies, runId, codingAgent) {
388232
+ try {
388233
+ recordCodingAgent(
388234
+ { cwd: dependencies.cwd, store: dependencies.store },
388235
+ runId,
388236
+ codingAgent
388237
+ );
388238
+ } catch {
388239
+ }
388240
+ }
388241
+ function readBaselineProofBestEffort(dependencies) {
388242
+ try {
388243
+ return readProofOutcome(
388244
+ { cwd: dependencies.cwd, store: dependencies.store },
388245
+ "oss-baseline"
388246
+ );
388247
+ } catch {
388248
+ return void 0;
388249
+ }
388250
+ }
386899
388251
  function recordRouteBestEffort(dependencies, runId, promptName) {
386900
388252
  try {
386901
388253
  recordServedPrompt(
@@ -386919,7 +388271,7 @@ function recordBestEffort(dependencies, event) {
386919
388271
  } catch {
386920
388272
  }
386921
388273
  }
386922
- var ONBOARD_SUBCOMMANDS, RUN_NOT_BOUND, REBASELINE_USAGE, ACCEPT_USAGE, AUTHORIZE_USAGE, EXCLUSIVE_MODE_USAGE, NOTHING_PROVED, NOTHING_AUTHORIZED, NOTHING_ACCEPTED, VISUAL_CHECK_OUTCOMES, DEVICE_CHECK_OUTCOMES, BLOCKER_CAUSES, BLOCKER_USAGE, SURFACE_CHECK_USAGE, FRONTEND_URL_USAGE, PROOF_STEPS, PROOF_OUTCOMES, BASELINE_PREDICATE_COUNT, PROOF_USAGE, BLOCKER_REPORTS;
388274
+ var ONBOARD_SUBCOMMANDS, READ_RUN_NOT_BOUND, IDENTIFY_RUN_NOT_BOUND, STEP_RUN_NOT_BOUND, REBASELINE_USAGE, ACCEPT_USAGE, AUTHORIZE_USAGE, ACCEPT_CREDENTIAL_USAGE, PRIOR_CHANGE_USAGE, UNPLANNED_USAGE, EXCLUSIVE_MODE_USAGE, NOTHING_PROVED, NOTHING_AUTHORIZED, NOTHING_ACCEPTED, VISUAL_CHECK_OUTCOMES, DEVICE_CHECK_OUTCOMES, BLOCKER_CAUSES, BLOCKER_USAGE, SURFACE_CHECK_USAGE, FRONTEND_URL_USAGE, PROOF_STEPS, PROOF_OUTCOMES, BASELINE_PREDICATE_COUNT, PROOF_USAGE, IDENTIFY_USAGE, BLOCKER_REPORTS;
386923
388275
  var init_onboard = __esm({
386924
388276
  async "apps/cli/src/commands/onboard.ts"() {
386925
388277
  "use strict";
@@ -386927,7 +388279,6 @@ var init_onboard = __esm({
386927
388279
  init_config_service();
386928
388280
  init_onboarding_graph();
386929
388281
  init_onboarding_friction();
386930
- init_onboarding_feedback();
386931
388282
  init_onboarding_checkpoint();
386932
388283
  init_onboarding_state();
386933
388284
  init_onboarding_protected_paths();
@@ -386940,6 +388291,7 @@ var init_onboard = __esm({
386940
388291
  init_resolved_dependencies();
386941
388292
  ONBOARD_SUBCOMMANDS = [
386942
388293
  "start",
388294
+ "identify",
386943
388295
  "read",
386944
388296
  "route",
386945
388297
  "classify",
@@ -386948,14 +388300,24 @@ var init_onboard = __esm({
386948
388300
  "checkpoint",
386949
388301
  "proof",
386950
388302
  "complete",
386951
- "feedback",
386952
388303
  "friction"
386953
388304
  ];
386954
- RUN_NOT_BOUND = "No onboarding run is bound to this directory.\n\n`onboard read` reports every node it serves against the run `onboard start`\ndeclared. Minting one here would record this directory as a second run of a\nsession that already has one, and leave the first looking like a stall.\n\nIf this session has not started, run `copilotkit onboard start` here.\nIf it has, run `copilotkit onboard start --run <id>` here with the id the\nfirst start printed, or read from the directory you started in.\n\nThis is a missing start, not a failed step: nothing has been proved\nunsupported.";
388305
+ READ_RUN_NOT_BOUND = runNotBound(
388306
+ "`onboard read` reports every node it serves against the run `onboard start`\ndeclared. Minting one here would record this directory as a second run of a\nsession that already has one, and leave the first looking like a stall."
388307
+ );
388308
+ IDENTIFY_RUN_NOT_BOUND = runNotBound(
388309
+ "`onboard identify` records the coding agent against the run `onboard start`\ndeclared. Minting one here would file this identify, and the login that\nfollows it, under a run no other step in the session ever reports against."
388310
+ );
388311
+ STEP_RUN_NOT_BOUND = runNotBound(
388312
+ "This step reports against the run `onboard start` declared. Minting one here\nwould bind a second run to this directory alone, and take the route, the\nprotected baseline and the proof record with it."
388313
+ );
386955
388314
  REBASELINE_USAGE = "Usage: copilotkit onboard protect --rebaseline --path <path> [--path <path>]\nName the paths to re-capture. A re-baseline with no path would be a request to\nre-read the whole baseline, which is the one thing this command must never do.";
386956
388315
  ACCEPT_USAGE = "Usage: copilotkit onboard protect --accept-external --path <path> [--path <path>]\nName the paths to accept. An acceptance with no path would accept every change\nthis run has not seen, which is the one thing this command must never do.";
386957
388316
  AUTHORIZE_USAGE = "Usage: copilotkit onboard protect --authorize --path <path> [--path <path>]\n --reason <why this run must change it>\nName the paths and say why. Consent with no path would license every file the\ndeveloper owns, and consent with no reason leaves the closing report unable to\ntell them what their file was changed for.";
386958
- EXCLUSIVE_MODE_USAGE = "Use one of --rebaseline, --accept-external or --authorize, not more than one.\n--rebaseline records a file this run wrote. --accept-external records a change\nthat came from outside the run. --authorize records the developer allowing this\nrun to change a file of theirs. One path cannot be more than one of them.";
388317
+ ACCEPT_CREDENTIAL_USAGE = "Usage: copilotkit onboard protect --accept-credential --path <path> [--path <path>]\nName the env files whose new credential you accept. This route checks that no\ncredential the baseline recorded was lost, so it needs the paths to check.";
388318
+ PRIOR_CHANGE_USAGE = "--with-prior-change belongs to --authorize and to nothing else.\nIt widens one authorization to cover a change the developer already made to\nthe path. No other mode records consent, so nothing there can carry it.";
388319
+ UNPLANNED_USAGE = "--unplanned belongs to --authorize and to nothing else.\nIt records that the developer gave this consent mid-run, after the approved\nplan was settled. No other mode records consent, so nothing there can carry it.";
388320
+ EXCLUSIVE_MODE_USAGE = "Use one of --rebaseline, --accept-external, --accept-credential or --authorize,\nnot more than one. --rebaseline records a file this run wrote.\n--accept-external records a change that came from outside the run.\n--accept-credential records a credential the developer placed in an env file\nbecause the run asked. --authorize records the developer allowing this run to\nchange a file of theirs. One path cannot be more than one of them.";
386959
388321
  NOTHING_PROVED = "This is a missing baseline, not a preservation failure: no protected path has\nbeen proved changed, and none has been proved unchanged either.\n";
386960
388322
  NOTHING_AUTHORIZED = "Nothing was recorded. No path in this call was authorized, including any path\nnamed before the one above.\n";
386961
388323
  NOTHING_ACCEPTED = "Nothing was recorded. No path in this call was accepted, including any path\nnamed before the one above.\n";
@@ -386982,8 +388344,8 @@ blocked reads the unsupported terminal instead, and reports a path that works
386982
388344
  as one this release does not carry.`;
386983
388345
  SURFACE_CHECK_USAGE = "Usage: copilotkit onboard complete --visual-check <performed|skipped-no-browser-tool|failed>\n or: copilotkit onboard complete --device-check <performed|skipped-no-device|failed>\nPass exactly one. A web journey is proven in a browser and a mobile one on a device;\nwhich flag you pass is how this run states which surface it proved.";
386984
388346
  FRONTEND_URL_USAGE = "Usage: copilotkit onboard complete <surface-check> --frontend-url <absolute url>\nPass the URL a browser actually opened, for example http://localhost:3000.\nOnly the kind of host is recorded -- loopback hostname, loopback IP literal,\nother IP literal, other name -- never the host itself.";
386985
- PROOF_STEPS = ["oss-baseline", "round-trip"];
386986
- PROOF_OUTCOMES = ["passed", "failed", "skipped"];
388347
+ PROOF_STEPS = ONBOARDING_PROOF_STEPS;
388348
+ PROOF_OUTCOMES = ONBOARDING_PROOF_OUTCOMES;
386987
388349
  BASELINE_PREDICATE_COUNT = 6;
386988
388350
  PROOF_USAGE = `Usage: copilotkit onboard proof --step <${PROOF_STEPS.join("|")}> --outcome <${PROOF_OUTCOMES.join("|")}>
386989
388351
  [--predicate <1-${BASELINE_PREDICATE_COUNT}>]
@@ -386994,6 +388356,7 @@ trip.
386994
388356
  Pass --predicate with a failed or skipped oss-baseline to name which of the
386995
388357
  six predicates it was. A passed gate has no predicate to name, and the
386996
388358
  round trip has no numbered predicates at all.`;
388359
+ IDENTIFY_USAGE = "Usage: copilotkit onboard identify --coding-agent <slug>";
386997
388360
  BLOCKER_REPORTS = {
386998
388361
  inspector: {
386999
388362
  cause: "the debugging surface for this frontend did not open.",
@@ -389970,6 +391333,7 @@ init_feature_flags();
389970
391333
  init_exit_code();
389971
391334
  init_unknown_input();
389972
391335
  await init_telemetry();
391336
+ init_event_properties();
389973
391337
  import { parseArgs as parseArgs4 } from "node:util";
389974
391338
  import { realpathSync as realpathSync3 } from "node:fs";
389975
391339
  import path44 from "node:path";
@@ -390204,8 +391568,8 @@ General:
390204
391568
  --verbose Mirror CLI diagnostics to stderr
390205
391569
 
390206
391570
  Privacy:
390207
- CopilotKit collects CLI usage data to improve the product. Onboarding feedback
390208
- may send up to 2,048 UTF-8 bytes through this telemetry path. To opt out, set
391571
+ CopilotKit collects CLI usage data to improve the product. An onboarding
391572
+ friction report sends up to 2,048 UTF-8 bytes through this telemetry path. To opt out, set
390209
391573
  DO_NOT_TRACK=1 or COPILOTKIT_TELEMETRY_DISABLED=1 in your environment.
390210
391574
  `,
390211
391575
  login: `Usage: copilotkit login [--json]
@@ -390217,19 +391581,22 @@ Options:
390217
391581
  -h, --help Show help for login
390218
391582
  `,
390219
391583
  onboard: `Usage: copilotkit onboard start [--intent <slug>] [--run <id>] [--coding-agent <slug>]
391584
+ copilotkit onboard identify --coding-agent <slug>
390220
391585
  copilotkit onboard read <prompt-name>
390221
391586
  copilotkit onboard route
390222
391587
  copilotkit onboard classify --starting-state <state> --agent-framework <framework> --frontend <frontend>
390223
391588
  copilotkit onboard protect [--path <path>] [--rebaseline --path <path>]
390224
391589
  [--accept-external --path <path>]
390225
- [--authorize --path <path> --reason <why>]
391590
+ [--accept-credential --path <path>]
391591
+ [--authorize --path <path> --reason <why>
391592
+ [--with-prior-change] [--unplanned]]
390226
391593
  copilotkit onboard audit
390227
391594
  copilotkit onboard checkpoint --phase <slug> [--attempt <n>]
390228
391595
  copilotkit onboard proof --step <oss-baseline|round-trip> --outcome <passed|failed|skipped>
390229
391596
  [--predicate <1-6>]
390230
391597
  copilotkit onboard complete
390231
- copilotkit onboard feedback
390232
- copilotkit onboard friction --category <slug> --cost-seconds <seconds>
391598
+ copilotkit onboard friction --category <slug> [--cost-seconds <seconds>]
391599
+ [--phase <repair|stop|completion>]
390233
391600
 
390234
391601
  Guide a coding agent through the Markdown graph bundled with this exact CLI.
390235
391602
 
@@ -390244,12 +391611,12 @@ Subcommands:
390244
391611
  checkpoint Report how far a long step has got
390245
391612
  proof Record what one proof gate returned
390246
391613
  complete Mark a proven onboarding run complete
390247
- feedback Read one non-empty message from standard input
390248
391614
  friction Report one papercut that slowed a run down
390249
391615
 
390250
- Feedback must be no larger than 2,048 UTF-8 bytes. Do not include secrets,
390251
- source code, logs, or command output. The global telemetry setting applies.
390252
- When telemetry is disabled or unavailable, feedback exits zero and is not sent.
391616
+ A friction report must be no larger than 2,048 UTF-8 bytes. Do not include
391617
+ secrets, source code, logs, or command output. The global telemetry setting
391618
+ applies. When telemetry is off, or the send fails, the command exits zero and
391619
+ says which.
390253
391620
 
390254
391621
  Protect captures the paths this run must not change -- the developer's work in
390255
391622
  progress -- as path and digest, derived from the working tree rather than taken
@@ -390269,6 +391636,13 @@ report. Accept a path only when the run can show it did not write that path
390269
391636
  itself, and never one of the two files above: those exist to be rewritten by the
390270
391637
  run, so accepting one would record the run's own damage as the baseline.
390271
391638
 
391639
+ An env file is the exception, because the run asks the developer to write their
391640
+ model credential into it. Accept that with protect --accept-credential --path
391641
+ <path>. It takes nobody's word: it compares the variable names the baseline
391642
+ recorded with the names the file holds now, and refuses when a recorded
391643
+ credential is gone or empty. So the developer's own paste passes, and a step
391644
+ that rewrites .env and drops the project key still fails.
391645
+
390272
391646
  Adding a feature to an app the developer already built needs the opposite
390273
391647
  record. The option lives in a file they wrote, so the run has to change it. The
390274
391648
  plan asks for that path, approving the plan grants it, and the grant is recorded
@@ -390276,12 +391650,23 @@ with protect --authorize --path <path> --reason <why> before any edit. The audit
390276
391650
  then reports the path instead of failing on it, and every later audit and the
390277
391651
  closing report name it with its reason. An authorization is refused once the
390278
391652
  path has moved, because consent taken afterwards cannot be told apart from a run
390279
- clearing a failure it caused.
391653
+ clearing a failure it caused. Add --with-prior-change for the one case that rule
391654
+ had no answer for: the developer changed the file after the capture, and the run
391655
+ must change the same file. The earlier change is recorded as drift beside the
391656
+ consent, so both authors stay visible in the closing report.
391657
+
391658
+ Consent belongs to the plan the developer approved. Once the run reports that
391659
+ plan with checkpoint --phase plan-written, --authorize is refused for every path
391660
+ the plan did not name: the developer approved the plan, not whatever the run
391661
+ reaches later. Where the run must change such a path, it asks the developer and
391662
+ records their answer with --unplanned, which marks the consent as taken outside
391663
+ the plan wherever it is printed. The flag is refused before the plan is
391664
+ reported, so it can never stand in for the plan's own approval.
390280
391665
 
390281
391666
  Checkpoint reports progress from inside a step, where the graph would
390282
391667
  otherwise say nothing between one prompt and the next. --phase takes one of:
390283
- research-returned, starter-cloned, plan-written, build-validated,
390284
- journey-attempted, repair-attempted. Pass --attempt <1-9>
391668
+ research-returned, starter-cloned, plan-written, container-surveyed,
391669
+ container-settled, build-validated, journey-attempted, repair-attempted. Pass --attempt <1-9>
390285
391670
  where the step loops, so a repair cycle can be counted.
390286
391671
  A refused checkpoint exits zero and prints the closed set. It is called from
390287
391672
  the middle of the longest step of a run, and a non-zero exit there reads as a
@@ -390310,6 +391695,10 @@ report from standard input, at most 2,000 characters and four lines of prose.
390310
391695
  --category takes one of: docs-missing, docs-wrong, docs-sequential, cli-gap,
390311
391696
  sdk-gap, environment, port-collision, credential, validation-loop, other.
390312
391697
  --cost-seconds takes the reporting agent's own estimate of the seconds lost.
391698
+ --phase takes one of: repair, stop, completion, and defaults to completion. A
391699
+ repair report is filed once a repair cycle has resolved. A stop report is the
391700
+ one that can leave --cost-seconds off, because a run that stopped cannot
391701
+ separate one papercut's cost from the cost of the whole run.
390313
391702
 
390314
391703
  A report containing a secret shape, a fenced code block, or pasted output is
390315
391704
  refused before anything is sent, and the reason is printed. Both commands print
@@ -390317,19 +391706,28 @@ what they sent. Every refusal exits zero and leaves onboarding unaffected.
390317
391706
  `,
390318
391707
  verify: `Usage: copilotkit verify [--json] [--runtime-url <url>] [--round-trip]
390319
391708
  [--expect-runtime <mode>] [--frontend-url <url>]
391709
+ [--expect-learning-container <id>]
390320
391710
 
390321
391711
  Check that this project's CopilotKit wiring works, and report what it found.
390322
391712
 
390323
391713
  Checks that a hosted project is selected, that a project API key is present and
390324
391714
  authenticates against Intelligence, that the CopilotKit runtime responds, that
390325
- it declares at least one agent, that it accepts the origin a browser opens, and
390326
- that the installed CopilotKit packages match the version it reports.
390327
- Reports the runtime version, the agent framework in use, whether transcription
390328
- is wired, the realtime gateway wiring, and the license state.
391715
+ it declares at least one agent, that it holds an Intelligence client and calls
391716
+ the same deployment the key was proven against, that it accepts the origin a
391717
+ browser opens, and that the installed CopilotKit packages match the version it
391718
+ reports. Reports the runtime version, the agent framework in use, whether
391719
+ transcription is wired, the realtime gateway wiring, and the license state.
390329
391720
 
390330
391721
  Every check reports PASS, FAIL, or UNKNOWN. UNKNOWN means the check could not
390331
391722
  run \u2014 it never means the check passed. Exits non-zero unless every check passed.
390332
391723
 
391724
+ The runtime's /info route reports that an Intelligence client was constructed.
391725
+ It does not report that the client reached anything, so no check here reads it
391726
+ as a successful call. Set INTELLIGENCE_API_URL in the env file the app loads:
391727
+ without it the runtime falls back to its own built-in host while this command
391728
+ proves the key against the host baked into this binary, and a valid key then
391729
+ gets 401 on every request.
391730
+
390333
391731
  The report names the runtime URL it probed and where that URL came from. Nothing
390334
391732
  answering at a URL the project named is a FAIL; nothing answering at the assumed
390335
391733
  default is UNKNOWN, because an app running on a port this command never learned
@@ -390340,6 +391738,13 @@ the answer back from the thread, which is the only check here that proves the
390340
391738
  agent runs rather than that it is configured. That costs a model call and
390341
391739
  records a thread, so it is opt-in.
390342
391740
 
391741
+ A runtime mounted mode: "single-route" runs the request through its agent/run
391742
+ envelope, and the answer is read from the platform because that mount carries
391743
+ its thread routes inside the envelope rather than as REST paths this command
391744
+ can call. The report names which read answered: through the app, the answer
391745
+ belongs to the caller the app identified; from the platform, the run and its
391746
+ answer are proved and the end user they belonged to is not.
391747
+
390343
391748
  With --expect-runtime oss, hosted project and credential checks do not apply.
390344
391749
  The command exits zero only when valid /info data declares the named agent,
390345
391750
  reports no Intelligence entitlement, and --round-trip --agent <id> passes.
@@ -390358,6 +391763,12 @@ Options:
390358
391763
  to send a real CORS preflight when that origin differs
390359
391764
  from the runtime's
390360
391765
  --expect-runtime <mode> Require intelligence (default) or oss runtime mode
391766
+ --expect-learning-container <id>
391767
+ Require the round trip's thread to carry this
391768
+ Learning Container. Needs --round-trip --agent <id>.
391769
+ Read from the platform, so it answers for a runtime
391770
+ mounted mode: "single-route" too. A plan entitlement
391771
+ or an /info flag is not evidence.
390361
391772
  --round-trip Also run the agent and read its answer back
390362
391773
  --agent <id> Which declared agent to run, when there are several
390363
391774
  --timeout <seconds> How long to wait for the answer (default: 90)
@@ -390653,6 +392064,7 @@ Actions:
390653
392064
  learning containers list List Learning Containers (alias: ls)
390654
392065
  learning containers get <id> Show one Learning Container (alias: show)
390655
392066
  learning containers create Create a Learning Container
392067
+ learning containers select Pick one, or create one, in a terminal
390656
392068
  learning containers update <id> Change a name or prompt context
390657
392069
  learning containers delete <id> Delete an unused Learning Container
390658
392070
 
@@ -391245,7 +392657,7 @@ async function applyGlobalArgs(parsed) {
391245
392657
  setCliLogsVerbose2(true);
391246
392658
  }
391247
392659
  }
391248
- async function runWhoami() {
392660
+ async function runWhoami(ctx) {
391249
392661
  const {
391250
392662
  clearAuthOnTerminalSessionInvalidation: clearAuthOnTerminalSessionInvalidation2,
391251
392663
  TERMINAL_SESSION_INVALID_MESSAGE: TERMINAL_SESSION_INVALID_MESSAGE2,
@@ -391265,17 +392677,20 @@ async function runWhoami() {
391265
392677
  if (clearAuthOnTerminalSessionInvalidation2(error98)) {
391266
392678
  process.stdout.write(`${TERMINAL_SESSION_INVALID_MESSAGE2}
391267
392679
  `);
392680
+ ctx.reportFailure({ errorCode: "auth" });
391268
392681
  return;
391269
392682
  }
391270
392683
  if (error98 instanceof ApiClientError2 && error98.status > 0) {
391271
392684
  process.stdout.write(`${error98.message}
391272
392685
  `);
392686
+ ctx.reportFailure({ errorCode: classifyError(error98) });
391273
392687
  return;
391274
392688
  }
391275
392689
  throw error98;
391276
392690
  }
391277
392691
  if (!session) {
391278
392692
  process.stdout.write("Session expired. Please run: copilotkit login\n");
392693
+ ctx.reportFailure({ errorCode: "auth" });
391279
392694
  return;
391280
392695
  }
391281
392696
  process.stdout.write(`Email: ${session.user.email}
@@ -391736,6 +393151,15 @@ function parseLearningContainersCommandArgs(argv) {
391736
393151
  ...parsed.values.cursor === void 0 ? {} : { cursor: parsed.values.cursor }
391737
393152
  };
391738
393153
  }
393154
+ if (subcommand === "select") {
393155
+ const parsed = parseArgs4({
393156
+ args,
393157
+ options: { json: { type: "boolean" } },
393158
+ strict: true,
393159
+ allowPositionals: false
393160
+ });
393161
+ return { action: "select", json: parsed.values.json === true };
393162
+ }
391739
393163
  if (subcommand === "get") {
391740
393164
  const parsed = parseArgs4({
391741
393165
  args,
@@ -391974,7 +393398,7 @@ function learningParseFailureSubcommand(argv) {
391974
393398
  const resource = argv[0];
391975
393399
  const action = argv[1];
391976
393400
  if (resource === "containers") {
391977
- return action === "list" || action === "get" || action === "show" || action === "create" || action === "update" || action === "delete" ? `containers.${action === "show" ? "get" : action}` : "containers.invalid";
393401
+ return action === "list" || action === "get" || action === "show" || action === "create" || action === "select" || action === "update" || action === "delete" ? `containers.${action === "show" ? "get" : action}` : "containers.invalid";
391978
393402
  }
391979
393403
  if (resource === "insights" || resource === "skills") {
391980
393404
  return action === "list" || action === "ls" ? `${resource}.list` : `${resource}.invalid`;
@@ -392078,10 +393502,10 @@ ${helpTextForTopic("learning")}`
392078
393502
  createLearningContainersCommandDependencies: createLearningContainersCommandDependencies2,
392079
393503
  runLearningContainersCommand: runLearningContainersCommand2
392080
393504
  } = await init_learning_containers().then(() => learning_containers_exports);
392081
- await runLearningContainersCommand2(
392082
- command2,
392083
- createLearningContainersCommandDependencies2()
392084
- );
393505
+ await runLearningContainersCommand2(command2, {
393506
+ ...createLearningContainersCommandDependencies2(),
393507
+ telemetry: { setProperties: telemetryContext.setProperties }
393508
+ });
392085
393509
  }
392086
393510
  );
392087
393511
  }
@@ -392173,6 +393597,7 @@ async function runVerifyCommand(argv) {
392173
393597
  options: {
392174
393598
  agent: { type: "string" },
392175
393599
  "expect-runtime": { type: "string" },
393600
+ "expect-learning-container": { type: "string" },
392176
393601
  "frontend-url": { type: "string" },
392177
393602
  header: { multiple: true, type: "string" },
392178
393603
  json: { type: "boolean" },
@@ -392226,17 +393651,44 @@ async function runVerifyCommand(argv) {
392226
393651
  await exitWithFlush(1);
392227
393652
  }
392228
393653
  const agent = parsed.values["agent"];
393654
+ const expectLearningContainer = parsed.values["expect-learning-container"];
393655
+ if (expectLearningContainer !== void 0 && !/^[a-z0-9]+(?:-[a-z0-9]+)*$/u.test(expectLearningContainer)) {
393656
+ process.stderr.write(
393657
+ "Error: --expect-learning-container expects 1-64 lowercase letters, numbers, and single hyphens.\n"
393658
+ );
393659
+ await exitWithFlush(1);
393660
+ }
392229
393661
  const { runVerify: runVerify2 } = await Promise.resolve().then(() => (init_verify(), verify_exports));
392230
- await runVerify2({
392231
- json: parsed.values["json"] === true,
392232
- ...agent === void 0 ? {} : { agent },
392233
- ...expectedRuntime === void 0 ? {} : { expectRuntime: expectedRuntime },
392234
- ...headers === void 0 || Object.keys(headers).length === 0 ? {} : { headers },
392235
- ...frontendUrl === void 0 ? {} : { frontendUrl },
392236
- ...parsed.values["round-trip"] === true ? { roundTrip: true } : {},
392237
- ...runtimeUrl === void 0 ? {} : { runtimeUrl },
392238
- ...timeoutSeconds === void 0 ? {} : { timeoutMs: Number(timeoutSeconds) * 1e3 }
392239
- });
393662
+ await runVerify2(
393663
+ {
393664
+ json: parsed.values["json"] === true,
393665
+ ...agent === void 0 ? {} : { agent },
393666
+ ...expectLearningContainer === void 0 ? {} : { expectLearningContainer },
393667
+ ...expectedRuntime === void 0 ? {} : { expectRuntime: expectedRuntime },
393668
+ ...headers === void 0 || Object.keys(headers).length === 0 ? {} : { headers },
393669
+ ...frontendUrl === void 0 ? {} : { frontendUrl },
393670
+ ...parsed.values["round-trip"] === true ? { roundTrip: true } : {},
393671
+ ...runtimeUrl === void 0 ? {} : { runtimeUrl },
393672
+ ...timeoutSeconds === void 0 ? {} : { timeoutMs: Number(timeoutSeconds) * 1e3 }
393673
+ },
393674
+ {
393675
+ // A point event rather than a property on the command's own lifecycle
393676
+ // event. `verify` is dispatched as `auto`, which owns the bookend and does
393677
+ // not hand the runner its telemetry context, and the outcome is worth its
393678
+ // own row: the lifecycle event answers "did the command run", this answers
393679
+ // "did Learning prove out for this project".
393680
+ recordLearningContainerCheck: ({ outcome }) => {
393681
+ recordTelemetryEvent({
393682
+ event: "cli.verify.learning_container_checked",
393683
+ properties: {
393684
+ command: "verify",
393685
+ learning_check_outcome: outcome,
393686
+ ...currentOnboardingRunProperties()
393687
+ }
393688
+ });
393689
+ }
393690
+ }
393691
+ );
392240
393692
  }
392241
393693
  async function runTypegenCommand(argv) {
392242
393694
  const parsed = parseArgs4({
@@ -392498,13 +393950,17 @@ async function runInitCommand(invokedAs, argv) {
392498
393950
  await runInit2(flags, callbacks);
392499
393951
  });
392500
393952
  }
393953
+ var UNWRAPPED_TELEMETRY_CONTEXT = {
393954
+ setProperties: () => void 0,
393955
+ reportFailure: () => void 0
393956
+ };
392501
393957
  var ONBOARD_SUBCOMMANDS2 = [
392502
393958
  "audit",
392503
393959
  "checkpoint",
392504
393960
  "classify",
392505
393961
  "complete",
392506
- "feedback",
392507
393962
  "friction",
393963
+ "identify",
392508
393964
  "proof",
392509
393965
  "protect",
392510
393966
  "read",
@@ -392567,8 +394023,8 @@ var COMMAND_TABLE = {
392567
394023
  whoami: {
392568
394024
  kind: "auto",
392569
394025
  command: "whoami",
392570
- run: async () => {
392571
- await runWhoami();
394026
+ run: async (_argv, _token, ctx) => {
394027
+ await runWhoami(ctx);
392572
394028
  }
392573
394029
  },
392574
394030
  docs: {
@@ -392731,13 +394187,13 @@ async function main(rawArgv = process.argv.slice(2)) {
392731
394187
  command: entry.command,
392732
394188
  ...subcommand === void 0 ? {} : { subcommand }
392733
394189
  },
392734
- async () => {
392735
- await entry.run(commandArgv, command2);
394190
+ async (ctx) => {
394191
+ await entry.run(commandArgv, command2, ctx);
392736
394192
  }
392737
394193
  );
392738
394194
  return;
392739
394195
  }
392740
- await entry.run(commandArgv, command2);
394196
+ await entry.run(commandArgv, command2, UNWRAPPED_TELEMETRY_CONTEXT);
392741
394197
  }
392742
394198
  function resolveRealPath(candidatePath) {
392743
394199
  const absolutePath = path44.resolve(candidatePath);