@topolo/cli 0.13.10 → 0.13.12

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.
@@ -5,22 +5,60 @@ from .storage import PackError,atomic_json,canonical,read_json,safe_id
5
5
  class ConnectionSourceRefused(PackError):
6
6
  pass
7
7
 
8
+ def managed_runtime_selection(path):
9
+ """Configuration custody only, never a health or native permission ACK."""
10
+ from . import live
11
+ before,raw=live.adoption_snapshot(path)
12
+ live.adoption_require(before['mode']==0o600 and len(raw)<=2*1024*1024,'private runtime descriptor required')
13
+ value=json.loads(raw)
14
+ live.adoption_keys(value,['schemaVersion','library','ownerGeneration','profile','runtime','preserve'])
15
+ live.adoption_require(value['schemaVersion']==1 and type(value['schemaVersion']) is int and
16
+ pathlib.Path(path).parent==pathlib.Path(value['library'])/'launchers','owned runtime descriptor location required')
17
+ live.adoption_read_inputs(value)
18
+ live.adoption_pin(value['ownerGeneration'],value['profile'])
19
+ env=live.adoption_runtime(value['runtime'],value['profile'])
20
+ for pin in value['preserve']:live.adoption_pin(pin,value['profile'])
21
+ live.adoption_require(live.adoption_snapshot(path,profile=value['profile'])[0]==before,'runtime descriptor changed')
22
+ return value,env
23
+
24
+
25
+ def managed_mcp_main(path,args=()):
26
+ from .live import adoption_require
27
+ adoption_require(len(args)<=1 and all(isinstance(v,str) and re.fullmatch(r'[A-Za-z0-9_-]+',v) for v in args),'closed MCP agent name required')
28
+ value,env=managed_runtime_selection(path)
29
+ if args:env['TOPOLO_AGENT_NAME']=args[0]
30
+ runtime=value['runtime']
31
+ # Only a later owner-admitted ordinary native startup invokes this wrapper.
32
+ # Credential resolution/refresh/identity are real private effects, not preflight.
33
+ # Replace this wrapper, retaining the native host's PID/stdin/cancellation
34
+ # custody instead of leaving an intermediate parent that can orphan MCP.
35
+ return os.execve(runtime['node']['path'],[runtime['node']['path'],runtime['mcp']['path']],env)
36
+
37
+
8
38
  class Client:
9
- def __init__(self,environment,context,binary=None):
39
+ def __init__(self,environment,context,binary=None,env=None,node=None):
10
40
  if environment not in {'development','staging','production'}:
11
41
  raise PackError('Explicit Topolo environment required')
12
42
  if not context or any(c in context for c in '\n\r'):
13
43
  raise PackError('Explicit Topolo context required')
14
- if any(os.environ.get(k) for k in ['TOPOLO_API_KEY','TOPOLO_ACCESS_TOKEN','TOPOLO_'+environment.upper()+'_API_KEY','TOPOLO_'+environment.upper()+'_ACCESS_TOKEN']):
44
+ selected=os.environ if env is None else env
45
+ descriptor=selected.get('TOPOLO_AGENT_PACK_RUNTIME')
46
+ if descriptor:
47
+ value,selected=managed_runtime_selection(descriptor)
48
+ if (environment!=value['profile']['environment'] or context!=value['profile']['contextKey'] or binary is not None or node is not None):
49
+ raise ConnectionSourceRefused('Managed private runtime tuple or explicit override differs')
50
+ binary=value['runtime']['cli']['path'];node=value['runtime']['node']['path']
51
+ if any(selected.get(k) for k in ['TOPOLO_API_KEY','TOPOLO_ACCESS_TOKEN','TOPOLO_'+environment.upper()+'_API_KEY','TOPOLO_'+environment.upper()+'_ACCESS_TOKEN']):
15
52
  raise PackError('Pinned connections require the CLI protected account context, not injected credentials')
16
53
  self.environment=environment;self.context=context
17
54
  self.binary=binary or shutil.which('topolo')
18
55
  if not self.binary:
19
56
  raise PackError('Install the public @topolo/cli and authenticate before connecting')
20
- self.env={**os.environ,'TOPOLO_CONTEXT':context}
21
- self.env['PATH']=str(pathlib.Path(self.binary).parent)+os.pathsep+self.env.get('PATH','')
57
+ self.env={**selected,'TOPOLO_CONTEXT':context}
58
+ self.command=[node,self.binary] if node else [self.binary]
59
+ self.env['PATH']=(str(pathlib.Path(node).parent)+os.pathsep+'/usr/bin:/bin') if node else str(pathlib.Path(self.binary).parent)+os.pathsep+self.env.get('PATH','')
22
60
  def run(self,args):
23
- p=subprocess.run([self.binary,'--env',self.environment,*args,'--json'],env=self.env,capture_output=True,text=True,timeout=90)
61
+ p=subprocess.run([*self.command,'--env',self.environment,*args,'--json'],env=self.env,capture_output=True,text=True,timeout=90)
24
62
  if p.returncode:
25
63
  raise PackError('Topolo command failed (exit '+str(p.returncode)+'); inspect the published action, account permissions and environment. No fallback was used.')
26
64
  try:value=json.loads(p.stdout)
@@ -599,6 +637,8 @@ def connection_lock(lib,args):
599
637
  yield
600
638
 
601
639
  def dispatch(lib,args):
640
+ if args.command=='remote-context' and getattr(args,'continuity_input',None):
641
+ return native_cli_continuity_read(lib,args)
602
642
  client=Client(args.environment,args.context_key)
603
643
  if args.command=='connect':return connect(lib,args,client)
604
644
  if args.command=='remote-context':return remote_context(lib,args,client)[1]
@@ -610,3 +650,124 @@ def dispatch(lib,args):
610
650
  reference=read_json(args.reference)
611
651
  return read_artifact(client,binding,reference['key'],reference,args.destination)
612
652
  raise PackError('Unsupported Topolo command')
653
+
654
+
655
+
656
+ def native_cli_response(stdout,stderr,service):
657
+ """Preserve only canonical public response metadata; never echo raw stderr."""
658
+ from . import lanes
659
+ if len(stdout.encode())>262144 or len(stderr.encode())>65536:
660
+ raise PackError('native_cli_request_metadata_unavailable: bounded public response required')
661
+ try:
662
+ body=json.loads(stdout)
663
+ except ValueError as error:
664
+ raise PackError('native_cli_request_metadata_unavailable: invalid public JSON') from error
665
+ if not isinstance(body,dict) or body.get('error'):
666
+ raise PackError('native_cli_request_metadata_unavailable: unsuccessful public response')
667
+ events=[];seen=set()
668
+ pattern=r'^\[topolo\] ← (\d{3}) (GET|POST) (auth|agent) (/[^\s?#\\]+) \([0-9.]+ms, req=([A-Za-z0-9][A-Za-z0-9._:-]{0,127})\)$'
669
+ for line in stderr.splitlines():
670
+ match=re.fullmatch(pattern,line)
671
+ if not match:
672
+ continue
673
+ status,method,target,path,request_id=match.groups()
674
+ if request_id=='unavailable' or request_id in seen or not 200<=int(status)<300:
675
+ raise PackError('native_cli_request_metadata_unavailable: ambiguous or unsuccessful response request IDs')
676
+ seen.add(request_id);events.append({'requestId':request_id,'method':method,'service':target,'path':path,'status':int(status)})
677
+ if not 1<=len(events)<=8 or service not in {event['service'] for event in events}:
678
+ raise PackError('native_cli_request_metadata_unavailable: actual canonical server response IDs required')
679
+ return body.get('data',body),events
680
+
681
+
682
+ def native_cli_command_response(client,args,service):
683
+ env={**client.env,'TOPOLO_DEBUG':'1'}
684
+ result=subprocess.run([*client.command,'--env',client.environment,*args,'--json'],env=env,
685
+ capture_output=True,text=True,timeout=90)
686
+ if result.returncode:
687
+ raise PackError('native_cli_request_metadata_unavailable: public command refused; no fallback or retry')
688
+ return native_cli_response(result.stdout,result.stderr,service)
689
+
690
+
691
+ def native_cli_selected_environment(value,binding,host_env):
692
+ from . import lanes
693
+ from types import SimpleNamespace
694
+ context=value['context'];profile=binding.get('privateCredentialProfile')
695
+ lanes.native_cli_closed(profile,{'format','schemaVersion','configPath','environment','contextKey','identity'},'private profile reference')
696
+ if (profile['format']!='topolo-private-credential-profile' or profile['schemaVersion']!=1 or
697
+ profile['environment']!=context['environment'] or profile['contextKey']!=context['contextKey'] or
698
+ profile['identity']!={'userId':context['principalId'],'organizationId':context['organizationId']}):
699
+ raise PackError('Exact native-cli approved profile/principal/context reference required')
700
+ selected=SimpleNamespace(env={'TOPOLO_CONFIG_PATH':profile['configPath']},environment=context['environment'],context=context['contextKey'])
701
+ args=SimpleNamespace(private_profile=True,environment=context['environment'],context_key=context['contextKey'])
702
+ private_profile_reference(selected,args)
703
+ for path,sha in [(value['cli']['nodeExecutable'],value['cli']['nodeDigest']),(value['cli']['entry'],value['cli']['entryDigest'])]:
704
+ p=pathlib.Path(path);info=p.lstat()
705
+ if (p.resolve()!=p or not stat.S_ISREG(info.st_mode) or info.st_uid not in {0,os.getuid()} or info.st_mode&0o022 or
706
+ not info.st_mode&0o111 or hashlib.sha256(p.read_bytes()).hexdigest()!=sha):
707
+ raise PackError('Native-cli executable source/provenance changed')
708
+ allowed={'HOME','USER','LOGNAME','PATH','LANG','LC_ALL','TMPDIR'}
709
+ env={k:v for k,v in host_env.items() if k in allowed and isinstance(v,str)}
710
+ env['PATH']=str(pathlib.Path(value['cli']['nodeExecutable']).parent)+os.pathsep+'/usr/bin:/bin'
711
+ env.update(TOPOLO_CONFIG_PATH=profile['configPath'],TOPOLO_ENV=context['environment'],TOPOLO_CONTEXT=context['contextKey'])
712
+ return env
713
+
714
+
715
+ def native_cli_continuity_read(lib,args,*,_admit=None,_client_factory=None,_response=None):
716
+ """Native command producer. No current runtime authority producer exists.
717
+
718
+ Injected callbacks are internal hermetic seams, never CLI/JSON options.
719
+ Receipt output is public response evidence, not native-query attribution.
720
+ """
721
+ from . import lanes
722
+ path=pathlib.Path(args.continuity_input);info=path.lstat()
723
+ if (path.is_symlink() or not stat.S_ISREG(info.st_mode) or info.st_uid!=os.getuid() or info.st_nlink!=1 or
724
+ info.st_mode&0o077 or info.st_size>65536):
725
+ raise PackError('Exact owned bounded native-cli input required')
726
+ value=lanes.native_cli_input(read_json(path))
727
+ (lanes.native_cli_admission if _admit is None else _admit)(value)
728
+ context=value['context']
729
+ if (args.environment!=context['environment'] or args.context_key!=context['contextKey'] or args.role!=context['logicalId'] or
730
+ value['sourceRoleKey']!=args.name+'/'+args.role):
731
+ raise PackError('Native-cli command differs from the exact source/operation')
732
+ file=binding_path(lib,args.name,args.environment,args.context_key);info=file.lstat()
733
+ if (file.is_symlink() or not stat.S_ISREG(info.st_mode) or info.st_uid!=os.getuid() or info.st_nlink!=1 or
734
+ hashlib.sha256(file.read_bytes()).hexdigest()!=value['source']['bindingDigest']):
735
+ raise PackError('Native-cli current owned binding source differs')
736
+ binding=read_json(file);roles=[r for r in binding['input']['roles'] if r['logicalId']==args.role]
737
+ if (len(roles)!=1 or binding['identity']!={'userId':context['principalId'],'organizationId':context['organizationId']} or
738
+ binding['packRevision']!=value['source']['packRevision'] or binding['input']['instanceId']!=context['installationId'] or
739
+ binding['agentWorkspaceId']!=context['agentWorkspaceId'] or binding['input']['bytesWorkspaceId']!=context['bytesWorkspaceId'] or
740
+ binding['input']['bytesScope']!=context['bytesScope'] or roles[0]['agentId']!=context['agentId'] or roles[0]['agentVersionId']!=context['agentVersionId']):
741
+ raise PackError('Native-cli source principal/Agent/Bytes binding differs')
742
+ env=native_cli_selected_environment(value,binding,os.environ)
743
+ client=(Client if _client_factory is None else _client_factory)(args.environment,args.context_key,
744
+ binary=value['cli']['entry'],env=env,node=value['cli']['nodeExecutable'])
745
+ call=native_cli_command_response if _response is None else _response
746
+ identity,identity_events=call(client,['whoami'],'auth')
747
+ if (identity.get('user',{}).get('id')!=context['principalId'] or (identity.get('organization')or{}).get('id')!=context['organizationId']):
748
+ raise PackError('Actual native-cli public identity differs')
749
+ with tempfile.TemporaryDirectory(prefix='topolo-native-cli-context-') as directory:
750
+ input_file=pathlib.Path(directory)/'input.json';atomic_json(input_file,{'instanceId':context['installationId'],'logicalId':context['logicalId']})
751
+ envelope,context_events=call(client,['actions','call','app_topolo_agent.agent_packs.context','--detail','--data','@'+str(input_file),
752
+ '--resource-type','workspace','--resource-id',context['agentWorkspaceId']],'agent')
753
+ result=envelope.get('data',envelope)
754
+ actual=result.get('context',{})
755
+ expected={'organizationId':context['organizationId'],'workspaceId':context['agentWorkspaceId'],'instanceId':context['installationId'],
756
+ 'logicalId':context['logicalId'],'agentId':context['agentId'],'agentVersionId':context['agentVersionId'],
757
+ 'artifacts':{'appId':'app_topolo_bytes','resourceType':'workspace','resourceId':context['bytesWorkspaceId'],'scope':context['bytesScope']}}
758
+ if envelope.get('success') is False or any(actual.get(k)!=v for k,v in expected.items()):
759
+ raise PackError('Actual native-cli public Agent/Bytes context differs')
760
+ # Recheck mutable public binding, binary and stat-only profile after awaited reads.
761
+ if hashlib.sha256(file.read_bytes()).hexdigest()!=value['source']['bindingDigest']:
762
+ raise PackError('Native-cli binding changed during response; no receipt ACK')
763
+ native_cli_selected_environment(value,binding,os.environ)
764
+ (lanes.native_cli_admission if _admit is None else _admit)(value)
765
+ responses={}
766
+ for kind,body,events in [('identity',{'userId':context['principalId'],'organizationId':context['organizationId']},identity_events),
767
+ ('context',expected,context_events)]:
768
+ responses[kind]={'requestEvents':events,'bodyProjectionDigest':lanes.digest(body),'actionId':None if kind=='identity' else 'app_topolo_agent.agent_packs.context',
769
+ 'resourceType':None if kind=='identity' else 'workspace','resourceId':None if kind=='identity' else context['agentWorkspaceId']}
770
+ receipt={k:value[k] for k in lanes.NATIVE_CLI_RECEIPT_FIELDS-{'format','schemaVersion','responses','claim'}}
771
+ receipt.update(format='topolo-native-cli-continuity-receipt',schemaVersion=1,responses=responses,
772
+ claim='PUBLIC_IDENTITY_CONTEXT_RESPONSE_ONLY_NATIVE_ATTRIBUTION_REQUIRED')
773
+ return lanes.native_cli_receipt(value,receipt)
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env node
2
2
 
3
3
  // src/lib/claude-pack-backend.ts
4
- import { createHash, randomBytes, randomUUID } from "crypto";
4
+ import { createHash as createHash2, randomBytes, randomUUID } from "crypto";
5
5
  import { closeSync, existsSync, fsyncSync, lstatSync, mkdirSync, openSync, readFileSync, realpathSync, renameSync, unlinkSync, writeFileSync } from "fs";
6
6
  import * as filesystem from "fs";
7
7
  import * as cryptography from "crypto";
@@ -13,6 +13,7 @@ import { createConnection } from "net";
13
13
  import { WebSocket } from "undici";
14
14
 
15
15
  // src/lib/claude-native-pack.ts
16
+ import { createHash } from "crypto";
16
17
  async function nativeClaudePackOperation(manager, sidebar, plan, apply, checkpoint, verifyContext = () => {
17
18
  }) {
18
19
  const fenceKey = /* @__PURE__ */ Symbol.for("topolo.agent-pack.native-operation.v1");
@@ -849,7 +850,7 @@ async function nativeClaudeApprovalOperation(manager, routes, operation, fingerp
849
850
  const session = await manager.getSession(route.sessionId);
850
851
  if (!session || session.sessionId !== route.sessionId || session.cwd !== route.cwd || session.title !== route.title || session.isArchived)
851
852
  throw new Error("Native approval session identity differs: " + route.key);
852
- if (!descriptor || descriptor.sessionId !== route.sessionId || descriptor.cwd !== route.cwd || descriptor.title !== route.title || descriptor.isArchived || descriptor.backend?.kind !== "local" || descriptor.backend.remoteTarget || descriptor.worktreePath || descriptor.worktreeLazy || (route.dynamic ? descriptor.spawnedFrom?.sessionId !== route.dynamic.nativeParentId || descriptor.spawnedFrom?.sideSession !== true || route.dynamic.nativeParentId !== route.intakeSessionId || !/^[a-f0-9]{64}$/.test(route.dynamic.planDigest) : descriptor.spawnedFrom))
853
+ if (!descriptor || descriptor.sessionId !== route.sessionId || descriptor.cwd !== route.cwd || descriptor.title !== route.title || descriptor.isArchived || descriptor.backend?.kind !== "local" || descriptor.backend.remoteTarget || descriptor.worktreePath || descriptor.worktreeLazy || (route.dynamic ? (route.dynamic.continuityTransport === "native-cli" ? Boolean(descriptor.spawnedFrom) || route.dynamic.nativeParentId !== null : descriptor.spawnedFrom?.sessionId !== route.dynamic.nativeParentId || descriptor.spawnedFrom?.sideSession !== true || route.dynamic.nativeParentId !== route.intakeSessionId) || !/^[a-f0-9]{64}$/.test(route.dynamic.planDigest) : descriptor.spawnedFrom))
853
854
  throw new Error("Native approval session descriptor identity differs: " + route.key);
854
855
  return session;
855
856
  };
@@ -993,11 +994,30 @@ async function nativeClaudeApprovalOperation(manager, routes, operation, fingerp
993
994
  if (operation.kind === "list") return { requests: [...state.entries.values()].map((e) => ({ ...e.record })) };
994
995
  const entry = state.entries.get(operation.key);
995
996
  if (!entry || entry.record.state !== "pending" || entry.record.intakeSessionId !== operation.intake || entry.record.fingerprint !== operation.fingerprint) throw new Error("Exact pending request and owning intake required.");
996
- if (operation.kind === "respond" && operation.decision === "once" && byId.get(entry.record.sourceSessionId)?.dynamic)
997
- throw Object.assign(
997
+ let cliFinalGuard;
998
+ if (operation.kind === "respond" && operation.decision === "once" && byId.get(entry.record.sourceSessionId)?.dynamic) {
999
+ const route = byId.get(entry.record.sourceSessionId);
1000
+ if (route.dynamic?.continuityTransport === "native-cli") {
1001
+ const producer = state.dynamicLifecycle?.get(entry.record.sourceSessionId)?.authorizeNativeCLI;
1002
+ if (typeof producer !== "function") throw Object.assign(new Error("native_cli_startup_unqualified: actual native CLI admission producer unavailable."), { code: "native_cli_startup_unqualified" });
1003
+ const admission = await producer(entry.record, entry.request, operation);
1004
+ if (!admission || !["bootstrap", "work"].includes(admission.phase) || admission.nativeId !== entry.record.sourceSessionId || admission.intakeNativeId !== entry.record.intakeSessionId || admission.fingerprint !== entry.record.fingerprint || admission.generation !== route.dynamic.generation || typeof route.dynamic.generation !== "string" || !route.dynamic.generation || !admission.query || typeof admission.verifyCurrent !== "function" || typeof admission.model !== "string" || !admission.model || typeof admission.effort !== "string" || !admission.effort)
1005
+ throw new Error("Exact current native CLI query/intake admission differs.");
1006
+ const raw = await manager.getSessionWhenLoaded(entry.record.sourceSessionId, "topolo-native-cli-permission", { warnOnMiss: false });
1007
+ if (raw?.query !== admission.query || typeof manager.readRunningModel !== "function" || typeof manager.getEffort !== "function" || await manager.readRunningModel(raw, raw.query) !== admission.model || await manager.getEffort(raw.sessionId) !== admission.effort)
1008
+ throw new Error("Actual same-query native model/effort acknowledgement differs.");
1009
+ cliFinalGuard = () => {
1010
+ if (state.dynamicLifecycle?.get(entry.record.sourceSessionId)?.authorizeNativeCLI !== producer || raw.query !== admission.query || admission.verifyCurrent() !== void 0) throw new Error("Current native CLI admission changed before dispatch.");
1011
+ };
1012
+ if (admission.phase === "bootstrap") {
1013
+ if (entry.request.toolName !== "Bash" || entry.request.input?.command !== admission.command || admission.commandDigest !== fingerprint(admission.command))
1014
+ throw new Error("Only the exact native CLI bootstrap command may precede context acknowledgement.");
1015
+ } else if (!/^[a-f0-9]{64}$/.test(admission.contextReceiptDigest ?? "")) throw new Error("Native CLI work requires verified same-query context receipt.");
1016
+ } else throw Object.assign(
998
1017
  new Error("native_private_query_prestart_contract_unqualified: dynamic private query authorization remains closed."),
999
1018
  { code: "native_private_query_prestart_contract_unqualified" }
1000
1019
  );
1020
+ }
1001
1021
  const pending = await current(entry);
1002
1022
  if (manager[symbol] !== state || state.entries.get(operation.key) !== entry || entry.record.state !== "pending" || state.auditFailed)
1003
1023
  throw new Error("Exact pending request changed during native identity validation; reconcile without replay.");
@@ -1005,6 +1025,7 @@ async function nativeClaudeApprovalOperation(manager, routes, operation, fingerp
1005
1025
  if (operation.kind !== "respond" || operation.humanDecisionRecorded !== true || !["once", "deny"].includes(operation.decision ?? ""))
1006
1026
  throw new Error("Recorded human one-request decision required; never auto-approve.");
1007
1027
  if (operation.decision !== "deny" && entry.record.cardOnly) throw new Error("Claude requires the original card; intake cannot impersonate its origin.");
1028
+ cliFinalGuard?.();
1008
1029
  entry.record.state = "response-may-have-effects";
1009
1030
  checkpoint({ ...entry.record });
1010
1031
  await manager.respondToToolPermission(pending.requestId, operation.decision, void 0, "elsewhere");
@@ -1019,17 +1040,26 @@ async function nativeClaudeApprovalOperation(manager, routes, operation, fingerp
1019
1040
  }
1020
1041
  async function nativeClaudeAppendDynamicRoute(manager, route, verify, checkpoint, lifecycle) {
1021
1042
  const state = manager[/* @__PURE__ */ Symbol.for("topolo.agent-pack.approvals.v1")];
1022
- if (!state || state.auditFailed || !state.byId || !state.byKey || !route.dynamic || !/^[a-f0-9]{64}$/.test(route.dynamic.planDigest) || route.dynamic.nativeParentId !== route.intakeSessionId)
1043
+ if (!state || state.auditFailed || !state.byId || !state.byKey || !route.dynamic || !/^[a-f0-9]{64}$/.test(route.dynamic.planDigest) || (route.dynamic.continuityTransport === "native-cli" ? route.dynamic.nativeParentId !== null : route.dynamic.nativeParentId !== route.intakeSessionId))
1023
1044
  throw new Error("Current qualified original approval listener required.");
1045
+ let cliAdmission;
1046
+ if (route.dynamic.continuityTransport === "native-cli") {
1047
+ if (typeof lifecycle?.authorizeNativeCLI !== "function") throw Object.assign(new Error("native_cli_startup_unqualified: actual native CLI admission producer unavailable."), { code: "native_cli_startup_unqualified" });
1048
+ cliAdmission = await lifecycle.authorizeNativeCLI(null, null, { kind: "route-append" });
1049
+ }
1024
1050
  const intake = state.byId.get(route.intakeSessionId);
1025
1051
  if (!intake || intake.key !== route.intakeKey || intake.contextKey !== route.contextKey || !intake.key.includes("/intakes/"))
1026
1052
  throw new Error("Dynamic approval route has no exact same-context original intake.");
1027
1053
  await verify();
1028
1054
  const raw = await manager.getSessionWhenLoaded(route.sessionId, "topolo-dynamic-route", { warnOnMiss: false });
1029
1055
  const dto = await manager.getSession(route.sessionId);
1030
- if (!raw || !dto || raw.sessionId !== route.sessionId || raw.cwd !== route.cwd || raw.title !== route.title || dto.sessionId !== route.sessionId || dto.cwd !== route.cwd || dto.title !== route.title || raw.isArchived || dto.isArchived || raw.backend?.kind !== "local" || raw.backend.remoteTarget || raw.worktreePath || raw.worktreeLazy || raw.spawnedFrom?.sessionId !== route.intakeSessionId || raw.spawnedFrom?.sideSession !== true)
1056
+ if (!raw || !dto || raw.sessionId !== route.sessionId || raw.cwd !== route.cwd || raw.title !== route.title || dto.sessionId !== route.sessionId || dto.cwd !== route.cwd || dto.title !== route.title || raw.isArchived || dto.isArchived || raw.backend?.kind !== "local" || raw.backend.remoteTarget || raw.worktreePath || raw.worktreeLazy || (route.dynamic.continuityTransport === "native-cli" ? Boolean(raw.spawnedFrom) : raw.spawnedFrom?.sessionId !== route.intakeSessionId || raw.spawnedFrom?.sideSession !== true))
1031
1057
  throw new Error("Actual dynamic child descriptor differs before route append.");
1058
+ if (route.dynamic.continuityTransport === "native-cli" && (!cliAdmission?.query || raw.query !== cliAdmission.query || cliAdmission.nativeId !== route.sessionId || cliAdmission.intakeNativeId !== route.intakeSessionId || cliAdmission.generation !== route.dynamic.generation || typeof route.dynamic.generation !== "string" || !route.dynamic.generation || typeof cliAdmission.verifyCurrent !== "function" || typeof cliAdmission.model !== "string" || !cliAdmission.model || typeof cliAdmission.effort !== "string" || !cliAdmission.effort || typeof manager.readRunningModel !== "function" || typeof manager.getEffort !== "function" || await manager.readRunningModel(raw, raw.query) !== cliAdmission.model || await manager.getEffort(raw.sessionId) !== cliAdmission.effort))
1059
+ throw new Error("Actual native CLI route query/model/effort admission differs.");
1032
1060
  await verify();
1061
+ if (route.dynamic.continuityTransport === "native-cli" && (raw.query !== cliAdmission.query || cliAdmission.verifyCurrent() !== void 0))
1062
+ throw new Error("Current native CLI route admission changed before append.");
1033
1063
  if (manager[/* @__PURE__ */ Symbol.for("topolo.agent-pack.approvals.v1")] !== state || state.auditFailed)
1034
1064
  throw new Error("Original native permission connection changed.");
1035
1065
  const old = state.byId.get(route.sessionId);
@@ -1188,8 +1218,8 @@ function prepareClaudeNativePlan(store, pack, policyPath, mode = "configure") {
1188
1218
  captureMarkdown(cwd);
1189
1219
  const charter = resolve(cwd, "CLAUDE.md");
1190
1220
  const transcript = realpathSync(record.transcript);
1191
- context[charter] = createHash("sha256").update(readFileSync(charter)).digest("hex");
1192
- context[transcript] = createHash("sha256").update(readFileSync(transcript)).digest("hex");
1221
+ context[charter] = createHash2("sha256").update(readFileSync(charter)).digest("hex");
1222
+ context[transcript] = createHash2("sha256").update(readFileSync(transcript)).digest("hex");
1193
1223
  roleContextFiles[record.desktopSessionId] = [charter, transcript];
1194
1224
  members.push({
1195
1225
  key: record.key,
@@ -1207,7 +1237,7 @@ function prepareClaudeNativePlan(store, pack, policyPath, mode = "configure") {
1207
1237
  });
1208
1238
  }
1209
1239
  for (const file of [resolve(root, "claude/state.json"), realpathSync(policyPath)])
1210
- context[file] = createHash("sha256").update(readFileSync(file)).digest("hex");
1240
+ context[file] = createHash2("sha256").update(readFileSync(file)).digest("hex");
1211
1241
  const activePath = resolve(root, "claude/active.json");
1212
1242
  const active = existsSync(activePath) ? JSON.parse(readFileSync(activePath, "utf8")) : null;
1213
1243
  const target = new Set(members.map((m) => m.key));
@@ -1224,7 +1254,7 @@ function prepareClaudeNativePlan(store, pack, policyPath, mode = "configure") {
1224
1254
  if (!cwd.startsWith(resolve(root, "claude/workspaces", record.pack) + sep)) throw new Error("Outgoing workspace is outside the owned pack.");
1225
1255
  captureMarkdown(cwd);
1226
1256
  for (const file of [resolve(cwd, "CLAUDE.md"), realpathSync(record.transcript)])
1227
- context[file] = createHash("sha256").update(readFileSync(file)).digest("hex");
1257
+ context[file] = createHash2("sha256").update(readFileSync(file)).digest("hex");
1228
1258
  outgoing.push({ key, sessionId: record.desktopSessionId, cwd, title: record.title });
1229
1259
  }
1230
1260
  } else if (mode === "switch") throw new Error("Configure and verify an initial active roster before switching.");
@@ -1528,7 +1558,7 @@ async function configureClaudePack(options, evaluate = evaluateClaudeMain, quali
1528
1558
  if (!journal.startsWith(realpathSync(directory) + sep)) throw new Error("Recovery journal is outside the owned library.");
1529
1559
  const lines = readFileSync(journal, "utf8").split("\n").filter(Boolean);
1530
1560
  const line = lines[0];
1531
- if (createHash("sha256").update(line).digest("hex") !== marker.planHash) throw new Error("Recovery plan identity changed.");
1561
+ if (createHash2("sha256").update(line).digest("hex") !== marker.planHash) throw new Error("Recovery plan identity changed.");
1532
1562
  const record = JSON.parse(line);
1533
1563
  if (record.pack !== options.pack || record.operationId !== marker.operationId || !record.apply) throw new Error("Recovery pack or operation identity differs.");
1534
1564
  plan = { ...record, approvalRoutes: record.approvalRoutes ?? [], recovery: true, noEffects: marker.format === 2 && marker.dispatchState === "not-dispatched" && !lines.map((line2) => JSON.parse(line2)).some((r) => r.kind === "attempt") };
@@ -1542,7 +1572,7 @@ async function configureClaudePack(options, evaluate = evaluateClaudeMain, quali
1542
1572
  throw new Error("Unowned native approval connection.");
1543
1573
  const connection = JSON.parse(readFileSync(connectionPath, "utf8"));
1544
1574
  if (connection.pid === options.pid && connection.pack === options.pack && JSON.stringify(connection.routes) === JSON.stringify(plan.approvalRoutes) && JSON.stringify(connection.installationConsent) === JSON.stringify(plan.installationConsent)) {
1545
- if (typeof connection.secretPath !== "string" || typeof connection.socket !== "string" || !resolve(connection.secretPath).startsWith(realpathSync(resolve(root, "claude/private")) + sep) || realpathSync(connection.secretPath) !== resolve(connection.secretPath) || dirname(resolve(connection.socket)) !== resolve("/tmp", "topolo-claude-pack-" + createHash("sha256").update(root).digest("hex").slice(0, 16)))
1575
+ if (typeof connection.secretPath !== "string" || typeof connection.socket !== "string" || !resolve(connection.secretPath).startsWith(realpathSync(resolve(root, "claude/private")) + sep) || realpathSync(connection.secretPath) !== resolve(connection.secretPath) || dirname(resolve(connection.socket)) !== resolve("/tmp", "topolo-claude-pack-" + createHash2("sha256").update(root).digest("hex").slice(0, 16)))
1546
1576
  throw new Error("Native approval connection is outside owned control paths.");
1547
1577
  const secret = lstatSync(connection.secretPath);
1548
1578
  if (!secret.isFile() || secret.isSymbolicLink() || typeof process.getuid !== "function" || secret.uid !== process.getuid() || secret.mode & 63)
@@ -1553,7 +1583,7 @@ async function configureClaudePack(options, evaluate = evaluateClaudeMain, quali
1553
1583
  if (!plan.control) {
1554
1584
  const directory2 = resolve(root, "claude/private");
1555
1585
  mkdirSync(directory2, { recursive: true, mode: 448 });
1556
- const socketDirectory = resolve("/tmp", "topolo-claude-pack-" + createHash("sha256").update(root).digest("hex").slice(0, 16));
1586
+ const socketDirectory = resolve("/tmp", "topolo-claude-pack-" + createHash2("sha256").update(root).digest("hex").slice(0, 16));
1557
1587
  mkdirSync(socketDirectory, { recursive: true, mode: 448 });
1558
1588
  for (const path of [directory2, socketDirectory]) {
1559
1589
  const stat = lstatSync(path);
@@ -1568,7 +1598,7 @@ async function configureClaudePack(options, evaluate = evaluateClaudeMain, quali
1568
1598
  journal = resolve(directory, operationId + ".jsonl");
1569
1599
  const record = { kind: "plan", pack: options.pack, ...plan, apply: options.apply };
1570
1600
  durableRecord(journal, record, "wx");
1571
- marker = { format: 2, dispatchState: "not-dispatched", operationId, journal, planHash: createHash("sha256").update(JSON.stringify(record)).digest("hex") };
1601
+ marker = { format: 2, dispatchState: "not-dispatched", operationId, journal, planHash: createHash2("sha256").update(JSON.stringify(record)).digest("hex") };
1572
1602
  if (options.apply) durableRecord(markerPath, marker, "wx");
1573
1603
  syncDirectory(directory);
1574
1604
  syncDirectory(resolve(root, "claude"));
@@ -1837,8 +1867,9 @@ function prepareClaudeDynamicLane(store, pack, policyPath, laneId) {
1837
1867
  if (lstatSync(file).size > 131072) throw new Error("Dynamic lane record exceeds its schema bound.");
1838
1868
  const record = JSON.parse(readFileSync(file, "utf8"));
1839
1869
  const canonical = (value) => JSON.stringify(value, (_key, item) => item && typeof item === "object" && !Array.isArray(item) ? Object.fromEntries(Object.keys(item).sort().map((key) => [key, item[key]])) : item);
1840
- const digest = (value) => createHash("sha256").update(canonical(value)).digest("hex");
1841
- if (record.format !== "topolo-dynamic-lane" || record.schemaVersion !== 1 || record.harness !== "claude" || record.laneId !== laneId || record.planDigest !== digest(record.plan) || record.creationReceiptDigest !== digest(record.creationReceipt) || typeof record.nativeTitle !== "string" || !record.nativeTitle || record.nativeTitle.length > 256 || record.plan.role.packId !== pack || record.plan.nativeParentId !== record.plan.intake.nativeId)
1870
+ const digest = (value) => createHash2("sha256").update(canonical(value)).digest("hex");
1871
+ const nativeCLI = record.schemaVersion === 2 && record.plan?.schemaVersion === 2 && record.plan.continuityTransport === "native-cli";
1872
+ if (record.format !== "topolo-dynamic-lane" || !(record.schemaVersion === 1 || nativeCLI) || record.harness !== "claude" || record.laneId !== laneId || record.planDigest !== digest(record.plan) || record.creationReceiptDigest !== digest(record.creationReceipt) || typeof record.nativeTitle !== "string" || !record.nativeTitle || record.nativeTitle.length > 256 || record.plan.role.packId !== pack || (nativeCLI ? record.plan.nativeParentId !== null : record.plan.nativeParentId !== record.plan.intake.nativeId))
1842
1873
  throw new Error("Durable dynamic child identity or plan digest differs.");
1843
1874
  const stateFile = owned(resolve(root, "claude/state.json"));
1844
1875
  const state = JSON.parse(readFileSync(stateFile, "utf8"));
@@ -1847,8 +1878,8 @@ function prepareClaudeDynamicLane(store, pack, policyPath, laneId) {
1847
1878
  if (state.harness !== "claude" || policy.format !== "topolo-agent-execution-policy" || policy.pack !== pack || policy.sourceRevision !== record.plan.role.packRevision || !policy.installationConsent)
1848
1879
  throw new Error("Dynamic child source policy or organization-bound installation is stale.");
1849
1880
  const context = {
1850
- [stateFile]: createHash("sha256").update(readFileSync(stateFile)).digest("hex"),
1851
- [policyFile]: createHash("sha256").update(readFileSync(policyFile)).digest("hex")
1881
+ [stateFile]: createHash2("sha256").update(readFileSync(stateFile)).digest("hex"),
1882
+ [policyFile]: createHash2("sha256").update(readFileSync(policyFile)).digest("hex")
1852
1883
  };
1853
1884
  const inventories = {};
1854
1885
  const fixed = (descriptor) => {
@@ -1861,7 +1892,7 @@ function prepareClaudeDynamicLane(store, pack, policyPath, laneId) {
1861
1892
  throw new Error("Dynamic source workspace or current fixed settings differ.");
1862
1893
  const files = [resolve(cwd, "CLAUDE.md"), resolve(cwd, "topolo-connection.json"), resolve(cwd, ".mcp.json")];
1863
1894
  const hashes = {};
1864
- for (const f of files) hashes[owned(f)] = createHash("sha256").update(readFileSync(f)).digest("hex");
1895
+ for (const f of files) hashes[owned(f)] = createHash2("sha256").update(readFileSync(f)).digest("hex");
1865
1896
  const connection = JSON.parse(readFileSync(files[1], "utf8"));
1866
1897
  const expected = {
1867
1898
  environment: descriptor.environment,
@@ -1898,6 +1929,7 @@ function prepareClaudeDynamicLane(store, pack, policyPath, laneId) {
1898
1929
  planDigest: record.planDigest,
1899
1930
  nativeId: record.nativeId,
1900
1931
  cwd: record.creationReceipt.cwd,
1932
+ ...nativeCLI ? { continuityTransport: "native-cli", continuity: record.plan.continuity } : {},
1901
1933
  title: record.nativeTitle,
1902
1934
  source,
1903
1935
  intake,
@@ -1981,7 +2013,7 @@ function prepareClaudePrivateHelperConnection(store, pack, policyPath, sourceRol
1981
2013
  const policyBytes = readFileSync(policyFile), policy = JSON.parse(policyBytes.toString("utf8")), consent = policy.installationConsent;
1982
2014
  if (!consent || !["development", "staging", "production"].includes(consent.environment) || typeof consent.contextKey !== "string")
1983
2015
  throw new Error("Existing approved per-environment private connection required.");
1984
- const bindingFile = resolve(root, "connections", pack, consent.environment, createHash("sha256").update(consent.contextKey).digest("hex") + ".json");
2016
+ const bindingFile = resolve(root, "connections", pack, consent.environment, createHash2("sha256").update(consent.contextKey).digest("hex") + ".json");
1985
2017
  const bindingBytes = readFileSync(bindingFile), binding = JSON.parse(bindingBytes.toString("utf8"));
1986
2018
  const connection = {
1987
2019
  format: "topolo-private-helper-connection",
@@ -1991,9 +2023,9 @@ function prepareClaudePrivateHelperConnection(store, pack, policyPath, sourceRol
1991
2023
  sourceRoleKey,
1992
2024
  policyFile,
1993
2025
  bindingFile,
1994
- policyDigest: createHash("sha256").update(policyBytes).digest("hex"),
1995
- bindingDigest: createHash("sha256").update(bindingBytes).digest("hex"),
1996
- stateDigest: createHash("sha256").update(readFileSync(resolve(root, "claude/state.json"))).digest("hex"),
2026
+ policyDigest: createHash2("sha256").update(policyBytes).digest("hex"),
2027
+ bindingDigest: createHash2("sha256").update(bindingBytes).digest("hex"),
2028
+ stateDigest: createHash2("sha256").update(readFileSync(resolve(root, "claude/state.json"))).digest("hex"),
1997
2029
  profile: binding.privateCredentialProfile
1998
2030
  };
1999
2031
  privateClaudeHelperEnvironment(connection, filesystem, cryptography, paths, process.env);
@@ -2025,6 +2057,11 @@ function runClaudeLaneHelper(root, pack, policyPath, action, payload, source, co
2025
2057
  return Promise.reject(new Error("Closed typed native lifecycle helper required."));
2026
2058
  const encoded = JSON.stringify(payload);
2027
2059
  if (Buffer.byteLength(encoded) > 2097152) return Promise.reject(new Error("Own-child native transcript exceeds bounded transport; no broad history read."));
2060
+ try {
2061
+ requireClaudePrivateQueryEffectQualified("helper", payload);
2062
+ } catch (error) {
2063
+ return Promise.reject(error);
2064
+ }
2028
2065
  const selectedRole = payload.sourceRoleKey ?? payload.request?.sourceRoleKey ?? payload.plan?.role?.key ?? payload.operation?.record?.plan?.role?.key;
2029
2066
  if (!connection || root !== connection.root || pack !== connection.pack || policyPath !== connection.policyFile || selectedRole !== void 0 && selectedRole !== connection.sourceRoleKey)
2030
2067
  return Promise.reject(new Error("Private helper arguments differ from the exact bound source connection."));
@@ -2072,7 +2109,14 @@ function runClaudeLaneHelper(root, pack, policyPath, action, payload, source, co
2072
2109
  child.stdin.end(encoded);
2073
2110
  });
2074
2111
  }
2075
- function requireClaudePrivateQueryEffectQualified(operation) {
2112
+ function requireClaudePrivateQueryEffectQualified(operation, input) {
2113
+ const candidates = [input, input?.request, input?.plan, input?.record?.plan, input?.operation?.record?.plan];
2114
+ const transports = candidates.map((value) => value?.continuityTransport).filter((value) => value !== void 0);
2115
+ if (transports.some((value) => !["native-cli", "private-mcp"].includes(value)) || new Set(transports).size > 1)
2116
+ throw new Error("Closed explicit continuity transport required; no fallback.");
2117
+ const transport = transports[0];
2118
+ if (transport === "native-cli" || candidates.some((value) => value?.schemaVersion === 2))
2119
+ throw Object.assign(new Error("native_cli_startup_unqualified: current startup, profile refresh authority and native result producers are unavailable."), { code: "native_cli_startup_unqualified" });
2076
2120
  if (["create", "configure", "context-start", "fixture-start", "retire", "approval-once"].includes(operation))
2077
2121
  throw Object.assign(
2078
2122
  new Error("native_private_query_prestart_contract_unqualified: private native query startup, exclusion and owned lifecycle are not qualified."),
@@ -2082,12 +2126,12 @@ function requireClaudePrivateQueryEffectQualified(operation) {
2082
2126
  function claudeLaneExpression(options, source, journal, prepared) {
2083
2127
  if (!Number.isSafeInteger(options.pid) || options.pid < 1 || !["plan", "create", "create-read", "adopt", "read", "configure", "context-start", "context-read", "fixture-start", "fixture-read", "retire"].includes(options.operation))
2084
2128
  throw new Error("Closed typed Claude lane operation required.");
2085
- requireClaudePrivateQueryEffectQualified(options.operation);
2129
+ requireClaudePrivateQueryEffectQualified(options.operation, options.input);
2086
2130
  if (!options.privateConnection) throw new Error("Explicit approved private helper connection required before native access.");
2087
2131
  return `(async()=>{
2088
2132
  const expected=${JSON.stringify({ ...options, qualifier: CLAUDE_NATIVE_QUALIFIER, source, journal })};
2089
2133
  const requireClaudePrivateQueryEffectQualified=(${requireClaudePrivateQueryEffectQualified.toString()});
2090
- requireClaudePrivateQueryEffectQualified(expected.operation);
2134
+ requireClaudePrivateQueryEffectQualified(expected.operation,expected.input);
2091
2135
  if(process.pid!==expected.pid || typeof process.getBuiltinModule!=='function')throw new Error('Native process identity changed.');
2092
2136
  const load=process.getBuiltinModule('module').createRequire(process.resourcesPath+'/app.asar/package.json');
2093
2137
  const fs=load('node:fs'),crypto=load('node:crypto'),path=load('node:path');
@@ -2203,7 +2247,7 @@ function claudeLaneExpression(options, source, journal, prepared) {
2203
2247
  if(!secretInfo.isFile()||secretInfo.isSymbolicLink()||secretInfo.uid!==process.getuid()||secretInfo.mode&63)throw new Error('Unowned private native control secret.');
2204
2248
  const secret=JSON.parse(fs.readFileSync(control.secretPath,'utf8'));
2205
2249
  const ownedOperation=async op=>{
2206
- requireClaudePrivateQueryEffectQualified(op.kind==='approval-respond'&&op.decision==='once'?'approval-once':op.kind);
2250
+ requireClaudePrivateQueryEffectQualified(op.kind==='approval-respond'&&op.decision==='once'?'approval-once':op.kind,{continuityTransport:nativePlan.continuityTransport});
2207
2251
  qualify();const current=await helper('read',{laneId:nativePlan.laneId});
2208
2252
  const scopedPlan={...nativePlan,lifecycleState:current.state,deadline:Date.now()+200000};
2209
2253
  if(op.kind.startsWith('approval-')){
@@ -2270,7 +2314,7 @@ function claudeLaneExpression(options, source, journal, prepared) {
2270
2314
  })()`;
2271
2315
  }
2272
2316
  async function operateClaudeLane(options, evaluate = evaluateClaudeMain) {
2273
- requireClaudePrivateQueryEffectQualified(options.operation);
2317
+ requireClaudePrivateQueryEffectQualified(options.operation, options.input);
2274
2318
  validateInspectorEndpoint(options.endpoint);
2275
2319
  const root = realpathSync(options.store);
2276
2320
  const policy = realpathSync(options.policy);
@@ -2285,6 +2329,7 @@ async function operateClaudeLane(options, evaluate = evaluateClaudeMain) {
2285
2329
  const journal = resolve(directory, randomUUID() + ".jsonl");
2286
2330
  durableRecord(journal, { operation: options.operation, pid: options.pid, at: Date.now() }, "wx");
2287
2331
  const prepared = ["plan", "create", "create-read", "adopt"].includes(options.operation) ? void 0 : prepareClaudeDynamicLane(root, options.pack, policy, options.input.laneId);
2332
+ if (prepared?.record.plan.continuityTransport === "native-cli") requireClaudePrivateQueryEffectQualified(options.operation, prepared.record.plan);
2288
2333
  let sourceRoleKey = prepared?.record.plan.role.key ?? (options.operation === "plan" ? options.input.request?.sourceRoleKey : options.input.plan?.role?.key);
2289
2334
  if (["create", "create-read"].includes(options.operation)) {
2290
2335
  if (typeof options.input.laneId !== "string" || !/^[a-z0-9][a-z0-9-]*$/.test(options.input.laneId)) throw new Error("Exact existing creation lane required.");
@@ -2307,8 +2352,8 @@ async function operateClaudeLane(options, evaluate = evaluateClaudeMain) {
2307
2352
  mkdirSync(directory2, { mode: 448 });
2308
2353
  const secretPath = resolve(directory2, "secret.json");
2309
2354
  durableRecord(secretPath, { token: randomBytes(32).toString("hex") }, "wx");
2310
- const identity = createHash("sha256").update(JSON.stringify({ pid: options.pid, laneId, planDigest: prepared.record.planDigest, qualifier: CLAUDE_NATIVE_QUALIFIER })).digest("hex");
2311
- const socketDirectory = resolve("/tmp", "topolo-claude-" + process.getuid?.() + "-" + createHash("sha256").update(root + "\0" + laneId).digest("hex").slice(0, 24));
2355
+ const identity = createHash2("sha256").update(JSON.stringify({ pid: options.pid, laneId, planDigest: prepared.record.planDigest, qualifier: CLAUDE_NATIVE_QUALIFIER })).digest("hex");
2356
+ const socketDirectory = resolve("/tmp", "topolo-claude-" + process.getuid?.() + "-" + createHash2("sha256").update(root + "\0" + laneId).digest("hex").slice(0, 24));
2312
2357
  mkdirSync(socketDirectory, { mode: 448 });
2313
2358
  const socket = resolve(socketDirectory, "control.sock");
2314
2359
  control = { socket, secretPath, identity };
@@ -2335,7 +2380,7 @@ async function operateClaudeLane(options, evaluate = evaluateClaudeMain) {
2335
2380
  }
2336
2381
  }
2337
2382
  function operateClaudeLaneControl(options, request = requestClaudeApprovalControl) {
2338
- requireClaudePrivateQueryEffectQualified(options.operation.kind === "approval-respond" && options.operation.decision === "once" ? "approval-once" : options.operation.kind);
2383
+ requireClaudePrivateQueryEffectQualified(options.operation.kind === "approval-respond" && options.operation.decision === "once" ? "approval-once" : options.operation.kind, options.operation);
2339
2384
  if (!/^[a-z0-9][a-z0-9-]*$/.test(options.connection)) throw new Error("Exact owned native lane connection ID required.");
2340
2385
  const root = realpathSync(options.store);
2341
2386
  const directory = resolve(root, "claude/dynamic-controls", options.connection);