@praxis-ai/praxis 0.1.1 → 0.1.2
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.
- package/dist/agentCore/index.d.ts +45 -6
- package/dist/agentCore/index.js +14 -2
- package/dist/applicationLayer/applicationContract.d.ts +2 -0
- package/dist/applicationLayer/applicationRuntime.d.ts +6 -1
- package/dist/applicationLayer/applicationRuntime.js +37 -3
- package/dist/applicationLayer/index.d.ts +1 -0
- package/dist/basetool/core/shellRun.js +6 -1
- package/dist/rax_packageManager/raxCli.js +42 -1
- package/dist/runtimeImplementation/praxisRuntimeKernel.d.ts +6 -0
- package/dist/runtimeImplementation/praxisRuntimeKernel.js +165 -14
- package/dist/runtimeImplementation/runtime.componentPlane/runtimeComponentRegistry.d.ts +1 -1
- package/dist/runtimeImplementation/runtime.componentPlane/runtimeComponentRegistry.js +2 -2
- package/dist/runtimeImplementation/runtime.dependencyPlane/dependencySourceRegistry.d.ts +1 -1
- package/dist/runtimeImplementation/runtime.dependencyPlane/dependencySourceRegistry.js +12 -0
- package/dist/runtimeImplementation/runtime.dependencyPlane/dependencyTypes.js +2 -0
- package/dist/runtimeImplementation/runtime.execEngine/baseToolExecutorPortFactory.d.ts +3 -0
- package/dist/runtimeImplementation/runtime.execEngine/baseToolExecutorPortFactory.js +45 -7
- package/dist/runtimeImplementation/runtime.execEngine/mcpRuntimeAdapter.js +56 -0
- package/dist/runtimeImplementation/runtime.mcpPlane/index.d.ts +114 -0
- package/dist/runtimeImplementation/runtime.mcpPlane/index.js +167 -0
- package/dist/runtimeImplementation/runtime.sandboxPlane/baseToolSandboxPlanner.js +0 -2
- package/dist/runtimeImplementation/runtime.sandboxPlane/raxcellSandboxProvider.d.ts +19 -0
- package/dist/runtimeImplementation/runtime.sandboxPlane/raxcellSandboxProvider.js +172 -0
- package/dist/runtimeImplementation/runtime.sandboxPlane/sandboxCommandRunner.d.ts +13 -1
- package/dist/runtimeImplementation/runtime.sandboxPlane/sandboxCommandRunner.js +230 -186
- package/dist/runtimeImplementation/runtime.sandboxPlane/sandboxPolicyMiddleware.d.ts +175 -0
- package/dist/runtimeImplementation/runtime.sandboxPlane/sandboxPolicyMiddleware.js +142 -0
- package/dist/runtimeImplementation/runtime.sandboxPlane/sandboxRuntimeProvider.d.ts +9 -0
- package/dist/runtimeImplementation/runtime.sandboxPlane/sandboxRuntimeProvider.js +115 -205
- package/dist/runtimeImplementation/runtimeAgentManifest.js +7 -3
- package/package.json +3 -1
- package/raxode-tui/dist/raxode-cli/backend/agents/codingAgent/agent.js +3 -3
- package/raxode-tui/dist/raxode-cli/backend/application/backendModuleInventory.js +3 -3
- package/raxode-tui/dist/raxode-cli/backend/application/localReadinessProbe.d.ts +1 -0
- package/raxode-tui/dist/raxode-cli/backend/application/localReadinessProbe.js +50 -4
- package/raxode-tui/dist/raxode-cli/backend/application/raxcellSandboxProvider.d.ts +12 -0
- package/raxode-tui/dist/raxode-cli/backend/application/raxcellSandboxProvider.js +58 -0
- package/raxode-tui/dist/raxode-cli/backend/application/runtimeReadiness.d.ts +1 -0
- package/raxode-tui/dist/raxode-cli/backend/application/runtimeReadiness.js +3 -1
- package/raxode-tui/dist/raxode-cli/backend/application/stdioApplicationServer.d.ts +2 -0
- package/raxode-tui/dist/raxode-cli/backend/application/stdioApplicationServer.js +7 -0
- package/raxode-tui/dist/raxode-cli/backend/directApplicationBackend.d.ts +2 -0
- package/raxode-tui/dist/raxode-cli/backend/directApplicationBackend.js +21 -1
- package/raxode-tui/dist/raxode-cli/backend/raxodeBackend.d.ts +1 -1
- package/raxode-tui/dist/raxode-cli/backend/raxodeBackend.js +8 -0
- package/raxode-tui/dist/raxode-cli/frontend/tui/cli/raxode-cli.js +19 -1
- package/raxode-tui/package.json +2 -1
- package/tsconfig.json +16 -1
|
@@ -0,0 +1,142 @@
|
|
|
1
|
+
/*
|
|
2
|
+
* 文件定位:Agent 运行态实现层 / 沙箱策略中间件。
|
|
3
|
+
* 核心目的:把 Praxis policy/governance/approval 的结果翻译给可插拔沙箱 provider。
|
|
4
|
+
* 边界:本文件不替代 policy matrix,不实现沙箱 backend;provider 只报告环境事实并执行。
|
|
5
|
+
*/
|
|
6
|
+
export const sandboxPolicyMiddlewareDescriptor = {
|
|
7
|
+
surface: "runtime.sandboxPlane.sandboxPolicyMiddleware",
|
|
8
|
+
policyOwner: "praxis",
|
|
9
|
+
providerRole: "environment-and-execution",
|
|
10
|
+
publicSafe: true,
|
|
11
|
+
};
|
|
12
|
+
function appendGrant(request, grants) {
|
|
13
|
+
return {
|
|
14
|
+
...request,
|
|
15
|
+
policyGrants: [...request.policyGrants, ...grants],
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
function prepareFailureMessage(prepared) {
|
|
19
|
+
return prepared.environmentGap?.publicSafeMessage
|
|
20
|
+
?? prepared.denial?.message
|
|
21
|
+
?? "sandbox provider prepareRun failed";
|
|
22
|
+
}
|
|
23
|
+
async function audit(input) {
|
|
24
|
+
await input.audit?.({
|
|
25
|
+
type: input.type,
|
|
26
|
+
actionId: input.request.action.actionId,
|
|
27
|
+
sessionId: input.request.action.sessionId,
|
|
28
|
+
toolId: input.request.action.toolId,
|
|
29
|
+
providerId: input.provider.providerId,
|
|
30
|
+
providerFamily: input.provider.providerFamily,
|
|
31
|
+
payload: input.payload,
|
|
32
|
+
});
|
|
33
|
+
}
|
|
34
|
+
export async function runSandboxPolicyMiddleware(input) {
|
|
35
|
+
let request = input.request;
|
|
36
|
+
const events = [];
|
|
37
|
+
let prepared = await input.provider.prepareRun(request);
|
|
38
|
+
events.push("runtime.sandbox.middleware.prepareRun");
|
|
39
|
+
await audit({
|
|
40
|
+
...input,
|
|
41
|
+
request,
|
|
42
|
+
type: "runtime.sandbox.middleware.prepareRun",
|
|
43
|
+
payload: {
|
|
44
|
+
ok: prepared.ok,
|
|
45
|
+
environmentGap: prepared.environmentGap ?? null,
|
|
46
|
+
denial: prepared.denial ?? null,
|
|
47
|
+
filesystemLowering: prepared.filesystemLowering ?? null,
|
|
48
|
+
backendArtifacts: prepared.backendArtifacts,
|
|
49
|
+
},
|
|
50
|
+
});
|
|
51
|
+
if (!prepared.ok && prepared.environmentGap !== undefined && prepared.environmentGap !== null) {
|
|
52
|
+
const decision = await input.decideEnvironmentGap?.({
|
|
53
|
+
request,
|
|
54
|
+
prepared,
|
|
55
|
+
environmentGap: prepared.environmentGap,
|
|
56
|
+
}) ?? { type: "deny", reason: prepared.environmentGap.publicSafeMessage };
|
|
57
|
+
events.push(`runtime.sandbox.middleware.policyApplied.${decision.type}`);
|
|
58
|
+
await audit({
|
|
59
|
+
...input,
|
|
60
|
+
request,
|
|
61
|
+
type: "runtime.sandbox.middleware.policyApplied",
|
|
62
|
+
payload: {
|
|
63
|
+
decision: decision.type,
|
|
64
|
+
reason: "reason" in decision ? decision.reason : undefined,
|
|
65
|
+
grants: "grants" in decision ? decision.grants : undefined,
|
|
66
|
+
},
|
|
67
|
+
});
|
|
68
|
+
if (decision.type === "deny") {
|
|
69
|
+
return {
|
|
70
|
+
ok: false,
|
|
71
|
+
request,
|
|
72
|
+
prepared,
|
|
73
|
+
error: {
|
|
74
|
+
code: "SANDBOX_DENIED",
|
|
75
|
+
message: decision.reason,
|
|
76
|
+
publicSafe: true,
|
|
77
|
+
denial: prepared.denial,
|
|
78
|
+
},
|
|
79
|
+
events,
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
request = decision.type === "grant" ? appendGrant(request, decision.grants) : decision.request;
|
|
83
|
+
prepared = await input.provider.prepareRun(request);
|
|
84
|
+
events.push("runtime.sandbox.middleware.prepareRun.afterPolicy");
|
|
85
|
+
await audit({
|
|
86
|
+
...input,
|
|
87
|
+
request,
|
|
88
|
+
type: "runtime.sandbox.middleware.prepareRun.afterPolicy",
|
|
89
|
+
payload: {
|
|
90
|
+
ok: prepared.ok,
|
|
91
|
+
environmentGap: prepared.environmentGap ?? null,
|
|
92
|
+
denial: prepared.denial ?? null,
|
|
93
|
+
filesystemLowering: prepared.filesystemLowering ?? null,
|
|
94
|
+
backendArtifacts: prepared.backendArtifacts,
|
|
95
|
+
},
|
|
96
|
+
});
|
|
97
|
+
}
|
|
98
|
+
if (!prepared.ok) {
|
|
99
|
+
return {
|
|
100
|
+
ok: false,
|
|
101
|
+
request,
|
|
102
|
+
prepared,
|
|
103
|
+
error: {
|
|
104
|
+
code: "SANDBOX_PREPARE_FAILED",
|
|
105
|
+
message: prepareFailureMessage(prepared),
|
|
106
|
+
publicSafe: true,
|
|
107
|
+
denial: prepared.denial,
|
|
108
|
+
},
|
|
109
|
+
events,
|
|
110
|
+
};
|
|
111
|
+
}
|
|
112
|
+
const result = await input.provider.run(request);
|
|
113
|
+
events.push("runtime.sandbox.provider.run");
|
|
114
|
+
await audit({
|
|
115
|
+
...input,
|
|
116
|
+
request,
|
|
117
|
+
type: "runtime.sandbox.provider.run",
|
|
118
|
+
payload: {
|
|
119
|
+
ok: result.ok,
|
|
120
|
+
exitCode: result.exitCode,
|
|
121
|
+
timedOut: result.timedOut,
|
|
122
|
+
denial: result.denial ?? null,
|
|
123
|
+
environmentGap: result.environmentGap ?? null,
|
|
124
|
+
filesystemLowering: result.filesystemLowering ?? null,
|
|
125
|
+
},
|
|
126
|
+
});
|
|
127
|
+
if (!result.ok) {
|
|
128
|
+
return {
|
|
129
|
+
ok: false,
|
|
130
|
+
request,
|
|
131
|
+
prepared,
|
|
132
|
+
error: {
|
|
133
|
+
code: "SANDBOX_RUN_FAILED",
|
|
134
|
+
message: result.denial?.message ?? "sandbox provider run failed",
|
|
135
|
+
publicSafe: true,
|
|
136
|
+
denial: result.denial,
|
|
137
|
+
},
|
|
138
|
+
events,
|
|
139
|
+
};
|
|
140
|
+
}
|
|
141
|
+
return { ok: true, request, prepared, result, events };
|
|
142
|
+
}
|
|
@@ -74,6 +74,7 @@ export type SandboxRuntimeProvider = {
|
|
|
74
74
|
prepare(spec: SandboxSpec, input?: {
|
|
75
75
|
cwd?: string;
|
|
76
76
|
runSmoke?: boolean;
|
|
77
|
+
providerReady?: boolean;
|
|
77
78
|
}): Promise<SandboxRuntimePrepareResult>;
|
|
78
79
|
runSmoke(spec: SandboxSpec, input?: {
|
|
79
80
|
cwd?: string;
|
|
@@ -87,8 +88,16 @@ export declare const sandboxRuntimeProviderDescriptor: {
|
|
|
87
88
|
readonly linuxLiveProvider: "linux-bubblewrap";
|
|
88
89
|
readonly unsafeSideEffects: false;
|
|
89
90
|
};
|
|
91
|
+
export declare function resolveRaxcellBinaryPath(input?: {
|
|
92
|
+
env?: Readonly<Record<string, string | undefined>>;
|
|
93
|
+
pathEnv?: string;
|
|
94
|
+
platform?: NodeJS.Platform;
|
|
95
|
+
fileExists?: (filePath: string) => boolean;
|
|
96
|
+
resolvePackage?: (packageName: string) => string | undefined;
|
|
97
|
+
}): string | undefined;
|
|
90
98
|
export declare function createSandboxRuntimeProvider(providerFamily: SandboxProviderFamily): SandboxRuntimeProvider;
|
|
91
99
|
export declare function prepareSandboxRuntime(spec: SandboxSpec, input?: {
|
|
92
100
|
cwd?: string;
|
|
93
101
|
runSmoke?: boolean;
|
|
102
|
+
providerReady?: boolean;
|
|
94
103
|
}): Promise<SandboxRuntimePrepareResult>;
|
|
@@ -4,11 +4,14 @@
|
|
|
4
4
|
* 边界:本文件不替代 BaseTool 语义;工具执行仍然必须走 registry/handler/executor。
|
|
5
5
|
*/
|
|
6
6
|
import { execFile } from "node:child_process";
|
|
7
|
-
import {
|
|
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.
|
|
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.
|
|
203
|
+
if (input.missingDependencies.includes("dependency.binary.raxcell")) {
|
|
162
204
|
return [{
|
|
163
|
-
hintId: "linux-bubblewrap:
|
|
205
|
+
hintId: "linux-bubblewrap:configure-raxcell",
|
|
164
206
|
severity: "warning",
|
|
165
|
-
action: "
|
|
166
|
-
message: "
|
|
167
|
-
commandPreview: ["
|
|
168
|
-
requiresApproval:
|
|
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:
|
|
186
|
-
commandPreview: dependencyId === "dependency.binary.
|
|
187
|
-
? ["
|
|
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: "
|
|
336
|
-
publicSafeMessage: "linux-bubblewrap sandbox requires
|
|
410
|
+
nextAction: "manualProviderSetup",
|
|
411
|
+
publicSafeMessage: "linux-bubblewrap sandbox requires a configured Raxcell provider before it can run",
|
|
337
412
|
metadata: {
|
|
338
|
-
installHint: "
|
|
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
|
|
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
|
-
|
|
451
|
-
|
|
452
|
-
|
|
453
|
-
|
|
454
|
-
|
|
455
|
-
|
|
456
|
-
|
|
457
|
-
|
|
458
|
-
|
|
459
|
-
|
|
460
|
-
|
|
461
|
-
|
|
462
|
-
|
|
463
|
-
|
|
464
|
-
|
|
465
|
-
|
|
466
|
-
|
|
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 =
|
|
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" &&
|
|
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
|
|
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: "
|
|
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(
|
|
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.
|
|
3
|
+
"version": "0.1.2",
|
|
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("
|
|
100
|
+
praxis.dependency.binary("raxcell", {
|
|
101
101
|
required: options.sandboxProfile === "linuxBubblewrap",
|
|
102
102
|
install: "manual",
|
|
103
|
-
reason: "Prepare the Linux
|
|
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: "
|
|
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.
|
|
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.
|
|
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
|
-
`
|
|
203
|
+
`hasRaxcellDependency=${dependencyIds.has("dependency.binary.raxcell")}`,
|
|
204
204
|
],
|
|
205
205
|
},
|
|
206
206
|
{
|