@web42/cli 0.1.17 → 0.2.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.
- package/README.md +73 -0
- package/dist/commands/init.js +246 -53
- package/dist/commands/install.js +22 -5
- package/dist/commands/pack.js +179 -67
- package/dist/commands/pull.js +176 -108
- package/dist/commands/push.js +264 -124
- package/dist/commands/send.d.ts +2 -0
- package/dist/commands/send.js +124 -0
- package/dist/commands/serve.d.ts +2 -0
- package/dist/commands/serve.js +206 -0
- package/dist/index.js +4 -0
- package/dist/platforms/base.d.ts +18 -0
- package/dist/platforms/claude/__tests__/adapter.test.d.ts +1 -0
- package/dist/platforms/claude/__tests__/adapter.test.js +257 -0
- package/dist/platforms/claude/__tests__/security.test.d.ts +1 -0
- package/dist/platforms/claude/__tests__/security.test.js +166 -0
- package/dist/platforms/claude/adapter.d.ts +34 -0
- package/dist/platforms/claude/adapter.js +525 -0
- package/dist/platforms/claude/security.d.ts +15 -0
- package/dist/platforms/claude/security.js +67 -0
- package/dist/platforms/claude/templates.d.ts +5 -0
- package/dist/platforms/claude/templates.js +22 -0
- package/dist/platforms/registry.js +2 -0
- package/dist/utils/config.d.ts +2 -0
- package/dist/utils/config.js +10 -0
- package/dist/utils/sync.d.ts +1 -1
- package/dist/utils/sync.js +2 -2
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +6 -2
|
@@ -0,0 +1,166 @@
|
|
|
1
|
+
import { describe, it, expect } from "vitest";
|
|
2
|
+
import { stripForbiddenFrontmatter } from "../security.js";
|
|
3
|
+
describe("stripForbiddenFrontmatter", () => {
|
|
4
|
+
it("strips hooks from frontmatter", () => {
|
|
5
|
+
const input = `---
|
|
6
|
+
name: test-agent
|
|
7
|
+
description: A test agent
|
|
8
|
+
hooks: some-hook-config
|
|
9
|
+
model: sonnet
|
|
10
|
+
---
|
|
11
|
+
|
|
12
|
+
Body content here.
|
|
13
|
+
`;
|
|
14
|
+
const { cleaned, stripped } = stripForbiddenFrontmatter(input);
|
|
15
|
+
expect(stripped).toEqual(["hooks"]);
|
|
16
|
+
expect(cleaned).not.toContain("hooks");
|
|
17
|
+
expect(cleaned).toContain("name: test-agent");
|
|
18
|
+
expect(cleaned).toContain("model: sonnet");
|
|
19
|
+
expect(cleaned).toContain("Body content here.");
|
|
20
|
+
});
|
|
21
|
+
it("strips mcpServers from frontmatter", () => {
|
|
22
|
+
const input = `---
|
|
23
|
+
name: test-agent
|
|
24
|
+
mcpServers: some-server
|
|
25
|
+
---
|
|
26
|
+
|
|
27
|
+
Body.
|
|
28
|
+
`;
|
|
29
|
+
const { cleaned, stripped } = stripForbiddenFrontmatter(input);
|
|
30
|
+
expect(stripped).toEqual(["mcpServers"]);
|
|
31
|
+
expect(cleaned).not.toContain("mcpServers");
|
|
32
|
+
expect(cleaned).toContain("name: test-agent");
|
|
33
|
+
});
|
|
34
|
+
it("strips permissionMode from frontmatter", () => {
|
|
35
|
+
const input = `---
|
|
36
|
+
name: test-agent
|
|
37
|
+
permissionMode: full
|
|
38
|
+
---
|
|
39
|
+
|
|
40
|
+
Body.
|
|
41
|
+
`;
|
|
42
|
+
const { cleaned, stripped } = stripForbiddenFrontmatter(input);
|
|
43
|
+
expect(stripped).toEqual(["permissionMode"]);
|
|
44
|
+
expect(cleaned).not.toContain("permissionMode");
|
|
45
|
+
});
|
|
46
|
+
it("strips multiple forbidden keys at once", () => {
|
|
47
|
+
const input = `---
|
|
48
|
+
name: test-agent
|
|
49
|
+
hooks: PostToolUse
|
|
50
|
+
mcpServers: my-server
|
|
51
|
+
permissionMode: full
|
|
52
|
+
model: sonnet
|
|
53
|
+
---
|
|
54
|
+
|
|
55
|
+
Body.
|
|
56
|
+
`;
|
|
57
|
+
const { cleaned, stripped } = stripForbiddenFrontmatter(input);
|
|
58
|
+
expect(stripped).toContain("hooks");
|
|
59
|
+
expect(stripped).toContain("mcpServers");
|
|
60
|
+
expect(stripped).toContain("permissionMode");
|
|
61
|
+
expect(stripped).toHaveLength(3);
|
|
62
|
+
expect(cleaned).toContain("name: test-agent");
|
|
63
|
+
expect(cleaned).toContain("model: sonnet");
|
|
64
|
+
expect(cleaned).not.toContain("hooks");
|
|
65
|
+
expect(cleaned).not.toContain("mcpServers");
|
|
66
|
+
expect(cleaned).not.toContain("permissionMode");
|
|
67
|
+
});
|
|
68
|
+
it("preserves all safe frontmatter keys", () => {
|
|
69
|
+
const input = `---
|
|
70
|
+
name: test-agent
|
|
71
|
+
description: A test agent
|
|
72
|
+
tools: Read, Grep, Glob, Bash
|
|
73
|
+
model: sonnet
|
|
74
|
+
---
|
|
75
|
+
|
|
76
|
+
Body.
|
|
77
|
+
`;
|
|
78
|
+
const { cleaned, stripped } = stripForbiddenFrontmatter(input);
|
|
79
|
+
expect(stripped).toEqual([]);
|
|
80
|
+
expect(cleaned).toBe(input);
|
|
81
|
+
});
|
|
82
|
+
it("handles content with no frontmatter", () => {
|
|
83
|
+
const input = "Just some markdown content.\nNo frontmatter here.";
|
|
84
|
+
const { cleaned, stripped } = stripForbiddenFrontmatter(input);
|
|
85
|
+
expect(stripped).toEqual([]);
|
|
86
|
+
expect(cleaned).toBe(input);
|
|
87
|
+
});
|
|
88
|
+
it("handles empty frontmatter", () => {
|
|
89
|
+
const input = `---
|
|
90
|
+
---
|
|
91
|
+
|
|
92
|
+
Body content.
|
|
93
|
+
`;
|
|
94
|
+
const { cleaned, stripped } = stripForbiddenFrontmatter(input);
|
|
95
|
+
expect(stripped).toEqual([]);
|
|
96
|
+
expect(cleaned).toBe(input);
|
|
97
|
+
});
|
|
98
|
+
it("returns list of stripped keys", () => {
|
|
99
|
+
const input = `---
|
|
100
|
+
name: test
|
|
101
|
+
hooks: something
|
|
102
|
+
mcpServers: something-else
|
|
103
|
+
---
|
|
104
|
+
|
|
105
|
+
Body.
|
|
106
|
+
`;
|
|
107
|
+
const { stripped } = stripForbiddenFrontmatter(input);
|
|
108
|
+
expect(stripped).toEqual(["hooks", "mcpServers"]);
|
|
109
|
+
});
|
|
110
|
+
it("preserves body content after frontmatter", () => {
|
|
111
|
+
const input = `---
|
|
112
|
+
name: test
|
|
113
|
+
hooks: should-be-removed
|
|
114
|
+
---
|
|
115
|
+
|
|
116
|
+
# Main Heading
|
|
117
|
+
|
|
118
|
+
This is the body content.
|
|
119
|
+
It has multiple lines.
|
|
120
|
+
|
|
121
|
+
## Section 2
|
|
122
|
+
|
|
123
|
+
More content here.
|
|
124
|
+
`;
|
|
125
|
+
const { cleaned } = stripForbiddenFrontmatter(input);
|
|
126
|
+
expect(cleaned).toContain("# Main Heading");
|
|
127
|
+
expect(cleaned).toContain("This is the body content.");
|
|
128
|
+
expect(cleaned).toContain("## Section 2");
|
|
129
|
+
expect(cleaned).toContain("More content here.");
|
|
130
|
+
});
|
|
131
|
+
it("handles multiline frontmatter values (indented lines)", () => {
|
|
132
|
+
const input = `---
|
|
133
|
+
name: test-agent
|
|
134
|
+
hooks:
|
|
135
|
+
PostToolUse:
|
|
136
|
+
- matcher: "Edit|Write"
|
|
137
|
+
PreToolUse:
|
|
138
|
+
- type: command
|
|
139
|
+
model: sonnet
|
|
140
|
+
skills:
|
|
141
|
+
- skill-one
|
|
142
|
+
- skill-two
|
|
143
|
+
---
|
|
144
|
+
|
|
145
|
+
Body.
|
|
146
|
+
`;
|
|
147
|
+
const { cleaned, stripped } = stripForbiddenFrontmatter(input);
|
|
148
|
+
expect(stripped).toEqual(["hooks"]);
|
|
149
|
+
expect(cleaned).toContain("name: test-agent");
|
|
150
|
+
expect(cleaned).toContain("model: sonnet");
|
|
151
|
+
expect(cleaned).toContain("skills:");
|
|
152
|
+
expect(cleaned).toContain(" - skill-one");
|
|
153
|
+
expect(cleaned).not.toContain("PostToolUse");
|
|
154
|
+
expect(cleaned).not.toContain("matcher");
|
|
155
|
+
});
|
|
156
|
+
it("handles malformed frontmatter (no closing ---)", () => {
|
|
157
|
+
const input = `---
|
|
158
|
+
name: test
|
|
159
|
+
hooks: something
|
|
160
|
+
No closing delimiter
|
|
161
|
+
`;
|
|
162
|
+
const { cleaned, stripped } = stripForbiddenFrontmatter(input);
|
|
163
|
+
expect(stripped).toEqual([]);
|
|
164
|
+
expect(cleaned).toBe(input);
|
|
165
|
+
});
|
|
166
|
+
});
|
|
@@ -0,0 +1,34 @@
|
|
|
1
|
+
import type { InitConfig, InstalledAgent, InstallOptions, InstallResult, PackOptions, PackResult, PlatformAdapter, UninstallOptions, UninstallResult } from "../base.js";
|
|
2
|
+
declare const HARDCODED_EXCLUDES: string[];
|
|
3
|
+
export interface AgentCandidate {
|
|
4
|
+
name: string;
|
|
5
|
+
description?: string;
|
|
6
|
+
model?: string;
|
|
7
|
+
skills: string[];
|
|
8
|
+
path: string;
|
|
9
|
+
}
|
|
10
|
+
export interface ResolvedSkill {
|
|
11
|
+
name: string;
|
|
12
|
+
sourcePath: string;
|
|
13
|
+
found: boolean;
|
|
14
|
+
}
|
|
15
|
+
export declare class ClaudeAdapter implements PlatformAdapter {
|
|
16
|
+
name: string;
|
|
17
|
+
home: string;
|
|
18
|
+
/**
|
|
19
|
+
* Discover agent .md files in known locations.
|
|
20
|
+
*/
|
|
21
|
+
discoverAgents(cwd: string): AgentCandidate[];
|
|
22
|
+
/**
|
|
23
|
+
* Resolve skill directories from known locations.
|
|
24
|
+
*/
|
|
25
|
+
resolveSkills(skillNames: string[], cwd: string): ResolvedSkill[];
|
|
26
|
+
extractInitConfig(cwd: string): InitConfig | null;
|
|
27
|
+
pack(options: PackOptions): Promise<PackResult>;
|
|
28
|
+
install(options: InstallOptions): Promise<InstallResult>;
|
|
29
|
+
uninstall(options: UninstallOptions): Promise<UninstallResult>;
|
|
30
|
+
listInstalled(workspacePath?: string): Promise<InstalledAgent[]>;
|
|
31
|
+
resolveInstallPath(_localName: string, global?: boolean): string;
|
|
32
|
+
}
|
|
33
|
+
export declare const claudeAdapter: ClaudeAdapter;
|
|
34
|
+
export { HARDCODED_EXCLUDES as CLAUDE_HARDCODED_EXCLUDES };
|