@praxis-ai/praxis 0.1.1 → 0.1.3

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 (49) hide show
  1. package/dist/agentCore/index.d.ts +45 -6
  2. package/dist/agentCore/index.js +14 -2
  3. package/dist/applicationLayer/applicationContract.d.ts +2 -0
  4. package/dist/applicationLayer/applicationRuntime.d.ts +13 -1
  5. package/dist/applicationLayer/applicationRuntime.js +39 -3
  6. package/dist/applicationLayer/index.d.ts +2 -0
  7. package/dist/applicationLayer/index.js +1 -0
  8. package/dist/basetool/core/shellRun.js +6 -1
  9. package/dist/rax_packageManager/raxCli.js +42 -1
  10. package/dist/runtimeImplementation/praxisRuntimeKernel.d.ts +13 -0
  11. package/dist/runtimeImplementation/praxisRuntimeKernel.js +550 -15
  12. package/dist/runtimeImplementation/runtime.componentPlane/runtimeComponentRegistry.d.ts +1 -1
  13. package/dist/runtimeImplementation/runtime.componentPlane/runtimeComponentRegistry.js +2 -2
  14. package/dist/runtimeImplementation/runtime.dependencyPlane/dependencySourceRegistry.d.ts +1 -1
  15. package/dist/runtimeImplementation/runtime.dependencyPlane/dependencySourceRegistry.js +12 -0
  16. package/dist/runtimeImplementation/runtime.dependencyPlane/dependencyTypes.js +2 -0
  17. package/dist/runtimeImplementation/runtime.execEngine/baseToolExecutorPortFactory.d.ts +3 -0
  18. package/dist/runtimeImplementation/runtime.execEngine/baseToolExecutorPortFactory.js +45 -7
  19. package/dist/runtimeImplementation/runtime.execEngine/mcpRuntimeAdapter.js +56 -0
  20. package/dist/runtimeImplementation/runtime.mcpPlane/index.d.ts +225 -0
  21. package/dist/runtimeImplementation/runtime.mcpPlane/index.js +549 -0
  22. package/dist/runtimeImplementation/runtime.sandboxPlane/baseToolSandboxPlanner.js +0 -2
  23. package/dist/runtimeImplementation/runtime.sandboxPlane/raxcellSandboxProvider.d.ts +19 -0
  24. package/dist/runtimeImplementation/runtime.sandboxPlane/raxcellSandboxProvider.js +172 -0
  25. package/dist/runtimeImplementation/runtime.sandboxPlane/sandboxCommandRunner.d.ts +13 -1
  26. package/dist/runtimeImplementation/runtime.sandboxPlane/sandboxCommandRunner.js +230 -186
  27. package/dist/runtimeImplementation/runtime.sandboxPlane/sandboxPolicyMiddleware.d.ts +175 -0
  28. package/dist/runtimeImplementation/runtime.sandboxPlane/sandboxPolicyMiddleware.js +142 -0
  29. package/dist/runtimeImplementation/runtime.sandboxPlane/sandboxRuntimeProvider.d.ts +9 -0
  30. package/dist/runtimeImplementation/runtime.sandboxPlane/sandboxRuntimeProvider.js +115 -205
  31. package/dist/runtimeImplementation/runtimeAgentManifest.js +7 -3
  32. package/package.json +3 -1
  33. package/raxode-tui/dist/raxode-cli/backend/agents/codingAgent/agent.js +3 -3
  34. package/raxode-tui/dist/raxode-cli/backend/application/backendModuleInventory.js +3 -3
  35. package/raxode-tui/dist/raxode-cli/backend/application/localReadinessProbe.d.ts +1 -0
  36. package/raxode-tui/dist/raxode-cli/backend/application/localReadinessProbe.js +50 -4
  37. package/raxode-tui/dist/raxode-cli/backend/application/raxcellSandboxProvider.d.ts +12 -0
  38. package/raxode-tui/dist/raxode-cli/backend/application/raxcellSandboxProvider.js +58 -0
  39. package/raxode-tui/dist/raxode-cli/backend/application/runtimeReadiness.d.ts +1 -0
  40. package/raxode-tui/dist/raxode-cli/backend/application/runtimeReadiness.js +3 -1
  41. package/raxode-tui/dist/raxode-cli/backend/application/stdioApplicationServer.d.ts +2 -0
  42. package/raxode-tui/dist/raxode-cli/backend/application/stdioApplicationServer.js +7 -0
  43. package/raxode-tui/dist/raxode-cli/backend/directApplicationBackend.d.ts +2 -0
  44. package/raxode-tui/dist/raxode-cli/backend/directApplicationBackend.js +21 -1
  45. package/raxode-tui/dist/raxode-cli/backend/raxodeBackend.d.ts +1 -1
  46. package/raxode-tui/dist/raxode-cli/backend/raxodeBackend.js +8 -0
  47. package/raxode-tui/dist/raxode-cli/frontend/tui/cli/raxode-cli.js +19 -1
  48. package/raxode-tui/package.json +2 -1
  49. package/tsconfig.json +16 -1
@@ -4,11 +4,14 @@
4
4
  * 边界:本文件不替代 BaseTool 语义;工具执行仍然必须走 registry/handler/executor。
5
5
  */
6
6
  import { execFile } from "node:child_process";
7
- import { mkdir, readFile } from "node:fs/promises";
7
+ import { existsSync } from "node:fs";
8
+ import { readFile } from "node:fs/promises";
9
+ import { createRequire } from "node:module";
8
10
  import path from "node:path";
9
11
  import { promisify } from "node:util";
10
12
  import { canonicalDependencyId } from "../runtime.dependencyPlane/index.js";
11
13
  const execFileAsync = promisify(execFile);
14
+ const requireFromHere = createRequire(import.meta.url);
12
15
  export const sandboxRuntimeProviderDescriptor = {
13
16
  surface: "runtime.sandboxPlane",
14
17
  capability: "sandboxRuntimeProvider",
@@ -28,12 +31,51 @@ function providerFamilyFor(spec) {
28
31
  function dependencyRefsFor(spec) {
29
32
  const refs = spec.dependencyRefs ?? [];
30
33
  if (providerFamilyFor(spec) === "linux-bubblewrap" && refs.length === 0) {
31
- return ["dependency.binary.bwrap"];
34
+ return ["dependency.binary.raxcell"];
32
35
  }
33
36
  return refs.map(canonicalDependencyId);
34
37
  }
38
+ function executableNames(name, platform) {
39
+ if (platform !== "win32")
40
+ return [name];
41
+ const extensions = (process.env.PATHEXT ?? ".EXE;.CMD;.BAT;.COM")
42
+ .split(";")
43
+ .filter(Boolean);
44
+ return [name, ...extensions.map((extension) => `${name}${extension.toLowerCase()}`), ...extensions.map((extension) => `${name}${extension.toUpperCase()}`)];
45
+ }
46
+ function defaultResolvePackage(packageName) {
47
+ try {
48
+ return requireFromHere.resolve(packageName);
49
+ }
50
+ catch {
51
+ return undefined;
52
+ }
53
+ }
54
+ export function resolveRaxcellBinaryPath(input = {}) {
55
+ const explicitBinary = (input.env?.RAXCELL_BIN ?? process.env.RAXCELL_BIN)?.trim();
56
+ const fileExists = input.fileExists ?? existsSync;
57
+ if (explicitBinary !== undefined && explicitBinary.length > 0) {
58
+ return fileExists(explicitBinary) ? explicitBinary : undefined;
59
+ }
60
+ const platform = input.platform ?? process.platform;
61
+ const entries = (input.pathEnv ?? process.env.PATH ?? "").split(path.delimiter).filter(Boolean);
62
+ for (const entry of entries) {
63
+ for (const name of executableNames("raxcell", platform)) {
64
+ const candidate = path.join(entry, name);
65
+ if (fileExists(candidate))
66
+ return candidate;
67
+ }
68
+ }
69
+ const resolvedPackage = (input.resolvePackage ?? defaultResolvePackage)("@praxis-ai/raxcell/package.json");
70
+ if (resolvedPackage === undefined)
71
+ return undefined;
72
+ const packageBinary = path.resolve(path.dirname(resolvedPackage), "dist/cli.js");
73
+ return fileExists(packageBinary) ? packageBinary : undefined;
74
+ }
35
75
  function dependencyBinary(ref) {
36
76
  const canonical = canonicalDependencyId(ref);
77
+ if (canonical === "dependency.binary.raxcell")
78
+ return resolveRaxcellBinaryPath();
37
79
  if (canonical === "dependency.binary.bwrap")
38
80
  return "bwrap";
39
81
  if (canonical === "dependency.binary.rg")
@@ -158,14 +200,14 @@ function repairHints(input) {
158
200
  requiresApproval: false,
159
201
  }];
160
202
  }
161
- if (input.missingDependencies.includes("dependency.binary.bwrap")) {
203
+ if (input.missingDependencies.includes("dependency.binary.raxcell")) {
162
204
  return [{
163
- hintId: "linux-bubblewrap:install-bwrap",
205
+ hintId: "linux-bubblewrap:configure-raxcell",
164
206
  severity: "warning",
165
- action: "installDependency",
166
- message: "Install bubblewrap through the system package manager, then rerun rax test.",
167
- commandPreview: ["apt install bubblewrap", "dnf install bubblewrap", "pacman -S bubblewrap"],
168
- requiresApproval: true,
207
+ action: "manualProviderSetup",
208
+ message: "Configure the Raxcell CLI binary path through RAXCELL_BIN or inject RaxcellSandboxProvider at runtime.",
209
+ commandPreview: ["export RAXCELL_BIN=/absolute/path/to/raxcell"],
210
+ requiresApproval: false,
169
211
  }];
170
212
  }
171
213
  return [{
@@ -182,9 +224,9 @@ function dependencyInstallEnvelopes(input) {
182
224
  dependencyId,
183
225
  providerFamily: input.providerFamily,
184
226
  action: "installDependency",
185
- installTarget: dependencyId === "dependency.binary.bwrap" ? "system-global" : "manual",
186
- commandPreview: dependencyId === "dependency.binary.bwrap"
187
- ? ["apt install bubblewrap", "dnf install bubblewrap", "pacman -S bubblewrap"]
227
+ installTarget: "manual",
228
+ commandPreview: dependencyId === "dependency.binary.raxcell"
229
+ ? ["export RAXCELL_BIN=/absolute/path/to/raxcell"]
188
230
  : [],
189
231
  requiresApproval: true,
190
232
  approvalSurface: "interface/application",
@@ -305,12 +347,45 @@ async function probeContractOnly(spec) {
305
347
  },
306
348
  };
307
349
  }
308
- async function probeLinuxBubblewrap(spec) {
350
+ async function probeLinuxBubblewrap(spec, input = {}) {
309
351
  const providerFamily = providerFamilyFor(spec);
310
352
  if (process.platform !== "linux") {
311
353
  return unsupported(providerFamily, spec, "linux-bubblewrap sandbox only runs on Linux");
312
354
  }
313
355
  const dependencyRefs = dependencyRefsFor(spec);
356
+ if (input.providerReady === true) {
357
+ const dependencyChecks = [
358
+ {
359
+ dependencyId: "dependency.binary.raxcell",
360
+ required: true,
361
+ status: "available",
362
+ source: "custom",
363
+ installTarget: "manual",
364
+ publicSafeMessage: "RaxcellSandboxProvider is injected by the Praxis runtime",
365
+ },
366
+ ...(await linuxOptionalChecks()),
367
+ ];
368
+ return {
369
+ providerFamily,
370
+ profile: spec.profile,
371
+ status: "available",
372
+ platform: process.platform,
373
+ dependencyRefs,
374
+ availableDependencies: dependencyRefs,
375
+ missingDependencies: [],
376
+ dependencyChecks,
377
+ dependencyInstallEnvelopes: [],
378
+ selfRepairHints: repairHints({ providerFamily, missingDependencies: [], status: "available" }),
379
+ nextAction: "none",
380
+ publicSafeMessage: "Injected Raxcell linux-bubblewrap sandbox provider is available",
381
+ metadata: {
382
+ sandboxId: spec.sandboxId,
383
+ isolationLevel: spec.isolationLevel ?? "process-namespace",
384
+ provider: "raxcell",
385
+ injectedProvider: true,
386
+ },
387
+ };
388
+ }
314
389
  const dependencies = await dependencyAvailability(dependencyRefs);
315
390
  const dependencyChecks = [
316
391
  ...(await Promise.all(dependencyRefs.map((ref) => binaryCheck(ref, true)))),
@@ -332,11 +407,12 @@ async function probeLinuxBubblewrap(spec) {
332
407
  missingDependencies: dependencies.missing,
333
408
  status: "missingDependency",
334
409
  }),
335
- nextAction: "installDependency",
336
- publicSafeMessage: "linux-bubblewrap sandbox requires the bwrap binary before it can run",
410
+ nextAction: "manualProviderSetup",
411
+ publicSafeMessage: "linux-bubblewrap sandbox requires a configured Raxcell provider before it can run",
337
412
  metadata: {
338
- installHint: "Install bubblewrap through the system package manager, then rerun rax test.",
413
+ installHint: "Set RAXCELL_BIN or inject RaxcellSandboxProvider through runtime sandbox options.",
339
414
  sandboxId: spec.sandboxId,
415
+ requiredProvider: "raxcell",
340
416
  },
341
417
  };
342
418
  }
@@ -352,10 +428,12 @@ async function probeLinuxBubblewrap(spec) {
352
428
  dependencyInstallEnvelopes: [],
353
429
  selfRepairHints: repairHints({ providerFamily, missingDependencies: [], status: "available" }),
354
430
  nextAction: "none",
355
- publicSafeMessage: "linux-bubblewrap sandbox dependencies are available",
431
+ publicSafeMessage: "Raxcell linux-bubblewrap sandbox provider is available",
356
432
  metadata: {
357
433
  sandboxId: spec.sandboxId,
358
434
  isolationLevel: spec.isolationLevel ?? "process-namespace",
435
+ provider: "raxcell",
436
+ binaryPath: resolveRaxcellBinaryPath() ?? "raxcell",
359
437
  },
360
438
  };
361
439
  }
@@ -447,193 +525,23 @@ async function probeWindowsRestricted(spec) {
447
525
  },
448
526
  };
449
527
  }
450
- async function ensureLinuxBubblewrapPaths(cwd) {
451
- const workspace = path.resolve(cwd);
452
- const raxWorkspace = path.join(workspace, ".rax_workspace");
453
- const sandboxRoot = path.join(raxWorkspace, "sandbox");
454
- const home = path.join(sandboxRoot, "home");
455
- const tmp = path.join(sandboxRoot, "tmp");
456
- const artifacts = path.join(sandboxRoot, "artifacts");
457
- await Promise.all([
458
- mkdir(home, { recursive: true }),
459
- mkdir(tmp, { recursive: true }),
460
- mkdir(artifacts, { recursive: true }),
461
- ]);
462
- return { workspace, raxWorkspace, sandboxRoot, home, tmp, artifacts };
463
- }
464
- function linuxBubblewrapSystemMounts() {
465
- const args = [];
466
- for (const dir of ["/usr", "/bin", "/lib", "/lib64", "/etc", "/opt", "/nix"]) {
467
- args.push("--ro-bind-try", dir, dir);
468
- }
469
- return args;
470
- }
471
- function minimalDeviceMounts() {
472
- return [
473
- "--dir",
474
- "/dev",
475
- "--dev-bind",
476
- "/dev/null",
477
- "/dev/null",
478
- "--dev-bind",
479
- "/dev/zero",
480
- "/dev/zero",
481
- "--dev-bind",
482
- "/dev/random",
483
- "/dev/random",
484
- "--dev-bind",
485
- "/dev/urandom",
486
- "/dev/urandom",
487
- ];
488
- }
489
- function smokeScript() {
490
- return [
491
- "test \"$(pwd)\" = /workspace",
492
- "test \"$HOME\" = /sandbox-home",
493
- "test -d /workspace",
494
- "test -r /workspace",
495
- "test -w /workspace/.rax_workspace/sandbox",
496
- "test -w /tmp",
497
- "test -w /artifacts",
498
- "echo praxis-smoke >/workspace/.rax_workspace/sandbox/tmp/praxis-bwrap-smoke.txt",
499
- "test ! -e /home/proview/.ssh",
500
- "test ! -e /host-home",
501
- "test -d /proc",
502
- "echo check:cwd",
503
- "echo check:home",
504
- "echo check:workspace",
505
- "echo check:scratch",
506
- "echo check:tmp",
507
- "echo check:artifacts",
508
- "echo check:host-home-hidden",
509
- "echo check:proc",
510
- ].join(" && ");
511
- }
512
- function smokeCommand(paths) {
513
- return [
514
- "bwrap",
515
- "--unshare-pid",
516
- "--unshare-ipc",
517
- "--unshare-uts",
518
- "--unshare-net",
519
- "--die-with-parent",
520
- ...linuxBubblewrapSystemMounts(),
521
- "--proc",
522
- "/proc",
523
- ...minimalDeviceMounts(),
524
- "--ro-bind",
525
- paths.workspace,
526
- "/workspace",
527
- "--bind",
528
- paths.raxWorkspace,
529
- "/workspace/.rax_workspace",
530
- "--bind",
531
- paths.home,
532
- "/sandbox-home",
533
- "--bind",
534
- paths.tmp,
535
- "/tmp",
536
- "--bind",
537
- paths.artifacts,
538
- "/artifacts",
539
- "--setenv",
540
- "HOME",
541
- "/sandbox-home",
542
- "--setenv",
543
- "TMPDIR",
544
- "/tmp",
545
- "--setenv",
546
- "PRAXIS_SANDBOX",
547
- "linux-bubblewrap",
548
- "--chdir",
549
- "/workspace",
550
- "/usr/bin/env",
551
- "sh",
552
- "-lc",
553
- smokeScript(),
554
- ];
555
- }
556
- async function runLinuxBubblewrapSmoke(spec, input = {}) {
557
- const cwd = input.cwd ?? process.cwd();
558
- const paths = await ensureLinuxBubblewrapPaths(cwd);
559
- const command = smokeCommand(paths);
560
- if (process.platform !== "linux") {
561
- return {
562
- providerFamily: providerFamilyFor(spec),
563
- profile: spec.profile,
564
- status: "skipped",
565
- commandPreview: command,
566
- checks: [{ checkId: "platform", status: "skipped", publicSafeMessage: "linux-bubblewrap smoke only runs on Linux" }],
567
- publicSafeMessage: "linux-bubblewrap smoke is skipped outside Linux",
568
- metadata: { cwd, sandboxRoot: paths.sandboxRoot },
569
- };
570
- }
571
- try {
572
- const result = await execFileAsync(command[0] ?? "bwrap", [...command.slice(1)], {
573
- cwd,
574
- timeout: spec.resourceLimits.timeoutMs ?? 5_000,
575
- maxBuffer: spec.resourceLimits.maxOutputBytes ?? 64_000,
576
- env: {
577
- ...process.env,
578
- HOME: paths.home,
579
- TMPDIR: paths.tmp,
580
- },
581
- });
582
- const stdout = result.stdout ?? "";
583
- const passedChecks = [
584
- "cwd",
585
- "home",
586
- "workspace",
587
- "scratch",
588
- "tmp",
589
- "artifacts",
590
- "host-home-hidden",
591
- "proc",
592
- ].map((checkId) => ({
593
- checkId,
594
- status: stdout.includes(`check:${checkId}`) ? "passed" : "failed",
595
- publicSafeMessage: stdout.includes(`check:${checkId}`)
596
- ? `${checkId} boundary check passed`
597
- : `${checkId} boundary check did not report success`,
598
- }));
599
- return {
600
- providerFamily: providerFamilyFor(spec),
601
- profile: spec.profile,
602
- status: "passed",
603
- commandPreview: command,
604
- stdout: result.stdout,
605
- stderr: result.stderr,
606
- checks: passedChecks,
607
- publicSafeMessage: "linux-bubblewrap workspace-only smoke passed",
608
- metadata: {
609
- cwd,
610
- sandboxRoot: paths.sandboxRoot,
611
- home: paths.home,
612
- tmp: paths.tmp,
613
- artifacts: paths.artifacts,
614
- networkMode: "denied",
615
- deviceExposure: "minimal",
616
- },
617
- };
618
- }
619
- catch (error) {
620
- const err = error;
621
- return {
622
- providerFamily: providerFamilyFor(spec),
623
- profile: spec.profile,
624
- status: "failed",
625
- commandPreview: command,
626
- stdout: err.stdout,
627
- stderr: err.stderr,
628
- checks: [{ checkId: "linux-bubblewrap", status: "failed", publicSafeMessage: "bubblewrap command did not complete all boundary checks" }],
629
- publicSafeMessage: "linux-bubblewrap smoke failed; user namespaces or bwrap policy may be unavailable",
630
- metadata: {
631
- cwd,
632
- sandboxRoot: paths.sandboxRoot,
633
- error: err.message ?? "unknown bwrap failure",
634
- },
635
- };
636
- }
528
+ function runLinuxBubblewrapSmoke(spec, input = {}) {
529
+ return Promise.resolve({
530
+ providerFamily: providerFamilyFor(spec),
531
+ profile: spec.profile,
532
+ status: "skipped",
533
+ commandPreview: [],
534
+ checks: [{
535
+ checkId: "raxcell-provider",
536
+ status: "skipped",
537
+ publicSafeMessage: "Raxcell owns Linux backend execution checks; Praxis runtime provider only verifies provider availability.",
538
+ }],
539
+ publicSafeMessage: "Raxcell linux-bubblewrap smoke is provider-owned and skipped by Praxis runtime.",
540
+ metadata: {
541
+ cwd: input.cwd ?? process.cwd(),
542
+ provider: "raxcell",
543
+ },
544
+ });
637
545
  }
638
546
  export function createSandboxRuntimeProvider(providerFamily) {
639
547
  return {
@@ -651,12 +559,14 @@ export function createSandboxRuntimeProvider(providerFamily) {
651
559
  return probeContractOnly(spec);
652
560
  },
653
561
  async prepare(spec, input = {}) {
654
- const probe = await this.probe(spec);
562
+ const probe = providerFamilyFor(spec) === "linux-bubblewrap" && input.providerReady === true
563
+ ? await probeLinuxBubblewrap(spec, { providerReady: true })
564
+ : await this.probe(spec);
655
565
  const shouldSmoke = input.runSmoke === true && probe.status === "available" && providerFamilyFor(spec) === "linux-bubblewrap";
656
566
  const smoke = shouldSmoke
657
567
  ? await this.runSmoke(spec, { cwd: input.cwd })
658
568
  : undefined;
659
- const ready = probe.status === "available" && (smoke === undefined || smoke.status === "passed");
569
+ const ready = probe.status === "available" && smoke?.status !== "failed";
660
570
  return {
661
571
  providerFamily: providerFamilyFor(spec),
662
572
  profile: spec.profile,
@@ -11,6 +11,7 @@ import { createHash } from "node:crypto";
11
11
  import { createBaseToolSupportCatalog } from "./runtime.execEngine/baseToolSupportCatalog.js";
12
12
  import { canonicalDependencyId, dependencyKindFromId, } from "./runtime.dependencyPlane/index.js";
13
13
  import { capability as capabilityAuthoring, } from "./runtime.provisionPlane/index.js";
14
+ import { mcpHarnessModuleFrom, runtimeRequirementsForMcpModule, } from "./runtime.mcpPlane/index.js";
14
15
  export class PromptPack {
15
16
  promptPackId;
16
17
  base;
@@ -352,7 +353,7 @@ export const sandbox = {
352
353
  profile: "linux-bubblewrap",
353
354
  providerFamily: "linux-bubblewrap",
354
355
  isolationLevel: "process-namespace",
355
- dependencyRefs: input.dependencyRefs ?? ["binary:bwrap"],
356
+ dependencyRefs: input.dependencyRefs ?? ["dependency.binary.raxcell"],
356
357
  mountPolicy: input.mountPolicy ?? {
357
358
  workspaceRootRef: "rax.workspace",
358
359
  allowedReadRoots: ["workspace", ".rax_workspace"],
@@ -367,7 +368,7 @@ export const sandbox = {
367
368
  windows: "unsupported",
368
369
  },
369
370
  metadata: {
370
- provider: "bubblewrap",
371
+ provider: "raxcell",
371
372
  providerVersion: "v2",
372
373
  flatpakCompatible: true,
373
374
  fallback: "explicit-only",
@@ -1268,7 +1269,10 @@ function normalizeHarness(input, authoring, normalizedTools) {
1268
1269
  statePlane: authoring.statePlane,
1269
1270
  frameworkCore: authoring.frameworkCore,
1270
1271
  modules: input.modules ?? {},
1271
- runtimeRequirements: cleanList(input.runtimeRequirements),
1272
+ runtimeRequirements: cleanList([
1273
+ ...(input.runtimeRequirements ?? []),
1274
+ ...runtimeRequirementsForMcpModule(mcpHarnessModuleFrom({ modules: input.modules })),
1275
+ ]),
1272
1276
  capabilities: authoring.capabilities,
1273
1277
  dependencies: authoring.dependencies,
1274
1278
  metadata: input.metadata ?? {},
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@praxis-ai/praxis",
3
- "version": "0.1.1",
3
+ "version": "0.1.3",
4
4
  "private": false,
5
5
  "type": "module",
6
6
  "description": "Praxis agentCore architecture scaffold, tests, and engineering contracts.",
@@ -154,6 +154,8 @@
154
154
  "@lancedb/lancedb": "^0.27.2",
155
155
  "@modelcontextprotocol/sdk": "^1.29.0",
156
156
  "@openai/agents": "^0.7.2",
157
+ "@praxis-ai/mcp-plus": "^1.0.0",
158
+ "@praxis-ai/raxcell": "^0.1.5",
157
159
  "@types/react": "^18.3.28",
158
160
  "apache-arrow": "^18.1.0",
159
161
  "effect": "^3.21.2",
@@ -97,15 +97,15 @@ function createRaxodeProvisioning(options) {
97
97
  source: "raxode-backend",
98
98
  },
99
99
  }),
100
- praxis.dependency.binary("bwrap", {
100
+ praxis.dependency.binary("raxcell", {
101
101
  required: options.sandboxProfile === "linuxBubblewrap",
102
102
  install: "manual",
103
- reason: "Prepare the Linux bubblewrap sandbox provider; Praxis degrades to workspace rollback when it is unavailable.",
103
+ reason: "Prepare the Raxcell Linux sandbox provider; Praxis degrades to workspace rollback when it is unavailable.",
104
104
  metadata: {
105
105
  source: "raxode-sandbox",
106
106
  providerFamily: "linux-bubblewrap",
107
107
  defaultWithSandbox: true,
108
- installHint: "Install bubblewrap with the OS package manager, for example apt install bubblewrap.",
108
+ installHint: "Set RAXCELL_BIN or put the raxcell CLI on PATH.",
109
109
  },
110
110
  }),
111
111
  praxis.dependency.secretRef("provider.core.main", {
@@ -118,7 +118,7 @@ export function createRaxodeBackendModuleInventory(input) {
118
118
  hasModuleMode(manifest, "dependencyPlane"),
119
119
  dependencyIds.has("dependency.binary.node"),
120
120
  dependencyIds.has("dependency.npm.tsx"),
121
- dependencyIds.has("dependency.binary.bwrap"),
121
+ dependencyIds.has("dependency.binary.raxcell"),
122
122
  ],
123
123
  }),
124
124
  surface: "manifest.dependencies",
@@ -191,7 +191,7 @@ export function createRaxodeBackendModuleInventory(input) {
191
191
  hasRequirement(manifest, "praxis.sandboxPlane.declaredCapabilities"),
192
192
  capabilityIds.has("capability.raxode.sandbox"),
193
193
  typeof manifest.sandbox.profile === "string",
194
- dependencyIds.has("dependency.binary.bwrap"),
194
+ dependencyIds.has("dependency.binary.raxcell"),
195
195
  ],
196
196
  }),
197
197
  surface: "manifest.sandbox",
@@ -200,7 +200,7 @@ export function createRaxodeBackendModuleInventory(input) {
200
200
  evidence: [
201
201
  `profile=${manifest.sandbox.profile}`,
202
202
  `providerFamily=${manifest.sandbox.providerFamily ?? "auto"}`,
203
- `hasBwrapDependency=${dependencyIds.has("dependency.binary.bwrap")}`,
203
+ `hasRaxcellDependency=${dependencyIds.has("dependency.binary.raxcell")}`,
204
204
  ],
205
205
  },
206
206
  {
@@ -31,6 +31,7 @@ export type RaxodeLocalReadinessProbeInput = {
31
31
  now?: () => string;
32
32
  nodeVersion?: string;
33
33
  pathEnv?: string;
34
+ env?: Readonly<Record<string, string | undefined>>;
34
35
  platform?: NodeJS.Platform;
35
36
  fileExists?: (filePath: string) => boolean;
36
37
  resolvePackage?: (packageName: string) => string | undefined;
@@ -67,12 +67,34 @@ function dependencyDegrade(dependencyId) {
67
67
  return "block-backend-start";
68
68
  if (dependencyId === "dependency.npm.tsx")
69
69
  return "use-built-dist-or-install";
70
+ if (dependencyId === "dependency.binary.raxcell")
71
+ return "degrade-to-workspace-rollback";
70
72
  if (dependencyId === "dependency.binary.bwrap")
71
73
  return "degrade-to-workspace-rollback";
72
74
  if (dependencyId === "dependency.secret.provider.core.main")
73
75
  return "dry-run-or-auth-required-for-live";
74
76
  return "record-and-continue";
75
77
  }
78
+ function resolveRaxcellExecutable(input) {
79
+ const explicitBinary = (input.env?.RAXCELL_BIN ?? process.env.RAXCELL_BIN)?.trim();
80
+ const fileExists = input.fileExists ?? existsSync;
81
+ if (explicitBinary !== undefined && explicitBinary.length > 0) {
82
+ return fileExists(explicitBinary) ? explicitBinary : undefined;
83
+ }
84
+ const fromPath = findExecutableOnPath({
85
+ name: "raxcell",
86
+ pathEnv: input.pathEnv,
87
+ platform: input.platform,
88
+ fileExists,
89
+ });
90
+ if (fromPath !== undefined)
91
+ return fromPath;
92
+ const resolvedPackage = input.resolvePackage?.("@praxis-ai/raxcell/package.json");
93
+ if (resolvedPackage === undefined)
94
+ return undefined;
95
+ const packageBinary = path.resolve(path.dirname(resolvedPackage), "dist/cli.js");
96
+ return fileExists(packageBinary) ? packageBinary : undefined;
97
+ }
76
98
  function probeDependency(input) {
77
99
  const degrade = dependencyDegrade(input.dependencyId);
78
100
  if (input.dependencyId === "dependency.binary.node") {
@@ -103,6 +125,26 @@ function probeDependency(input) {
103
125
  : "tsx is resolvable from the Raxode backend package.",
104
126
  };
105
127
  }
128
+ if (input.dependencyId === "dependency.binary.raxcell") {
129
+ const resolvedPath = resolveRaxcellExecutable({
130
+ pathEnv: input.pathEnv,
131
+ env: input.env,
132
+ platform: input.platform,
133
+ fileExists: input.fileExists,
134
+ resolvePackage: input.resolvePackage,
135
+ });
136
+ return {
137
+ dependencyId: input.dependencyId,
138
+ status: resolvedPath === undefined ? "missing" : "ready",
139
+ required: input.required,
140
+ resolvedPath,
141
+ source: "process",
142
+ degrade,
143
+ message: resolvedPath === undefined
144
+ ? "Raxcell is not configured through RAXCELL_BIN, PATH, or the installed @praxis-ai/raxcell package; linux-bubblewrap will degrade to workspace-rollback."
145
+ : "Raxcell is available for linux-bubblewrap sandbox execution.",
146
+ };
147
+ }
106
148
  if (input.dependencyId === "dependency.binary.bwrap") {
107
149
  const resolvedPath = findExecutableOnPath({
108
150
  name: "bwrap",
@@ -163,11 +205,12 @@ function probeSandbox(input) {
163
205
  };
164
206
  }
165
207
  if (profile === "linux-bubblewrap" || profile === "linuxBubblewrap") {
166
- const executable = findExecutableOnPath({
167
- name: "bwrap",
208
+ const executable = resolveRaxcellExecutable({
168
209
  pathEnv: input.pathEnv,
210
+ env: input.env,
169
211
  platform: input.platform,
170
212
  fileExists: input.fileExists,
213
+ resolvePackage: input.resolvePackage,
171
214
  });
172
215
  return {
173
216
  profile,
@@ -176,8 +219,8 @@ function probeSandbox(input) {
176
219
  fallback: "workspace-rollback",
177
220
  executable,
178
221
  message: executable === undefined
179
- ? "bwrap was not found on PATH; runtime should degrade to workspace-rollback."
180
- : "bwrap was found on PATH.",
222
+ ? "Raxcell was not found through RAXCELL_BIN, PATH, or the installed @praxis-ai/raxcell package; runtime should degrade to workspace-rollback."
223
+ : "Raxcell was found for linux-bubblewrap sandbox execution.",
181
224
  };
182
225
  }
183
226
  return {
@@ -200,6 +243,7 @@ export function probeLocalRaxodeReadiness(input) {
200
243
  required: dependency.required ?? true,
201
244
  nodeVersion,
202
245
  pathEnv: input.pathEnv,
246
+ env: input.env,
203
247
  platform: input.platform,
204
248
  fileExists: input.fileExists,
205
249
  resolvePackage,
@@ -207,8 +251,10 @@ export function probeLocalRaxodeReadiness(input) {
207
251
  sandbox: probeSandbox({
208
252
  manifest: input.manifest,
209
253
  pathEnv: input.pathEnv,
254
+ env: input.env,
210
255
  platform: input.platform,
211
256
  fileExists: input.fileExists,
257
+ resolvePackage,
212
258
  }),
213
259
  };
214
260
  }
@@ -0,0 +1,12 @@
1
+ import type { SandboxExecutionProviderPort } from "@praxis-ai/praxis/agent-core";
2
+ import type { RaxodeOptions } from "../agents/codingAgent/config/raxodeOptions.js";
3
+ export type RaxodeRaxcellSandboxProviderOptions = Pick<RaxodeOptions, "sandboxProfile"> & {
4
+ sandboxProvider?: SandboxExecutionProviderPort;
5
+ env?: Readonly<Record<string, string | undefined>>;
6
+ pathEnv?: string;
7
+ platform?: NodeJS.Platform;
8
+ fileExists?: (filePath: string) => boolean;
9
+ resolvePackage?: (packageName: string) => string | undefined;
10
+ };
11
+ export declare function resolveRaxodeRaxcellBinaryPath(options?: Pick<RaxodeRaxcellSandboxProviderOptions, "env" | "pathEnv" | "platform" | "fileExists" | "resolvePackage">): string | undefined;
12
+ export declare function resolveRaxodeRaxcellSandboxProvider(options: RaxodeRaxcellSandboxProviderOptions): SandboxExecutionProviderPort | undefined;