forked from EduCraft/curriculum-project-hub
Compare commits
1 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
| 17c0536958 |
@@ -125,7 +125,8 @@ The boundary is enforced by the Claude Code SDK's built-in sandbox
|
|||||||
- Platform-curated Agent skills are immutable Hub release assets, loaded as a
|
- Platform-curated Agent skills are immutable Hub release assets, loaded as a
|
||||||
programmatic local plugin from a release-owned path. The sandbox exposes that
|
programmatic local plugin from a release-owned path. The sandbox exposes that
|
||||||
path read-only, and the SDK receives only plugin-qualified allowlist names
|
path read-only, and the SDK receives only plugin-qualified allowlist names
|
||||||
through its `skills` option. Filesystem setting sources remain disabled, so a
|
through its `skills` option; SDK-bundled skills are disabled. Filesystem
|
||||||
|
setting sources remain disabled, so a
|
||||||
project cannot register another skill or widen its tools through `.claude`
|
project cannot register another skill or widen its tools through `.claude`
|
||||||
settings. Requested skill ids are recorded on `run.created`; SDK
|
settings. Requested skill ids are recorded on `run.created`; SDK
|
||||||
initialization/results remain the authoritative evidence that loading
|
initialization/results remain the authoritative evidence that loading
|
||||||
|
|||||||
@@ -1,5 +1,5 @@
|
|||||||
{
|
{
|
||||||
"name": "cph-curated",
|
"name": "cph-curated",
|
||||||
"description": "Reviewed curriculum-production skills shipped with the Curriculum Project Hub.",
|
"description": "Reviewed curriculum-production skills shipped with the Curriculum Project Hub.",
|
||||||
"version": "0.0.1"
|
"version": "0.0.2"
|
||||||
}
|
}
|
||||||
|
|||||||
Generated
+2
-2
@@ -1,12 +1,12 @@
|
|||||||
{
|
{
|
||||||
"name": "@paradigm/hub",
|
"name": "@paradigm/hub",
|
||||||
"version": "0.0.8",
|
"version": "0.0.9",
|
||||||
"lockfileVersion": 3,
|
"lockfileVersion": 3,
|
||||||
"requires": true,
|
"requires": true,
|
||||||
"packages": {
|
"packages": {
|
||||||
"": {
|
"": {
|
||||||
"name": "@paradigm/hub",
|
"name": "@paradigm/hub",
|
||||||
"version": "0.0.8",
|
"version": "0.0.9",
|
||||||
"dependencies": {
|
"dependencies": {
|
||||||
"@anthropic-ai/claude-agent-sdk": "^0.3.202",
|
"@anthropic-ai/claude-agent-sdk": "^0.3.202",
|
||||||
"@fastify/cookie": "^11.0.2",
|
"@fastify/cookie": "^11.0.2",
|
||||||
|
|||||||
+1
-1
@@ -1,6 +1,6 @@
|
|||||||
{
|
{
|
||||||
"name": "@paradigm/hub",
|
"name": "@paradigm/hub",
|
||||||
"version": "0.0.8",
|
"version": "0.0.9",
|
||||||
"private": true,
|
"private": true,
|
||||||
"type": "module",
|
"type": "module",
|
||||||
"engines": {
|
"engines": {
|
||||||
|
|||||||
@@ -151,7 +151,9 @@ export async function runAgent(req: RunRequest): Promise<RunResult> {
|
|||||||
type QueryOptions = NonNullable<Parameters<typeof query>[0]["options"]>;
|
type QueryOptions = NonNullable<Parameters<typeof query>[0]["options"]>;
|
||||||
const options: QueryOptions = {
|
const options: QueryOptions = {
|
||||||
cwd: security.cwd,
|
cwd: security.cwd,
|
||||||
tools: [...toolConfig.tools],
|
// `skills` controls discovery/allowlisting, but an explicit `tools`
|
||||||
|
// list still has to expose the Skill dispatcher itself.
|
||||||
|
tools: [...toolConfig.tools, "Skill"],
|
||||||
allowedTools: [...toolConfig.allowedTools],
|
allowedTools: [...toolConfig.allowedTools],
|
||||||
maxTurns: cap,
|
maxTurns: cap,
|
||||||
includePartialMessages: true,
|
includePartialMessages: true,
|
||||||
@@ -169,6 +171,7 @@ export async function runAgent(req: RunRequest): Promise<RunResult> {
|
|||||||
// The project workspace is untrusted input. Do not load user/project
|
// The project workspace is untrusted input. Do not load user/project
|
||||||
// settings that could widen tools, hooks, MCP servers, or sandbox paths.
|
// settings that could widen tools, hooks, MCP servers, or sandbox paths.
|
||||||
settingSources: [],
|
settingSources: [],
|
||||||
|
settings: { disableBundledSkills: true },
|
||||||
plugins: [{ type: "local", path: security.skillPluginRoot, skipMcpDiscovery: true }],
|
plugins: [{ type: "local", path: security.skillPluginRoot, skipMcpDiscovery: true }],
|
||||||
skills: [...security.skillIds],
|
skills: [...security.skillIds],
|
||||||
strictMcpConfig: true,
|
strictMcpConfig: true,
|
||||||
|
|||||||
@@ -112,6 +112,7 @@ describe("runAgent", () => {
|
|||||||
permissionMode: "bypassPermissions",
|
permissionMode: "bypassPermissions",
|
||||||
allowDangerouslySkipPermissions: true,
|
allowDangerouslySkipPermissions: true,
|
||||||
settingSources: [],
|
settingSources: [],
|
||||||
|
settings: { disableBundledSkills: true },
|
||||||
plugins: [expect.objectContaining({ type: "local", skipMcpDiscovery: true })],
|
plugins: [expect.objectContaining({ type: "local", skipMcpDiscovery: true })],
|
||||||
skills: ["cph-curated:outline", "cph-curated:lesson-project", "cph-curated:data-processing-spec"],
|
skills: ["cph-curated:outline", "cph-curated:lesson-project", "cph-curated:data-processing-spec"],
|
||||||
strictMcpConfig: true,
|
strictMcpConfig: true,
|
||||||
@@ -182,13 +183,13 @@ describe("runAgent", () => {
|
|||||||
|
|
||||||
expect(queryMock.mock.calls[0]?.[0]).toMatchObject({
|
expect(queryMock.mock.calls[0]?.[0]).toMatchObject({
|
||||||
options: {
|
options: {
|
||||||
tools: ["Read", "Bash"],
|
tools: ["Read", "Bash", "Skill"],
|
||||||
allowedTools: ["Read", "Bash", "mcp__cph_hub__send_file"],
|
allowedTools: ["Read", "Bash", "mcp__cph_hub__send_file"],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
});
|
});
|
||||||
|
|
||||||
it("disables all SDK tools for an empty role tool whitelist", async () => {
|
it("keeps only the curated Skill dispatcher for an empty role tool whitelist", async () => {
|
||||||
queryMock.mockReturnValue(messages(assistantMessage("ok"), resultMessage("sdk-session-1")));
|
queryMock.mockReturnValue(messages(assistantMessage("ok"), resultMessage("sdk-session-1")));
|
||||||
|
|
||||||
await runAgent({
|
await runAgent({
|
||||||
@@ -204,7 +205,7 @@ describe("runAgent", () => {
|
|||||||
|
|
||||||
expect(queryMock.mock.calls[0]?.[0]).toMatchObject({
|
expect(queryMock.mock.calls[0]?.[0]).toMatchObject({
|
||||||
options: {
|
options: {
|
||||||
tools: [],
|
tools: ["Skill"],
|
||||||
allowedTools: [],
|
allowedTools: [],
|
||||||
},
|
},
|
||||||
});
|
});
|
||||||
|
|||||||
Reference in New Issue
Block a user