maka-agent 0.2.0-dev.16.20260903 → 0.2.0-dev.19.20260904

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (103) hide show
  1. package/RUNTIME_HOST_PEER_THIRD_PARTY_NOTICES.txt +1 -1
  2. package/dist/cli-core.js +7 -3
  3. package/dist/mcp-capability-provider.js +3 -9
  4. package/dist/runtime-host-cli.js +28 -6
  5. package/dist/runtime-host-lifecycle-transaction.js +27 -10
  6. package/dist/runtime-host-managed-deployment.js +112 -51
  7. package/dist/runtime-host-managed-lifecycle-manager.js +2 -5
  8. package/dist/runtime-host-package-deployment.js +35 -2
  9. package/dist/runtime-host-peer-artifact.js +3 -3
  10. package/dist/runtime-host-peer-management-command.js +4 -4
  11. package/dist/runtime-host-peer-mesh-management-command.js +1 -1
  12. package/dist/runtime-host-profile-command.js +1 -1
  13. package/dist/runtime-host-service-management-command.js +24 -3
  14. package/dist/runtime-host-setup-command.js +13 -16
  15. package/dist/runtime-host-update-command.js +13 -10
  16. package/dist/runtime-host-update-reconciliation.js +7 -7
  17. package/dist/runtime-host-windows-service.js +132 -0
  18. package/dist/runtime-host-windows-task-runner.js +90 -0
  19. package/native/runtime-host-peer/prebuilds/darwin-arm64/maka_runtime_host_peer.node +0 -0
  20. package/native/runtime-host-peer/prebuilds/linux-arm64/maka_runtime_host_peer.node +0 -0
  21. package/native/runtime-host-peer/prebuilds/linux-x64/maka_runtime_host_peer.node +0 -0
  22. package/native/runtime-host-peer/prebuilds/win32-x64/maka_runtime_host_peer.node +0 -0
  23. package/node_modules/@maka/core/dist/agent-run.js +23 -338
  24. package/node_modules/@maka/core/dist/execution-inspect.js +9 -20
  25. package/node_modules/@maka/core/dist/provider-registry.js +0 -9
  26. package/node_modules/@maka/core/dist/runtime-boundary.js +79 -27
  27. package/node_modules/@maka/core/dist/runtime-event-store.js +6 -0
  28. package/node_modules/@maka/core/dist/runtime-event.js +153 -0
  29. package/node_modules/@maka/core/dist/runtime-invocation.js +223 -0
  30. package/node_modules/@maka/core/dist/workhub-creation-intent.js +19 -5
  31. package/node_modules/@maka/core/package.json +2 -0
  32. package/node_modules/@maka/runtime/dist/agent-graph-timeline.js +12 -11
  33. package/node_modules/@maka/runtime/dist/agent-run-inspect.js +42 -77
  34. package/node_modules/@maka/runtime/dist/agent-run-recovery.js +36 -46
  35. package/node_modules/@maka/runtime/dist/agent-run.js +205 -329
  36. package/node_modules/@maka/runtime/dist/ai-sdk-backend.js +2 -2
  37. package/node_modules/@maka/runtime/dist/ai-sdk-compaction.js +28 -21
  38. package/node_modules/@maka/runtime/dist/context-diagnostics.js +8 -7
  39. package/node_modules/@maka/runtime/dist/continuation-replay.js +1 -1
  40. package/node_modules/@maka/runtime/dist/conversation-copy.js +93 -109
  41. package/node_modules/@maka/runtime/dist/execution-inspect.js +44 -39
  42. package/node_modules/@maka/runtime/dist/history-compact-checkpoint-coordinator.js +16 -6
  43. package/node_modules/@maka/runtime/dist/history-compact-ledger.js +6 -8
  44. package/node_modules/@maka/runtime/dist/history-compaction.js +9 -7
  45. package/node_modules/@maka/runtime/dist/interaction-authority.js +16 -0
  46. package/node_modules/@maka/runtime/dist/mcp-tools.js +83 -72
  47. package/node_modules/@maka/runtime/dist/model-history.js +13 -8
  48. package/node_modules/@maka/runtime/dist/model-projection-transition-ledger.js +3 -3
  49. package/node_modules/@maka/runtime/dist/openai-codex-history-compactor.js +1 -1
  50. package/node_modules/@maka/runtime/dist/prior-run-context.js +24 -94
  51. package/node_modules/@maka/runtime/dist/process-tree-terminator.js +2 -2
  52. package/node_modules/@maka/runtime/dist/runtime-event-backfill.js +21 -13
  53. package/node_modules/@maka/runtime/dist/runtime-event-read-model.js +75 -64
  54. package/node_modules/@maka/runtime/dist/runtime-kernel.js +101 -69
  55. package/node_modules/@maka/runtime/dist/runtime-ledger-repair.js +85 -393
  56. package/node_modules/@maka/runtime/dist/runtime-read-model.js +29 -112
  57. package/node_modules/@maka/runtime/dist/runtime-resume.js +69 -118
  58. package/node_modules/@maka/runtime/dist/session-manager.js +293 -334
  59. package/node_modules/@maka/runtime/dist/stream-graph-coordinator.js +0 -3
  60. package/node_modules/@maka/runtime/dist/stream-graph-projection.js +12 -15
  61. package/node_modules/@maka/runtime/dist/terminal-run-commit.js +37 -172
  62. package/node_modules/@maka/runtime-host/dist/client/host-profile.js +77 -29
  63. package/node_modules/@maka/runtime-host/dist/client/host-retirement.js +2 -2
  64. package/node_modules/@maka/runtime-host/dist/client/index.js +4 -3
  65. package/node_modules/@maka/runtime-host/dist/client/launcher.js +1 -1
  66. package/node_modules/@maka/runtime-host/dist/client/peer-client.js +2 -9
  67. package/node_modules/@maka/runtime-host/dist/client/reconnect-lifecycle.js +4 -2
  68. package/node_modules/@maka/runtime-host/dist/client/registered-host-termination.js +105 -0
  69. package/node_modules/@maka/runtime-host/dist/client/ssh-operator-activation.js +48 -11
  70. package/node_modules/@maka/runtime-host/dist/client/wsl-control.js +0 -8
  71. package/node_modules/@maka/runtime-host/dist/client/wsl-environment.js +12 -8
  72. package/node_modules/@maka/runtime-host/dist/client-capability-entity-id.js +27 -0
  73. package/node_modules/@maka/runtime-host/dist/operator/index.js +1 -0
  74. package/node_modules/@maka/runtime-host/dist/operator/managed-deployment.js +14 -5
  75. package/node_modules/@maka/runtime-host/dist/operator/operator-command.js +110 -0
  76. package/node_modules/@maka/runtime-host/dist/operator/service-management-frame.js +3 -6
  77. package/node_modules/@maka/runtime-host/dist/operator/setup-frame.js +17 -1
  78. package/node_modules/@maka/runtime-host/dist/peer-reachability/owner.js +1 -2
  79. package/node_modules/@maka/runtime-host/dist/peer-reachability/publisher.js +4 -4
  80. package/node_modules/@maka/runtime-host/dist/protocol/client-capability.js +11 -7
  81. package/node_modules/@maka/runtime-host/dist/server/canonical-turn-snapshot.js +19 -15
  82. package/node_modules/@maka/runtime-host/dist/server/client-capability-coordinator.js +42 -24
  83. package/node_modules/@maka/runtime-host/dist/server/execution-composition.js +22 -13
  84. package/node_modules/@maka/runtime-host/dist/server/execution-inspect-coordinator.js +35 -29
  85. package/node_modules/@maka/runtime-host/dist/server/hosted-execution-projection.js +12 -7
  86. package/node_modules/@maka/runtime-host/dist/server/hosted-execution-recovery.js +4 -5
  87. package/node_modules/@maka/runtime-host/dist/server/root-turn-coordinator.js +8 -16
  88. package/node_modules/@maka/runtime-host/dist/server/session-admission-gate.js +12 -0
  89. package/node_modules/@maka/runtime-host/dist/server/session-revision-coordinator.js +1 -1
  90. package/node_modules/@maka/runtime-host/dist/server/session-revision-graph-references.js +8 -7
  91. package/node_modules/@maka/runtime-host/dist/server/session-transcript-reader.js +2 -2
  92. package/node_modules/@maka/runtime-host/package.json +1 -0
  93. package/node_modules/@maka/storage/dist/agent-run-store.js +128 -215
  94. package/node_modules/@maka/storage/dist/artifact-store.js +12 -12
  95. package/node_modules/@maka/storage/dist/execution-record-codec.js +1 -22
  96. package/node_modules/@maka/storage/dist/execution-stores.js +10 -11
  97. package/node_modules/@maka/storage/dist/legacy-run-header.js +327 -0
  98. package/node_modules/@maka/storage/dist/runtime-event-persistence.js +5 -0
  99. package/node_modules/@maka/storage/dist/sqlite-artifact-metadata.js +20 -5
  100. package/node_modules/@maka/storage/dist/sqlite-core-execution-schema.js +10 -2
  101. package/node_modules/@maka/storage/dist/sqlite-runtime-schema.js +283 -1
  102. package/node_modules/@maka/storage/dist/sqlite-runtime-store.js +239 -63
  103. package/package.json +1 -1
@@ -5,7 +5,7 @@ Generated by scripts/generate-runtime-host-peer-notices.mjs from the exact
5
5
  four-target production dependency inventory. Do not edit this file by hand.
6
6
 
7
7
  Manifest: native/runtime-host-peer/Cargo.toml
8
- Cargo.lock SHA-256: e7d745e06c3d2d65d7a01e15075001e2f5fc95e127b77918ddb0d23c024984cd
8
+ Cargo.lock SHA-256: b1a7cdd67fee2bbde5bd8d91c6773f97e809515898604bde7ee0dbf4e04cbbd8
9
9
  Inventory SHA-256: c28a17749fa5f9af237a49dd2b4ad9149b6c4224d383c4a5050eeac3be14073c
10
10
 
11
11
  Packages
package/dist/cli-core.js CHANGED
@@ -20,7 +20,7 @@ import { readFile } from 'node:fs/promises';
20
20
  import { join } from 'node:path';
21
21
  import { fileURLToPath } from 'node:url';
22
22
  import { deriveMakaDataRoots, resolveMakaDataRoots } from './workspace-root.js';
23
- import { configureRuntimeHostPeerClient, resolveRuntimeHostPeerNativePath, } from './runtime-host-peer-artifact.js';
23
+ import { configureRuntimeHostPeerClient, resolveRuntimeHostNativePath, } from './runtime-host-peer-artifact.js';
24
24
  import { parseRuntimeHostCommand, parseRuntimeHostInstalledUpdateCommand, } from './runtime-host-cli.js';
25
25
  import { resolveCliUiLocale } from './cli-ui-locale.js';
26
26
  export const RELEASE_MAKA_CLI_LAUNCH_OPTIONS = {
@@ -264,6 +264,10 @@ export async function runMakaCli(argv = process.argv.slice(2), options = RELEASE
264
264
  const { config } = await resolveRuntimeHostManagedDeployment(command.managedDeployment.rootId);
265
265
  const peer = config.listeners.directPeer?.enabled ? config.listeners.directPeer : undefined;
266
266
  const packageLayout = resolveRuntimeHostNpmDeploymentLayout(config.deploymentRoot, config.launch.package.integrity);
267
+ if (process.platform === 'win32') {
268
+ const { ownWindowsRuntimeHostProcessTree } = await import('./runtime-host-windows-service.js');
269
+ await ownWindowsRuntimeHostProcessTree(packageLayout.cliPath);
270
+ }
267
271
  return runRuntimeHostServiceCli({
268
272
  rootPath: config.root.path,
269
273
  json: command.json,
@@ -276,7 +280,7 @@ export async function runMakaCli(argv = process.argv.slice(2), options = RELEASE
276
280
  ...(peer
277
281
  ? {
278
282
  peer: {
279
- nativePath: await resolveRuntimeHostPeerNativePath(packageLayout.cliPath),
283
+ nativePath: await resolveRuntimeHostNativePath(packageLayout.cliPath),
280
284
  keyPath: peer.keyPath,
281
285
  expectedPeerId: peer.peerId,
282
286
  listenAddresses: peer.listenAddresses,
@@ -681,7 +685,7 @@ export async function runMakaCli(argv = process.argv.slice(2), options = RELEASE
681
685
  id: command.id,
682
686
  name: command.name,
683
687
  distribution: command.distribution,
684
- operatorPath: command.operatorPath,
688
+ operator: command.operator,
685
689
  expectedRootId: command.expectedRootId,
686
690
  }, {}, profileOptions);
687
691
  }
@@ -17,6 +17,7 @@
17
17
  * under the License.
18
18
  */
19
19
  import { createHash } from 'node:crypto';
20
+ import { clientCapabilityEntityId } from '@maka/runtime-host/client-capability-entity-id';
20
21
  import { CLIENT_CAPABILITY_MAX_TOOLS, CLIENT_CAPABILITY_MAX_TOOLS_PER_OFFER, decodeClientCapabilityReplaceInput, } from '@maka/runtime-host/protocol';
21
22
  const CAPABILITY_VERSION = '0';
22
23
  export function createMcpCapabilityProvider(manager) {
@@ -32,7 +33,7 @@ export function createMcpCapabilityProvider(manager) {
32
33
  const projectedIdentities = new Set();
33
34
  const projected = [];
34
35
  for (const source of tools) {
35
- const descriptor = projectMcpTool(source.descriptor, capabilityEntityId(source.descriptor.serverId));
36
+ const descriptor = projectMcpTool(source.descriptor, clientCapabilityEntityId(source.descriptor.serverId));
36
37
  const identity = `${descriptor.serverId}\0${descriptor.name}`;
37
38
  if (projectedIdentities.has(identity)) {
38
39
  throw new Error('MCP tools collide after Client Capability identity normalization');
@@ -79,19 +80,12 @@ export function createMcpCapabilityProvider(manager) {
79
80
  function projectMcpTool(tool, wireServerId) {
80
81
  return {
81
82
  serverId: wireServerId,
82
- name: capabilityEntityId(tool.name),
83
+ name: clientCapabilityEntityId(tool.name),
83
84
  ...(tool.description ? { description: tool.description } : {}),
84
85
  inputSchema: structuredClone(tool.inputSchema),
85
86
  ...(tool.annotations ? { annotations: { ...tool.annotations } } : {}),
86
87
  };
87
88
  }
88
- function capabilityEntityId(value) {
89
- if (/^[A-Za-z0-9_-]{1,128}$/u.test(value))
90
- return value;
91
- const label = value.replace(/[^A-Za-z0-9_-]+/gu, '_').slice(0, 103) || 'mcp';
92
- const digest = createHash('sha256').update(value).digest('hex').slice(0, 24);
93
- return `${label}_${digest}`;
94
- }
95
89
  function projectMcpResult(result) {
96
90
  return {
97
91
  content: result.content.map((block) => structuredClone(block)),
@@ -18,7 +18,7 @@
18
18
  */
19
19
  import { isAbsolute } from 'node:path';
20
20
  import { isProductReleaseVersion, isSha512PackageIntegrity, } from '@maka/runtime-host/operator/update-package-evidence';
21
- import { decodeRuntimeHostWebRtcStunPolicy, } from '@maka/runtime-host/operator';
21
+ import { createRuntimeHostLegacyPosixOperatorCommand, decodeRuntimeHostPosixOperatorCommand, decodeRuntimeHostWebRtcStunPolicy, } from '@maka/runtime-host/operator';
22
22
  import { canonicalProjectDirectoryRootSpec, isCanonicalRuntimeHostWebSocketPath, PROJECT_DIRECTORY_MAX_ROOTS, projectDirectoryPosixRootSpecValid, projectDirectoryRootSpecValid, } from '@maka/runtime-host/protocol';
23
23
  import { hasEphemeralRuntimeHostPeerPort } from './runtime-host-peer-artifact.js';
24
24
  export function parseRuntimeHostCommand(argv) {
@@ -1348,6 +1348,7 @@ function parseProfileCommand(argv) {
1348
1348
  let sshWebSocketPath = '/runtime-host';
1349
1349
  let sshWebSocketPathConfigured = false;
1350
1350
  let wslDistribution;
1351
+ let operator;
1351
1352
  let operatorPath;
1352
1353
  let expectedRootId;
1353
1354
  let credentialEnv;
@@ -1362,6 +1363,7 @@ function parseProfileCommand(argv) {
1362
1363
  argument !== '--ssh-remote-port' &&
1363
1364
  argument !== '--ssh-websocket-path' &&
1364
1365
  argument !== '--wsl-distribution' &&
1366
+ argument !== '--operator-command' &&
1365
1367
  argument !== '--operator-path' &&
1366
1368
  argument !== '--expected-root' &&
1367
1369
  argument !== '--credential-env' &&
@@ -1395,6 +1397,14 @@ function parseProfileCommand(argv) {
1395
1397
  }
1396
1398
  if (argument === '--wsl-distribution')
1397
1399
  wslDistribution = parsed;
1400
+ if (argument === '--operator-command') {
1401
+ try {
1402
+ operator = decodeRuntimeHostPosixOperatorCommand(JSON.parse(parsed));
1403
+ }
1404
+ catch {
1405
+ return error('--operator-command must be a valid Runtime Host operator command JSON value');
1406
+ }
1407
+ }
1398
1408
  if (argument === '--operator-path')
1399
1409
  operatorPath = parsed;
1400
1410
  if (argument === '--expected-root')
@@ -1407,6 +1417,17 @@ function parseProfileCommand(argv) {
1407
1417
  return error('--id is required');
1408
1418
  if (!name)
1409
1419
  return error('--name is required');
1420
+ if (operator && operatorPath) {
1421
+ return error('--operator-command and --operator-path cannot be combined');
1422
+ }
1423
+ if (operatorPath) {
1424
+ try {
1425
+ operator = createRuntimeHostLegacyPosixOperatorCommand(operatorPath);
1426
+ }
1427
+ catch {
1428
+ return error('--operator-path must be an absolute POSIX path');
1429
+ }
1430
+ }
1410
1431
  if ((tlsUrl ? 1 : 0) +
1411
1432
  (plaintextUrl ? 1 : 0) +
1412
1433
  (sshDestination ? 1 : 0) +
@@ -1414,12 +1435,13 @@ function parseProfileCommand(argv) {
1414
1435
  1) {
1415
1436
  return error('exactly one of --tls-url, --plaintext-url, --ssh-destination, or --wsl-distribution is required');
1416
1437
  }
1417
- if (wslDistribution && !operatorPath) {
1418
- return error('--wsl-distribution requires --operator-path');
1438
+ if (wslDistribution && !operator) {
1439
+ return error('--wsl-distribution requires --operator-command or --operator-path');
1419
1440
  }
1420
- if (!wslDistribution && operatorPath) {
1441
+ if (!wslDistribution && operatorPath)
1421
1442
  return error('--operator-path requires --wsl-distribution');
1422
- }
1443
+ if (!wslDistribution && operator)
1444
+ return error('--operator-command requires --wsl-distribution');
1423
1445
  if (wslDistribution && credentialEnv) {
1424
1446
  return error('WSL environment profiles do not accept --credential-env');
1425
1447
  }
@@ -1451,7 +1473,7 @@ function parseProfileCommand(argv) {
1451
1473
  id,
1452
1474
  name,
1453
1475
  distribution: wslDistribution,
1454
- operatorPath: operatorPath,
1476
+ operator: operator,
1455
1477
  expectedRootId,
1456
1478
  };
1457
1479
  }
@@ -17,12 +17,11 @@
17
17
  * under the License.
18
18
  */
19
19
  import { randomUUID } from 'node:crypto';
20
- import { join } from 'node:path';
21
20
  import { isDeepStrictEqual } from 'node:util';
22
21
  import { resolveExistingStorageRoot, tryAcquireStateRootOwner, } from '@maka/storage/root-authority';
23
22
  import { connectExistingRuntimeHost, prepareConnectedRuntimeHostRetirement, RuntimeHostOperationError, RuntimeHostRequestInterruptedError, waitForRuntimeHostReady, } from '@maka/runtime-host/client';
24
23
  import { RUNTIME_HOST_PROTOCOL_VERSION } from '@maka/runtime-host/protocol';
25
- import { beginRuntimeHostManagedDeploymentTransition, blockRuntimeHostManagedDeploymentTransition, commitRuntimeHostManagedDeploymentTransition, decodeRuntimeHostManagedDeploymentConfig, readRuntimeHostManagedDeploymentAuthorityRecord, resolveRuntimeHostManagedDeploymentAuthority, resolveRuntimeHostNpmDeploymentLayout, rollbackRuntimeHostManagedDeploymentTransition, RuntimeHostManagedDeploymentError, } from '@maka/runtime-host/operator';
24
+ import { beginRuntimeHostManagedDeploymentTransition, blockRuntimeHostManagedDeploymentTransition, commitRuntimeHostManagedDeploymentTransition, decodeRuntimeHostManagedDeploymentConfig, readRuntimeHostManagedDeploymentAuthorityRecord, resolveRuntimeHostManagedDeploymentAuthority, resolveRuntimeHostNpmDeploymentLayout, runtimeHostManagedOperatorModulePath, rollbackRuntimeHostManagedDeploymentTransition, RuntimeHostManagedDeploymentError, } from '@maka/runtime-host/operator';
26
25
  /** The budget a managed Runtime Host has to become reachable after its lifecycle is activated. */
27
26
  export const RUNTIME_HOST_READY_TIMEOUT_MS = 45_000;
28
27
  export class RuntimeHostLifecycleTransactionError extends Error {
@@ -304,7 +303,7 @@ export async function replaceRuntimeHostLifecycle(input) {
304
303
  const desired = decodeRuntimeHostManagedDeploymentConfig(input.desired);
305
304
  const currentProvider = supervisedProvider(current ?? null, input.deps);
306
305
  if (desired.lifecycle.mode === 'supervised') {
307
- await input.deps.resolveProvider(desired.lifecycle.provider).supervisor.preflight();
306
+ await input.deps.resolveProvider(desired).supervisor.preflight();
308
307
  }
309
308
  const retirement = await retireRuntimeHostLifecycleOwner({
310
309
  rootPath: desired.root.path,
@@ -459,7 +458,7 @@ export async function activateRuntimeHostLifecycle(config, deps) {
459
458
  const canonical = decodeRuntimeHostManagedDeploymentConfig(config);
460
459
  if (canonical.lifecycle.mode !== 'supervised')
461
460
  return;
462
- const provider = deps.resolveProvider(canonical.lifecycle.provider);
461
+ const provider = deps.resolveProvider(canonical);
463
462
  await provider.supervisor.activate();
464
463
  if (canonical.reconciliation.trigger === 'scheduled') {
465
464
  await provider.reconciliationTrigger.activate();
@@ -470,7 +469,7 @@ export async function verifyRuntimeHostLifecycleReady(config, deps, timeoutMs =
470
469
  await verifyRuntimeHostLifecycleProjection(canonical, deps);
471
470
  if (canonical.lifecycle.mode !== 'supervised')
472
471
  return;
473
- const provider = deps.resolveProvider(canonical.lifecycle.provider);
472
+ const provider = deps.resolveProvider(canonical);
474
473
  const deadline = Date.now() + timeoutMs;
475
474
  let lastFailure = new Error('Runtime Host is not ready');
476
475
  while (Date.now() < deadline) {
@@ -513,13 +512,28 @@ export async function verifyRuntimeHostLifecycleReady(config, deps, timeoutMs =
513
512
  }
514
513
  throw new RuntimeHostLifecycleTransactionError('transition_failed', `Runtime Host did not become ready: ${lastFailure instanceof Error ? lastFailure.message : String(lastFailure)}`, { cause: lastFailure });
515
514
  }
515
+ /** Repairs update-control artifacts without interrupting the running Host supervisor. */
516
+ export async function convergeRuntimeHostLifecycleControlProjection(config, deps) {
517
+ const canonical = decodeRuntimeHostManagedDeploymentConfig(config);
518
+ await deps.convergeOperator(canonical, canonical);
519
+ if (canonical.lifecycle.mode !== 'supervised')
520
+ return;
521
+ const provider = deps.resolveProvider(canonical);
522
+ if (canonical.reconciliation.trigger === 'scheduled') {
523
+ await provider.reconciliationTrigger.converge(runtimeHostReconciliationTriggerDefinition(canonical));
524
+ await provider.reconciliationTrigger.activate();
525
+ }
526
+ else {
527
+ await provider.reconciliationTrigger.uninstall();
528
+ }
529
+ }
516
530
  /** Verifies the durable operator and supervisor projection without requiring a compatible Host. */
517
531
  export async function verifyRuntimeHostLifecycleProjection(config, deps) {
518
532
  const canonical = decodeRuntimeHostManagedDeploymentConfig(config);
519
533
  await deps.verifyOperator(canonical);
520
534
  if (canonical.lifecycle.mode !== 'supervised')
521
535
  return;
522
- const provider = deps.resolveProvider(canonical.lifecycle.provider);
536
+ const provider = deps.resolveProvider(canonical);
523
537
  await provider.supervisor.verify(runtimeHostSupervisorDefinition(canonical));
524
538
  if (canonical.reconciliation.trigger !== 'scheduled')
525
539
  return;
@@ -550,7 +564,12 @@ export function runtimeHostSupervisorDefinition(config) {
550
564
  export function runtimeHostReconciliationTriggerDefinition(config) {
551
565
  const canonical = decodeRuntimeHostManagedDeploymentConfig(config);
552
566
  return {
553
- command: [join(canonical.deploymentRoot, 'operator'), 'reconcile-update', '--framed'],
567
+ command: [
568
+ canonical.launch.nodePath,
569
+ runtimeHostManagedOperatorModulePath(canonical.deploymentRoot, process.platform === 'win32' ? 'win32' : 'posix'),
570
+ 'reconcile-update',
571
+ '--framed',
572
+ ],
554
573
  };
555
574
  }
556
575
  async function convergeLifecycleArtifacts(from, to, deps) {
@@ -600,7 +619,5 @@ async function restoreTransition(record, deps) {
600
619
  await convergeTransitionOwnership(record.to, record.from, record, deps);
601
620
  }
602
621
  function supervisedProvider(config, deps) {
603
- return config?.lifecycle.mode === 'supervised'
604
- ? deps.resolveProvider(config.lifecycle.provider)
605
- : undefined;
622
+ return config?.lifecycle.mode === 'supervised' ? deps.resolveProvider(config) : undefined;
606
623
  }
@@ -21,10 +21,10 @@ import { constants } from 'node:fs';
21
21
  import { access, lstat, mkdir, open, readdir, realpath, rename, rm } from 'node:fs/promises';
22
22
  import { homedir } from 'node:os';
23
23
  import { basename, dirname, isAbsolute, join, relative, resolve, sep } from 'node:path';
24
- import { openRuntimeHostPackageDeployment, prepareRuntimeHostPackageDeployment, pruneRuntimeHostPackageDeployments, resolveRuntimeHostPackageCliPath, RuntimeHostPackageDeploymentError as RuntimeHostManagedDeploymentError, } from './runtime-host-package-deployment.js';
24
+ import { openRuntimeHostPackageDeployment, prepareRuntimeHostPackageDeployment, pruneRuntimeHostPackageDeployments, removeDeploymentDirectory, resolveRuntimeHostPackageCliPath, RuntimeHostPackageDeploymentError as RuntimeHostManagedDeploymentError, } from './runtime-host-package-deployment.js';
25
25
  import { readStableBoundedFile, syncDirectory } from '@maka/storage/stable-storage';
26
26
  import { resolveExistingStorageRoot, tryAcquireStateRootOwner } from '@maka/storage/root-authority';
27
- import { resolveRuntimeHostManagedDeploymentAuthorityRoot, resolveRuntimeHostManagedDeploymentAuthority, resolveRuntimeHostNpmDeploymentLayout, } from '@maka/runtime-host/operator';
27
+ import { resolveRuntimeHostManagedDeploymentAuthorityRoot, resolveRuntimeHostManagedDeploymentAuthority, resolveRuntimeHostNpmDeploymentLayout, runtimeHostManagedOperatorModulePath, } from '@maka/runtime-host/operator';
28
28
  export { RuntimeHostPackageDeploymentError as RuntimeHostManagedDeploymentError } from './runtime-host-package-deployment.js';
29
29
  const CLEANUP_RECEIPT_FILE = 'cleanup-approved.json';
30
30
  export function resolveRuntimeHostManagedPackageCliPath(deploymentRoot, version, packageIntegrity) {
@@ -277,11 +277,16 @@ export function resolveRuntimeHostManagedDeploymentRoot(serviceId, options = {})
277
277
  function resolveRuntimeHostManagedDataHome(options = {}) {
278
278
  const env = options.env ?? process.env;
279
279
  const homeDir = options.homeDir ?? homedir();
280
- return (options.platform ?? process.platform) === 'darwin'
280
+ const platform = options.platform ?? process.platform;
281
+ return platform === 'darwin'
281
282
  ? join(homeDir, 'Library', 'Application Support')
282
- : env.XDG_DATA_HOME && isAbsolute(env.XDG_DATA_HOME)
283
- ? env.XDG_DATA_HOME
284
- : join(homeDir, '.local', 'share');
283
+ : platform === 'win32'
284
+ ? env.LOCALAPPDATA && isAbsolute(env.LOCALAPPDATA)
285
+ ? env.LOCALAPPDATA
286
+ : join(homeDir, 'AppData', 'Local')
287
+ : env.XDG_DATA_HOME && isAbsolute(env.XDG_DATA_HOME)
288
+ ? env.XDG_DATA_HOME
289
+ : join(homeDir, '.local', 'share');
285
290
  }
286
291
  export function resolveRuntimeHostManagedControlRoot(serviceId) {
287
292
  return join(resolveRuntimeHostManagedDeploymentAuthorityRoot(), serviceId, 'control');
@@ -372,24 +377,29 @@ export async function removeRuntimeHostManagedDeployment(root, serviceId) {
372
377
  // recognized as already complete and reclaimed by the next deployment.
373
378
  await syncDirectory(parent);
374
379
  }
375
- await rm(retiredRoot, { recursive: true, force: true });
380
+ await removeDeploymentDirectory(retiredRoot);
376
381
  await syncDirectory(parent);
377
382
  }
378
383
  function managedDeployment(staged, clientDataRoot, managedRootId) {
379
- const operatorPath = join(staged.root, 'operator');
384
+ const modulePath = runtimeHostManagedOperatorModulePath(staged.root, process.platform === 'win32' ? 'win32' : 'posix');
380
385
  return {
381
386
  version: staged.version,
382
387
  root: staged.root,
383
388
  cliPath: staged.cliPath,
384
- operatorPath,
385
- activate: () => writeOperatorLauncher(operatorPath, process.execPath, staged.cliPath, clientDataRoot, managedRootId),
389
+ activate: async () => {
390
+ await writeOperatorLauncher(modulePath, process.execPath, staged.cliPath, clientDataRoot, managedRootId);
391
+ await forwardLegacyOperatorIfPresent(staged.root, process.execPath, modulePath);
392
+ },
386
393
  cleanup: staged.cleanup,
387
394
  rollback: staged.rollback,
388
395
  };
389
396
  }
390
397
  async function writeOperatorLauncher(path, nodePath, cliPath, clientDataRoot, managedRootId, deploymentId) {
391
- const temporaryPath = `${path}.${randomUUID()}.tmp`;
392
398
  const contents = operatorLauncherContents(nodePath, cliPath, clientDataRoot, managedRootId, deploymentId);
399
+ await writeStableOperator(path, contents);
400
+ }
401
+ async function writeStableOperator(path, contents) {
402
+ const temporaryPath = `${path}.${randomUUID()}.tmp`;
393
403
  try {
394
404
  const file = await open(temporaryPath, 'wx', 0o700);
395
405
  try {
@@ -400,44 +410,53 @@ async function writeOperatorLauncher(path, nodePath, cliPath, clientDataRoot, ma
400
410
  await file.close();
401
411
  }
402
412
  await rename(temporaryPath, path);
403
- const parent = await open(dirname(path), 'r');
404
- try {
405
- await parent.sync();
406
- }
407
- finally {
408
- await parent.close();
409
- }
413
+ await syncDirectory(dirname(path));
410
414
  }
411
415
  finally {
412
416
  await rm(temporaryPath, { force: true });
413
417
  }
414
418
  }
415
419
  function operatorLauncherContents(nodePath, cliPath, clientDataRoot, managedRootId, deploymentId) {
416
- return [
417
- '#!/bin/sh',
418
- 'if [ "$#" -ge 1 ] && [ "$1" = "__cleanup-managed-deployment" ]; then',
419
- ' shift',
420
- ` exec ${quotePosix(nodePath)} ${quotePosix(cliPath)} runtime-host service cleanup-deployment "$@" --client-data-root ${quotePosix(clientDataRoot)} --managed-root-id ${quotePosix(managedRootId)}${deploymentId ? ` --operator-deployment-id ${quotePosix(deploymentId)}` : ''}`,
421
- 'fi',
422
- 'if [ "$#" -ge 1 ] && [ "$1" = "access" ]; then',
423
- ' shift',
424
- ` exec ${quotePosix(nodePath)} ${quotePosix(cliPath)} runtime-host access "$@"`,
425
- 'fi',
426
- 'if [ "$#" -ge 1 ] && [ "$1" = "activate" ]; then',
427
- ' shift',
428
- ` exec ${quotePosix(nodePath)} ${quotePosix(cliPath)} runtime-host activate "$@"`,
429
- 'fi',
430
- 'if [ "$#" -ge 1 ] && [ "$1" = "connect" ]; then',
431
- ' shift',
432
- ` exec ${quotePosix(nodePath)} ${quotePosix(cliPath)} runtime-host connect "$@"`,
433
- 'fi',
434
- 'if [ "$#" -ge 1 ] && [ "$1" = "serve" ]; then',
435
- ' shift',
436
- ` exec ${quotePosix(nodePath)} ${quotePosix(cliPath)} runtime-host serve "$@"`,
437
- 'fi',
438
- `exec ${quotePosix(nodePath)} ${quotePosix(cliPath)} runtime-host service "$@" --client-data-root ${quotePosix(clientDataRoot)} --managed-root-id ${quotePosix(managedRootId)}${deploymentId ? ` --operator-deployment-id ${quotePosix(deploymentId)}` : ''}`,
439
- '',
440
- ].join('\n');
420
+ const fixedServiceArguments = [
421
+ '--client-data-root',
422
+ clientDataRoot,
423
+ '--managed-root-id',
424
+ managedRootId,
425
+ ...(deploymentId ? ['--operator-deployment-id', deploymentId] : []),
426
+ ];
427
+ return `import { spawn } from 'node:child_process';
428
+
429
+ const [action, ...args] = process.argv.slice(2);
430
+ const direct = new Set(['access', 'activate', 'connect', 'serve']);
431
+ const cliArgs = action === '__cleanup-managed-deployment'
432
+ ? ['runtime-host', 'service', 'cleanup-deployment', ...args, ...${JSON.stringify(fixedServiceArguments)}]
433
+ : direct.has(action)
434
+ ? ['runtime-host', action, ...args]
435
+ : ['runtime-host', 'service', ...(action === undefined ? [] : [action]), ...args, ...${JSON.stringify(fixedServiceArguments)}];
436
+ const child = spawn(${JSON.stringify(nodePath)}, [${JSON.stringify(cliPath)}, ...cliArgs], {
437
+ stdio: 'inherit',
438
+ windowsHide: true,
439
+ });
440
+ const signalForwarders = new Map();
441
+ for (const signal of ['SIGINT', 'SIGTERM']) {
442
+ const forward = () => child.kill(signal);
443
+ signalForwarders.set(signal, forward);
444
+ process.on(signal, forward);
445
+ }
446
+ const stopForwardingSignals = () => {
447
+ for (const [signal, forward] of signalForwarders) process.off(signal, forward);
448
+ };
449
+ child.once('error', (error) => {
450
+ stopForwardingSignals();
451
+ console.error(error instanceof Error ? error.message : String(error));
452
+ process.exitCode = 1;
453
+ });
454
+ child.once('exit', (code, signal) => {
455
+ stopForwardingSignals();
456
+ if (signal) process.kill(process.pid, signal);
457
+ else process.exitCode = code ?? 1;
458
+ });
459
+ `;
441
460
  }
442
461
  export async function convergeRuntimeHostManagedOperator(current, desired) {
443
462
  const deployment = desired ?? current;
@@ -447,35 +466,77 @@ export async function convergeRuntimeHostManagedOperator(current, desired) {
447
466
  // is removed. Package cleanup removes it with the deployment root.
448
467
  if (!desired)
449
468
  return;
450
- const operatorPath = join(deployment.deploymentRoot, 'operator');
469
+ const operatorPath = runtimeHostManagedOperatorModulePath(deployment.deploymentRoot, process.platform === 'win32' ? 'win32' : 'posix');
451
470
  const layout = resolveRuntimeHostNpmDeploymentLayout(desired.deploymentRoot, desired.launch.package.integrity);
452
471
  await writeOperatorLauncher(operatorPath, desired.launch.nodePath, layout.cliPath, resolveRuntimeHostManagedControlRoot(desired.root.id), desired.root.id, desired.deploymentId);
472
+ await forwardLegacyOperatorIfPresent(deployment.deploymentRoot, desired.launch.nodePath, operatorPath);
473
+ }
474
+ function legacyOperatorLauncherContents(nodePath, modulePath) {
475
+ return `#!/bin/sh\nexec ${quotePosix(nodePath)} ${quotePosix(modulePath)} "$@"\n`;
476
+ }
477
+ async function forwardLegacyOperatorIfPresent(deploymentRoot, nodePath, modulePath) {
478
+ if (process.platform === 'win32')
479
+ return;
480
+ const path = join(deploymentRoot, 'operator');
481
+ const exists = await access(path, constants.F_OK).then(() => true, (error) => {
482
+ if (isNodeError(error, 'ENOENT'))
483
+ return false;
484
+ throw error;
485
+ });
486
+ if (exists) {
487
+ await writeStableOperator(path, legacyOperatorLauncherContents(nodePath, modulePath));
488
+ }
453
489
  }
454
490
  export async function restoreRuntimeHostLegacyManagedOperator(input) {
455
- await writeOperatorLauncher(join(input.deploymentRoot, 'operator'), input.nodePath, input.cliPath, input.clientDataRoot, input.serviceId);
491
+ await writeOperatorLauncher(runtimeHostManagedOperatorModulePath(input.deploymentRoot, 'posix'), input.nodePath, input.cliPath, input.clientDataRoot, input.serviceId);
456
492
  }
457
493
  export async function verifyRuntimeHostManagedOperator(config) {
458
494
  const layout = resolveRuntimeHostNpmDeploymentLayout(config.deploymentRoot, config.launch.package.integrity);
459
495
  const expected = operatorLauncherContents(config.launch.nodePath, layout.cliPath, resolveRuntimeHostManagedControlRoot(config.root.id), config.root.id, config.deploymentId);
496
+ const operatorPath = runtimeHostManagedOperatorModulePath(config.deploymentRoot, process.platform === 'win32' ? 'win32' : 'posix');
460
497
  const observed = await readStableBoundedFile({
461
- path: join(config.deploymentRoot, 'operator'),
498
+ path: operatorPath,
462
499
  maxBytes: Buffer.byteLength(expected),
463
500
  invalidFile: () => new Error('The managed Runtime Host operator is not a stable regular file'),
464
501
  }).then((contents) => new TextDecoder('utf-8', { fatal: true }).decode(contents));
465
502
  if (observed !== expected)
466
503
  throw new Error('The managed Runtime Host operator does not match its deployment');
467
- await access(join(config.deploymentRoot, 'operator'), constants.X_OK).catch((error) => {
468
- throw new Error('The managed Runtime Host operator is not executable', {
504
+ await access(operatorPath, constants.R_OK).catch((error) => {
505
+ throw new Error('The managed Runtime Host operator is not readable', {
469
506
  cause: error,
470
507
  });
471
508
  });
472
- }
473
- function quotePosix(value) {
474
- return `'${value.replaceAll("'", `'"'"'`)}'`;
509
+ const legacyOperatorPath = join(config.deploymentRoot, 'operator');
510
+ const legacyExpected = legacyOperatorLauncherContents(config.launch.nodePath, operatorPath);
511
+ const legacyExists = await access(legacyOperatorPath, constants.F_OK).then(() => true, (error) => {
512
+ if (isNodeError(error, 'ENOENT'))
513
+ return false;
514
+ throw error;
515
+ });
516
+ const legacyObserved = legacyExists
517
+ ? await readStableBoundedFile({
518
+ path: legacyOperatorPath,
519
+ maxBytes: Buffer.byteLength(legacyExpected),
520
+ invalidFile: () => new Error('The legacy managed Runtime Host operator is invalid'),
521
+ }).then((contents) => new TextDecoder('utf-8', { fatal: true }).decode(contents))
522
+ : null;
523
+ if (legacyObserved !== null && legacyObserved !== legacyExpected) {
524
+ throw new Error('The legacy managed Runtime Host operator does not match its deployment');
525
+ }
526
+ if (legacyObserved !== null) {
527
+ await access(legacyOperatorPath, constants.X_OK).catch((error) => {
528
+ throw new Error('The legacy managed Runtime Host operator is not executable', {
529
+ cause: error,
530
+ });
531
+ });
532
+ }
475
533
  }
476
534
  function isRecord(value) {
477
535
  return value !== null && typeof value === 'object' && !Array.isArray(value);
478
536
  }
537
+ function quotePosix(value) {
538
+ return `'${value.replaceAll("'", `'"'"'`)}'`;
539
+ }
479
540
  function isNodeError(error, code) {
480
541
  return error instanceof Error && 'code' in error && error.code === code;
481
542
  }
@@ -26,7 +26,7 @@ export async function manageRuntimeHostManagedLifecycle(rootId, input, dependenc
26
26
  const lifecycleDeps = {
27
27
  convergeOperator: (currentConfig, desiredConfig) => convergeRuntimeHostManagedOperator(currentConfig, desiredConfig),
28
28
  verifyOperator: verifyRuntimeHostManagedOperator,
29
- resolveProvider: (requested) => dependencies.resolveProvider(rootId, requested),
29
+ resolveProvider: dependencies.resolveProvider,
30
30
  };
31
31
  const resolved = await resolveRecoverableRuntimeHostManagedDeployment(rootId, lifecycleDeps, {
32
32
  ...(input.expectedTarget ? { expectedTarget: input.expectedTarget } : {}),
@@ -45,10 +45,7 @@ export async function manageRuntimeHostManagedLifecycle(rootId, input, dependenc
45
45
  if (dependencies.operatorClaim) {
46
46
  assertRuntimeHostManagedOperatorConfig(config, dependencies.operatorClaim.deploymentId, dependencies.operatorClaim.cliPath);
47
47
  }
48
- const supervisedLifecycle = config.lifecycle.mode === 'supervised' ? config.lifecycle : undefined;
49
- const provider = supervisedLifecycle
50
- ? dependencies.resolveProvider(rootId, supervisedLifecycle.provider)
51
- : undefined;
48
+ const provider = config.lifecycle.mode === 'supervised' ? dependencies.resolveProvider(config) : undefined;
52
49
  if (input.action === 'install') {
53
50
  throw new RuntimeHostServiceManagerError('target_mismatch', 'Managed Runtime Host installation must use runtime-host setup');
54
51
  }
@@ -17,6 +17,7 @@
17
17
  * under the License.
18
18
  */
19
19
  import { randomUUID } from 'node:crypto';
20
+ import { spawn } from 'node:child_process';
20
21
  import { cp, lstat, mkdir, readFile, readdir, realpath, rename, rm, stat } from 'node:fs/promises';
21
22
  import { basename, dirname, isAbsolute, join, parse, relative, resolve, sep } from 'node:path';
22
23
  import { resolveRuntimeHostNpmDeploymentLayout } from '@maka/runtime-host/operator';
@@ -223,12 +224,12 @@ async function removePackageAtomically(versionsRoot, packageName) {
223
224
  const packageRoot = join(versionsRoot, packageName);
224
225
  try {
225
226
  if (packageName.startsWith('.') && packageName.endsWith('.deleted')) {
226
- await rm(packageRoot, { recursive: true, force: true });
227
+ await removeDeploymentDirectory(packageRoot);
227
228
  return;
228
229
  }
229
230
  const tombstone = join(versionsRoot, `.${packageName}.${randomUUID()}.deleted`);
230
231
  await rename(packageRoot, tombstone);
231
- await rm(tombstone, { recursive: true, force: true });
232
+ await removeDeploymentDirectory(tombstone);
232
233
  }
233
234
  catch (error) {
234
235
  if (isNodeError(error, 'ENOENT'))
@@ -236,6 +237,38 @@ async function removePackageAtomically(versionsRoot, packageName) {
236
237
  throw new RuntimeHostPackageDeploymentError('deployment_failed', 'Unable to remove an inactive Runtime Host package', { cause: error });
237
238
  }
238
239
  }
240
+ export async function removeDeploymentDirectory(path) {
241
+ try {
242
+ await rm(path, { recursive: true, force: true });
243
+ }
244
+ catch (error) {
245
+ if (process.platform !== 'win32')
246
+ throw error;
247
+ deferWindowsDirectoryRemovalUntilExit(path);
248
+ }
249
+ }
250
+ function deferWindowsDirectoryRemovalUntilExit(path) {
251
+ // Loaded native addons remain locked until this operator exits. The caller
252
+ // has already renamed the directory out of authority before reaching here.
253
+ const script = `const { rm } = require('node:fs/promises');
254
+ const path = process.argv[1];
255
+ const parent = Number(process.argv[2]);
256
+ const wait = (ms) => new Promise((resolve) => setTimeout(resolve, ms));
257
+ (async () => {
258
+ for (let attempt = 0; attempt < 3000; attempt += 1) {
259
+ try { process.kill(parent, 0); } catch { break; }
260
+ await wait(100);
261
+ }
262
+ await rm(path, { recursive: true, force: true, maxRetries: 100, retryDelay: 100 });
263
+ })().catch(() => { process.exitCode = 1; });`;
264
+ const cleanup = spawn(process.execPath, ['-e', script, path, String(process.pid)], {
265
+ detached: true,
266
+ stdio: 'ignore',
267
+ windowsHide: true,
268
+ });
269
+ cleanup.on('error', () => undefined);
270
+ cleanup.unref();
271
+ }
239
272
  function registryPackageLayout(deploymentRoot, integrity) {
240
273
  try {
241
274
  return resolveRuntimeHostNpmDeploymentLayout(deploymentRoot, integrity);
@@ -20,7 +20,7 @@ import { access, realpath } from 'node:fs/promises';
20
20
  import { basename, dirname, join } from 'node:path';
21
21
  const PEER_NATIVE_FILE = 'maka_runtime_host_peer.node';
22
22
  const SUPPORTED_TARGETS = new Set(['darwin-arm64', 'linux-arm64', 'linux-x64', 'win32-x64']);
23
- export async function resolveRuntimeHostPeerNativePath(cliPath) {
23
+ export async function resolveRuntimeHostNativePath(cliPath) {
24
24
  const packageRoot = dirname(dirname(await realpath(cliPath)));
25
25
  const target = runtimeHostPeerTarget();
26
26
  const packaged = join(packageRoot, 'native', 'runtime-host-peer', 'prebuilds', target, PEER_NATIVE_FILE);
@@ -31,7 +31,7 @@ export async function resolveRuntimeHostPeerNativePath(cliPath) {
31
31
  if (await isReadable(development))
32
32
  return realpath(development);
33
33
  }
34
- throw new Error(`Maka does not include a direct-peer native artifact for ${target}`);
34
+ throw new Error(`Maka does not include a Runtime Host native artifact for ${target}`);
35
35
  }
36
36
  export function runtimeHostPeerTarget(platform = process.platform, arch = process.arch) {
37
37
  const target = `${platform}-${arch}`;
@@ -56,7 +56,7 @@ export async function configureRuntimeHostPeerClient(input) {
56
56
  if (explicitNativePath || explicitKeyPath)
57
57
  return Boolean(explicitNativePath && explicitKeyPath);
58
58
  try {
59
- environment.MAKA_RUNTIME_HOST_PEER_NATIVE_PATH = await resolveRuntimeHostPeerNativePath(input.cliPath);
59
+ environment.MAKA_RUNTIME_HOST_PEER_NATIVE_PATH = await resolveRuntimeHostNativePath(input.cliPath);
60
60
  environment.MAKA_RUNTIME_HOST_PEER_KEY_PATH = resolveRuntimeHostClientPeerKeyPath(input.clientDataRoot);
61
61
  return true;
62
62
  }