copilotkit 4.9.50 → 4.9.60

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 (67) hide show
  1. package/README.md +44 -4
  2. package/cli-build-info.json +7 -7
  3. package/index.js +1504 -210
  4. package/onboarding/index.json +1 -1
  5. package/onboarding/prompts/authenticate/start.md +41 -14
  6. package/onboarding/prompts/conversion/plan.md +3 -3
  7. package/onboarding/prompts/credentials/finalize-plan.md +54 -13
  8. package/onboarding/prompts/credentials/plan.md +20 -20
  9. package/onboarding/prompts/fallback/best-effort.md +6 -6
  10. package/onboarding/prompts/feature/a2ui/implement.md +3 -3
  11. package/onboarding/prompts/feature/a2ui/proof.md +3 -3
  12. package/onboarding/prompts/feature/a2ui/start.md +5 -5
  13. package/onboarding/prompts/feature/chat-suggestions/implement.md +3 -3
  14. package/onboarding/prompts/feature/chat-suggestions/proof.md +3 -3
  15. package/onboarding/prompts/feature/chat-suggestions/start.md +5 -5
  16. package/onboarding/prompts/feature/learning/implement.md +70 -8
  17. package/onboarding/prompts/feature/learning/proof.md +25 -7
  18. package/onboarding/prompts/feature/learning/start.md +11 -7
  19. package/onboarding/prompts/feature/open-generative-ui/implement.md +3 -3
  20. package/onboarding/prompts/feature/open-generative-ui/proof.md +3 -3
  21. package/onboarding/prompts/feature/open-generative-ui/start.md +5 -5
  22. package/onboarding/prompts/feature/realtime-sync/implement.md +4 -4
  23. package/onboarding/prompts/feature/realtime-sync/proof.md +3 -3
  24. package/onboarding/prompts/feature/realtime-sync/start.md +4 -4
  25. package/onboarding/prompts/feature/rich-threads/implement.md +5 -5
  26. package/onboarding/prompts/feature/rich-threads/proof.md +3 -3
  27. package/onboarding/prompts/feature/rich-threads/start.md +4 -4
  28. package/onboarding/prompts/feature/stop.md +4 -4
  29. package/onboarding/prompts/feature/voice/implement.md +3 -3
  30. package/onboarding/prompts/feature/voice/proof.md +3 -3
  31. package/onboarding/prompts/feature/voice/start.md +5 -5
  32. package/onboarding/prompts/framework/ag2.md +2 -2
  33. package/onboarding/prompts/framework/agno.md +2 -2
  34. package/onboarding/prompts/framework/built-in.md +2 -2
  35. package/onboarding/prompts/framework/claude-sdk-python.md +2 -2
  36. package/onboarding/prompts/framework/claude-sdk-typescript.md +2 -2
  37. package/onboarding/prompts/framework/crewai-flows.md +2 -2
  38. package/onboarding/prompts/framework/deep-agents.md +2 -2
  39. package/onboarding/prompts/framework/google-adk.md +2 -2
  40. package/onboarding/prompts/framework/langgraph-fastapi.md +2 -2
  41. package/onboarding/prompts/framework/langgraph-python.md +2 -2
  42. package/onboarding/prompts/framework/langgraph-typescript.md +2 -2
  43. package/onboarding/prompts/framework/llamaindex.md +2 -2
  44. package/onboarding/prompts/framework/mastra.md +2 -2
  45. package/onboarding/prompts/framework/ms-agent-dotnet.md +2 -2
  46. package/onboarding/prompts/framework/ms-agent-harness-dotnet.md +2 -2
  47. package/onboarding/prompts/framework/ms-agent-python.md +2 -2
  48. package/onboarding/prompts/framework/pydantic-ai.md +2 -2
  49. package/onboarding/prompts/framework/strands-python.md +2 -2
  50. package/onboarding/prompts/framework/strands-typescript.md +2 -2
  51. package/onboarding/prompts/frontend/angular.md +3 -3
  52. package/onboarding/prompts/frontend/nextjs.md +3 -3
  53. package/onboarding/prompts/frontend/plan.md +6 -6
  54. package/onboarding/prompts/frontend/react-native.md +2 -2
  55. package/onboarding/prompts/frontend/react-spa.md +2 -2
  56. package/onboarding/prompts/frontend/vue.md +2 -2
  57. package/onboarding/prompts/implementation/build-and-validate.md +58 -8
  58. package/onboarding/prompts/proof/complete.md +10 -10
  59. package/onboarding/prompts/proof/oss-baseline.md +16 -7
  60. package/onboarding/prompts/proof/round-trip.md +16 -9
  61. package/onboarding/prompts/starter/clone.md +5 -5
  62. package/onboarding/prompts/subagent/create-plan.md +1 -1
  63. package/onboarding/prompts/subagent/prove-oss-baseline.md +1 -1
  64. package/onboarding/prompts/subagent/prove-round-trip.md +13 -10
  65. package/onboarding/prompts/unsupported/no-validated-path.md +4 -4
  66. package/package.json +1 -1
  67. package/release/release-tool.js +1 -1
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.9.60" : "dev",
100
+ buildNumber: true ? "34616405214" : "dev",
101
+ commitSha: true ? "5f0f9a7cf15492544f1341f562fa5cd55387099c" : "dev",
102
102
  copilotKitCommit: getTemplateRef()
103
103
  };
104
104
  }
105
105
  function getTemplateRef() {
106
- return true ? "380ad1220a7bc78104baedc469c4d086c8910494" : "main";
106
+ return true ? "d1584b840f904674b470be5d2b16c4ccca99c4f4" : "main";
107
107
  }
108
108
  function getC15tBackendUrl() {
109
109
  return true ? "https://calm-hazelnut-joy-copilotkit.inth.app" : "";
@@ -28868,6 +28868,57 @@ function readOnboardingRoute(dependencies) {
28868
28868
  return [];
28869
28869
  return stored.route;
28870
28870
  }
28871
+ function readStoredProofs(store, key) {
28872
+ const stored = store.get(key);
28873
+ if (typeof stored !== "object" || stored === null)
28874
+ return void 0;
28875
+ if (typeof stored.runId !== "string")
28876
+ return void 0;
28877
+ return typeof stored.proofs === "object" && stored.proofs !== null ? stored : void 0;
28878
+ }
28879
+ function recordProofOutcome(dependencies, runId, step, proof) {
28880
+ const key = stateKey("proof", resolveAnchoredRoot(dependencies));
28881
+ const stored = readStoredProofs(dependencies.store, key);
28882
+ const previous = stored?.runId === runId ? stored.proofs : {};
28883
+ dependencies.store.set(key, {
28884
+ runId,
28885
+ proofs: { ...previous, [step]: proof }
28886
+ });
28887
+ }
28888
+ function readProofOutcome(dependencies, step) {
28889
+ const root2 = resolveAnchoredRoot(dependencies);
28890
+ const stored = readStoredProofs(dependencies.store, stateKey("proof", root2));
28891
+ if (stored === void 0)
28892
+ return void 0;
28893
+ const bound = readBoundRun(dependencies.store, root2);
28894
+ if (bound.state === "live" && bound.runId !== stored.runId)
28895
+ return void 0;
28896
+ return stored.proofs[step];
28897
+ }
28898
+ function readStoredCodingAgent(store, key) {
28899
+ const stored = store.get(key);
28900
+ if (typeof stored !== "object" || stored === null)
28901
+ return void 0;
28902
+ if (typeof stored.runId !== "string")
28903
+ return void 0;
28904
+ return typeof stored.codingAgent === "string" ? stored : void 0;
28905
+ }
28906
+ function recordCodingAgent(dependencies, runId, codingAgent) {
28907
+ dependencies.store.set(stateKey("agent", resolveAnchoredRoot(dependencies)), {
28908
+ codingAgent: normalizeCodingAgent(codingAgent),
28909
+ runId
28910
+ });
28911
+ }
28912
+ function readCodingAgent(dependencies) {
28913
+ const root2 = resolveAnchoredRoot(dependencies);
28914
+ const stored = readStoredCodingAgent(dependencies.store, stateKey("agent", root2));
28915
+ if (stored === void 0)
28916
+ return void 0;
28917
+ const bound = readBoundRun(dependencies.store, root2);
28918
+ if (bound.state === "live" && bound.runId !== stored.runId)
28919
+ return void 0;
28920
+ return stored.codingAgent;
28921
+ }
28871
28922
  function readOnboardingRunId(dependencies) {
28872
28923
  try {
28873
28924
  const bound = readBoundRun(
@@ -28890,21 +28941,6 @@ function readOnboardingIntent(dependencies) {
28890
28941
  return void 0;
28891
28942
  }
28892
28943
  }
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
28944
  function startOnboardingRun(dependencies, requestedRunId, requestedIntent) {
28909
28945
  if (requestedIntent !== void 0 && !ONBOARDING_INTENT_PATTERN.test(requestedIntent)) {
28910
28946
  throw new Error("Requested onboarding intent is invalid");
@@ -29761,7 +29797,7 @@ var require_redact = __commonJS({
29761
29797
  } = options;
29762
29798
  validatePaths(paths);
29763
29799
  const pathStructure = buildPathStructure(paths);
29764
- return function redact(obj) {
29800
+ return function redact2(obj) {
29765
29801
  if (strict2 && (obj === null || typeof obj !== "object")) {
29766
29802
  if (obj === null || obj === void 0) {
29767
29803
  return serialize3 ? serialize3(obj) : obj;
@@ -33238,7 +33274,7 @@ var require_pino = __commonJS({
33238
33274
  if (opts.level && typeof opts.level === "string" && DEFAULT_LEVELS[opts.level.toLowerCase()] !== void 0)
33239
33275
  opts.level = opts.level.toLowerCase();
33240
33276
  const {
33241
- redact,
33277
+ redact: redact2,
33242
33278
  crlf,
33243
33279
  serializers: serializers2,
33244
33280
  timestamp: timestamp2,
@@ -33272,8 +33308,8 @@ var require_pino = __commonJS({
33272
33308
  const stringifyFn = stringify4.bind({
33273
33309
  [stringifySafeSym]: stringifySafe
33274
33310
  });
33275
- const stringifiers = redact ? redaction(redact, stringifyFn) : {};
33276
- const formatOpts = redact ? { stringify: stringifiers[redactFmtSym] } : { stringify: stringifyFn };
33311
+ const stringifiers = redact2 ? redaction(redact2, stringifyFn) : {};
33312
+ const formatOpts = redact2 ? { stringify: stringifiers[redactFmtSym] } : { stringify: stringifyFn };
33277
33313
  const end = "}" + (crlf ? "\r\n" : "\n");
33278
33314
  const coreChindings = asChindings.bind(null, {
33279
33315
  [chindingsSym]: "",
@@ -91416,6 +91452,19 @@ function describeCredentialWriteDirectory(dir, ceilingDir) {
91416
91452
  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
91453
  `;
91418
91454
  }
91455
+ function envFileLoaderDeclaredIn(appDir, ceiling) {
91456
+ const filesystemRoot = path11.parse(appDir).root;
91457
+ let candidate = appDir;
91458
+ while (true) {
91459
+ if (readAppManifest(candidate)?.declaresEnvFileLoader === true) {
91460
+ return candidate;
91461
+ }
91462
+ if (candidate === ceiling || candidate === filesystemRoot) {
91463
+ return void 0;
91464
+ }
91465
+ candidate = path11.dirname(candidate);
91466
+ }
91467
+ }
91419
91468
  function resolveCredentialLoad(inputs) {
91420
91469
  if (inputs.variableName === void 0) {
91421
91470
  return { kind: "no-key" };
@@ -91428,8 +91477,12 @@ function resolveCredentialLoad(inputs) {
91428
91477
  return { apps: apps2, kind: "ambiguous" };
91429
91478
  }
91430
91479
  const appDir = apps2[0];
91431
- if (readAppManifest(appDir)?.declaresEnvFileLoader === true) {
91432
- return { appDir, kind: "loader-declared" };
91480
+ const declaredIn = envFileLoaderDeclaredIn(
91481
+ appDir,
91482
+ canonicalizeDir(inputs.ceiling)
91483
+ );
91484
+ if (declaredIn !== void 0) {
91485
+ return { appDir, declaredIn, kind: "loader-declared" };
91433
91486
  }
91434
91487
  if (inputs.source === void 0) {
91435
91488
  return { appDir, kind: "process-environment" };
@@ -91821,8 +91874,10 @@ __export(telemetry_exports, {
91821
91874
  cliLogTelemetryLogger: () => cliLogTelemetryLogger,
91822
91875
  currentAuthIdentity: () => currentAuthIdentity,
91823
91876
  currentCliStateProperties: () => currentCliStateProperties,
91877
+ currentOnboardingCodingAgent: () => currentOnboardingCodingAgent,
91824
91878
  currentOnboardingRunProperties: () => currentOnboardingRunProperties,
91825
91879
  currentProjectIdentity: () => currentProjectIdentity,
91880
+ describeSubmissionError: () => describeSubmissionError,
91826
91881
  exitWithFlush: () => exitWithFlush,
91827
91882
  flushTelemetry: () => flushTelemetry,
91828
91883
  getCliConsentProvider: () => getCliConsentProvider,
@@ -91831,6 +91886,7 @@ __export(telemetry_exports, {
91831
91886
  hasStandaloneTelemetryIdentityConsent: () => hasStandaloneTelemetryIdentityConsent,
91832
91887
  linkConsentSubjectToUser: () => linkConsentSubjectToUser,
91833
91888
  recordTelemetryEvent: () => recordTelemetryEvent,
91889
+ resolveReturnedOutcome: () => resolveReturnedOutcome,
91834
91890
  submitTelemetryEvent: () => submitTelemetryEvent,
91835
91891
  withTelemetry: () => withTelemetry
91836
91892
  });
@@ -91906,6 +91962,9 @@ function currentOnboardingRunProperties() {
91906
91962
  });
91907
91963
  return runId === void 0 ? {} : { onboarding_run_id: runId };
91908
91964
  }
91965
+ function currentOnboardingCodingAgent() {
91966
+ return readCodingAgent({ cwd: process.cwd(), store: configStore });
91967
+ }
91909
91968
  function currentAuthIdentity() {
91910
91969
  return resolveAuthIdentityProperties({
91911
91970
  readStoredAuth: () => authStore.get()
@@ -91956,8 +92015,21 @@ async function submitTelemetryEvent(event) {
91956
92015
  noticeShown: hasShownTelemetryNotice(configStore)
91957
92016
  });
91958
92017
  if (!gate.send)
91959
- return false;
91960
- return await getTelemetry().submitEvent(withProjectIdentity(event));
92018
+ return { status: "declined" };
92019
+ try {
92020
+ const accepted = await getTelemetry().submitEvent(
92021
+ withProjectIdentity(event)
92022
+ );
92023
+ return accepted ? { status: "sent" } : { status: "failed", detail: "the transport did not accept the event" };
92024
+ } catch (error98) {
92025
+ return { status: "failed", detail: describeSubmissionError(error98) };
92026
+ }
92027
+ }
92028
+ function describeSubmissionError(error98) {
92029
+ if (error98 instanceof Error && error98.message !== "")
92030
+ return error98.message;
92031
+ const described = String(error98);
92032
+ return described === "" ? "the telemetry transport threw" : described;
91961
92033
  }
91962
92034
  async function flushTelemetry(timeoutMs = DEFAULT_FLUSH_TIMEOUT_MS) {
91963
92035
  if (!instance)
@@ -91968,6 +92040,17 @@ async function exitWithFlush(code) {
91968
92040
  await flushTelemetry();
91969
92041
  process.exit(code);
91970
92042
  }
92043
+ function resolveReturnedOutcome(input) {
92044
+ if (input.declaredFailure !== null) {
92045
+ return {
92046
+ outcome: "failed",
92047
+ ...input.declaredFailure.errorCode === void 0 ? {} : { errorCode: input.declaredFailure.errorCode }
92048
+ };
92049
+ }
92050
+ const { exitCode } = input;
92051
+ const failedByExit = exitCode !== void 0 && exitCode !== 0 && exitCode !== "0";
92052
+ return failedByExit ? { outcome: "failed" } : { outcome: "succeeded" };
92053
+ }
91971
92054
  async function withTelemetry(base, fn) {
91972
92055
  const buildInfo = getBuildInfo();
91973
92056
  const provider = getConsentProvider();
@@ -91988,9 +92071,13 @@ async function withTelemetry(base, fn) {
91988
92071
  }
91989
92072
  const startedAt = Date.now();
91990
92073
  let extra = {};
92074
+ let declaredFailure = null;
91991
92075
  const ctx = {
91992
92076
  setProperties(next) {
91993
92077
  extra = { ...extra, ...next };
92078
+ },
92079
+ reportFailure(input) {
92080
+ declaredFailure = input ?? {};
91994
92081
  }
91995
92082
  };
91996
92083
  recordTelemetryEvent({
@@ -92003,14 +92090,19 @@ async function withTelemetry(base, fn) {
92003
92090
  });
92004
92091
  try {
92005
92092
  const result = await fn(ctx);
92093
+ const verdict = resolveReturnedOutcome({
92094
+ declaredFailure,
92095
+ exitCode: process.exitCode
92096
+ });
92006
92097
  recordTelemetryEvent({
92007
92098
  properties: {
92008
92099
  ...base,
92009
92100
  ...currentCliStateProperties(base.command),
92010
92101
  ...currentOnboardingRunProperties(),
92011
92102
  ...extra,
92012
- outcome: "succeeded",
92013
- duration_ms: Date.now() - startedAt
92103
+ outcome: verdict.outcome,
92104
+ duration_ms: Date.now() - startedAt,
92105
+ ...verdict.errorCode === void 0 ? {} : { error_code: verdict.errorCode }
92014
92106
  }
92015
92107
  });
92016
92108
  return result;
@@ -93755,6 +93847,9 @@ async function login(options = {}) {
93755
93847
  if (options.authHandoff) {
93756
93848
  loginParams.set("source", options.authHandoff.source);
93757
93849
  loginParams.set("mode", options.authHandoff.mode);
93850
+ if (options.authHandoff.agent !== void 0) {
93851
+ loginParams.set("agent", options.authHandoff.agent);
93852
+ }
93758
93853
  }
93759
93854
  const loginUrl = `${getOpsFrontendUrl()}/cli-auth?${loginParams.toString()}`;
93760
93855
  diagnostics.logPhase("login.browser-url-prepared", {
@@ -95890,6 +95985,27 @@ var init_project_list = __esm({
95890
95985
  });
95891
95986
 
95892
95987
  // apps/cli/src/services/hosted-project-name.ts
95988
+ function suggestFreeProjectName(raw2, existing) {
95989
+ const name = raw2.trim();
95990
+ const taken = new Set(
95991
+ existing.map((project) => project.name.trim().toLowerCase())
95992
+ );
95993
+ if (!taken.has(name.toLowerCase())) {
95994
+ return name;
95995
+ }
95996
+ const stripped = name.replace(NUMERIC_SUFFIX, "");
95997
+ const base = stripped === "" ? name : stripped;
95998
+ let candidate = base;
95999
+ for (let counter = 2; counter < SUGGESTION_ATTEMPTS + 2; counter += 1) {
96000
+ const suffix = `-${String(counter)}`;
96001
+ const room = MAX_PROJECT_NAME_LENGTH - suffix.length;
96002
+ candidate = `${base.slice(0, room)}${suffix}`;
96003
+ if (!taken.has(candidate.toLowerCase())) {
96004
+ return candidate;
96005
+ }
96006
+ }
96007
+ return candidate;
96008
+ }
95893
96009
  function validateProjectName(raw2, existing) {
95894
96010
  const name = raw2.trim();
95895
96011
  if (name === "") {
@@ -95914,16 +96030,19 @@ function validateProjectName(raw2, existing) {
95914
96030
  ok: false,
95915
96031
  reason: "duplicate",
95916
96032
  message: `You already have a project named "${duplicate.name}".`,
95917
- duplicate
96033
+ duplicate,
96034
+ suggestion: suggestFreeProjectName(name, existing)
95918
96035
  };
95919
96036
  }
95920
96037
  return { ok: true, name };
95921
96038
  }
95922
- var MAX_PROJECT_NAME_LENGTH;
96039
+ var MAX_PROJECT_NAME_LENGTH, NUMERIC_SUFFIX, SUGGESTION_ATTEMPTS;
95923
96040
  var init_hosted_project_name = __esm({
95924
96041
  "apps/cli/src/services/hosted-project-name.ts"() {
95925
96042
  "use strict";
95926
96043
  MAX_PROJECT_NAME_LENGTH = 100;
96044
+ NUMERIC_SUFFIX = /-\d+$/;
96045
+ SUGGESTION_ATTEMPTS = 1e3;
95927
96046
  }
95928
96047
  });
95929
96048
 
@@ -95953,6 +96072,12 @@ function defer() {
95953
96072
  function ProjectExplainer({ dim = false }) {
95954
96073
  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
96074
  }
96075
+ function describeNameRefusal(validation) {
96076
+ if (validation.suggestion === void 0) {
96077
+ return validation.message;
96078
+ }
96079
+ 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.`;
96080
+ }
95956
96081
  function HostedProjectSelect({
95957
96082
  apiClient,
95958
96083
  onResolved,
@@ -95967,6 +96092,7 @@ function HostedProjectSelect({
95967
96092
  const nameDirtyRef = (0, import_react37.useRef)(false);
95968
96093
  const [nameDirty, setNameDirty] = (0, import_react37.useState)(false);
95969
96094
  const [nameError, setNameError] = (0, import_react37.useState)("");
96095
+ const offeredNameRef = (0, import_react37.useRef)(null);
95970
96096
  const pickerIndexRef = (0, import_react37.useRef)(0);
95971
96097
  const [pickerIndex, setPickerIndex] = (0, import_react37.useState)(0);
95972
96098
  const choiceRef = (0, import_react37.useRef)(null);
@@ -95998,6 +96124,8 @@ function HostedProjectSelect({
95998
96124
  setNameDisplay(defaultName);
95999
96125
  nameDirtyRef.current = false;
96000
96126
  setNameDirty(false);
96127
+ offeredNameRef.current = null;
96128
+ setNameError("");
96001
96129
  setView({ kind: "name" });
96002
96130
  return deferred.promise;
96003
96131
  }
@@ -96081,22 +96209,30 @@ function HostedProjectSelect({
96081
96209
  nameDirtyRef.current = true;
96082
96210
  setNameDirty(true);
96083
96211
  }
96212
+ const offered = offeredNameRef.current;
96213
+ if (offered !== null && textBeforeNewline === "") {
96214
+ offeredNameRef.current = null;
96215
+ setNameError("");
96216
+ nameRef.current?.resolve(offered);
96217
+ return;
96218
+ }
96084
96219
  const validation = validateProjectName(
96085
96220
  nameBufferRef.current,
96086
96221
  projectsRef.current
96087
96222
  );
96088
96223
  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
- );
96224
+ offeredNameRef.current = validation.suggestion ?? null;
96225
+ setNameError(describeNameRefusal(validation));
96092
96226
  telemetry?.onCreateNameRejected?.(validation.reason);
96093
96227
  return;
96094
96228
  }
96229
+ offeredNameRef.current = null;
96095
96230
  setNameError("");
96096
96231
  nameRef.current?.resolve(validation.name);
96097
96232
  return;
96098
96233
  }
96099
96234
  if (key.backspace || key.delete) {
96235
+ offeredNameRef.current = null;
96100
96236
  const updated = nameDirtyRef.current ? nameBufferRef.current.slice(0, -1) : "";
96101
96237
  nameDirtyRef.current = true;
96102
96238
  setNameDirty(true);
@@ -96105,6 +96241,7 @@ function HostedProjectSelect({
96105
96241
  return;
96106
96242
  }
96107
96243
  if (input && !key.ctrl && !key.meta) {
96244
+ offeredNameRef.current = null;
96108
96245
  const base = nameDirtyRef.current ? nameBufferRef.current : "";
96109
96246
  nameDirtyRef.current = true;
96110
96247
  setNameDirty(true);
@@ -96645,7 +96782,8 @@ function createFlagPrompts(request) {
96645
96782
  kind: "name-rejected",
96646
96783
  reason: validation.reason,
96647
96784
  message: validation.message,
96648
- ...validation.duplicate ? { duplicateSlug: validation.duplicate.slug } : {}
96785
+ ...validation.duplicate ? { duplicateSlug: validation.duplicate.slug } : {},
96786
+ ...validation.suggestion === void 0 ? {} : { suggestedName: validation.suggestion }
96649
96787
  };
96650
96788
  return null;
96651
96789
  }
@@ -96688,7 +96826,8 @@ function createFlagPrompts(request) {
96688
96826
  }
96689
96827
  function formatFlagRefusal(refusal, command2 = "project select") {
96690
96828
  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}\`.`;
96829
+ const free = refusal.suggestedName === void 0 ? "Pass a different --create name" : `\`--create "${refusal.suggestedName}"\` is free`;
96830
+ const remedy = refusal.duplicateSlug === void 0 ? `${free}.` : `${free}, or select the existing project with \`copilotkit ${command2} --project ${refusal.duplicateSlug}\`.`;
96692
96831
  return `${refusal.message} ${remedy}
96693
96832
  `;
96694
96833
  }
@@ -96821,9 +96960,19 @@ async function driveFlagSelect(apiClient, request) {
96821
96960
  return withoutSelection({ kind: "canceled" });
96822
96961
  }
96823
96962
  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
- );
96963
+ if (recorded.kind === "not-found") {
96964
+ return withoutSelection({
96965
+ kind: "not-found",
96966
+ requested: recorded.requested
96967
+ });
96968
+ }
96969
+ return withoutSelection({
96970
+ kind: "name-rejected",
96971
+ // The refused name and the free one, in the message the payload carries.
96972
+ // A caller reading only `error` still learns which name to retry with.
96973
+ message: recorded.suggestedName === void 0 ? recorded.message : `${recorded.message} "${recorded.suggestedName}" is free.`,
96974
+ ...recorded.suggestedName === void 0 ? {} : { suggestedName: recorded.suggestedName }
96975
+ });
96827
96976
  }
96828
96977
  return await completeSelection(apiClient, result);
96829
96978
  }
@@ -96906,8 +97055,13 @@ async function runProjectSelectJson(options = {}) {
96906
97055
  throw exitError;
96907
97056
  }
96908
97057
  const error98 = exitError ?? new Error("Project selection did not complete.");
97058
+ const suggestedName = outcome.kind === "name-rejected" ? outcome.suggestedName : void 0;
96909
97059
  process.stdout.write(
96910
- `${JSON.stringify({ error: error98.message, type: "failed" })}
97060
+ `${JSON.stringify({
97061
+ error: error98.message,
97062
+ ...suggestedName === void 0 ? {} : { suggested_name: suggestedName },
97063
+ type: "failed"
97064
+ })}
96911
97065
  `
96912
97066
  );
96913
97067
  throw error98;
@@ -99860,12 +100014,50 @@ var init_learning = __esm({
99860
100014
  });
99861
100015
 
99862
100016
  // libs/app-api-contracts/src/threads.ts
99863
- var threadIdSchema;
100017
+ var threadIdSchema, appUserAliasSchema, collapseAppUserAliases, refuseInternalAppUserForms, threadAppUserSchema, threadReadQuerySchema;
99864
100018
  var init_threads = __esm({
99865
100019
  "libs/app-api-contracts/src/threads.ts"() {
99866
100020
  "use strict";
99867
100021
  init_zod();
99868
100022
  threadIdSchema = external_exports.string().uuid();
100023
+ appUserAliasSchema = external_exports.object({
100024
+ endUserId: external_exports.string().trim().min(1).optional(),
100025
+ end_user_id: external_exports.string().trim().min(1).optional(),
100026
+ userId: external_exports.string().trim().min(1).optional(),
100027
+ createdById: external_exports.string().trim().min(1).optional(),
100028
+ created_by_id: external_exports.string().trim().min(1).optional(),
100029
+ appUserId: external_exports.string().trim().min(1).optional(),
100030
+ app_user_id: external_exports.string().trim().min(1).optional()
100031
+ });
100032
+ collapseAppUserAliases = (data) => ({
100033
+ endUserId: data.endUserId ?? data.end_user_id ?? data.userId,
100034
+ createdById: data.createdById ?? data.created_by_id,
100035
+ appUserId: data.appUserId ?? data.app_user_id
100036
+ });
100037
+ refuseInternalAppUserForms = (data, ctx) => {
100038
+ if (data.createdById) {
100039
+ ctx.addIssue({
100040
+ code: external_exports.ZodIssueCode.custom,
100041
+ message: "createdById is internal; pass bare endUserId instead."
100042
+ });
100043
+ }
100044
+ if (data.appUserId) {
100045
+ ctx.addIssue({
100046
+ code: external_exports.ZodIssueCode.custom,
100047
+ message: "appUserId is not accepted; pass endUserId instead."
100048
+ });
100049
+ }
100050
+ };
100051
+ threadAppUserSchema = appUserAliasSchema.transform(collapseAppUserAliases).superRefine((data, ctx) => {
100052
+ if (!data.endUserId) {
100053
+ ctx.addIssue({
100054
+ code: external_exports.ZodIssueCode.custom,
100055
+ message: "endUserId is required."
100056
+ });
100057
+ }
100058
+ refuseInternalAppUserForms(data, ctx);
100059
+ }).transform((data) => ({ endUserId: data.endUserId }));
100060
+ threadReadQuerySchema = appUserAliasSchema.transform(collapseAppUserAliases).superRefine(refuseInternalAppUserForms).transform((data) => ({ endUserId: data.endUserId }));
99869
100061
  }
99870
100062
  });
99871
100063
 
@@ -100096,7 +100288,7 @@ async function loadLearningCommandContext() {
100096
100288
  productCredential: auth2.productCredential,
100097
100289
  productOrganizationId: auth2.clerkOrgId
100098
100290
  });
100099
- return { client: client2, projectId: project.projectId };
100291
+ return { client: client2, projectId: project.projectId, projectSlug: project.projectSlug };
100100
100292
  }
100101
100293
  var init_learning_command_context = __esm({
100102
100294
  "apps/cli/src/services/learning-command-context.ts"() {
@@ -100435,6 +100627,21 @@ async function runLearningInsightsCommand(command2, dependencies) {
100435
100627
  command2.candidateId,
100436
100628
  command2.action
100437
100629
  );
100630
+ if (command2.yes) {
100631
+ dependencies.telemetry.onReviewViewed({
100632
+ action: command2.action,
100633
+ durationMs: Date.now() - startedAt,
100634
+ operation: review.operation,
100635
+ reviewMode
100636
+ });
100637
+ dependencies.telemetry.onReviewDecided({
100638
+ action: command2.action,
100639
+ decision: "confirmed",
100640
+ durationMs: 0,
100641
+ operation: review.operation,
100642
+ reviewMode
100643
+ });
100644
+ }
100438
100645
  dependencies.telemetry.setProperties({
100439
100646
  candidate_operation: review.operation,
100440
100647
  review_mode: reviewMode,
@@ -100581,11 +100788,27 @@ var init_learning_containers_api = __esm({
100581
100788
  }
100582
100789
  });
100583
100790
 
100791
+ // apps/cli/src/services/learning-default-container.ts
100792
+ function defaultContainerIdFromProjectSlug(projectSlug) {
100793
+ const reshaped = projectSlug.toLowerCase().replace(/[^a-z0-9]+/gu, "-").replace(/^-+|-+$/gu, "");
100794
+ if (reshaped === "")
100795
+ return void 0;
100796
+ const bounded = reshaped.slice(0, MAX_ID_LENGTH).replace(/-+$/u, "");
100797
+ return bounded === "" ? void 0 : bounded;
100798
+ }
100799
+ var MAX_ID_LENGTH;
100800
+ var init_learning_default_container = __esm({
100801
+ "apps/cli/src/services/learning-default-container.ts"() {
100802
+ "use strict";
100803
+ MAX_ID_LENGTH = 64;
100804
+ }
100805
+ });
100806
+
100584
100807
  // apps/cli/src/ui/learning-container-prompts.tsx
100585
100808
  function LearningContainerCreatePrompt(props) {
100586
100809
  const firstStep = props.initial.id === void 0 ? "id" : props.initial.name === void 0 ? "name" : "prompt";
100587
100810
  const [step, setStep] = (0, import_react43.useState)(firstStep);
100588
- const [id, setId] = (0, import_react43.useState)(props.initial.id ?? "");
100811
+ const [id, setId] = (0, import_react43.useState)(props.initial.id ?? props.initial.proposedId ?? "");
100589
100812
  const [name, setName] = (0, import_react43.useState)(props.initial.name ?? "");
100590
100813
  const [promptContext, setPromptContext] = (0, import_react43.useState)(
100591
100814
  props.initial.promptContext ?? ""
@@ -100757,6 +100980,66 @@ function LearningContainerDeletePrompt(props) {
100757
100980
  /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { children: "(y/N) " })
100758
100981
  ] });
100759
100982
  }
100983
+ function LearningContainerSelectPrompt(props) {
100984
+ const createIndex = props.containers.length;
100985
+ const moreIndex = props.hasMore ? createIndex + 1 : -1;
100986
+ const itemCount = createIndex + (props.hasMore ? 2 : 1);
100987
+ const [index2, setIndex] = (0, import_react43.useState)(0);
100988
+ const indexRef = (0, import_react43.useRef)(0);
100989
+ const finished2 = (0, import_react43.useRef)(false);
100990
+ const move = (delta) => {
100991
+ const next = (indexRef.current + delta + itemCount) % itemCount;
100992
+ indexRef.current = next;
100993
+ setIndex(next);
100994
+ };
100995
+ const finish = (selection) => {
100996
+ if (finished2.current)
100997
+ return;
100998
+ finished2.current = true;
100999
+ props.onComplete(selection);
101000
+ };
101001
+ use_input_default((_input, key) => {
101002
+ if (key.downArrow) {
101003
+ move(1);
101004
+ return;
101005
+ }
101006
+ if (key.upArrow) {
101007
+ move(-1);
101008
+ return;
101009
+ }
101010
+ if (key.escape) {
101011
+ if (finished2.current)
101012
+ return;
101013
+ finished2.current = true;
101014
+ props.onCancel();
101015
+ return;
101016
+ }
101017
+ if (!key.return)
101018
+ return;
101019
+ const position = indexRef.current;
101020
+ if (position === moreIndex) {
101021
+ finish({ kind: "more" });
101022
+ return;
101023
+ }
101024
+ if (position === createIndex) {
101025
+ finish({ kind: "create" });
101026
+ return;
101027
+ }
101028
+ const container = props.containers[position];
101029
+ if (container === void 0)
101030
+ return;
101031
+ finish({ containerId: container.id, kind: "chosen" });
101032
+ });
101033
+ const marker = (position) => position === index2 ? ">" : " ";
101034
+ return /* @__PURE__ */ (0, import_jsx_runtime13.jsxs)(Box_default, { flexDirection: "column", children: [
101035
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { bold: true, children: "Select a Learning Container" }),
101036
+ props.containers.length === 0 ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { dimColor: true, children: "This project has none yet." }) : null,
101037
+ props.containers.map((container, position) => /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { children: `${marker(position)} ${container.id} ${container.name}` }, container.id)),
101038
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { children: `${marker(createIndex)} Create a new container` }),
101039
+ props.hasMore ? /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { children: `${marker(moreIndex)} Show more` }) : null,
101040
+ /* @__PURE__ */ (0, import_jsx_runtime13.jsx)(Text, { dimColor: true, children: "Up and down move, Enter selects, Esc cancels." })
101041
+ ] });
101042
+ }
100760
101043
  var import_react43, import_jsx_runtime13;
100761
101044
  var init_learning_container_prompts = __esm({
100762
101045
  async "apps/cli/src/ui/learning-container-prompts.tsx"() {
@@ -100806,6 +101089,22 @@ async function promptUpdate(container) {
100806
101089
  await app.waitUntilExit();
100807
101090
  return result;
100808
101091
  }
101092
+ async function promptSelect(input) {
101093
+ let result = null;
101094
+ const app = render_default(
101095
+ (0, import_react44.createElement)(LearningContainerSelectPrompt, {
101096
+ containers: input.containers,
101097
+ hasMore: input.hasMore,
101098
+ onCancel: () => setTimeout(() => app.unmount(), 0),
101099
+ onComplete: (selection) => {
101100
+ result = selection;
101101
+ setTimeout(() => app.unmount(), 0);
101102
+ }
101103
+ })
101104
+ );
101105
+ await app.waitUntilExit();
101106
+ return result;
101107
+ }
100809
101108
  async function confirmDelete(container) {
100810
101109
  let confirmed = false;
100811
101110
  const app = render_default(
@@ -100823,12 +101122,13 @@ async function confirmDelete(container) {
100823
101122
  function createLearningContainersCommandDependencies() {
100824
101123
  return {
100825
101124
  interactive: process.stdin.isTTY === true && process.stdout.isTTY === true,
100826
- interaction: { confirmDelete, promptCreate, promptUpdate },
101125
+ interaction: { confirmDelete, promptCreate, promptSelect, promptUpdate },
100827
101126
  loadContext: async () => {
100828
- const { client: client2, projectId } = await loadLearningCommandContext();
101127
+ const { client: client2, projectId, projectSlug } = await loadLearningCommandContext();
100829
101128
  return {
100830
101129
  api: createLearningContainersApi(client2),
100831
- projectId
101130
+ projectId,
101131
+ projectSlug
100832
101132
  };
100833
101133
  },
100834
101134
  writeStdout: (text2) => {
@@ -100973,6 +101273,59 @@ Created: ${container.createdAt}
100973
101273
  Updated: ${container.updatedAt}
100974
101274
  `;
100975
101275
  }
101276
+ async function selectLearningContainer(dependencies, projectId) {
101277
+ const { api, projectSlug } = await dependencies.loadContext();
101278
+ const proposedId = projectSlug === void 0 ? void 0 : defaultContainerIdFromProjectSlug(projectSlug);
101279
+ const seen = [];
101280
+ let cursor;
101281
+ let exhausted = false;
101282
+ let pagesRead = 0;
101283
+ const reportSurvey = (selection) => {
101284
+ dependencies.telemetry?.setProperties({
101285
+ container_count: seen.length,
101286
+ container_more_pages: !exhausted,
101287
+ container_pages_read: pagesRead,
101288
+ ...selection === void 0 ? {} : { container_selection: selection }
101289
+ });
101290
+ };
101291
+ for (; ; ) {
101292
+ if (!exhausted) {
101293
+ const page = await api.list(projectId, cursor);
101294
+ pagesRead += 1;
101295
+ seen.push(...page.containers);
101296
+ cursor = page.nextCursor ?? void 0;
101297
+ exhausted = cursor === void 0;
101298
+ }
101299
+ const answer = await dependencies.interaction.promptSelect({
101300
+ containers: [...seen],
101301
+ hasMore: !exhausted
101302
+ });
101303
+ if (answer === null) {
101304
+ reportSurvey();
101305
+ dependencies.writeStdout("Canceled.\n");
101306
+ throw userAbortedError2();
101307
+ }
101308
+ if (answer.kind === "more")
101309
+ continue;
101310
+ if (answer.kind === "create") {
101311
+ reportSurvey("created");
101312
+ const input = await dependencies.interaction.promptCreate(
101313
+ proposedId === void 0 ? {} : { proposedId }
101314
+ );
101315
+ if (input === null) {
101316
+ dependencies.writeStdout("Canceled.\n");
101317
+ throw userAbortedError2();
101318
+ }
101319
+ return api.create(projectId, input);
101320
+ }
101321
+ reportSurvey("chosen");
101322
+ const chosen = seen.find((held) => held.id === answer.containerId);
101323
+ if (chosen === void 0) {
101324
+ throw containerNotFoundError(answer.containerId);
101325
+ }
101326
+ return chosen;
101327
+ }
101328
+ }
100976
101329
  async function runLearningContainersCommand(command2, dependencies) {
100977
101330
  try {
100978
101331
  validateLearningContainersCommandFlags(command2);
@@ -100991,9 +101344,19 @@ async function runLearningContainersCommand(command2, dependencies) {
100991
101344
  "Learning Container delete needs --yes when confirmation is unavailable."
100992
101345
  );
100993
101346
  }
101347
+ if (command2.action === "select" && (command2.json || !dependencies.interactive)) {
101348
+ throw nonInteractiveError(
101349
+ "Learning Container select needs a terminal. Read them with `learning containers list --json` and make one with `learning containers create --id <id> --name <name>`."
101350
+ );
101351
+ }
100994
101352
  const { api, projectId } = await dependencies.loadContext();
100995
101353
  if (command2.action === "list") {
100996
101354
  const page = await api.list(projectId, command2.cursor);
101355
+ dependencies.telemetry?.setProperties({
101356
+ container_count: page.containers.length,
101357
+ container_more_pages: page.nextCursor !== null,
101358
+ container_pages_read: 1
101359
+ });
100997
101360
  if (command2.json) {
100998
101361
  writeJson2(dependencies, {
100999
101362
  command: "learning containers list",
@@ -101024,6 +101387,11 @@ async function runLearningContainersCommand(command2, dependencies) {
101024
101387
  }
101025
101388
  return;
101026
101389
  }
101390
+ if (command2.action === "select") {
101391
+ const container2 = await selectLearningContainer(dependencies, projectId);
101392
+ dependencies.writeStdout(renderLearningContainer(container2));
101393
+ return;
101394
+ }
101027
101395
  if (command2.action === "create") {
101028
101396
  let input;
101029
101397
  if (command2.id !== void 0 && command2.name !== void 0) {
@@ -101148,6 +101516,7 @@ var init_learning_containers = __esm({
101148
101516
  init_src6();
101149
101517
  init_learning_containers_api();
101150
101518
  init_learning_command_context();
101519
+ init_learning_default_container();
101151
101520
  await init_build2();
101152
101521
  import_react44 = __toESM(require_react(), 1);
101153
101522
  await init_learning_container_prompts();
@@ -101548,7 +101917,7 @@ function apiKeyPresentCheck(variableName, source, envSearch) {
101548
101917
  title
101549
101918
  };
101550
101919
  }
101551
- function apiKeyLoadableCheck(facts) {
101920
+ function apiKeyLoadableCheck(facts, runtime) {
101552
101921
  const title = "The app can load the project API key";
101553
101922
  const id = "api_key_loadable_by_app";
101554
101923
  switch (facts.kind) {
@@ -101575,7 +101944,7 @@ function apiKeyLoadableCheck(facts) {
101575
101944
  };
101576
101945
  case "loader-declared":
101577
101946
  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.`,
101947
+ 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
101948
  id,
101580
101949
  status: "undetermined",
101581
101950
  title
@@ -101594,13 +101963,24 @@ function apiKeyLoadableCheck(facts) {
101594
101963
  status: "pass",
101595
101964
  title
101596
101965
  };
101597
- case "not-loadable":
101966
+ case "not-loadable": {
101967
+ 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()}.`;
101968
+ const remedy = `Write it to ${facts.expectedFile}, or re-run \`copilotkit project select\` from ${facts.appDir}.`;
101969
+ if (runtime.kind === "ok" && reportsIntelligenceClient(runtime.info)) {
101970
+ return {
101971
+ 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}`,
101972
+ id,
101973
+ status: "undetermined",
101974
+ title
101975
+ };
101976
+ }
101598
101977
  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}.`,
101978
+ detail: `${located} So the running application never sees it. ${remedy}`,
101600
101979
  id,
101601
101980
  status: "fail",
101602
101981
  title
101603
101982
  };
101983
+ }
101604
101984
  }
101605
101985
  }
101606
101986
  function apiKeyAuthenticatesCheck(probe) {
@@ -101758,12 +102138,59 @@ function intelligenceConsumedCheck(credential, runtime) {
101758
102138
  };
101759
102139
  }
101760
102140
  return {
101761
- detail: `The runtime holds an Intelligence client and ${describeIntelligenceEntitlement(runtime.info)}, so the key is being used.`,
102141
+ 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
102142
  id: "intelligence_consumed",
101763
102143
  status: "pass",
101764
102144
  title
101765
102145
  };
101766
102146
  }
102147
+ function deploymentHost(url4) {
102148
+ let hostname5;
102149
+ try {
102150
+ hostname5 = new URL(url4).hostname.toLowerCase();
102151
+ } catch {
102152
+ return void 0;
102153
+ }
102154
+ return LOOPBACK_HOSTNAMES.has(hostname5) ? "localhost" : hostname5;
102155
+ }
102156
+ function intelligenceHostAgreementChecks(input) {
102157
+ const { credential, intelligenceTarget, runtime } = input;
102158
+ if (runtime.kind !== "ok" || credential.kind !== "ok")
102159
+ return [];
102160
+ if (!reportsIntelligenceClient(runtime.info))
102161
+ return [];
102162
+ const reportedGateway = runtime.info.intelligenceWsUrl;
102163
+ if (reportedGateway === void 0)
102164
+ return [];
102165
+ const observed = deploymentHost(reportedGateway);
102166
+ const verified = deploymentHost(intelligenceTarget.verifiedUrl);
102167
+ if (observed === void 0 || verified === void 0)
102168
+ return [];
102169
+ const accepted = new Set(
102170
+ [verified, ...intelligenceTarget.pairedGatewayUrls.map(deploymentHost)].filter(
102171
+ (host) => host !== void 0
102172
+ )
102173
+ );
102174
+ if (accepted.has(observed)) {
102175
+ return [
102176
+ {
102177
+ detail: `The runtime reports its Intelligence gateway on ${observed}, which belongs to the deployment this command proved the key against (${verified}).`,
102178
+ id: "intelligence_host_agreement",
102179
+ status: "pass",
102180
+ title: HOST_AGREEMENT_TITLE
102181
+ }
102182
+ ];
102183
+ }
102184
+ 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.` : "";
102185
+ return [
102186
+ {
102187
+ 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.`,
102188
+ id: "intelligence_host_agreement",
102189
+ status: "fail",
102190
+ title: HOST_AGREEMENT_TITLE
102191
+ }
102192
+ ];
102193
+ }
101767
102194
  function ossRuntimeModeCheck(runtime) {
101768
102195
  const title = "The runtime uses the expected OSS mode";
101769
102196
  if (runtime.kind !== "ok") {
@@ -101799,7 +102226,11 @@ function intelligenceThreadRoutesCheck(runtime) {
101799
102226
  title
101800
102227
  };
101801
102228
  }
101802
- const { intelligenceWsUrl, threadMutationsEnabled } = runtime.info;
102229
+ const {
102230
+ intelligenceWsUrl,
102231
+ singleRouteResourceOperations,
102232
+ threadMutationsEnabled
102233
+ } = runtime.info;
101803
102234
  if (!reportsIntelligenceClient(runtime.info)) {
101804
102235
  return {
101805
102236
  detail: "Not attempted: the runtime reports no Intelligence entitlement, so it has no Intelligence routes to serve. The check above names that.",
@@ -101808,6 +102239,14 @@ function intelligenceThreadRoutesCheck(runtime) {
101808
102239
  title
101809
102240
  };
101810
102241
  }
102242
+ if (runtime.transport === "single-route" && singleRouteResourceOperations === void 0) {
102243
+ return {
102244
+ 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.",
102245
+ id: "intelligence_thread_routes",
102246
+ status: "undetermined",
102247
+ title
102248
+ };
102249
+ }
101811
102250
  if (threadMutationsEnabled === void 0) {
101812
102251
  return {
101813
102252
  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 +102257,14 @@ function intelligenceThreadRoutesCheck(runtime) {
101818
102257
  }
101819
102258
  if (!threadMutationsEnabled) {
101820
102259
  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",
102260
+ 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
102261
  id: "intelligence_thread_routes",
101823
102262
  status: "fail",
101824
102263
  title
101825
102264
  };
101826
102265
  }
101827
102266
  return {
101828
- detail: "The runtime serves the thread routes, so saved Threads load.",
102267
+ 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
102268
  id: "intelligence_thread_routes",
101830
102269
  status: "pass",
101831
102270
  title
@@ -102014,11 +102453,12 @@ function runVerifyChecks(input, expectedRuntime = "intelligence") {
102014
102453
  input.apiKeySource,
102015
102454
  input.envSearch
102016
102455
  ),
102017
- apiKeyLoadableCheck(input.credentialLoad),
102456
+ apiKeyLoadableCheck(input.credentialLoad, input.runtime),
102018
102457
  apiKeyAuthenticatesCheck(input.credential),
102019
102458
  runtimeReachableCheck(input.runtime, input.runtimeUrl),
102020
102459
  runtimeAgentsCheck(input.runtime, input.runtimeUrl),
102021
102460
  intelligenceConsumedCheck(input.credential, input.runtime),
102461
+ ...intelligenceHostAgreementChecks(input),
102022
102462
  intelligenceThreadRoutesCheck(input.runtime),
102023
102463
  ...frontendAssetChecks(input),
102024
102464
  ...corsChecks(input),
@@ -102032,7 +102472,7 @@ function runVerifyChecks(input, expectedRuntime = "intelligence") {
102032
102472
  ok: checks.every((check4) => check4.status === "pass")
102033
102473
  };
102034
102474
  }
102035
- var API_KEY_VARIABLE_NAMES, VERSIONS_CHECK_TITLE, CORS_CHECK_TITLE;
102475
+ var API_KEY_VARIABLE_NAMES, LOOPBACK_HOSTNAMES, HOST_AGREEMENT_TITLE, VERSIONS_CHECK_TITLE, CORS_CHECK_TITLE;
102036
102476
  var init_verify_checks = __esm({
102037
102477
  "apps/cli/src/services/verify-checks.ts"() {
102038
102478
  "use strict";
@@ -102043,6 +102483,14 @@ var init_verify_checks = __esm({
102043
102483
  "COPILOTKIT_API_KEY",
102044
102484
  "INTELLIGENCE_API_KEY"
102045
102485
  ];
102486
+ LOOPBACK_HOSTNAMES = /* @__PURE__ */ new Set([
102487
+ "localhost",
102488
+ "127.0.0.1",
102489
+ "[::1]",
102490
+ "::1",
102491
+ "0.0.0.0"
102492
+ ]);
102493
+ HOST_AGREEMENT_TITLE = "The runtime and this command address the same Intelligence deployment";
102046
102494
  VERSIONS_CHECK_TITLE = "The installed packages match the runtime";
102047
102495
  CORS_CHECK_TITLE = "The runtime accepts the frontend origin";
102048
102496
  }
@@ -377720,6 +378168,9 @@ var init_telemetry2 = __esm({
377720
378168
  });
377721
378169
 
377722
378170
  // apps/cli/src/services/round-trip-checks.ts
378171
+ function describeReadVia(readVia) {
378172
+ 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.";
378173
+ }
377723
378174
  function runRoundTripCheck(agentId, probe, runtimeUrlSource) {
377724
378175
  const check4 = decideRoundTrip(agentId, probe);
377725
378176
  if (runtimeUrlSource !== "default" || probe.kind === "unreachable") {
@@ -377731,10 +378182,11 @@ function decideRoundTrip(agentId, probe) {
377731
378182
  if (probe.kind === "answered") {
377732
378183
  const toolNote = probe.toolCallNames.length > 0 ? ` It called ${probe.toolCallNames.join(", ")}.` : "";
377733
378184
  return {
377734
- detail: `Agent "${agentId}" answered with ${String(probe.text.length)} characters, recorded on thread ${probe.threadId}.${toolNote}`,
378185
+ detail: `Agent "${agentId}" answered with ${String(probe.text.length)} characters, recorded on thread ${probe.threadId}.${toolNote} ${describeReadVia(probe.readVia)}`,
377735
378186
  evidence: {
377736
378187
  agentId,
377737
378188
  answerCharacters: probe.text.length,
378189
+ readVia: probe.readVia,
377738
378190
  threadId: probe.threadId,
377739
378191
  toolCallNames: probe.toolCallNames
377740
378192
  },
@@ -377768,7 +378220,7 @@ function decideRoundTrip(agentId, probe) {
377768
378220
  };
377769
378221
  }
377770
378222
  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.`,
378223
+ 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
378224
  id: "agent_answers",
377773
378225
  status: "fail",
377774
378226
  title: TITLE
@@ -377813,13 +378265,26 @@ async function pollForAnswer(params, threadId) {
377813
378265
  const deadline = now() + (params.timeoutMs ?? DEFAULT_ROUND_TRIP_TIMEOUT_MS);
377814
378266
  for (; ; ) {
377815
378267
  const attempt = await readAnswer(params, threadId);
377816
- if (attempt.kind !== "no-answer")
377817
- return attempt;
377818
- if (now() >= deadline)
377819
- return attempt;
378268
+ if (attempt.kind === "read-refused") {
378269
+ if (!isRetryableRead(attempt.status))
378270
+ return refusedRead(attempt);
378271
+ if (now() >= deadline)
378272
+ return refusedRead(attempt);
378273
+ } else {
378274
+ if (attempt.kind !== "no-answer")
378275
+ return attempt;
378276
+ if (now() >= deadline)
378277
+ return attempt;
378278
+ }
377820
378279
  await sleep3(POLL_INTERVAL_MS);
377821
378280
  }
377822
378281
  }
378282
+ function isRetryableRead(status) {
378283
+ return status === 404 || status >= 500;
378284
+ }
378285
+ function refusedRead(attempt) {
378286
+ return { kind: "unreachable", message: attempt.message };
378287
+ }
377823
378288
  async function startRun(params, sentThreadId) {
377824
378289
  const body = {
377825
378290
  context: [],
@@ -377836,14 +378301,14 @@ async function startRun(params, sentThreadId) {
377836
378301
  threadId: sentThreadId,
377837
378302
  tools: []
377838
378303
  };
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
- );
378304
+ const singleRoute = params.transport === "single-route";
378305
+ const url4 = singleRoute ? params.runtimeUrl.replace(/\/+$/u, "") : runtimeRouteUrl(params.runtimeUrl, `agent/${params.agentId}/run`);
378306
+ const payload = singleRoute ? { body, method: "agent/run", params: { agentId: params.agentId } } : body;
378307
+ const response = await params.fetchImpl(url4, {
378308
+ body: JSON.stringify(payload),
378309
+ headers: { "content-type": "application/json", ...params.headers },
378310
+ method: "POST"
378311
+ });
377847
378312
  if (!response.ok) {
377848
378313
  const message = await refusalMessage(response);
377849
378314
  return isIdentityRefusal(message) ? { kind: "user-not-identified", message } : { kind: "run-error", message };
@@ -377896,13 +378361,49 @@ async function drain(response) {
377896
378361
  }
377897
378362
  }
377898
378363
  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();
378364
+ const platform4 = params.transport === "single-route" ? params.platform : void 0;
378365
+ const readVia = platform4 === void 0 ? "app-mount" : "app-api";
378366
+ const request = platform4 === void 0 ? {
378367
+ init: params.headers === void 0 ? void 0 : { headers: params.headers },
378368
+ url: runtimeRouteUrl(params.runtimeUrl, `threads/${threadId}/messages`)
378369
+ } : {
378370
+ init: {
378371
+ headers: {
378372
+ accept: "application/json",
378373
+ authorization: `Bearer ${platform4.apiKey}`
378374
+ }
378375
+ },
378376
+ url: `${platform4.appApiUrl.replace(/\/+$/u, "")}/api/threads/${threadId}/messages`
378377
+ };
378378
+ const response = await params.fetchImpl(request.url, request.init);
378379
+ if (!response.ok) {
378380
+ return {
378381
+ kind: "read-refused",
378382
+ message: `${request.url} answered ${String(response.status)}${await refusalDetail(response)}`,
378383
+ status: response.status
378384
+ };
378385
+ }
378386
+ let payload;
378387
+ try {
378388
+ payload = await response.json();
378389
+ } catch {
378390
+ return {
378391
+ kind: "read-refused",
378392
+ message: `${request.url} did not answer JSON`,
378393
+ status: response.status
378394
+ };
378395
+ }
377904
378396
  const answer = lastAssistantAnswer(payload);
377905
- return answer === void 0 ? { kind: "no-answer", threadId } : { kind: "answered", threadId, ...answer };
378397
+ return answer === void 0 ? { kind: "no-answer", readVia, threadId } : { kind: "answered", readVia, threadId, ...answer };
378398
+ }
378399
+ async function refusalDetail(response) {
378400
+ try {
378401
+ const body = await response.json();
378402
+ const code = typeof body === "object" && body !== null && typeof body.error === "object" && body.error !== null && typeof body.error.code === "string" ? body.error.code : void 0;
378403
+ return code === void 0 ? "" : ` (${code})`;
378404
+ } catch {
378405
+ return "";
378406
+ }
377906
378407
  }
377907
378408
  function lastAssistantAnswer(payload) {
377908
378409
  const messages = typeof payload === "object" && payload !== null && "messages" in payload && Array.isArray(payload.messages) ? payload.messages : [];
@@ -377933,6 +378434,68 @@ var init_round_trip_probe = __esm({
377933
378434
  }
377934
378435
  });
377935
378436
 
378437
+ // apps/cli/src/services/learning-container-check.ts
378438
+ function redact(text2, apiKey) {
378439
+ return text2.split(apiKey).join("[redacted]");
378440
+ }
378441
+ async function checkLearningContainer(params) {
378442
+ const { apiKey } = params;
378443
+ if (apiKey === void 0) {
378444
+ return {
378445
+ kind: "not-attempted",
378446
+ message: "Not attempted: no Intelligence API key was resolved, and the thread read needs one."
378447
+ };
378448
+ }
378449
+ const url4 = `${params.appApiUrl.replace(/\/+$/u, "")}/api/threads/${params.threadId}`;
378450
+ let response;
378451
+ try {
378452
+ response = await params.fetchImpl(url4, {
378453
+ headers: { accept: "application/json", authorization: `Bearer ${apiKey}` },
378454
+ method: "GET"
378455
+ });
378456
+ } catch (error98) {
378457
+ const detail = error98 instanceof Error ? error98.message : String(error98);
378458
+ return {
378459
+ kind: "unreachable",
378460
+ message: `could not reach ${url4} (${redact(detail, apiKey)})`
378461
+ };
378462
+ }
378463
+ if (!response.ok) {
378464
+ return {
378465
+ kind: "unreachable",
378466
+ message: `${url4} answered ${String(response.status)}`
378467
+ };
378468
+ }
378469
+ let body;
378470
+ try {
378471
+ body = await response.json();
378472
+ } catch {
378473
+ return { kind: "unreachable", message: `${url4} did not answer JSON` };
378474
+ }
378475
+ const thread = typeof body === "object" && body !== null && typeof body.thread === "object" && body.thread !== null ? body.thread : void 0;
378476
+ if (thread === void 0) {
378477
+ return {
378478
+ kind: "unreachable",
378479
+ message: `${url4} answered 200 without a thread`
378480
+ };
378481
+ }
378482
+ const actual = typeof thread["learningContainerId"] === "string" ? thread["learningContainerId"] : void 0;
378483
+ if (actual === params.expected) {
378484
+ return { containerId: actual, kind: "proved", threadId: params.threadId };
378485
+ }
378486
+ return {
378487
+ actual,
378488
+ expected: params.expected,
378489
+ kind: "mismatch",
378490
+ threadId: params.threadId
378491
+ };
378492
+ }
378493
+ var init_learning_container_check = __esm({
378494
+ "apps/cli/src/services/learning-container-check.ts"() {
378495
+ "use strict";
378496
+ }
378497
+ });
378498
+
377936
378499
  // apps/cli/src/services/installed-packages.ts
377937
378500
  import { readFileSync as readFileSync16 } from "node:fs";
377938
378501
  import { dirname as dirname10, join as join21, sep } from "node:path";
@@ -378088,7 +378651,8 @@ function toRuntimeProbe(body, status, transport) {
378088
378651
  }
378089
378652
  );
378090
378653
  const wsUrl = parsed.data.intelligence?.wsUrl;
378091
- const mutations = parsed.data.threadEndpoints?.mutations;
378654
+ const singleRoute = parsed.data.singleRoute;
378655
+ const mutations = singleRoute === void 0 ? parsed.data.threadEndpoints?.mutations : singleRoute.threadEndpoints?.mutations;
378092
378656
  const info = {
378093
378657
  agents,
378094
378658
  ...parsed.data.audioFileTranscriptionEnabled === void 0 ? {} : {
@@ -378098,6 +378662,7 @@ function toRuntimeProbe(body, status, transport) {
378098
378662
  ...parsed.data.licenseStatus === void 0 ? {} : { licenseStatus: parsed.data.licenseStatus },
378099
378663
  ...parsed.data.runtimeEntitlements === void 0 ? {} : { runtimeEntitlements: parsed.data.runtimeEntitlements },
378100
378664
  openGenerativeUIEnabled: parsed.data.openGenerativeUIEnabled ?? false,
378665
+ ...singleRoute?.resourceOperations === void 0 ? {} : { singleRouteResourceOperations: singleRoute.resourceOperations },
378101
378666
  ...mutations === void 0 ? {} : { threadMutationsEnabled: mutations },
378102
378667
  version: parsed.data.version
378103
378668
  };
@@ -378241,6 +378806,15 @@ var init_verify_probes = __esm({
378241
378806
  licenseStatus: external_exports.string().optional(),
378242
378807
  runtimeEntitlements: external_exports.object({ status: external_exports.string().optional() }).loose().optional(),
378243
378808
  openGenerativeUIEnabled: external_exports.boolean().optional(),
378809
+ /**
378810
+ * Reported only by a single-route mount, from `@copilotkit/runtime` 1.70.2
378811
+ * onward. Its `threadEndpoints` describes the mount; the top-level one
378812
+ * describes the `info` call that carried this payload (OSS-1166).
378813
+ */
378814
+ singleRoute: external_exports.object({
378815
+ resourceOperations: external_exports.boolean().optional(),
378816
+ threadEndpoints: external_exports.object({ mutations: external_exports.boolean().optional() }).loose().optional()
378817
+ }).loose().optional(),
378244
378818
  threadEndpoints: external_exports.object({ mutations: external_exports.boolean().optional() }).loose().optional(),
378245
378819
  version: external_exports.string()
378246
378820
  });
@@ -378325,8 +378899,8 @@ function factRows(facts) {
378325
378899
  }
378326
378900
  return rows;
378327
378901
  }
378328
- function renderSummary(result, roundTrip) {
378329
- const all = [...result.checks, ...roundTrip ? [roundTrip] : []];
378902
+ function renderSummary(result, roundTrip, extra = []) {
378903
+ const all = [...result.checks, ...roundTrip ? [roundTrip] : [], ...extra];
378330
378904
  const passed = all.filter((check4) => check4.status === "pass").length;
378331
378905
  const failed2 = all.filter((check4) => check4.status === "fail").length;
378332
378906
  const unknown3 = all.filter(
@@ -378341,7 +378915,7 @@ function renderSummary(result, roundTrip) {
378341
378915
  }
378342
378916
  return parts.join(", ");
378343
378917
  }
378344
- function renderVerifyReport(result, context3, roundTrip) {
378918
+ function renderVerifyReport(result, context3, roundTrip, extra = []) {
378345
378919
  const urlNote = `Runtime URL: ${context3.runtimeUrl} ${describeRuntimeUrlSource(context3)}`;
378346
378920
  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
378921
  const lines = [
@@ -378361,6 +378935,10 @@ function renderVerifyReport(result, context3, roundTrip) {
378361
378935
  );
378362
378936
  lines.push(` ${roundTrip.detail}`);
378363
378937
  }
378938
+ for (const check4 of extra) {
378939
+ lines.push(` ${STATUS_LABELS[check4.status].padEnd(7)} ${check4.title}`);
378940
+ lines.push(` ${check4.detail}`);
378941
+ }
378364
378942
  const rows = factRows(result.facts);
378365
378943
  if (rows.length > 0) {
378366
378944
  const labelWidth = Math.max(...rows.map(([label]) => label.length));
@@ -378369,10 +378947,10 @@ function renderVerifyReport(result, context3, roundTrip) {
378369
378947
  lines.push(` ${label.padEnd(labelWidth)} ${value}`);
378370
378948
  }
378371
378949
  }
378372
- lines.push("", renderSummary(result, roundTrip), "");
378950
+ lines.push("", renderSummary(result, roundTrip, extra), "");
378373
378951
  return lines.join("\n");
378374
378952
  }
378375
- function renderVerifyJson(result, context3, roundTrip) {
378953
+ function renderVerifyJson(result, context3, roundTrip, extra = []) {
378376
378954
  return `${JSON.stringify(
378377
378955
  {
378378
378956
  checks: result.checks,
@@ -378380,8 +378958,9 @@ function renderVerifyJson(result, context3, roundTrip) {
378380
378958
  // `ok` answers "is this project proven", so a requested round trip that
378381
378959
  // did not pass makes it false. Omitting the round trip from the verdict
378382
378960
  // would let the strongest evidence in the report contradict its summary.
378383
- ok: result.ok && (roundTrip === void 0 || roundTrip.status === "pass"),
378961
+ ok: result.ok && (roundTrip === void 0 || roundTrip.status === "pass") && extra.every((check4) => check4.status === "pass"),
378384
378962
  ...roundTrip === void 0 ? {} : { roundTrip },
378963
+ ...extra.length === 0 ? {} : { extraChecks: extra },
378385
378964
  // The origin a caller opens, so it never composes one. Absent rather than
378386
378965
  // guessed when the project named no port (OSS-1126).
378387
378966
  ...context3.frontendUrl.url === void 0 ? {} : { frontendUrl: context3.frontendUrl.url },
@@ -378419,6 +378998,7 @@ function liveDependencies() {
378419
378998
  return {
378420
378999
  appApiUrl: getAppApiUrl(),
378421
379000
  cwd: process.cwd(),
379001
+ hostedGatewayUrl: getHostedGatewayUrl(),
378422
379002
  env: process.env,
378423
379003
  fetchImpl: fetch,
378424
379004
  newId: (prefix) => `${prefix}-${randomUUID8()}`,
@@ -378459,7 +379039,9 @@ async function runVerify(options, overrides = {}) {
378459
379039
  projectEnvValues: projectEnv.values,
378460
379040
  ...options.frontendUrl === void 0 ? {} : { flagUrl: options.frontendUrl }
378461
379041
  });
378462
- const appApiUrl = (mergedEnv["INTELLIGENCE_API_URL"] ?? "").trim() || deps.appApiUrl;
379042
+ const projectApiUrl = (mergedEnv["INTELLIGENCE_API_URL"] ?? "").trim();
379043
+ const appApiUrl = projectApiUrl || deps.appApiUrl;
379044
+ const pairedGatewayUrls = (projectApiUrl === "" ? [deps.hostedGatewayUrl] : [(mergedEnv["INTELLIGENCE_GATEWAY_WS_URL"] ?? "").trim()]).filter((url4) => url4 !== "");
378463
379045
  const corsApplies = options.frontendUrl !== void 0 && frontendUrlResolution.url !== void 0 && new URL(frontendUrlResolution.url).origin !== new URL(runtimeUrl).origin;
378464
379046
  const [credential, runtime, frontendAssets, cors] = await Promise.all([
378465
379047
  probeCredential(appApiUrl, apiKey?.key, deps.fetchImpl),
@@ -378503,6 +379085,11 @@ async function runVerify(options, overrides = {}) {
378503
379085
  frontendAssets,
378504
379086
  frontendUrl: frontendUrlResolution,
378505
379087
  installedPackages,
379088
+ intelligenceTarget: {
379089
+ pairedGatewayUrls,
379090
+ source: projectApiUrl === "" ? "cli-default" : "project-env",
379091
+ verifiedUrl: appApiUrl
379092
+ },
378506
379093
  projectConfig,
378507
379094
  runtime,
378508
379095
  runtimeUrl: runtimeUrlResolution
@@ -378511,24 +379098,89 @@ async function runVerify(options, overrides = {}) {
378511
379098
  );
378512
379099
  const roundTrip = expectedRuntime === "oss" && (options.roundTrip !== true || options.agent === void 0) ? notAttempted(
378513
379100
  "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;
379101
+ ) : options.roundTrip === true ? await runLiveRoundTrip(
379102
+ options,
379103
+ deps,
379104
+ runtimeUrlResolution,
379105
+ runtime,
379106
+ appApiUrl,
379107
+ apiKey?.key
379108
+ ) : void 0;
378515
379109
  const context3 = {
378516
379110
  frontendUrl: frontendUrlResolution,
378517
379111
  runtimeUrl,
378518
379112
  runtimeUrlSource: runtimeUrlResolution.source,
378519
379113
  ...runtimeUrlResolution.origin === void 0 ? {} : { runtimeUrlOrigin: runtimeUrlResolution.origin }
378520
379114
  };
379115
+ const learningContainer = options.expectLearningContainer === void 0 ? void 0 : await runLearningContainerCheck(
379116
+ options.expectLearningContainer,
379117
+ deps,
379118
+ appApiUrl,
379119
+ apiKey?.key,
379120
+ roundTrip
379121
+ );
379122
+ const extra = learningContainer === void 0 ? [] : [learningContainer];
378521
379123
  deps.stdout(
378522
- options.json ? renderVerifyJson(result, context3, roundTrip) : renderVerifyReport(result, context3, roundTrip)
379124
+ options.json ? renderVerifyJson(result, context3, roundTrip, extra) : renderVerifyReport(result, context3, roundTrip, extra)
378523
379125
  );
378524
- if (!result.ok || roundTrip !== void 0 && roundTrip.status !== "pass") {
379126
+ if (!result.ok || roundTrip !== void 0 && roundTrip.status !== "pass" || extra.some((check4) => check4.status !== "pass")) {
378525
379127
  process.exitCode = 1;
378526
379128
  }
378527
379129
  }
378528
- async function runLiveRoundTrip(options, deps, runtimeUrl, runtime) {
378529
- if (runtime.kind === "ok" && runtime.transport === "single-route") {
379130
+ async function runLearningContainerCheck(expected, deps, appApiUrl, apiKey, roundTrip) {
379131
+ const base = {
379132
+ id: "learning_container_assigned",
379133
+ title: LEARNING_TITLE
379134
+ };
379135
+ const threadId = roundTrip?.evidence?.threadId;
379136
+ if (threadId === void 0) {
379137
+ deps.recordLearningContainerCheck?.({ outcome: "undetermined" });
379138
+ return {
379139
+ ...base,
379140
+ 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.",
379141
+ status: "undetermined"
379142
+ };
379143
+ }
379144
+ const checked = await checkLearningContainer({
379145
+ apiKey,
379146
+ // The resolved host, not the build-time default. A project that names
379147
+ // `INTELLIGENCE_API_URL` — a self-hosted deployment, or a test standing up
379148
+ // a stub — is the project this check must ask about.
379149
+ appApiUrl,
379150
+ expected,
379151
+ fetchImpl: deps.fetchImpl,
379152
+ threadId
379153
+ });
379154
+ if (checked.kind === "proved") {
379155
+ deps.recordLearningContainerCheck?.({ outcome: "proved" });
379156
+ return {
379157
+ ...base,
379158
+ 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.`,
379159
+ status: "pass"
379160
+ };
379161
+ }
379162
+ if (checked.kind === "mismatch") {
379163
+ deps.recordLearningContainerCheck?.({
379164
+ outcome: checked.actual === void 0 ? "unassigned" : "other-container"
379165
+ });
379166
+ return {
379167
+ ...base,
379168
+ 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.`,
379169
+ status: "fail"
379170
+ };
379171
+ }
379172
+ deps.recordLearningContainerCheck?.({ outcome: "undetermined" });
379173
+ return {
379174
+ ...base,
379175
+ detail: `Not proven: ${checked.message}`,
379176
+ status: "undetermined"
379177
+ };
379178
+ }
379179
+ async function runLiveRoundTrip(options, deps, runtimeUrl, runtime, appApiUrl, apiKey) {
379180
+ const singleRoute = runtime.kind === "ok" && runtime.transport === "single-route";
379181
+ if (singleRoute && apiKey === void 0) {
378530
379182
  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.'
379183
+ "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
379184
  );
378533
379185
  }
378534
379186
  const declared = runtime.kind === "ok" ? runtime.info.agents : [];
@@ -378553,6 +379205,10 @@ async function runLiveRoundTrip(options, deps, runtimeUrl, runtime) {
378553
379205
  const probe = await probeRoundTrip({
378554
379206
  agentId,
378555
379207
  fetchImpl: deps.fetchImpl,
379208
+ ...singleRoute ? {
379209
+ platform: { apiKey: apiKey ?? "", appApiUrl },
379210
+ transport: "single-route"
379211
+ } : {},
378556
379212
  newId: deps.newId,
378557
379213
  newThreadId: deps.newThreadId,
378558
379214
  runtimeUrl: runtimeUrl.url,
@@ -378570,6 +379226,7 @@ function notAttempted(detail) {
378570
379226
  title: "The agent answers a real request"
378571
379227
  };
378572
379228
  }
379229
+ var LEARNING_TITLE;
378573
379230
  var init_verify = __esm({
378574
379231
  "apps/cli/src/commands/verify.ts"() {
378575
379232
  "use strict";
@@ -378579,6 +379236,7 @@ var init_verify = __esm({
378579
379236
  init_project_env();
378580
379237
  init_round_trip_checks();
378581
379238
  init_round_trip_probe();
379239
+ init_learning_container_check();
378582
379240
  init_verify_checks();
378583
379241
  init_installed_packages();
378584
379242
  init_verify_probes();
@@ -378586,6 +379244,7 @@ var init_verify = __esm({
378586
379244
  init_runtime_url();
378587
379245
  init_frontend_url();
378588
379246
  init_runtime_url();
379247
+ LEARNING_TITLE = "The run is assigned to the Learning Container";
378589
379248
  }
378590
379249
  });
378591
379250
 
@@ -384520,6 +385179,7 @@ async function runLoginJson(dependencies = {
384520
385179
  login,
384521
385180
  recordEvent: recordTelemetryEvent,
384522
385181
  readAuthIdentity: currentAuthIdentity,
385182
+ readCodingAgent: currentOnboardingCodingAgent,
384523
385183
  readOnboardingRun: currentOnboardingRunProperties
384524
385184
  }) {
384525
385185
  try {
@@ -384533,8 +385193,13 @@ async function runLoginJson(dependencies = {
384533
385193
  return;
384534
385194
  }
384535
385195
  let loginUrlWritten = false;
385196
+ const codingAgent = dependencies.readCodingAgent();
384536
385197
  await dependencies.login({
384537
- authHandoff: { source: "cli", mode: "agent_onboarding" },
385198
+ authHandoff: {
385199
+ source: "cli",
385200
+ mode: "agent_onboarding",
385201
+ ...codingAgent === void 0 ? {} : { agent: codingAgent }
385202
+ },
384538
385203
  openBrowser: false,
384539
385204
  onLoginUrl: (url4) => {
384540
385205
  if (loginUrlWritten) {
@@ -384994,6 +385659,8 @@ var init_onboarding_checkpoint = __esm({
384994
385659
  "research-returned",
384995
385660
  "starter-cloned",
384996
385661
  "plan-written",
385662
+ "container-surveyed",
385663
+ "container-settled",
384997
385664
  "build-validated",
384998
385665
  "journey-attempted",
384999
385666
  "repair-attempted"
@@ -385005,13 +385672,70 @@ var init_onboarding_checkpoint = __esm({
385005
385672
  // apps/cli/src/services/onboarding-protected-paths.ts
385006
385673
  import { execFileSync as execFileSync5 } from "node:child_process";
385007
385674
  import { createHash as createHash7 } from "node:crypto";
385008
- import { existsSync as existsSync24, readFileSync as readFileSync24, statSync as statSync4 } from "node:fs";
385675
+ import { existsSync as existsSync24, readFileSync as readFileSync24, readdirSync as readdirSync4, statSync as statSync4 } from "node:fs";
385009
385676
  import { isAbsolute, join as join31, relative as relative3, resolve as resolve7, sep as sep3 } from "node:path";
385677
+ function deriveProjectFiles(root2) {
385678
+ const found = [];
385679
+ const pending = [root2];
385680
+ while (pending.length > 0) {
385681
+ const directory = pending.pop();
385682
+ if (directory === void 0)
385683
+ break;
385684
+ let entries;
385685
+ try {
385686
+ entries = readdirSync4(directory, { withFileTypes: true });
385687
+ } catch {
385688
+ continue;
385689
+ }
385690
+ for (const entry of entries) {
385691
+ const absolute = join31(directory, entry.name);
385692
+ if (entry.isDirectory()) {
385693
+ if (!SKIPPED_DIRECTORIES3.has(entry.name))
385694
+ pending.push(absolute);
385695
+ continue;
385696
+ }
385697
+ const relativePath = toRepositoryRelative(root2, absolute);
385698
+ if (relativePath !== void 0)
385699
+ found.push(relativePath);
385700
+ }
385701
+ }
385702
+ return found;
385703
+ }
385010
385704
  function isGraphOwned(relativePath) {
385011
385705
  return GRAPH_OWNED_SUFFIXES.some(
385012
385706
  (suffix) => relativePath === suffix || relativePath.endsWith(`/${suffix}`)
385013
385707
  );
385014
385708
  }
385709
+ function isEnvPath(relativePath) {
385710
+ return relativePath === ".env" || relativePath.endsWith("/.env");
385711
+ }
385712
+ function envKeysOf(root2, relativePath) {
385713
+ const absolute = join31(root2, relativePath);
385714
+ try {
385715
+ if (!existsSync24(absolute))
385716
+ return [];
385717
+ const values = readDotEnvValues(readFileSync24(absolute, "utf8"));
385718
+ return Object.entries(values).map(([name, value]) => ({
385719
+ name,
385720
+ hasValue: value.trim() !== ""
385721
+ }));
385722
+ } catch {
385723
+ return "unreadable";
385724
+ }
385725
+ }
385726
+ function lostCredentials(recorded, current) {
385727
+ const now = new Map(current.map((key) => [key.name, key.hasValue]));
385728
+ return recorded.filter((key) => key.hasValue && now.get(key.name) !== true).map((key) => key.name);
385729
+ }
385730
+ function isEnvKeyList(value) {
385731
+ if (value === void 0)
385732
+ return true;
385733
+ if (!Array.isArray(value))
385734
+ return false;
385735
+ return value.every(
385736
+ (key) => typeof key === "object" && key !== null && typeof key.name === "string" && typeof key.hasValue === "boolean"
385737
+ );
385738
+ }
385015
385739
  function isAcceptedDrift(value) {
385016
385740
  if (value === void 0)
385017
385741
  return true;
@@ -385026,7 +385750,7 @@ function isPathAuthorization(value) {
385026
385750
  if (typeof value !== "object" || value === null)
385027
385751
  return false;
385028
385752
  const candidate = value;
385029
- return typeof candidate.reason === "string" && typeof candidate.at === "string";
385753
+ return typeof candidate.reason === "string" && typeof candidate.at === "string" && (candidate.unplanned === void 0 || candidate.unplanned === true);
385030
385754
  }
385031
385755
  function changeBetween(captured, current) {
385032
385756
  if (captured === void 0)
@@ -385059,13 +385783,19 @@ function readManifest(dependencies) {
385059
385783
  return "malformed";
385060
385784
  if (typeof stored.capturedAt !== "string")
385061
385785
  return "malformed";
385786
+ if (stored.implementationStartedAt !== void 0 && typeof stored.implementationStartedAt !== "string") {
385787
+ return "malformed";
385788
+ }
385062
385789
  if (!Array.isArray(stored.entries))
385063
385790
  return "malformed";
385064
385791
  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)
385792
+ (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
385793
  );
385067
385794
  return wellFormed ? stored : "malformed";
385068
385795
  }
385796
+ function startedMark(stored) {
385797
+ return stored?.implementationStartedAt === void 0 ? {} : { implementationStartedAt: stored.implementationStartedAt };
385798
+ }
385069
385799
  function digestOf(root2, relativePath) {
385070
385800
  const absolute = join31(root2, relativePath);
385071
385801
  try {
@@ -385084,8 +385814,8 @@ function byPath(entries) {
385084
385814
  );
385085
385815
  }
385086
385816
  function deriveChangedPaths(root2) {
385087
- if (!existsSync24(join31(root2, ".git")))
385088
- return [];
385817
+ if (findRepositoryRoot(root2) === void 0)
385818
+ return "no-repository";
385089
385819
  let output;
385090
385820
  try {
385091
385821
  output = execFileSync5(
@@ -385140,10 +385870,14 @@ function captureEntry(root2, relativePath, derived) {
385140
385870
  const read = digestOf(root2, relativePath);
385141
385871
  if (read === "unreadable")
385142
385872
  return "unreadable";
385873
+ const envKeys = isEnvPath(relativePath) ? envKeysOf(root2, relativePath) : void 0;
385874
+ if (envKeys === "unreadable")
385875
+ return "unreadable";
385143
385876
  return {
385144
385877
  path: relativePath,
385145
385878
  pathClass: derived && isGraphOwned(relativePath) ? "deferred" : "protected",
385146
- ...read.digest === void 0 ? {} : { digest: read.digest }
385879
+ ...read.digest === void 0 ? {} : { digest: read.digest },
385880
+ ...envKeys === void 0 ? {} : { envKeys }
385147
385881
  };
385148
385882
  }
385149
385883
  function captureProtectedPaths(dependencies, input) {
@@ -385181,7 +385915,8 @@ function captureProtectedPaths(dependencies, input) {
385181
385915
  if (changed === "failed") {
385182
385916
  return { status: "blocked", reason: "git-failed", detail: root2 };
385183
385917
  }
385184
- for (const path45 of changed)
385918
+ const derived = changed === "no-repository" ? deriveProjectFiles(root2) : changed;
385919
+ for (const path45 of derived)
385185
385920
  candidates.add(path45);
385186
385921
  for (const path45 of probeGraphOwned(root2, dependencies.cwd)) {
385187
385922
  candidates.add(path45);
@@ -385204,6 +385939,7 @@ function captureProtectedPaths(dependencies, input) {
385204
385939
  dependencies.store.set(protectedBaselineKey(dependencies), {
385205
385940
  runId: input.runId,
385206
385941
  capturedAt: ownBaseline?.capturedAt ?? (/* @__PURE__ */ new Date()).toISOString(),
385942
+ ...startedMark(ownBaseline),
385207
385943
  entries
385208
385944
  });
385209
385945
  return {
@@ -385318,10 +386054,19 @@ function rebaselineProtectedPaths(dependencies, input) {
385318
386054
  detail: entry.path
385319
386055
  };
385320
386056
  }
386057
+ const promotedKeys = isEnvPath(entry.path) ? envKeysOf(root2, entry.path) : void 0;
386058
+ if (promotedKeys === "unreadable") {
386059
+ return {
386060
+ status: "blocked",
386061
+ reason: "unreadable-path",
386062
+ detail: entry.path
386063
+ };
386064
+ }
385321
386065
  const next = {
385322
386066
  path: entry.path,
385323
386067
  pathClass: "protected",
385324
- ...read.digest === void 0 ? {} : { digest: read.digest }
386068
+ ...read.digest === void 0 ? {} : { digest: read.digest },
386069
+ ...promotedKeys === void 0 ? {} : { envKeys: promotedKeys }
385325
386070
  };
385326
386071
  entries.push(next);
385327
386072
  promoted.push(next);
@@ -385329,6 +386074,7 @@ function rebaselineProtectedPaths(dependencies, input) {
385329
386074
  dependencies.store.set(protectedBaselineKey(dependencies), {
385330
386075
  runId: stored.runId,
385331
386076
  capturedAt: stored.capturedAt,
386077
+ ...startedMark(stored),
385332
386078
  entries: byPath(entries)
385333
386079
  });
385334
386080
  return { status: "passed", runId: stored.runId, promoted: byPath(promoted) };
@@ -385436,16 +386182,166 @@ function acceptProtectedPathDrift(dependencies, input) {
385436
386182
  path: entry.path,
385437
386183
  pathClass: entry.pathClass,
385438
386184
  ...digest === void 0 ? {} : { digest },
386185
+ // Carried rather than rebuilt. No env path reaches here today, because
386186
+ // every one of them is graph-owned and refused above. That is a guard one
386187
+ // edit away from changing, and dropping the record would leave the
386188
+ // credential route refusing `unrecorded-keys` on a path it should answer.
386189
+ ...entry.envKeys === void 0 ? {} : { envKeys: entry.envKeys },
385439
386190
  acceptedDrift
385440
386191
  });
385441
386192
  }
385442
386193
  dependencies.store.set(protectedBaselineKey(dependencies), {
385443
386194
  runId: stored.runId,
385444
386195
  capturedAt: stored.capturedAt,
386196
+ ...startedMark(stored),
386197
+ entries: byPath(entries)
386198
+ });
386199
+ return { status: "passed", runId: stored.runId, accepted: byPath(accepted) };
386200
+ }
386201
+ function acceptCredentialPlacement(dependencies, input) {
386202
+ const root2 = resolveAnchoredRoot(dependencies);
386203
+ const stored = readManifest(dependencies);
386204
+ if (stored === void 0) {
386205
+ return { status: "blocked", reason: "no-baseline", detail: input.runId };
386206
+ }
386207
+ if (stored === "malformed") {
386208
+ return {
386209
+ status: "blocked",
386210
+ reason: "unreadable-baseline",
386211
+ detail: input.runId
386212
+ };
386213
+ }
386214
+ if (stored.runId !== input.runId) {
386215
+ return { status: "blocked", reason: "run-mismatch", detail: stored.runId };
386216
+ }
386217
+ const at = (/* @__PURE__ */ new Date()).toISOString();
386218
+ const placed = /* @__PURE__ */ new Map();
386219
+ const accepted = [];
386220
+ for (const path45 of input.paths) {
386221
+ const absolute = isAbsolute(path45) ? path45 : resolve7(dependencies.cwd, path45);
386222
+ const relativePath = toRepositoryRelative(root2, absolute);
386223
+ if (relativePath === void 0) {
386224
+ return { status: "blocked", reason: "unknown-path", detail: path45 };
386225
+ }
386226
+ if (placed.has(relativePath))
386227
+ continue;
386228
+ if (!isEnvPath(relativePath)) {
386229
+ return { status: "blocked", reason: "not-env-path", detail: relativePath };
386230
+ }
386231
+ const entry = stored.entries.find((held) => held.path === relativePath);
386232
+ if (entry === void 0) {
386233
+ return { status: "blocked", reason: "unknown-path", detail: relativePath };
386234
+ }
386235
+ if (entry.pathClass === "deferred") {
386236
+ return {
386237
+ status: "blocked",
386238
+ reason: "deferred-path",
386239
+ detail: relativePath
386240
+ };
386241
+ }
386242
+ const read = digestOf(root2, relativePath);
386243
+ if (read === "unreadable") {
386244
+ return {
386245
+ status: "blocked",
386246
+ reason: "unreadable-path",
386247
+ detail: relativePath
386248
+ };
386249
+ }
386250
+ if (read.digest === entry.digest) {
386251
+ return {
386252
+ status: "blocked",
386253
+ reason: "unchanged-path",
386254
+ detail: relativePath
386255
+ };
386256
+ }
386257
+ const current = envKeysOf(root2, relativePath);
386258
+ if (current === "unreadable") {
386259
+ return {
386260
+ status: "blocked",
386261
+ reason: "unreadable-path",
386262
+ detail: relativePath
386263
+ };
386264
+ }
386265
+ if (entry.envKeys === void 0) {
386266
+ return {
386267
+ status: "blocked",
386268
+ reason: "unrecorded-keys",
386269
+ detail: relativePath
386270
+ };
386271
+ }
386272
+ const lost = lostCredentials(entry.envKeys, current);
386273
+ if (lost.length > 0) {
386274
+ return {
386275
+ status: "blocked",
386276
+ reason: "credential-lost",
386277
+ detail: `${relativePath}: ${lost.join(", ")}`
386278
+ };
386279
+ }
386280
+ const change = changeBetween(entry.digest, read.digest);
386281
+ placed.set(relativePath, {
386282
+ change,
386283
+ at,
386284
+ envKeys: current,
386285
+ ...read.digest === void 0 ? {} : { digest: read.digest }
386286
+ });
386287
+ accepted.push({ path: relativePath, change, at });
386288
+ }
386289
+ const entries = [];
386290
+ for (const entry of stored.entries) {
386291
+ const moved = placed.get(entry.path);
386292
+ if (moved === void 0) {
386293
+ entries.push(entry);
386294
+ continue;
386295
+ }
386296
+ const { digest, envKeys, ...acceptedDrift } = moved;
386297
+ entries.push({
386298
+ path: entry.path,
386299
+ pathClass: entry.pathClass,
386300
+ ...digest === void 0 ? {} : { digest },
386301
+ ...entry.authorization === void 0 ? {} : { authorization: entry.authorization },
386302
+ acceptedDrift,
386303
+ envKeys
386304
+ });
386305
+ }
386306
+ dependencies.store.set(protectedBaselineKey(dependencies), {
386307
+ runId: stored.runId,
386308
+ capturedAt: stored.capturedAt,
386309
+ ...startedMark(stored),
385445
386310
  entries: byPath(entries)
385446
386311
  });
385447
386312
  return { status: "passed", runId: stored.runId, accepted: byPath(accepted) };
385448
386313
  }
386314
+ function markImplementationStarted(dependencies, input) {
386315
+ const stored = readManifest(dependencies);
386316
+ if (stored === void 0) {
386317
+ return { status: "blocked", reason: "no-baseline", detail: input.runId };
386318
+ }
386319
+ if (stored === "malformed") {
386320
+ return {
386321
+ status: "blocked",
386322
+ reason: "unreadable-baseline",
386323
+ detail: input.runId
386324
+ };
386325
+ }
386326
+ if (stored.runId !== input.runId) {
386327
+ return { status: "blocked", reason: "run-mismatch", detail: stored.runId };
386328
+ }
386329
+ if (stored.implementationStartedAt !== void 0) {
386330
+ return {
386331
+ status: "passed",
386332
+ runId: stored.runId,
386333
+ startedAt: stored.implementationStartedAt
386334
+ };
386335
+ }
386336
+ const startedAt = (/* @__PURE__ */ new Date()).toISOString();
386337
+ dependencies.store.set(protectedBaselineKey(dependencies), {
386338
+ runId: stored.runId,
386339
+ capturedAt: stored.capturedAt,
386340
+ implementationStartedAt: startedAt,
386341
+ entries: stored.entries
386342
+ });
386343
+ return { status: "passed", runId: stored.runId, startedAt };
386344
+ }
385449
386345
  function authorizeProtectedPathChange(dependencies, input) {
385450
386346
  const root2 = resolveAnchoredRoot(dependencies);
385451
386347
  const stored = readManifest(dependencies);
@@ -385468,6 +386364,7 @@ function authorizeProtectedPathChange(dependencies, input) {
385468
386364
  }
385469
386365
  const at = (/* @__PURE__ */ new Date()).toISOString();
385470
386366
  const granted = /* @__PURE__ */ new Map();
386367
+ const priorDrift = /* @__PURE__ */ new Map();
385471
386368
  const authorized = [];
385472
386369
  for (const path45 of input.paths) {
385473
386370
  const absolute = isAbsolute(path45) ? path45 : resolve7(dependencies.cwd, path45);
@@ -385495,6 +386392,24 @@ function authorizeProtectedPathChange(dependencies, input) {
385495
386392
  detail: relativePath
385496
386393
  };
385497
386394
  }
386395
+ const started = stored.implementationStartedAt !== void 0;
386396
+ if (started && input.unplanned !== true) {
386397
+ return {
386398
+ status: "blocked",
386399
+ reason: "unplanned-path",
386400
+ detail: relativePath
386401
+ };
386402
+ }
386403
+ if (!started && input.unplanned === true) {
386404
+ return { status: "blocked", reason: "planned-path", detail: relativePath };
386405
+ }
386406
+ if (started && input.acceptPriorChange === true) {
386407
+ return {
386408
+ status: "blocked",
386409
+ reason: "prior-change-after-start",
386410
+ detail: relativePath
386411
+ };
386412
+ }
385498
386413
  const read = digestOf(root2, relativePath);
385499
386414
  if (read === "unreadable") {
385500
386415
  return {
@@ -385504,18 +386419,45 @@ function authorizeProtectedPathChange(dependencies, input) {
385504
386419
  };
385505
386420
  }
385506
386421
  if (read.digest !== entry.digest) {
385507
- return { status: "blocked", reason: "changed-path", detail: relativePath };
386422
+ if (input.acceptPriorChange !== true) {
386423
+ return {
386424
+ status: "blocked",
386425
+ reason: "changed-path",
386426
+ detail: relativePath
386427
+ };
386428
+ }
386429
+ priorDrift.set(relativePath, {
386430
+ change: changeBetween(entry.digest, read.digest),
386431
+ at,
386432
+ ...read.digest === void 0 ? {} : { digest: read.digest }
386433
+ });
385508
386434
  }
385509
- granted.set(relativePath, { reason, at });
385510
- authorized.push({ path: relativePath, reason, at });
386435
+ const authorization = input.unplanned === true ? { reason, at, unplanned: true } : { reason, at };
386436
+ granted.set(relativePath, authorization);
386437
+ authorized.push({ path: relativePath, ...authorization });
385511
386438
  }
385512
386439
  const entries = stored.entries.map((entry) => {
385513
386440
  const authorization = granted.get(entry.path);
385514
- return authorization === void 0 ? entry : { ...entry, authorization };
386441
+ if (authorization === void 0)
386442
+ return entry;
386443
+ const moved = priorDrift.get(entry.path);
386444
+ if (moved === void 0)
386445
+ return { ...entry, authorization };
386446
+ const { digest, ...acceptedDrift } = moved;
386447
+ return {
386448
+ path: entry.path,
386449
+ pathClass: entry.pathClass,
386450
+ ...digest === void 0 ? {} : { digest },
386451
+ // Carried for the same reason as in the acceptance route above.
386452
+ ...entry.envKeys === void 0 ? {} : { envKeys: entry.envKeys },
386453
+ acceptedDrift,
386454
+ authorization
386455
+ };
385515
386456
  });
385516
386457
  dependencies.store.set(protectedBaselineKey(dependencies), {
385517
386458
  runId: stored.runId,
385518
386459
  capturedAt: stored.capturedAt,
386460
+ ...startedMark(stored),
385519
386461
  entries: byPath(entries)
385520
386462
  });
385521
386463
  return {
@@ -385524,26 +386466,55 @@ function authorizeProtectedPathChange(dependencies, input) {
385524
386466
  authorized: byPath(authorized)
385525
386467
  };
385526
386468
  }
385527
- var GRAPH_OWNED_SUFFIXES;
386469
+ var SKIPPED_DIRECTORIES3, GRAPH_OWNED_SUFFIXES;
385528
386470
  var init_onboarding_protected_paths = __esm({
385529
386471
  "apps/cli/src/services/onboarding-protected-paths.ts"() {
385530
386472
  "use strict";
386473
+ init_dotenv_read();
386474
+ init_repository_root();
385531
386475
  init_onboarding_state();
386476
+ SKIPPED_DIRECTORIES3 = /* @__PURE__ */ new Set([
386477
+ "node_modules",
386478
+ "dist",
386479
+ "build",
386480
+ "out",
386481
+ "coverage",
386482
+ ".next",
386483
+ "venv",
386484
+ "__pycache__"
386485
+ ]);
385532
386486
  GRAPH_OWNED_SUFFIXES = [".env", ".copilotkit/project.json"];
385533
386487
  }
385534
386488
  });
385535
386489
 
385536
386490
  // apps/cli/src/services/onboarding-classification.ts
385537
- function unprovenBaselineRefusal(startingState, route) {
385538
- if (startingState !== "both-oss")
386491
+ function unprovenBaselineRefusal(startingState, route, proof) {
386492
+ if (startingState !== "both-oss" && startingState !== "both-copilotkit-unproved") {
385539
386493
  return void 0;
385540
- if (route.length === 0)
386494
+ }
386495
+ if (route.length > 0 && !route.includes(OSS_BASELINE_NODE)) {
386496
+ return `--starting-state ${startingState} records a project whose CopilotKit integration was reached, and this run never served ${OSS_BASELINE_NODE}.
386497
+ Its route is: ${route.join(",")}.
386498
+ Read ${OSS_BASELINE_NODE} and record the state its proof returns.`;
386499
+ }
386500
+ if (proof === void 0)
385541
386501
  return void 0;
385542
- if (route.includes(OSS_BASELINE_NODE))
386502
+ if (startingState === "both-oss") {
386503
+ return proof.outcome === "passed" ? void 0 : `--starting-state both-oss records a proved OSS baseline, and this run recorded that baseline as ${proof.outcome}.
386504
+ Record --starting-state both-copilotkit-unproved instead: the CopilotKit integration is present and its round trip did not prove.`;
386505
+ }
386506
+ 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.
386507
+ Record --starting-state both-oss instead, and keep the proof evidence with the plan.` : void 0;
386508
+ }
386509
+ function contradictedIntegrationRefusal(startingState, route) {
386510
+ if (!ABSENCE_STATES.some((state) => state === startingState)) {
386511
+ return void 0;
386512
+ }
386513
+ if (!route.includes(OSS_BASELINE_NODE))
385543
386514
  return void 0;
385544
- return `--starting-state both-oss records a proved OSS baseline, and this run never served ${OSS_BASELINE_NODE}.
386515
+ 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.
385545
386516
  Its route is: ${route.join(",")}.
385546
- Read ${OSS_BASELINE_NODE} and record the state its proof returns.`;
386517
+ Record --starting-state both-oss for a baseline that proved, or --starting-state both-copilotkit-unproved for one that did not.`;
385547
386518
  }
385548
386519
  function unresearchedBaselineWarning(promptName, route) {
385549
386520
  if (promptName !== OSS_BASELINE_NODE)
@@ -385563,7 +386534,7 @@ function requireOnboardingChoice(flag, value, choices) {
385563
386534
  }
385564
386535
  return selected;
385565
386536
  }
385566
- var ONBOARDING_STARTING_STATES, ONBOARDING_AGENT_FRAMEWORKS, ONBOARDING_FRONTENDS, OSS_BASELINE_NODE, TERMINAL_NODES, REPOSITORY_RESEARCH_NODE;
386537
+ var ONBOARDING_STARTING_STATES, ONBOARDING_AGENT_FRAMEWORKS, ONBOARDING_FRONTENDS, ONBOARDING_PROOF_STEPS, ONBOARDING_PROOF_OUTCOMES, ABSENCE_STATES, OSS_BASELINE_NODE, TERMINAL_NODES, REPOSITORY_RESEARCH_NODE;
385567
386538
  var init_onboarding_classification = __esm({
385568
386539
  "apps/cli/src/services/onboarding-classification.ts"() {
385569
386540
  "use strict";
@@ -385572,6 +386543,7 @@ var init_onboarding_classification = __esm({
385572
386543
  "agent-only",
385573
386544
  "frontend-only",
385574
386545
  "both",
386546
+ "both-copilotkit-unproved",
385575
386547
  "both-oss"
385576
386548
  ];
385577
386549
  ONBOARDING_AGENT_FRAMEWORKS = [
@@ -385602,6 +386574,18 @@ var init_onboarding_classification = __esm({
385602
386574
  "vue",
385603
386575
  "react-native"
385604
386576
  ];
386577
+ ONBOARDING_PROOF_STEPS = ["oss-baseline", "round-trip"];
386578
+ ONBOARDING_PROOF_OUTCOMES = [
386579
+ "passed",
386580
+ "failed",
386581
+ "skipped"
386582
+ ];
386583
+ ABSENCE_STATES = [
386584
+ "empty",
386585
+ "agent-only",
386586
+ "frontend-only",
386587
+ "both"
386588
+ ];
385605
386589
  OSS_BASELINE_NODE = "proof/oss-baseline";
385606
386590
  TERMINAL_NODES = {
385607
386591
  "fallback/best-effort": "best-effort",
@@ -385780,7 +386764,7 @@ async function runOnboard(argv, dependencies) {
385780
386764
  deps,
385781
386765
  () => deps.loadStartPrompt(parsed.values.intent)
385782
386766
  );
385783
- const binding2 = startOnboardingRun(
386767
+ const binding = startOnboardingRun(
385784
386768
  {
385785
386769
  cwd: deps.cwd,
385786
386770
  store: deps.store,
@@ -385791,14 +386775,39 @@ async function runOnboard(argv, dependencies) {
385791
386775
  );
385792
386776
  recordStarted(
385793
386777
  deps,
385794
- binding2.runId,
386778
+ binding.runId,
385795
386779
  "start",
385796
- binding2.idOrigin,
386780
+ binding.idOrigin,
385797
386781
  parsed.values["coding-agent"]
385798
386782
  );
385799
- printRunId(deps, binding2.runId);
386783
+ if (parsed.values["coding-agent"] !== void 0) {
386784
+ recordCodingAgentBestEffort(
386785
+ deps,
386786
+ binding.runId,
386787
+ parsed.values["coding-agent"]
386788
+ );
386789
+ }
386790
+ printRunId(deps, binding.runId);
385800
386791
  await printGraphTree(deps);
385801
- writePrompt(deps, binding2.runId, startPrompt);
386792
+ writePrompt(deps, binding.runId, startPrompt);
386793
+ return;
386794
+ }
386795
+ if (subcommand === "identify") {
386796
+ const parsed = parseIdentify(argv.slice(1));
386797
+ const runId2 = requireBoundRun(deps, IDENTIFY_RUN_NOT_BOUND);
386798
+ recordCodingAgentBestEffort(deps, runId2, parsed.codingAgent);
386799
+ recordBestEffort(deps, {
386800
+ event: "cli.onboarding.identified",
386801
+ properties: {
386802
+ command: "onboard",
386803
+ ...onboardingIntentProperties(deps),
386804
+ onboarding_run_id: runId2,
386805
+ cli_version: deps.cliVersion,
386806
+ coding_agent: normalizeCodingAgent(parsed.codingAgent)
386807
+ }
386808
+ });
386809
+ deps.stdout.write(`Coding agent recorded for run ${runId2}.
386810
+ `);
385802
386811
  return;
385803
386812
  }
385804
386813
  if (subcommand === "route") {
@@ -385812,23 +386821,21 @@ async function runOnboard(argv, dependencies) {
385812
386821
  if (argv.length !== 2 || promptName === void 0) {
385813
386822
  throw new Error("Usage: copilotkit onboard read <prompt-name>");
385814
386823
  }
385815
- await printPrompt(deps, requireBoundRun(deps), promptName);
386824
+ await printPrompt(
386825
+ deps,
386826
+ requireBoundRun(deps, READ_RUN_NOT_BOUND),
386827
+ promptName
386828
+ );
385816
386829
  return;
385817
386830
  }
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
386831
+ if (subcommand === void 0 || !ONBOARD_SUBCOMMANDS.includes(subcommand)) {
386832
+ throw new Error(
386833
+ `Usage: copilotkit onboard <${ONBOARD_SUBCOMMANDS.join("|")}>`
385830
386834
  );
385831
386835
  }
386836
+ const runId = readOnboardingRunId({ cwd: deps.cwd, store: deps.store });
386837
+ if (runId === void 0)
386838
+ throw new Error(STEP_RUN_NOT_BOUND);
385832
386839
  if (subcommand === "complete") {
385833
386840
  const opened = parseFrontendUrl(argv.slice(1));
385834
386841
  if (opened === void 0)
@@ -385839,14 +386846,14 @@ async function runOnboard(argv, dependencies) {
385839
386846
  const check4 = parseSurfaceCheck(blocked2.rest);
385840
386847
  if (check4 === void 0)
385841
386848
  throw new Error(SURFACE_CHECK_USAGE);
385842
- const accepted = readAcceptedDriftBestEffort(deps, binding.runId);
385843
- const authorized = readAuthorizationsBestEffort(deps, binding.runId);
386849
+ const accepted = readAcceptedDriftBestEffort(deps, runId);
386850
+ const authorized = readAuthorizationsBestEffort(deps, runId);
385844
386851
  recordBestEffort(deps, {
385845
386852
  event: "cli.onboarding.completed",
385846
386853
  properties: {
385847
386854
  command: "onboard",
385848
386855
  ...onboardingIntentProperties(deps),
385849
- onboarding_run_id: binding.runId,
386856
+ onboarding_run_id: runId,
385850
386857
  cli_version: deps.cliVersion,
385851
386858
  accepted_count: accepted.length,
385852
386859
  authorized_count: authorized.length,
@@ -385882,7 +386889,7 @@ async function runOnboard(argv, dependencies) {
385882
386889
  const requestedFramework = parsed.values["agent-framework"];
385883
386890
  const startingState = reportingRefusal(
385884
386891
  deps,
385885
- binding.runId,
386892
+ runId,
385886
386893
  "starting-state-invalid",
385887
386894
  {},
385888
386895
  () => requireOnboardingChoice(
@@ -385893,7 +386900,7 @@ async function runOnboard(argv, dependencies) {
385893
386900
  );
385894
386901
  const agentFramework = reportingRefusal(
385895
386902
  deps,
385896
- binding.runId,
386903
+ runId,
385897
386904
  "agent-framework-invalid",
385898
386905
  { requested_agent_framework: reportableSlug(requestedFramework) },
385899
386906
  () => requireOnboardingChoice(
@@ -385904,7 +386911,7 @@ async function runOnboard(argv, dependencies) {
385904
386911
  );
385905
386912
  const frontend = reportingRefusal(
385906
386913
  deps,
385907
- binding.runId,
386914
+ runId,
385908
386915
  "frontend-invalid",
385909
386916
  {},
385910
386917
  () => requireOnboardingChoice(
@@ -385913,12 +386920,19 @@ async function runOnboard(argv, dependencies) {
385913
386920
  ONBOARDING_FRONTENDS
385914
386921
  )
385915
386922
  );
386923
+ const route = readOnboardingRoute({ cwd: deps.cwd, store: deps.store });
386924
+ const contradiction = contradictedIntegrationRefusal(startingState, route);
386925
+ if (contradiction !== void 0) {
386926
+ recordClassifyRefusal(deps, runId, "integration-contradicted", {});
386927
+ throw new Error(contradiction);
386928
+ }
385916
386929
  const refusal = unprovenBaselineRefusal(
385917
386930
  startingState,
385918
- readOnboardingRoute({ cwd: deps.cwd, store: deps.store })
386931
+ route,
386932
+ readBaselineProofBestEffort(deps)
385919
386933
  );
385920
386934
  if (refusal !== void 0) {
385921
- recordClassifyRefusal(deps, binding.runId, "baseline-unproven", {});
386935
+ recordClassifyRefusal(deps, runId, "baseline-unproven", {});
385922
386936
  throw new Error(refusal);
385923
386937
  }
385924
386938
  recordBestEffort(deps, {
@@ -385926,7 +386940,7 @@ async function runOnboard(argv, dependencies) {
385926
386940
  properties: {
385927
386941
  command: "onboard",
385928
386942
  ...onboardingIntentProperties(deps),
385929
- onboarding_run_id: binding.runId,
386943
+ onboarding_run_id: runId,
385930
386944
  cli_version: deps.cliVersion,
385931
386945
  starting_state: startingState,
385932
386946
  // Mapped at the emit boundary, never at the flag: the graph's own
@@ -385943,11 +386957,11 @@ async function runOnboard(argv, dependencies) {
385943
386957
  if (argv.length !== 1) {
385944
386958
  throw new Error("Usage: copilotkit onboard feedback");
385945
386959
  }
385946
- await reportFeedback(deps, binding.runId);
386960
+ await reportFeedback(deps, runId);
385947
386961
  return;
385948
386962
  }
385949
386963
  if (subcommand === "friction") {
385950
- await reportFriction(deps, binding.runId, argv.slice(1));
386964
+ await reportFriction(deps, runId, argv.slice(1));
385951
386965
  return;
385952
386966
  }
385953
386967
  if (subcommand === "protect") {
@@ -385955,11 +386969,14 @@ async function runOnboard(argv, dependencies) {
385955
386969
  args: [...argv.slice(1)],
385956
386970
  allowPositionals: false,
385957
386971
  options: {
386972
+ "accept-credential": { type: "boolean" },
385958
386973
  "accept-external": { type: "boolean" },
385959
386974
  authorize: { type: "boolean" },
385960
386975
  path: { type: "string", multiple: true },
385961
386976
  reason: { type: "string" },
385962
- rebaseline: { type: "boolean" }
386977
+ rebaseline: { type: "boolean" },
386978
+ unplanned: { type: "boolean" },
386979
+ "with-prior-change": { type: "boolean" }
385963
386980
  },
385964
386981
  strict: true
385965
386982
  });
@@ -385967,21 +386984,52 @@ async function runOnboard(argv, dependencies) {
385967
386984
  const target = { cwd: deps.cwd, store: deps.store };
385968
386985
  const rebaseline = parsed.values.rebaseline === true;
385969
386986
  const acceptExternal = parsed.values["accept-external"] === true;
386987
+ const acceptCredential = parsed.values["accept-credential"] === true;
385970
386988
  const authorize = parsed.values.authorize === true;
385971
- if ([rebaseline, acceptExternal, authorize].filter(Boolean).length > 1) {
386989
+ const withPriorChange = parsed.values["with-prior-change"] === true;
386990
+ const unplanned = parsed.values.unplanned === true;
386991
+ if ([rebaseline, acceptExternal, acceptCredential, authorize].filter(Boolean).length > 1) {
385972
386992
  throw new Error(EXCLUSIVE_MODE_USAGE);
385973
386993
  }
386994
+ if (withPriorChange && !authorize) {
386995
+ throw new Error(PRIOR_CHANGE_USAGE);
386996
+ }
386997
+ if (unplanned && !authorize) {
386998
+ throw new Error(UNPLANNED_USAGE);
386999
+ }
387000
+ if (acceptCredential) {
387001
+ if (paths.length === 0)
387002
+ throw new Error(ACCEPT_CREDENTIAL_USAGE);
387003
+ const placed = acceptCredentialPlacement(target, {
387004
+ runId,
387005
+ paths
387006
+ });
387007
+ recordProtect(
387008
+ deps,
387009
+ runId,
387010
+ "accept-credential",
387011
+ placed,
387012
+ (result) => ({
387013
+ path_count: result.accepted.length,
387014
+ drift_kinds: joinChanges(result.accepted.map((one) => one.change))
387015
+ })
387016
+ );
387017
+ deps.stdout.write(credentialReport(placed));
387018
+ return;
387019
+ }
385974
387020
  if (authorize) {
385975
387021
  const reason = parsed.values.reason ?? "";
385976
387022
  if (paths.length === 0 || reason.trim() === "") {
385977
387023
  throw new Error(AUTHORIZE_USAGE);
385978
387024
  }
385979
387025
  const authorized = authorizeProtectedPathChange(target, {
385980
- runId: binding.runId,
387026
+ runId,
385981
387027
  paths,
385982
- reason
387028
+ reason,
387029
+ acceptPriorChange: withPriorChange,
387030
+ unplanned
385983
387031
  });
385984
- recordProtect(deps, binding.runId, "authorize", authorized, (result) => ({
387032
+ recordProtect(deps, runId, "authorize", authorized, (result) => ({
385985
387033
  path_count: result.authorized.length
385986
387034
  }));
385987
387035
  deps.stdout.write(authorizationReport(authorized));
@@ -385991,10 +387039,10 @@ async function runOnboard(argv, dependencies) {
385991
387039
  if (paths.length === 0)
385992
387040
  throw new Error(ACCEPT_USAGE);
385993
387041
  const accepted = acceptProtectedPathDrift(target, {
385994
- runId: binding.runId,
387042
+ runId,
385995
387043
  paths
385996
387044
  });
385997
- recordProtect(deps, binding.runId, "accept", accepted, (result) => ({
387045
+ recordProtect(deps, runId, "accept", accepted, (result) => ({
385998
387046
  path_count: result.accepted.length,
385999
387047
  drift_kinds: joinChanges(result.accepted.map((one) => one.change))
386000
387048
  }));
@@ -386005,20 +387053,20 @@ async function runOnboard(argv, dependencies) {
386005
387053
  if (paths.length === 0)
386006
387054
  throw new Error(REBASELINE_USAGE);
386007
387055
  const promoted = rebaselineProtectedPaths(target, {
386008
- runId: binding.runId,
387056
+ runId,
386009
387057
  paths
386010
387058
  });
386011
- recordProtect(deps, binding.runId, "rebaseline", promoted, (result) => ({
387059
+ recordProtect(deps, runId, "rebaseline", promoted, (result) => ({
386012
387060
  path_count: result.promoted.length
386013
387061
  }));
386014
387062
  deps.stdout.write(rebaselineReport(promoted));
386015
387063
  return;
386016
387064
  }
386017
387065
  const captured = captureProtectedPaths(target, {
386018
- runId: binding.runId,
387066
+ runId,
386019
387067
  paths
386020
387068
  });
386021
- recordProtect(deps, binding.runId, "capture", captured, (result) => ({
387069
+ recordProtect(deps, runId, "capture", captured, (result) => ({
386022
387070
  path_count: result.added.length,
386023
387071
  protect_derived: result.derived
386024
387072
  }));
@@ -386026,17 +387074,21 @@ async function runOnboard(argv, dependencies) {
386026
387074
  return;
386027
387075
  }
386028
387076
  if (subcommand === "checkpoint") {
386029
- reportCheckpoint(deps, binding.runId, argv.slice(1));
387077
+ reportCheckpoint(deps, runId, argv.slice(1));
386030
387078
  return;
386031
387079
  }
386032
387080
  if (subcommand === "proof") {
386033
387081
  const proof = parseProof(argv.slice(1));
387082
+ recordProofBestEffort(deps, runId, proof.step, {
387083
+ outcome: proof.outcome,
387084
+ ...proof.predicate === void 0 ? {} : { predicate: proof.predicate }
387085
+ });
386034
387086
  recordBestEffort(deps, {
386035
387087
  event: "cli.onboarding.proof_recorded",
386036
387088
  properties: {
386037
387089
  command: "onboard",
386038
387090
  ...onboardingIntentProperties(deps),
386039
- onboarding_run_id: binding.runId,
387091
+ onboarding_run_id: runId,
386040
387092
  cli_version: deps.cliVersion,
386041
387093
  proof_step: proof.step,
386042
387094
  proof_outcome: proof.outcome,
@@ -386053,14 +387105,14 @@ async function runOnboard(argv, dependencies) {
386053
387105
  throw new Error("Usage: copilotkit onboard audit");
386054
387106
  const audit = auditProtectedPaths(
386055
387107
  { cwd: deps.cwd, store: deps.store },
386056
- { runId: binding.runId }
387108
+ { runId }
386057
387109
  );
386058
387110
  recordBestEffort(deps, {
386059
387111
  event: "cli.onboarding.audit_completed",
386060
387112
  properties: {
386061
387113
  command: "onboard",
386062
387114
  ...onboardingIntentProperties(deps),
386063
- onboarding_run_id: binding.runId,
387115
+ onboarding_run_id: runId,
386064
387116
  cli_version: deps.cliVersion,
386065
387117
  ...describeAudit(audit)
386066
387118
  }
@@ -386068,17 +387120,17 @@ async function runOnboard(argv, dependencies) {
386068
387120
  deps.stdout.write(auditReport(audit));
386069
387121
  return;
386070
387122
  }
386071
- throw new Error(
386072
- `Usage: copilotkit onboard <${ONBOARD_SUBCOMMANDS.join("|")}>`
386073
- );
386074
387123
  }
386075
- function requireBoundRun(dependencies) {
387124
+ function runNotBound(reason) {
387125
+ 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.";
387126
+ }
387127
+ function requireBoundRun(dependencies, refusal) {
386076
387128
  const runId = readOnboardingRunId({
386077
387129
  cwd: dependencies.cwd,
386078
387130
  store: dependencies.store
386079
387131
  });
386080
387132
  if (runId === void 0)
386081
- throw new Error(RUN_NOT_BOUND);
387133
+ throw new Error(refusal);
386082
387134
  return runId;
386083
387135
  }
386084
387136
  function plural(count, noun) {
@@ -386164,6 +387216,59 @@ ${detail}`;
386164
387216
  ""
386165
387217
  ].join("\n");
386166
387218
  }
387219
+ function credentialReport(result) {
387220
+ if (result.status === "blocked") {
387221
+ const detail = {
387222
+ "no-baseline": `No protected-path baseline was captured for run ${result.detail}.
387223
+ Run \`copilotkit onboard protect\` first.
387224
+ `,
387225
+ "run-mismatch": `The captured baseline belongs to run ${result.detail}, not to this run.
387226
+ A credential can only be accepted against the baseline of the run that
387227
+ asked for it.
387228
+ `,
387229
+ "unreadable-baseline": `The captured baseline for run ${result.detail} could not be read.
387230
+ Capture it again before accepting anything against it.
387231
+ `,
387232
+ "unreadable-path": `The protected path \`${result.detail}\` could not be read, so the credential
387233
+ it now holds could not be checked.
387234
+ `,
387235
+ "unknown-path": `The path \`${result.detail}\` is not in this run\u2019s baseline.
387236
+ Only a captured path can be accepted.
387237
+ `,
387238
+ "deferred-path": `The path \`${result.detail}\` is deferred, not protected.
387239
+ This graph has not finished writing it, so promote it first with
387240
+ \`onboard protect --rebaseline --path <path>\`.
387241
+ `,
387242
+ "not-env-path": `The path \`${result.detail}\` is not an env file.
387243
+ This route reads variable names to prove no credential was lost, which only
387244
+ means something for a file of \`KEY=value\` lines.
387245
+ `,
387246
+ "unchanged-path": `The path \`${result.detail}\` matches the digest captured for it.
387247
+ Nothing was placed in it, so there is no credential to accept.
387248
+ `,
387249
+ "unrecorded-keys": `The baseline holds no variable names for \`${result.detail}\`.
387250
+ This route proves no credential was lost by comparing them, so with none
387251
+ recorded it can prove nothing. Capture the path again with
387252
+ \`onboard protect --path <path>\` before the developer writes to it.
387253
+ `,
387254
+ "credential-lost": `A credential recorded for \`${result.detail}\` is gone.
387255
+ This route accepts a credential the developer added. It refuses a change
387256
+ that drops one, which is the failure the baseline exists to catch. Do not
387257
+ repair or rewrite the file. Report the missing variable and route out.
387258
+ `
387259
+ }[result.reason];
387260
+ return `Status: blocked
387261
+ ${detail}${NOTHING_ACCEPTED}`;
387262
+ }
387263
+ return [
387264
+ "Status: passed",
387265
+ `Accepted the placed credential in ${plural(result.accepted.length, "env file")} for run ${result.runId}.`,
387266
+ ...result.accepted.map(changeLine),
387267
+ "Every credential the baseline recorded is still there.",
387268
+ "Report each accepted path in the summary.",
387269
+ ""
387270
+ ].join("\n");
387271
+ }
386167
387272
  function acceptanceReport(result) {
386168
387273
  if (result.status === "blocked") {
386169
387274
  const detail = {
@@ -386217,7 +387322,8 @@ ${detail}${NOTHING_ACCEPTED}`;
386217
387322
  ].join("\n");
386218
387323
  }
386219
387324
  function authorizationLine(granted) {
386220
- return ` ${granted.path} \u2014 ${granted.reason}`;
387325
+ const source = granted.unplanned === true ? " (outside the approved plan)" : "";
387326
+ return ` ${granted.path} \u2014 ${granted.reason}${source}`;
386221
387327
  }
386222
387328
  function authorizedLines(authorized) {
386223
387329
  return authorized.length === 0 ? [] : ["Authorized to change:", ...authorized.map(authorizationLine)];
@@ -386249,11 +387355,31 @@ Nothing outside the run writes it, so consent here would only license the
386249
387355
  run against its own credential output.
386250
387356
  `,
386251
387357
  "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",
387358
+ "unplanned-path": `The path \`${result.detail}\` is not one the approved plan asked for.
387359
+ This run has already reported its plan, so the developer has approved every
387360
+ path they are going to approve. They did not approve this one. Ask them
387361
+ to allow the change, and record the answer they give with
387362
+ \`onboard protect --authorize --unplanned --path <path> --reason "<their
387363
+ answer>"\`. If you cannot ask, route out. Do not repair the path.
387364
+ `,
387365
+ "prior-change-after-start": `The path \`${result.detail}\` cannot carry a prior-change claim any more.
387366
+ That claim says the developer changed the file before this run implemented
387367
+ anything, and this run has already reported its plan. A protected path that
387368
+ changed after that is this run\u2019s own work. Route out rather than record
387369
+ consent over it.
387370
+ `,
387371
+ "planned-path": `The path \`${result.detail}\` can still be authorized by the plan itself.
387372
+ This run has not reported its plan yet, so --unplanned describes nothing:
387373
+ consent here is the developer approving the plan. Record it without the
387374
+ flag, or add the path to the plan and have the developer approve that.
387375
+ `,
386252
387376
  "changed-path": `The path \`${result.detail}\` has already changed since it was captured.
386253
387377
  Consent has to be recorded before the change, or it cannot be told apart from
386254
387378
  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.
387379
+ section from this run names the path, route out. If none does, the developer
387380
+ changed it, and either accept it with \`onboard protect --accept-external
387381
+ --path <path>\` or, when this run must change the same file, record consent
387382
+ over their change by adding --with-prior-change.
386257
387383
  `
386258
387384
  }[result.reason];
386259
387385
  return `Status: blocked
@@ -386385,6 +387511,24 @@ function parseProof(args) {
386385
387511
  }
386386
387512
  return { step, outcome, predicate };
386387
387513
  }
387514
+ function parseIdentify(args) {
387515
+ let parsed;
387516
+ try {
387517
+ parsed = parseArgs2({
387518
+ args: [...args],
387519
+ allowPositionals: false,
387520
+ options: { "coding-agent": { type: "string" } },
387521
+ strict: true
387522
+ });
387523
+ } catch {
387524
+ throw new Error(IDENTIFY_USAGE);
387525
+ }
387526
+ const codingAgent = parsed.values["coding-agent"];
387527
+ if (codingAgent === void 0 || codingAgent.trim().length === 0) {
387528
+ throw new Error(IDENTIFY_USAGE);
387529
+ }
387530
+ return { codingAgent };
387531
+ }
386388
387532
  function reportCheckpoint(dependencies, runId, args) {
386389
387533
  let parsed;
386390
387534
  try {
@@ -386410,6 +387554,12 @@ function reportCheckpoint(dependencies, runId, args) {
386410
387554
  if (!reviewed.ok) {
386411
387555
  return printCheckpointRefusal(dependencies, runId, reviewed.refusal);
386412
387556
  }
387557
+ if (reviewed.checkpoint.phase === "plan-written") {
387558
+ markImplementationStarted(
387559
+ { cwd: dependencies.cwd, store: dependencies.store },
387560
+ { runId }
387561
+ );
387562
+ }
386413
387563
  recordBestEffort(dependencies, {
386414
387564
  event: "cli.onboarding.checkpoint",
386415
387565
  properties: {
@@ -386623,9 +387773,9 @@ async function reportFeedback(dependencies, runId) {
386623
387773
  if (!reviewed.ok)
386624
387774
  return printFeedbackRefusal(dependencies, runId, reviewed.refusal);
386625
387775
  const feedbackText = reviewed.text;
386626
- let sent = false;
387776
+ let submission;
386627
387777
  try {
386628
- sent = await dependencies.submitFeedbackEvent({
387778
+ submission = await dependencies.submitFeedbackEvent({
386629
387779
  event: "cli.onboarding.feedback_submitted",
386630
387780
  properties: {
386631
387781
  command: "onboard",
@@ -386635,15 +387785,25 @@ async function reportFeedback(dependencies, runId) {
386635
387785
  feedback_text: feedbackText
386636
387786
  }
386637
387787
  });
386638
- } catch {
386639
- sent = false;
387788
+ } catch (error98) {
387789
+ submission = { status: "failed", detail: describeSubmissionError(error98) };
386640
387790
  }
386641
387791
  dependencies.stdout.write(
386642
- `${sent ? "Feedback sent." : "Feedback was not sent because telemetry is disabled or unavailable."}
387792
+ `${describeSubmission("Feedback", submission)}
386643
387793
  report: ${feedbackText}
386644
387794
  `
386645
387795
  );
386646
387796
  }
387797
+ function describeSubmission(subject, submission) {
387798
+ switch (submission.status) {
387799
+ case "sent":
387800
+ return subject === "Feedback" ? "Feedback sent." : "Friction reported.";
387801
+ case "declined":
387802
+ return `${subject} was not sent because telemetry is off.`;
387803
+ default:
387804
+ return `${subject} was not sent because the telemetry send failed: ${submission.detail}`;
387805
+ }
387806
+ }
386647
387807
  function printFeedbackRefusal(dependencies, runId, refusal) {
386648
387808
  recordReportRefused(dependencies, runId, "feedback", refusal.code);
386649
387809
  dependencies.stdout.write(
@@ -386668,9 +387828,9 @@ async function reportFriction(dependencies, runId, args) {
386668
387828
  if (!reviewed.ok)
386669
387829
  return printFrictionRefusal(dependencies, runId, reviewed.refusal);
386670
387830
  const report = reviewed.report;
386671
- let sent = false;
387831
+ let submission;
386672
387832
  try {
386673
- sent = await dependencies.submitFeedbackEvent({
387833
+ submission = await dependencies.submitFeedbackEvent({
386674
387834
  event: "cli.onboarding.friction_reported",
386675
387835
  properties: {
386676
387836
  command: "onboard",
@@ -386685,10 +387845,10 @@ async function reportFriction(dependencies, runId, args) {
386685
387845
  friction_text: report.text
386686
387846
  }
386687
387847
  });
386688
- } catch {
386689
- sent = false;
387848
+ } catch (error98) {
387849
+ submission = { status: "failed", detail: describeSubmissionError(error98) };
386690
387850
  }
386691
- printFrictionReport(dependencies, report, sent);
387851
+ printFrictionReport(dependencies, report, submission);
386692
387852
  }
386693
387853
  function parseFrictionArguments(args) {
386694
387854
  try {
@@ -386726,9 +387886,9 @@ ${refusal.code}: ${refusal.message}
386726
387886
  `
386727
387887
  );
386728
387888
  }
386729
- function printFrictionReport(dependencies, report, sent) {
387889
+ function printFrictionReport(dependencies, report, submission) {
386730
387890
  dependencies.stdout.write(
386731
- `${sent ? "Friction reported." : "Friction was not sent because telemetry is disabled or unavailable."}
387891
+ `${describeSubmission("Friction", submission)}
386732
387892
  category: ${report.category}
386733
387893
  cost_seconds_estimated: ${report.costSecondsEstimated}
386734
387894
  ` + (report.docsPath === void 0 ? "" : `docs_path: ${report.docsPath}
@@ -386896,6 +388056,37 @@ function readRouteBestEffort(dependencies) {
386896
388056
  return [];
386897
388057
  }
386898
388058
  }
388059
+ function recordProofBestEffort(dependencies, runId, step, proof) {
388060
+ try {
388061
+ recordProofOutcome(
388062
+ { cwd: dependencies.cwd, store: dependencies.store },
388063
+ runId,
388064
+ step,
388065
+ proof
388066
+ );
388067
+ } catch {
388068
+ }
388069
+ }
388070
+ function recordCodingAgentBestEffort(dependencies, runId, codingAgent) {
388071
+ try {
388072
+ recordCodingAgent(
388073
+ { cwd: dependencies.cwd, store: dependencies.store },
388074
+ runId,
388075
+ codingAgent
388076
+ );
388077
+ } catch {
388078
+ }
388079
+ }
388080
+ function readBaselineProofBestEffort(dependencies) {
388081
+ try {
388082
+ return readProofOutcome(
388083
+ { cwd: dependencies.cwd, store: dependencies.store },
388084
+ "oss-baseline"
388085
+ );
388086
+ } catch {
388087
+ return void 0;
388088
+ }
388089
+ }
386899
388090
  function recordRouteBestEffort(dependencies, runId, promptName) {
386900
388091
  try {
386901
388092
  recordServedPrompt(
@@ -386919,7 +388110,7 @@ function recordBestEffort(dependencies, event) {
386919
388110
  } catch {
386920
388111
  }
386921
388112
  }
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;
388113
+ 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
388114
  var init_onboard = __esm({
386924
388115
  async "apps/cli/src/commands/onboard.ts"() {
386925
388116
  "use strict";
@@ -386940,6 +388131,7 @@ var init_onboard = __esm({
386940
388131
  init_resolved_dependencies();
386941
388132
  ONBOARD_SUBCOMMANDS = [
386942
388133
  "start",
388134
+ "identify",
386943
388135
  "read",
386944
388136
  "route",
386945
388137
  "classify",
@@ -386951,11 +388143,22 @@ var init_onboard = __esm({
386951
388143
  "feedback",
386952
388144
  "friction"
386953
388145
  ];
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.";
388146
+ READ_RUN_NOT_BOUND = runNotBound(
388147
+ "`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."
388148
+ );
388149
+ IDENTIFY_RUN_NOT_BOUND = runNotBound(
388150
+ "`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."
388151
+ );
388152
+ STEP_RUN_NOT_BOUND = runNotBound(
388153
+ "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."
388154
+ );
386955
388155
  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
388156
  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
388157
  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.";
388158
+ 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.";
388159
+ 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.";
388160
+ 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.";
388161
+ 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
388162
  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
388163
  NOTHING_AUTHORIZED = "Nothing was recorded. No path in this call was authorized, including any path\nnamed before the one above.\n";
386961
388164
  NOTHING_ACCEPTED = "Nothing was recorded. No path in this call was accepted, including any path\nnamed before the one above.\n";
@@ -386982,8 +388185,8 @@ blocked reads the unsupported terminal instead, and reports a path that works
386982
388185
  as one this release does not carry.`;
386983
388186
  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
388187
  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"];
388188
+ PROOF_STEPS = ONBOARDING_PROOF_STEPS;
388189
+ PROOF_OUTCOMES = ONBOARDING_PROOF_OUTCOMES;
386987
388190
  BASELINE_PREDICATE_COUNT = 6;
386988
388191
  PROOF_USAGE = `Usage: copilotkit onboard proof --step <${PROOF_STEPS.join("|")}> --outcome <${PROOF_OUTCOMES.join("|")}>
386989
388192
  [--predicate <1-${BASELINE_PREDICATE_COUNT}>]
@@ -386994,6 +388197,7 @@ trip.
386994
388197
  Pass --predicate with a failed or skipped oss-baseline to name which of the
386995
388198
  six predicates it was. A passed gate has no predicate to name, and the
386996
388199
  round trip has no numbered predicates at all.`;
388200
+ IDENTIFY_USAGE = "Usage: copilotkit onboard identify --coding-agent <slug>";
386997
388201
  BLOCKER_REPORTS = {
386998
388202
  inspector: {
386999
388203
  cause: "the debugging surface for this frontend did not open.",
@@ -389970,6 +391174,7 @@ init_feature_flags();
389970
391174
  init_exit_code();
389971
391175
  init_unknown_input();
389972
391176
  await init_telemetry();
391177
+ init_event_properties();
389973
391178
  import { parseArgs as parseArgs4 } from "node:util";
389974
391179
  import { realpathSync as realpathSync3 } from "node:fs";
389975
391180
  import path44 from "node:path";
@@ -390217,12 +391422,15 @@ Options:
390217
391422
  -h, --help Show help for login
390218
391423
  `,
390219
391424
  onboard: `Usage: copilotkit onboard start [--intent <slug>] [--run <id>] [--coding-agent <slug>]
391425
+ copilotkit onboard identify --coding-agent <slug>
390220
391426
  copilotkit onboard read <prompt-name>
390221
391427
  copilotkit onboard route
390222
391428
  copilotkit onboard classify --starting-state <state> --agent-framework <framework> --frontend <frontend>
390223
391429
  copilotkit onboard protect [--path <path>] [--rebaseline --path <path>]
390224
391430
  [--accept-external --path <path>]
390225
- [--authorize --path <path> --reason <why>]
391431
+ [--accept-credential --path <path>]
391432
+ [--authorize --path <path> --reason <why>
391433
+ [--with-prior-change] [--unplanned]]
390226
391434
  copilotkit onboard audit
390227
391435
  copilotkit onboard checkpoint --phase <slug> [--attempt <n>]
390228
391436
  copilotkit onboard proof --step <oss-baseline|round-trip> --outcome <passed|failed|skipped>
@@ -390249,7 +391457,7 @@ Subcommands:
390249
391457
 
390250
391458
  Feedback must be no larger than 2,048 UTF-8 bytes. Do not include secrets,
390251
391459
  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.
391460
+ When telemetry is off, or the send fails, feedback exits zero and says which.
390253
391461
 
390254
391462
  Protect captures the paths this run must not change -- the developer's work in
390255
391463
  progress -- as path and digest, derived from the working tree rather than taken
@@ -390269,6 +391477,13 @@ report. Accept a path only when the run can show it did not write that path
390269
391477
  itself, and never one of the two files above: those exist to be rewritten by the
390270
391478
  run, so accepting one would record the run's own damage as the baseline.
390271
391479
 
391480
+ An env file is the exception, because the run asks the developer to write their
391481
+ model credential into it. Accept that with protect --accept-credential --path
391482
+ <path>. It takes nobody's word: it compares the variable names the baseline
391483
+ recorded with the names the file holds now, and refuses when a recorded
391484
+ credential is gone or empty. So the developer's own paste passes, and a step
391485
+ that rewrites .env and drops the project key still fails.
391486
+
390272
391487
  Adding a feature to an app the developer already built needs the opposite
390273
391488
  record. The option lives in a file they wrote, so the run has to change it. The
390274
391489
  plan asks for that path, approving the plan grants it, and the grant is recorded
@@ -390276,12 +391491,23 @@ with protect --authorize --path <path> --reason <why> before any edit. The audit
390276
391491
  then reports the path instead of failing on it, and every later audit and the
390277
391492
  closing report name it with its reason. An authorization is refused once the
390278
391493
  path has moved, because consent taken afterwards cannot be told apart from a run
390279
- clearing a failure it caused.
391494
+ clearing a failure it caused. Add --with-prior-change for the one case that rule
391495
+ had no answer for: the developer changed the file after the capture, and the run
391496
+ must change the same file. The earlier change is recorded as drift beside the
391497
+ consent, so both authors stay visible in the closing report.
391498
+
391499
+ Consent belongs to the plan the developer approved. Once the run reports that
391500
+ plan with checkpoint --phase plan-written, --authorize is refused for every path
391501
+ the plan did not name: the developer approved the plan, not whatever the run
391502
+ reaches later. Where the run must change such a path, it asks the developer and
391503
+ records their answer with --unplanned, which marks the consent as taken outside
391504
+ the plan wherever it is printed. The flag is refused before the plan is
391505
+ reported, so it can never stand in for the plan's own approval.
390280
391506
 
390281
391507
  Checkpoint reports progress from inside a step, where the graph would
390282
391508
  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>
391509
+ research-returned, starter-cloned, plan-written, container-surveyed,
391510
+ container-settled, build-validated, journey-attempted, repair-attempted. Pass --attempt <1-9>
390285
391511
  where the step loops, so a repair cycle can be counted.
390286
391512
  A refused checkpoint exits zero and prints the closed set. It is called from
390287
391513
  the middle of the longest step of a run, and a non-zero exit there reads as a
@@ -390317,19 +391543,28 @@ what they sent. Every refusal exits zero and leaves onboarding unaffected.
390317
391543
  `,
390318
391544
  verify: `Usage: copilotkit verify [--json] [--runtime-url <url>] [--round-trip]
390319
391545
  [--expect-runtime <mode>] [--frontend-url <url>]
391546
+ [--expect-learning-container <id>]
390320
391547
 
390321
391548
  Check that this project's CopilotKit wiring works, and report what it found.
390322
391549
 
390323
391550
  Checks that a hosted project is selected, that a project API key is present and
390324
391551
  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.
391552
+ it declares at least one agent, that it holds an Intelligence client and calls
391553
+ the same deployment the key was proven against, that it accepts the origin a
391554
+ browser opens, and that the installed CopilotKit packages match the version it
391555
+ reports. Reports the runtime version, the agent framework in use, whether
391556
+ transcription is wired, the realtime gateway wiring, and the license state.
390329
391557
 
390330
391558
  Every check reports PASS, FAIL, or UNKNOWN. UNKNOWN means the check could not
390331
391559
  run \u2014 it never means the check passed. Exits non-zero unless every check passed.
390332
391560
 
391561
+ The runtime's /info route reports that an Intelligence client was constructed.
391562
+ It does not report that the client reached anything, so no check here reads it
391563
+ as a successful call. Set INTELLIGENCE_API_URL in the env file the app loads:
391564
+ without it the runtime falls back to its own built-in host while this command
391565
+ proves the key against the host baked into this binary, and a valid key then
391566
+ gets 401 on every request.
391567
+
390333
391568
  The report names the runtime URL it probed and where that URL came from. Nothing
390334
391569
  answering at a URL the project named is a FAIL; nothing answering at the assumed
390335
391570
  default is UNKNOWN, because an app running on a port this command never learned
@@ -390340,6 +391575,13 @@ the answer back from the thread, which is the only check here that proves the
390340
391575
  agent runs rather than that it is configured. That costs a model call and
390341
391576
  records a thread, so it is opt-in.
390342
391577
 
391578
+ A runtime mounted mode: "single-route" runs the request through its agent/run
391579
+ envelope, and the answer is read from the platform because that mount carries
391580
+ its thread routes inside the envelope rather than as REST paths this command
391581
+ can call. The report names which read answered: through the app, the answer
391582
+ belongs to the caller the app identified; from the platform, the run and its
391583
+ answer are proved and the end user they belonged to is not.
391584
+
390343
391585
  With --expect-runtime oss, hosted project and credential checks do not apply.
390344
391586
  The command exits zero only when valid /info data declares the named agent,
390345
391587
  reports no Intelligence entitlement, and --round-trip --agent <id> passes.
@@ -390358,6 +391600,12 @@ Options:
390358
391600
  to send a real CORS preflight when that origin differs
390359
391601
  from the runtime's
390360
391602
  --expect-runtime <mode> Require intelligence (default) or oss runtime mode
391603
+ --expect-learning-container <id>
391604
+ Require the round trip's thread to carry this
391605
+ Learning Container. Needs --round-trip --agent <id>.
391606
+ Read from the platform, so it answers for a runtime
391607
+ mounted mode: "single-route" too. A plan entitlement
391608
+ or an /info flag is not evidence.
390361
391609
  --round-trip Also run the agent and read its answer back
390362
391610
  --agent <id> Which declared agent to run, when there are several
390363
391611
  --timeout <seconds> How long to wait for the answer (default: 90)
@@ -390653,6 +391901,7 @@ Actions:
390653
391901
  learning containers list List Learning Containers (alias: ls)
390654
391902
  learning containers get <id> Show one Learning Container (alias: show)
390655
391903
  learning containers create Create a Learning Container
391904
+ learning containers select Pick one, or create one, in a terminal
390656
391905
  learning containers update <id> Change a name or prompt context
390657
391906
  learning containers delete <id> Delete an unused Learning Container
390658
391907
 
@@ -391245,7 +392494,7 @@ async function applyGlobalArgs(parsed) {
391245
392494
  setCliLogsVerbose2(true);
391246
392495
  }
391247
392496
  }
391248
- async function runWhoami() {
392497
+ async function runWhoami(ctx) {
391249
392498
  const {
391250
392499
  clearAuthOnTerminalSessionInvalidation: clearAuthOnTerminalSessionInvalidation2,
391251
392500
  TERMINAL_SESSION_INVALID_MESSAGE: TERMINAL_SESSION_INVALID_MESSAGE2,
@@ -391265,17 +392514,20 @@ async function runWhoami() {
391265
392514
  if (clearAuthOnTerminalSessionInvalidation2(error98)) {
391266
392515
  process.stdout.write(`${TERMINAL_SESSION_INVALID_MESSAGE2}
391267
392516
  `);
392517
+ ctx.reportFailure({ errorCode: "auth" });
391268
392518
  return;
391269
392519
  }
391270
392520
  if (error98 instanceof ApiClientError2 && error98.status > 0) {
391271
392521
  process.stdout.write(`${error98.message}
391272
392522
  `);
392523
+ ctx.reportFailure({ errorCode: classifyError(error98) });
391273
392524
  return;
391274
392525
  }
391275
392526
  throw error98;
391276
392527
  }
391277
392528
  if (!session) {
391278
392529
  process.stdout.write("Session expired. Please run: copilotkit login\n");
392530
+ ctx.reportFailure({ errorCode: "auth" });
391279
392531
  return;
391280
392532
  }
391281
392533
  process.stdout.write(`Email: ${session.user.email}
@@ -391736,6 +392988,15 @@ function parseLearningContainersCommandArgs(argv) {
391736
392988
  ...parsed.values.cursor === void 0 ? {} : { cursor: parsed.values.cursor }
391737
392989
  };
391738
392990
  }
392991
+ if (subcommand === "select") {
392992
+ const parsed = parseArgs4({
392993
+ args,
392994
+ options: { json: { type: "boolean" } },
392995
+ strict: true,
392996
+ allowPositionals: false
392997
+ });
392998
+ return { action: "select", json: parsed.values.json === true };
392999
+ }
391739
393000
  if (subcommand === "get") {
391740
393001
  const parsed = parseArgs4({
391741
393002
  args,
@@ -391974,7 +393235,7 @@ function learningParseFailureSubcommand(argv) {
391974
393235
  const resource = argv[0];
391975
393236
  const action = argv[1];
391976
393237
  if (resource === "containers") {
391977
- return action === "list" || action === "get" || action === "show" || action === "create" || action === "update" || action === "delete" ? `containers.${action === "show" ? "get" : action}` : "containers.invalid";
393238
+ return action === "list" || action === "get" || action === "show" || action === "create" || action === "select" || action === "update" || action === "delete" ? `containers.${action === "show" ? "get" : action}` : "containers.invalid";
391978
393239
  }
391979
393240
  if (resource === "insights" || resource === "skills") {
391980
393241
  return action === "list" || action === "ls" ? `${resource}.list` : `${resource}.invalid`;
@@ -392078,10 +393339,10 @@ ${helpTextForTopic("learning")}`
392078
393339
  createLearningContainersCommandDependencies: createLearningContainersCommandDependencies2,
392079
393340
  runLearningContainersCommand: runLearningContainersCommand2
392080
393341
  } = await init_learning_containers().then(() => learning_containers_exports);
392081
- await runLearningContainersCommand2(
392082
- command2,
392083
- createLearningContainersCommandDependencies2()
392084
- );
393342
+ await runLearningContainersCommand2(command2, {
393343
+ ...createLearningContainersCommandDependencies2(),
393344
+ telemetry: { setProperties: telemetryContext.setProperties }
393345
+ });
392085
393346
  }
392086
393347
  );
392087
393348
  }
@@ -392173,6 +393434,7 @@ async function runVerifyCommand(argv) {
392173
393434
  options: {
392174
393435
  agent: { type: "string" },
392175
393436
  "expect-runtime": { type: "string" },
393437
+ "expect-learning-container": { type: "string" },
392176
393438
  "frontend-url": { type: "string" },
392177
393439
  header: { multiple: true, type: "string" },
392178
393440
  json: { type: "boolean" },
@@ -392226,17 +393488,44 @@ async function runVerifyCommand(argv) {
392226
393488
  await exitWithFlush(1);
392227
393489
  }
392228
393490
  const agent = parsed.values["agent"];
393491
+ const expectLearningContainer = parsed.values["expect-learning-container"];
393492
+ if (expectLearningContainer !== void 0 && !/^[a-z0-9]+(?:-[a-z0-9]+)*$/u.test(expectLearningContainer)) {
393493
+ process.stderr.write(
393494
+ "Error: --expect-learning-container expects 1-64 lowercase letters, numbers, and single hyphens.\n"
393495
+ );
393496
+ await exitWithFlush(1);
393497
+ }
392229
393498
  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
- });
393499
+ await runVerify2(
393500
+ {
393501
+ json: parsed.values["json"] === true,
393502
+ ...agent === void 0 ? {} : { agent },
393503
+ ...expectLearningContainer === void 0 ? {} : { expectLearningContainer },
393504
+ ...expectedRuntime === void 0 ? {} : { expectRuntime: expectedRuntime },
393505
+ ...headers === void 0 || Object.keys(headers).length === 0 ? {} : { headers },
393506
+ ...frontendUrl === void 0 ? {} : { frontendUrl },
393507
+ ...parsed.values["round-trip"] === true ? { roundTrip: true } : {},
393508
+ ...runtimeUrl === void 0 ? {} : { runtimeUrl },
393509
+ ...timeoutSeconds === void 0 ? {} : { timeoutMs: Number(timeoutSeconds) * 1e3 }
393510
+ },
393511
+ {
393512
+ // A point event rather than a property on the command's own lifecycle
393513
+ // event. `verify` is dispatched as `auto`, which owns the bookend and does
393514
+ // not hand the runner its telemetry context, and the outcome is worth its
393515
+ // own row: the lifecycle event answers "did the command run", this answers
393516
+ // "did Learning prove out for this project".
393517
+ recordLearningContainerCheck: ({ outcome }) => {
393518
+ recordTelemetryEvent({
393519
+ event: "cli.verify.learning_container_checked",
393520
+ properties: {
393521
+ command: "verify",
393522
+ learning_check_outcome: outcome,
393523
+ ...currentOnboardingRunProperties()
393524
+ }
393525
+ });
393526
+ }
393527
+ }
393528
+ );
392240
393529
  }
392241
393530
  async function runTypegenCommand(argv) {
392242
393531
  const parsed = parseArgs4({
@@ -392498,6 +393787,10 @@ async function runInitCommand(invokedAs, argv) {
392498
393787
  await runInit2(flags, callbacks);
392499
393788
  });
392500
393789
  }
393790
+ var UNWRAPPED_TELEMETRY_CONTEXT = {
393791
+ setProperties: () => void 0,
393792
+ reportFailure: () => void 0
393793
+ };
392501
393794
  var ONBOARD_SUBCOMMANDS2 = [
392502
393795
  "audit",
392503
393796
  "checkpoint",
@@ -392505,6 +393798,7 @@ var ONBOARD_SUBCOMMANDS2 = [
392505
393798
  "complete",
392506
393799
  "feedback",
392507
393800
  "friction",
393801
+ "identify",
392508
393802
  "proof",
392509
393803
  "protect",
392510
393804
  "read",
@@ -392567,8 +393861,8 @@ var COMMAND_TABLE = {
392567
393861
  whoami: {
392568
393862
  kind: "auto",
392569
393863
  command: "whoami",
392570
- run: async () => {
392571
- await runWhoami();
393864
+ run: async (_argv, _token, ctx) => {
393865
+ await runWhoami(ctx);
392572
393866
  }
392573
393867
  },
392574
393868
  docs: {
@@ -392731,13 +394025,13 @@ async function main(rawArgv = process.argv.slice(2)) {
392731
394025
  command: entry.command,
392732
394026
  ...subcommand === void 0 ? {} : { subcommand }
392733
394027
  },
392734
- async () => {
392735
- await entry.run(commandArgv, command2);
394028
+ async (ctx) => {
394029
+ await entry.run(commandArgv, command2, ctx);
392736
394030
  }
392737
394031
  );
392738
394032
  return;
392739
394033
  }
392740
- await entry.run(commandArgv, command2);
394034
+ await entry.run(commandArgv, command2, UNWRAPPED_TELEMETRY_CONTEXT);
392741
394035
  }
392742
394036
  function resolveRealPath(candidatePath) {
392743
394037
  const absolutePath = path44.resolve(candidatePath);