@capekai/core 1.0.2 → 1.0.4
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/README.md
CHANGED
|
@@ -10,3 +10,46 @@ Requires Bun 1.3 or newer.
|
|
|
10
10
|
npm install @capekai/core
|
|
11
11
|
```
|
|
12
12
|
Public subpaths include `composition`, `plugins`, `hosts`, `execution`, `providers`, `tools`, `ask-authority`, `sandbox`, `workspace`, `configuration`, `tool`, and `storage`.
|
|
13
|
+
|
|
14
|
+
## Workspace policy
|
|
15
|
+
|
|
16
|
+
Čapek owns path resolution and containment. Embedding hosts can supply their own blocked paths, sensitive patterns, and home directory when composing an agent:
|
|
17
|
+
|
|
18
|
+
```ts
|
|
19
|
+
import { createComposition } from '@capekai/core/composition';
|
|
20
|
+
|
|
21
|
+
const composition = await createComposition(processScope, {
|
|
22
|
+
...values,
|
|
23
|
+
workspacePolicy: {
|
|
24
|
+
blockedPaths: ['/proc/', '/sys/'],
|
|
25
|
+
sensitivePatterns: ['.env', '.pem', '.key'],
|
|
26
|
+
homeDir: '/home/agent',
|
|
27
|
+
},
|
|
28
|
+
});
|
|
29
|
+
```
|
|
30
|
+
|
|
31
|
+
Hosts building a custom plugin profile can configure the same policy directly:
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import { workspacePolicyPlugin } from '@capekai/core/plugins';
|
|
35
|
+
|
|
36
|
+
workspacePolicyPlugin('host.workspace-policy', {
|
|
37
|
+
blockedPaths: [],
|
|
38
|
+
sensitivePatterns: ['credentials'],
|
|
39
|
+
homeDir: '/srv/agent',
|
|
40
|
+
});
|
|
41
|
+
```
|
|
42
|
+
|
|
43
|
+
For workspace helpers used outside an agent scope, configure the process-wide policy during host bootstrap:
|
|
44
|
+
|
|
45
|
+
```ts
|
|
46
|
+
import { configureWorkspacePolicy } from '@capekai/core/workspace';
|
|
47
|
+
|
|
48
|
+
configureWorkspacePolicy({
|
|
49
|
+
blockedPaths: ['/proc/', '/sys/'],
|
|
50
|
+
sensitivePatterns: ['.env', '.pem', '.key'],
|
|
51
|
+
homeDir: '/home/agent',
|
|
52
|
+
});
|
|
53
|
+
```
|
|
54
|
+
|
|
55
|
+
Call `configureWorkspacePolicy()` with no argument, or omit composition options, to retain the compatibility defaults.
|
package/package.json
CHANGED
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@capekai/core",
|
|
3
|
-
"version": "1.0.
|
|
3
|
+
"version": "1.0.4",
|
|
4
4
|
"description": "Bun-native composable agent runtime and framework for Capek.",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
7
7
|
"type": "git",
|
|
8
|
-
"url": "git+https://github.com/capek-dev/
|
|
8
|
+
"url": "git+https://github.com/capek-dev/capek.git",
|
|
9
9
|
"directory": "packages/capek"
|
|
10
10
|
},
|
|
11
11
|
"type": "module",
|
|
@@ -77,7 +77,7 @@
|
|
|
77
77
|
"dependencies": {
|
|
78
78
|
"@ai-sdk/deepseek": "^2.0.35",
|
|
79
79
|
"@ai-sdk/openai": "^3.0.84",
|
|
80
|
-
"@capekai/tool": "^1.0.
|
|
80
|
+
"@capekai/tool": "^1.0.2",
|
|
81
81
|
"@capekai/types": "^1.0.1",
|
|
82
82
|
"@openrouter/ai-sdk-provider": "^2.3.3",
|
|
83
83
|
"@zip.js/zip.js": "^2.7.60",
|
|
@@ -16,6 +16,7 @@ import type { SandboxController } from '../sandbox/controller';
|
|
|
16
16
|
import type { StorageBundle } from '../storage/contracts';
|
|
17
17
|
import type { ToolRegistryResolver } from '../tools/registry';
|
|
18
18
|
import type { WorkspaceToolDiscovery } from '../tools/tool-source';
|
|
19
|
+
import type { WorkspacePolicyOptions } from '../workspace/contracts';
|
|
19
20
|
import { getSchedulerHost } from '../scheduler/host';
|
|
20
21
|
import { getSessionSearchHost } from '../session-search/host';
|
|
21
22
|
import { createContextSectionsPlugin } from './context-sections';
|
|
@@ -64,6 +65,9 @@ export interface FacadeScopeValues {
|
|
|
64
65
|
host: RuntimeHost;
|
|
65
66
|
contextSources: Partial<ContextSources>;
|
|
66
67
|
workspaceToolDiscovery: WorkspaceToolDiscovery;
|
|
68
|
+
/** Host-owned path classification values. When omitted, the current
|
|
69
|
+
* compatibility defaults apply. */
|
|
70
|
+
workspacePolicy?: WorkspacePolicyOptions;
|
|
67
71
|
/** Optional compatibility resolver. When omitted, the facade
|
|
68
72
|
* composition derives the resolver from the composed scope's effective
|
|
69
73
|
* contributed tool payloads. The explicit value is the rollback
|
|
@@ -109,7 +113,7 @@ export function createFacadeAgentPlugins(values: FacadeScopeValues): readonly Ca
|
|
|
109
113
|
retryPolicyPlugin('facade.retry-policy'),
|
|
110
114
|
compactionPolicyPlugin('facade.compaction-policy'),
|
|
111
115
|
permissionPolicyPlugin('facade.permission-policy'),
|
|
112
|
-
workspacePolicyPlugin('facade.workspace-policy'),
|
|
116
|
+
workspacePolicyPlugin('facade.workspace-policy', values.workspacePolicy),
|
|
113
117
|
toolOutputPolicyPlugin('facade.tool-output-policy'),
|
|
114
118
|
contextSourcesValuePlugin('facade.context-sources', values.contextSources),
|
|
115
119
|
// Facade context parity: the facade keeps the legacy self-delegation and
|
|
@@ -1,11 +1,6 @@
|
|
|
1
1
|
import type { CapekPlugin, PluginContext } from '../kernel/types';
|
|
2
|
-
import {
|
|
3
|
-
import {
|
|
4
|
-
import {
|
|
5
|
-
BLOCKED_PATHS,
|
|
6
|
-
createWorkspaceService,
|
|
7
|
-
type WorkspacePolicyOptions,
|
|
8
|
-
} from '../workspace/policy';
|
|
2
|
+
import type { WorkspacePolicyOptions } from '../workspace/contracts';
|
|
3
|
+
import { createWorkspaceService } from '../workspace/policy';
|
|
9
4
|
import { capekWorkspacePolicyKey } from './service-keys';
|
|
10
5
|
|
|
11
6
|
/**
|
|
@@ -17,17 +12,15 @@ import { capekWorkspacePolicyKey } from './service-keys';
|
|
|
17
12
|
* current containment, root classification, expansion, and sensitive/blocked
|
|
18
13
|
* denial behavior.
|
|
19
14
|
*/
|
|
20
|
-
export function workspacePolicyPlugin(
|
|
15
|
+
export function workspacePolicyPlugin(
|
|
16
|
+
id: string,
|
|
17
|
+
options?: WorkspacePolicyOptions,
|
|
18
|
+
): CapekPlugin<unknown> {
|
|
21
19
|
return {
|
|
22
20
|
id,
|
|
23
21
|
scope: 'agent',
|
|
24
22
|
provides: [capekWorkspacePolicyKey],
|
|
25
23
|
setup(context: PluginContext) {
|
|
26
|
-
const options: WorkspacePolicyOptions = {
|
|
27
|
-
blockedPaths: [...BLOCKED_PATHS],
|
|
28
|
-
sensitivePatterns: [...SENSITIVE_FILE_PATTERNS],
|
|
29
|
-
homeDir: homedir(),
|
|
30
|
-
};
|
|
31
24
|
context.provide(
|
|
32
25
|
capekWorkspacePolicyKey,
|
|
33
26
|
createWorkspaceService({ id, options }),
|
package/src/tools/executor.ts
CHANGED
|
@@ -205,6 +205,7 @@ export async function executeTool(options: ExecuteToolOptions): Promise<ToolResu
|
|
|
205
205
|
logger: createLogger(tool.definition.name, sessionId),
|
|
206
206
|
fetch: globalThis.fetch.bind(globalThis),
|
|
207
207
|
resolvePath: workspace.resolvePath,
|
|
208
|
+
resolvePathFrom: workspace.resolvePathFrom,
|
|
208
209
|
isWithinWorkspace: workspace.isWithinWorkspace,
|
|
209
210
|
isSensitivePath: workspace.isSensitivePath,
|
|
210
211
|
isBlockedPath: workspace.isBlockedPath,
|
|
@@ -41,6 +41,7 @@ export interface WorkspaceCapability {
|
|
|
41
41
|
allowedRoots: string[];
|
|
42
42
|
tempDir: string;
|
|
43
43
|
resolvePath(path: string): string;
|
|
44
|
+
resolvePathFrom(path: string, basePath: string): string;
|
|
44
45
|
isWithinWorkspace(path: string): boolean;
|
|
45
46
|
isSensitivePath(path: string): boolean;
|
|
46
47
|
isBlockedPath(path: string): boolean;
|
package/src/workspace/policy.ts
CHANGED
|
@@ -47,6 +47,14 @@ function defaultOptions(): WorkspacePolicyOptions {
|
|
|
47
47
|
};
|
|
48
48
|
}
|
|
49
49
|
|
|
50
|
+
function freezeOptions(options: WorkspacePolicyOptions): Readonly<WorkspacePolicyOptions> {
|
|
51
|
+
return Object.freeze({
|
|
52
|
+
blockedPaths: Object.freeze([...options.blockedPaths]),
|
|
53
|
+
sensitivePatterns: Object.freeze([...options.sensitivePatterns]),
|
|
54
|
+
homeDir: options.homeDir,
|
|
55
|
+
});
|
|
56
|
+
}
|
|
57
|
+
|
|
50
58
|
// ── Mandatory containment runtime (C6 step 6) ───────────────────────────
|
|
51
59
|
// The tool-runtime capability is constructed HERE, not by provider methods:
|
|
52
60
|
// a custom provider supplies only frozen options (blocked paths, sensitive
|
|
@@ -78,14 +86,18 @@ export function createWorkspaceCapabilityWithOptions(
|
|
|
78
86
|
const additionalRoots = (host.additionalRoots ?? []).map((path) => resolve(path));
|
|
79
87
|
const allowedRoots = (host.allowedRoots ?? []).map((path) => resolve(path));
|
|
80
88
|
|
|
81
|
-
function
|
|
89
|
+
function resolvePathFrom(path: string, basePath: string): string {
|
|
82
90
|
if (path === '~' || path.startsWith('~/')) {
|
|
83
91
|
return join(options.homeDir, path.slice(1));
|
|
84
92
|
}
|
|
85
93
|
if (isAbsolute(path)) {
|
|
86
94
|
return resolve(path);
|
|
87
95
|
}
|
|
88
|
-
return resolve(
|
|
96
|
+
return resolve(basePath, path);
|
|
97
|
+
}
|
|
98
|
+
|
|
99
|
+
function resolvePath(path: string): string {
|
|
100
|
+
return resolvePathFrom(path, effectiveRoot);
|
|
89
101
|
}
|
|
90
102
|
|
|
91
103
|
return {
|
|
@@ -94,6 +106,7 @@ export function createWorkspaceCapabilityWithOptions(
|
|
|
94
106
|
allowedRoots,
|
|
95
107
|
tempDir: host.tempDir,
|
|
96
108
|
resolvePath,
|
|
109
|
+
resolvePathFrom,
|
|
97
110
|
isWithinWorkspace(path: string): boolean {
|
|
98
111
|
const resolvedPath = resolvePath(path);
|
|
99
112
|
return [effectiveRoot, ...additionalRoots]
|
|
@@ -125,7 +138,7 @@ export function createWorkspaceService(
|
|
|
125
138
|
createOptions: WorkspaceServiceCreateOptions = {},
|
|
126
139
|
): WorkspaceService {
|
|
127
140
|
const id = createOptions.id ?? 'workspace.default';
|
|
128
|
-
const options = createOptions.options ?? defaultOptions();
|
|
141
|
+
const options = freezeOptions(createOptions.options ?? defaultOptions());
|
|
129
142
|
|
|
130
143
|
const service: WorkspaceService = {
|
|
131
144
|
id,
|
|
@@ -246,6 +259,15 @@ export function getWorkspaceService(): WorkspaceService {
|
|
|
246
259
|
?? (processDefaultService ??= createWorkspaceService({ id: 'workspace.process-default' }));
|
|
247
260
|
}
|
|
248
261
|
|
|
262
|
+
/** Configures the process-wide policy used outside an agent scope. Omitting
|
|
263
|
+
* options restores the compatibility defaults. */
|
|
264
|
+
export function configureWorkspacePolicy(options?: WorkspacePolicyOptions): void {
|
|
265
|
+
processDefaultService = createWorkspaceService({
|
|
266
|
+
id: 'workspace.process-default',
|
|
267
|
+
options,
|
|
268
|
+
});
|
|
269
|
+
}
|
|
270
|
+
|
|
249
271
|
/** Builds the tool-runtime capability over the active workspace policy. */
|
|
250
272
|
export function createWorkspaceCapability(host: WorkspaceCapabilityHost): WorkspaceCapability {
|
|
251
273
|
return createWorkspaceCapabilityWithOptions(host, getWorkspaceService().options);
|