@llmtune/cli 0.1.0 → 0.1.1
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 +1 -1
- package/dist/agent/conversation.d.ts +42 -0
- package/dist/agent/conversation.js +105 -0
- package/dist/agent/loop.d.ts +19 -0
- package/dist/agent/loop.js +185 -0
- package/dist/agent/planner.d.ts +8 -0
- package/dist/agent/planner.js +43 -0
- package/dist/auth/client.d.ts +4 -0
- package/dist/auth/client.js +24 -0
- package/dist/auth/config.d.ts +21 -0
- package/dist/auth/config.js +83 -0
- package/dist/commands/chat.d.ts +5 -0
- package/dist/commands/chat.js +27 -0
- package/dist/commands/config.d.ts +2 -0
- package/dist/commands/config.js +37 -0
- package/dist/commands/login.d.ts +2 -0
- package/dist/commands/login.js +93 -0
- package/dist/commands/marketplace.d.ts +6 -0
- package/dist/commands/marketplace.js +213 -0
- package/dist/commands/models.d.ts +2 -0
- package/dist/commands/models.js +53 -0
- package/dist/compact/history-store.d.ts +29 -0
- package/dist/compact/history-store.js +110 -0
- package/dist/compact/microcompact.d.ts +10 -0
- package/dist/compact/microcompact.js +43 -0
- package/dist/compact/service.d.ts +13 -0
- package/dist/compact/service.js +156 -0
- package/dist/context/analyzer.d.ts +26 -0
- package/dist/context/analyzer.js +99 -0
- package/dist/context/builder.d.ts +13 -0
- package/dist/context/builder.js +144 -0
- package/dist/context/cache.d.ts +6 -0
- package/dist/context/cache.js +8 -0
- package/dist/context/git-context.d.ts +9 -0
- package/dist/context/git-context.js +49 -0
- package/dist/context/llmtune-md.d.ts +6 -0
- package/dist/context/llmtune-md.js +73 -0
- package/dist/context/workspace.d.ts +11 -0
- package/dist/context/workspace.js +115 -0
- package/dist/index.d.ts +3 -0
- package/dist/index.js +1 -1
- package/dist/marketplace/client.d.ts +52 -0
- package/dist/marketplace/client.js +86 -0
- package/dist/memory/files.d.ts +14 -0
- package/dist/memory/files.js +116 -0
- package/dist/memory/service.d.ts +22 -0
- package/dist/memory/service.js +146 -0
- package/dist/repl/repl.d.ts +8 -0
- package/dist/repl/repl.js +374 -0
- package/dist/skills/args.d.ts +10 -0
- package/dist/skills/args.js +37 -0
- package/dist/skills/frontmatter.d.ts +6 -0
- package/dist/skills/frontmatter.js +44 -0
- package/dist/skills/loader.d.ts +5 -0
- package/dist/skills/loader.js +59 -0
- package/dist/skills/registry.d.ts +27 -0
- package/dist/skills/registry.js +162 -0
- package/dist/skills/signing/signer.d.ts +19 -0
- package/dist/skills/signing/signer.js +110 -0
- package/dist/skills/trust.d.ts +11 -0
- package/dist/skills/trust.js +42 -0
- package/dist/telemetry/logger.d.ts +51 -0
- package/dist/telemetry/logger.js +135 -0
- package/dist/tools/permissions.d.ts +20 -0
- package/dist/tools/permissions.js +58 -0
- package/dist/tools/protocol.d.ts +22 -0
- package/dist/tools/protocol.js +3 -0
- package/dist/tools/registry.d.ts +20 -0
- package/dist/tools/registry.js +77 -0
- package/dist/tools/sandbox/docker.d.ts +16 -0
- package/dist/tools/sandbox/docker.js +240 -0
- package/dist/tools/sandbox/index.d.ts +18 -0
- package/dist/tools/sandbox/index.js +80 -0
- package/dist/tools/tools/ask-user.d.ts +3 -0
- package/dist/tools/tools/ask-user.js +56 -0
- package/dist/tools/tools/bash.d.ts +3 -0
- package/dist/tools/tools/bash.js +85 -0
- package/dist/tools/tools/edit.d.ts +3 -0
- package/dist/tools/tools/edit.js +138 -0
- package/dist/tools/tools/glob.d.ts +3 -0
- package/dist/tools/tools/glob.js +63 -0
- package/dist/tools/tools/grep.d.ts +3 -0
- package/dist/tools/tools/grep.js +148 -0
- package/dist/tools/tools/read.d.ts +3 -0
- package/dist/tools/tools/read.js +85 -0
- package/dist/tools/tools/web-fetch.d.ts +3 -0
- package/dist/tools/tools/web-fetch.js +142 -0
- package/dist/tools/tools/write.d.ts +3 -0
- package/dist/tools/tools/write.js +84 -0
- package/dist/tools/validation.d.ts +13 -0
- package/dist/tools/validation.js +142 -0
- package/dist/utils/markdown.d.ts +9 -0
- package/dist/utils/markdown.js +89 -0
- package/dist/utils/streaming.d.ts +10 -0
- package/dist/utils/streaming.js +63 -0
- package/dist/utils/tokens.d.ts +12 -0
- package/dist/utils/tokens.js +44 -0
- package/package.json +2 -2
- package/dist/agent/conversation.d.ts.map +0 -1
- package/dist/agent/loop.d.ts.map +0 -1
- package/dist/agent/planner.d.ts.map +0 -1
- package/dist/auth/client.d.ts.map +0 -1
- package/dist/auth/config.d.ts.map +0 -1
- package/dist/commands/chat.d.ts.map +0 -1
- package/dist/commands/config.d.ts.map +0 -1
- package/dist/commands/login.d.ts.map +0 -1
- package/dist/commands/marketplace.d.ts.map +0 -1
- package/dist/commands/models.d.ts.map +0 -1
- package/dist/compact/history-store.d.ts.map +0 -1
- package/dist/compact/microcompact.d.ts.map +0 -1
- package/dist/compact/service.d.ts.map +0 -1
- package/dist/context/analyzer.d.ts.map +0 -1
- package/dist/context/builder.d.ts.map +0 -1
- package/dist/context/cache.d.ts.map +0 -1
- package/dist/context/git-context.d.ts.map +0 -1
- package/dist/context/llmtune-md.d.ts.map +0 -1
- package/dist/context/workspace.d.ts.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/marketplace/client.d.ts.map +0 -1
- package/dist/memory/files.d.ts.map +0 -1
- package/dist/memory/service.d.ts.map +0 -1
- package/dist/repl/repl.d.ts.map +0 -1
- package/dist/skills/args.d.ts.map +0 -1
- package/dist/skills/frontmatter.d.ts.map +0 -1
- package/dist/skills/loader.d.ts.map +0 -1
- package/dist/skills/registry.d.ts.map +0 -1
- package/dist/skills/signing/signer.d.ts.map +0 -1
- package/dist/skills/trust.d.ts.map +0 -1
- package/dist/telemetry/logger.d.ts.map +0 -1
- package/dist/tools/permissions.d.ts.map +0 -1
- package/dist/tools/protocol.d.ts.map +0 -1
- package/dist/tools/registry.d.ts.map +0 -1
- package/dist/tools/sandbox/docker.d.ts.map +0 -1
- package/dist/tools/sandbox/index.d.ts.map +0 -1
- package/dist/tools/tools/ask-user.d.ts.map +0 -1
- package/dist/tools/tools/bash.d.ts.map +0 -1
- package/dist/tools/tools/edit.d.ts.map +0 -1
- package/dist/tools/tools/glob.d.ts.map +0 -1
- package/dist/tools/tools/grep.d.ts.map +0 -1
- package/dist/tools/tools/read.d.ts.map +0 -1
- package/dist/tools/tools/web-fetch.d.ts.map +0 -1
- package/dist/tools/tools/write.d.ts.map +0 -1
- package/dist/tools/validation.d.ts.map +0 -1
- package/dist/utils/markdown.d.ts.map +0 -1
- package/dist/utils/streaming.d.ts.map +0 -1
- package/dist/utils/tokens.d.ts.map +0 -1
- package/src/agent/conversation.ts +0 -140
- package/src/agent/loop.ts +0 -215
- package/src/agent/planner.ts +0 -55
- package/src/auth/client.ts +0 -19
- package/src/auth/config.ts +0 -89
- package/src/commands/chat.ts +0 -28
- package/src/commands/config.ts +0 -36
- package/src/commands/login.ts +0 -63
- package/src/commands/marketplace.ts +0 -190
- package/src/commands/models.ts +0 -74
- package/src/compact/history-store.ts +0 -101
- package/src/compact/microcompact.ts +0 -49
- package/src/compact/service.ts +0 -154
- package/src/context/analyzer.ts +0 -127
- package/src/context/builder.ts +0 -123
- package/src/context/cache.ts +0 -11
- package/src/context/git-context.ts +0 -58
- package/src/context/llmtune-md.ts +0 -48
- package/src/context/workspace.ts +0 -139
- package/src/index.ts +0 -100
- package/src/marketplace/client.ts +0 -118
- package/src/memory/files.ts +0 -81
- package/src/memory/service.ts +0 -124
- package/src/repl/repl.ts +0 -400
- package/src/skills/args.ts +0 -35
- package/src/skills/builtin/explain-code/SKILL.md +0 -30
- package/src/skills/frontmatter.ts +0 -47
- package/src/skills/loader.ts +0 -25
- package/src/skills/registry.ts +0 -155
- package/src/skills/signing/signer.ts +0 -101
- package/src/skills/trust.ts +0 -50
- package/src/telemetry/logger.ts +0 -108
- package/src/tools/permissions.ts +0 -83
- package/src/tools/protocol.ts +0 -24
- package/src/tools/registry.ts +0 -93
- package/src/tools/sandbox/docker.ts +0 -225
- package/src/tools/sandbox/index.ts +0 -91
- package/src/tools/tools/ask-user.ts +0 -60
- package/src/tools/tools/bash.ts +0 -97
- package/src/tools/tools/edit.ts +0 -111
- package/src/tools/tools/glob.ts +0 -68
- package/src/tools/tools/grep.ts +0 -121
- package/src/tools/tools/read.ts +0 -57
- package/src/tools/tools/web-fetch.ts +0 -158
- package/src/tools/tools/write.ts +0 -52
- package/src/tools/validation.ts +0 -164
- package/src/utils/markdown.ts +0 -96
- package/src/utils/streaming.ts +0 -63
- package/src/utils/tokens.ts +0 -41
- package/tsconfig.json +0 -20
|
@@ -0,0 +1,162 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.SkillRegistry = void 0;
|
|
37
|
+
const fs = __importStar(require("fs"));
|
|
38
|
+
const path = __importStar(require("path"));
|
|
39
|
+
const os = __importStar(require("os"));
|
|
40
|
+
const frontmatter_1 = require("./frontmatter");
|
|
41
|
+
const args_1 = require("./args");
|
|
42
|
+
const SKILL_DIRS = () => {
|
|
43
|
+
const dirs = [];
|
|
44
|
+
const primary = path.join(os.homedir(), ".llmtune", "skills");
|
|
45
|
+
dirs.push(primary);
|
|
46
|
+
return dirs;
|
|
47
|
+
};
|
|
48
|
+
class SkillRegistry {
|
|
49
|
+
skills = new Map();
|
|
50
|
+
loadAll(projectRoot) {
|
|
51
|
+
this.skills.clear();
|
|
52
|
+
for (const dir of SKILL_DIRS()) {
|
|
53
|
+
this.loadFromDir(dir, "user");
|
|
54
|
+
}
|
|
55
|
+
const managedEnv = process.env.LLMTUNE_MANAGED_SKILLS_DIR;
|
|
56
|
+
if (managedEnv) {
|
|
57
|
+
this.loadFromDir(managedEnv, "managed");
|
|
58
|
+
}
|
|
59
|
+
if (projectRoot) {
|
|
60
|
+
const projectDir = path.join(projectRoot, ".llmtune", "skills");
|
|
61
|
+
this.loadFromDir(projectDir, "project");
|
|
62
|
+
const compatDir = path.join(projectRoot, ".claude", "skills");
|
|
63
|
+
this.loadFromDir(compatDir, "project");
|
|
64
|
+
}
|
|
65
|
+
}
|
|
66
|
+
loadFromDir(baseDir, loadedFrom) {
|
|
67
|
+
const resolved = path.resolve(baseDir);
|
|
68
|
+
if (!fs.existsSync(resolved) || !fs.statSync(resolved).isDirectory())
|
|
69
|
+
return;
|
|
70
|
+
for (const entry of fs.readdirSync(resolved).sort()) {
|
|
71
|
+
const skillPath = path.join(resolved, entry);
|
|
72
|
+
if (!fs.statSync(skillPath).isDirectory())
|
|
73
|
+
continue;
|
|
74
|
+
const mdPath = path.join(skillPath, "SKILL.md");
|
|
75
|
+
if (!fs.existsSync(mdPath))
|
|
76
|
+
continue;
|
|
77
|
+
const raw = fs.readFileSync(mdPath, "utf-8");
|
|
78
|
+
const { frontmatter, body } = (0, frontmatter_1.parseFrontmatter)(raw);
|
|
79
|
+
const description = String(frontmatter.description ?? extractFirstLine(body) ?? `Skill: ${entry}`);
|
|
80
|
+
const userInvocable = frontmatter["user-invocable"] !== false;
|
|
81
|
+
const allowedTools = asStrList(frontmatter["allowed-tools"]);
|
|
82
|
+
const argNames = parseArgNames(frontmatter.arguments);
|
|
83
|
+
const trustLevel = resolveTrustLevel(frontmatter.trust, loadedFrom);
|
|
84
|
+
const skill = {
|
|
85
|
+
name: entry,
|
|
86
|
+
description,
|
|
87
|
+
content: body,
|
|
88
|
+
loadedFrom,
|
|
89
|
+
userInvocable,
|
|
90
|
+
allowedTools,
|
|
91
|
+
argNames,
|
|
92
|
+
trustLevel,
|
|
93
|
+
skillRoot: skillPath,
|
|
94
|
+
};
|
|
95
|
+
if (!this.skills.has(entry.toLowerCase())) {
|
|
96
|
+
this.skills.set(entry.toLowerCase(), skill);
|
|
97
|
+
}
|
|
98
|
+
}
|
|
99
|
+
}
|
|
100
|
+
get(name) {
|
|
101
|
+
return this.skills.get(name.toLowerCase());
|
|
102
|
+
}
|
|
103
|
+
list() {
|
|
104
|
+
return Array.from(this.skills.values());
|
|
105
|
+
}
|
|
106
|
+
listUserInvocable() {
|
|
107
|
+
return this.list().filter((s) => s.userInvocable);
|
|
108
|
+
}
|
|
109
|
+
prepareExecution(name, args) {
|
|
110
|
+
const skill = this.get(name);
|
|
111
|
+
if (!skill)
|
|
112
|
+
return null;
|
|
113
|
+
const argMap = {};
|
|
114
|
+
for (let i = 0; i < Math.min(args.length, skill.argNames.length); i++) {
|
|
115
|
+
argMap[skill.argNames[i]] = args[i];
|
|
116
|
+
}
|
|
117
|
+
const userMessage = (0, args_1.substituteArguments)(skill.content, argMap);
|
|
118
|
+
return {
|
|
119
|
+
systemPrompt: `You are executing the "${skill.name}" skill. ${skill.description}`,
|
|
120
|
+
userMessage,
|
|
121
|
+
allowedTools: skill.allowedTools.length > 0 ? skill.allowedTools : undefined,
|
|
122
|
+
};
|
|
123
|
+
}
|
|
124
|
+
}
|
|
125
|
+
exports.SkillRegistry = SkillRegistry;
|
|
126
|
+
function resolveTrustLevel(raw, loadedFrom) {
|
|
127
|
+
const str = String(raw ?? "").toLowerCase().trim();
|
|
128
|
+
if (str === "signed")
|
|
129
|
+
return "signed";
|
|
130
|
+
if (str === "verified")
|
|
131
|
+
return "verified";
|
|
132
|
+
if (str === "community")
|
|
133
|
+
return "community";
|
|
134
|
+
if (loadedFrom === "user" || loadedFrom === "project")
|
|
135
|
+
return "local";
|
|
136
|
+
return "community";
|
|
137
|
+
}
|
|
138
|
+
function extractFirstLine(body) {
|
|
139
|
+
for (const line of body.split("\n")) {
|
|
140
|
+
const stripped = line.trim();
|
|
141
|
+
if (!stripped || stripped.startsWith("#"))
|
|
142
|
+
continue;
|
|
143
|
+
return stripped.slice(0, 200);
|
|
144
|
+
}
|
|
145
|
+
return null;
|
|
146
|
+
}
|
|
147
|
+
function parseArgNames(raw) {
|
|
148
|
+
return asStrList(raw);
|
|
149
|
+
}
|
|
150
|
+
function asStrList(val) {
|
|
151
|
+
if (val == null)
|
|
152
|
+
return [];
|
|
153
|
+
if (Array.isArray(val))
|
|
154
|
+
return val.map(String).filter(Boolean);
|
|
155
|
+
const s = String(val).trim();
|
|
156
|
+
if (!s)
|
|
157
|
+
return [];
|
|
158
|
+
if (s.includes(","))
|
|
159
|
+
return s.split(",").map((x) => x.trim()).filter(Boolean);
|
|
160
|
+
return [s];
|
|
161
|
+
}
|
|
162
|
+
//# sourceMappingURL=registry.js.map
|
|
@@ -0,0 +1,19 @@
|
|
|
1
|
+
export interface SkillSignature {
|
|
2
|
+
algorithm: string;
|
|
3
|
+
signature: string;
|
|
4
|
+
publicKey: string;
|
|
5
|
+
signedAt: string;
|
|
6
|
+
skillName: string;
|
|
7
|
+
contentHash: string;
|
|
8
|
+
}
|
|
9
|
+
export declare function hashSkillContent(skillDir: string): string;
|
|
10
|
+
export declare function signSkill(skillDir: string, privateKey: string, publicKey: string): SkillSignature;
|
|
11
|
+
export declare function verifySkill(skillDir: string, expectedPublicKey?: string): {
|
|
12
|
+
valid: boolean;
|
|
13
|
+
reason?: string;
|
|
14
|
+
};
|
|
15
|
+
export declare function generateKeyPair(): {
|
|
16
|
+
publicKey: string;
|
|
17
|
+
privateKey: string;
|
|
18
|
+
};
|
|
19
|
+
//# sourceMappingURL=signer.d.ts.map
|
|
@@ -0,0 +1,110 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.hashSkillContent = hashSkillContent;
|
|
37
|
+
exports.signSkill = signSkill;
|
|
38
|
+
exports.verifySkill = verifySkill;
|
|
39
|
+
exports.generateKeyPair = generateKeyPair;
|
|
40
|
+
const fs = __importStar(require("fs"));
|
|
41
|
+
const path = __importStar(require("path"));
|
|
42
|
+
const crypto = __importStar(require("crypto"));
|
|
43
|
+
const SIGNATURE_FILE = "SIGNATURE.json";
|
|
44
|
+
function hashSkillContent(skillDir) {
|
|
45
|
+
const mdPath = path.join(skillDir, "SKILL.md");
|
|
46
|
+
if (!fs.existsSync(mdPath)) {
|
|
47
|
+
throw new Error(`No SKILL.md found in ${skillDir}`);
|
|
48
|
+
}
|
|
49
|
+
const content = fs.readFileSync(mdPath, "utf-8");
|
|
50
|
+
return crypto.createHash("sha256").update(content).digest("hex");
|
|
51
|
+
}
|
|
52
|
+
function signSkill(skillDir, privateKey, publicKey) {
|
|
53
|
+
const contentHash = hashSkillContent(skillDir);
|
|
54
|
+
const skillName = path.basename(skillDir);
|
|
55
|
+
const signature = crypto
|
|
56
|
+
.createSign("sha256")
|
|
57
|
+
.update(contentHash)
|
|
58
|
+
.sign(privateKey, "base64");
|
|
59
|
+
const sig = {
|
|
60
|
+
algorithm: "sha256-rsa",
|
|
61
|
+
signature,
|
|
62
|
+
publicKey,
|
|
63
|
+
signedAt: new Date().toISOString(),
|
|
64
|
+
skillName,
|
|
65
|
+
contentHash,
|
|
66
|
+
};
|
|
67
|
+
const sigPath = path.join(skillDir, SIGNATURE_FILE);
|
|
68
|
+
fs.writeFileSync(sigPath, JSON.stringify(sig, null, 2), "utf-8");
|
|
69
|
+
return sig;
|
|
70
|
+
}
|
|
71
|
+
function verifySkill(skillDir, expectedPublicKey) {
|
|
72
|
+
const sigPath = path.join(skillDir, SIGNATURE_FILE);
|
|
73
|
+
const mdPath = path.join(skillDir, "SKILL.md");
|
|
74
|
+
if (!fs.existsSync(sigPath)) {
|
|
75
|
+
return { valid: false, reason: "No signature file found" };
|
|
76
|
+
}
|
|
77
|
+
if (!fs.existsSync(mdPath)) {
|
|
78
|
+
return { valid: false, reason: "No SKILL.md found" };
|
|
79
|
+
}
|
|
80
|
+
try {
|
|
81
|
+
const sig = JSON.parse(fs.readFileSync(sigPath, "utf-8"));
|
|
82
|
+
const content = fs.readFileSync(mdPath, "utf-8");
|
|
83
|
+
const contentHash = crypto.createHash("sha256").update(content).digest("hex");
|
|
84
|
+
if (contentHash !== sig.contentHash) {
|
|
85
|
+
return { valid: false, reason: "Content hash mismatch - skill has been modified" };
|
|
86
|
+
}
|
|
87
|
+
if (expectedPublicKey && sig.publicKey !== expectedPublicKey) {
|
|
88
|
+
return { valid: false, reason: "Public key mismatch - signed by different author" };
|
|
89
|
+
}
|
|
90
|
+
const verifier = crypto.createVerify("sha256");
|
|
91
|
+
verifier.update(sig.contentHash);
|
|
92
|
+
const isValid = verifier.verify(sig.publicKey, sig.signature, "base64");
|
|
93
|
+
if (!isValid) {
|
|
94
|
+
return { valid: false, reason: "Signature verification failed" };
|
|
95
|
+
}
|
|
96
|
+
return { valid: true };
|
|
97
|
+
}
|
|
98
|
+
catch (err) {
|
|
99
|
+
return { valid: false, reason: `Verification error: ${err.message}` };
|
|
100
|
+
}
|
|
101
|
+
}
|
|
102
|
+
function generateKeyPair() {
|
|
103
|
+
const { publicKey, privateKey } = crypto.generateKeyPairSync("rsa", {
|
|
104
|
+
modulusLength: 2048,
|
|
105
|
+
publicKeyEncoding: { type: "spki", format: "pem" },
|
|
106
|
+
privateKeyEncoding: { type: "pkcs8", format: "pem" },
|
|
107
|
+
});
|
|
108
|
+
return { publicKey, privateKey };
|
|
109
|
+
}
|
|
110
|
+
//# sourceMappingURL=signer.js.map
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { Skill } from "./registry";
|
|
2
|
+
export type TrustLevel = "local" | "community" | "verified" | "signed";
|
|
3
|
+
export interface TrustPolicy {
|
|
4
|
+
allowedTools: string[];
|
|
5
|
+
canExecuteBash: boolean;
|
|
6
|
+
canWriteFiles: boolean;
|
|
7
|
+
}
|
|
8
|
+
export declare function getTrustPolicy(level: TrustLevel): TrustPolicy;
|
|
9
|
+
export declare function resolveTrustLevel(skill: Skill): TrustLevel;
|
|
10
|
+
export declare function isToolAllowedForSkill(toolName: string, trustLevel: TrustLevel): boolean;
|
|
11
|
+
//# sourceMappingURL=trust.d.ts.map
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.getTrustPolicy = getTrustPolicy;
|
|
4
|
+
exports.resolveTrustLevel = resolveTrustLevel;
|
|
5
|
+
exports.isToolAllowedForSkill = isToolAllowedForSkill;
|
|
6
|
+
const POLICIES = {
|
|
7
|
+
local: {
|
|
8
|
+
allowedTools: ["read", "write", "edit", "bash", "glob", "grep"],
|
|
9
|
+
canExecuteBash: true,
|
|
10
|
+
canWriteFiles: true,
|
|
11
|
+
},
|
|
12
|
+
community: {
|
|
13
|
+
allowedTools: ["read", "glob", "grep"],
|
|
14
|
+
canExecuteBash: false,
|
|
15
|
+
canWriteFiles: false,
|
|
16
|
+
},
|
|
17
|
+
verified: {
|
|
18
|
+
allowedTools: ["read", "write", "edit", "bash", "glob", "grep"],
|
|
19
|
+
canExecuteBash: true,
|
|
20
|
+
canWriteFiles: true,
|
|
21
|
+
},
|
|
22
|
+
signed: {
|
|
23
|
+
allowedTools: ["read", "write", "edit", "bash", "glob", "grep"],
|
|
24
|
+
canExecuteBash: true,
|
|
25
|
+
canWriteFiles: true,
|
|
26
|
+
},
|
|
27
|
+
};
|
|
28
|
+
function getTrustPolicy(level) {
|
|
29
|
+
return POLICIES[level];
|
|
30
|
+
}
|
|
31
|
+
function resolveTrustLevel(skill) {
|
|
32
|
+
if (skill.loadedFrom === "project" || skill.loadedFrom === "user")
|
|
33
|
+
return "local";
|
|
34
|
+
if (skill.trustLevel)
|
|
35
|
+
return skill.trustLevel;
|
|
36
|
+
return "community";
|
|
37
|
+
}
|
|
38
|
+
function isToolAllowedForSkill(toolName, trustLevel) {
|
|
39
|
+
const policy = POLICIES[trustLevel];
|
|
40
|
+
return policy.allowedTools.includes(toolName.toLowerCase());
|
|
41
|
+
}
|
|
42
|
+
//# sourceMappingURL=trust.js.map
|
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
export type TelemetryEvent = {
|
|
2
|
+
event: "tool_call";
|
|
3
|
+
tool: string;
|
|
4
|
+
latency_ms: number;
|
|
5
|
+
input_preview?: string;
|
|
6
|
+
} | {
|
|
7
|
+
event: "llm_response";
|
|
8
|
+
tokens_in: number;
|
|
9
|
+
tokens_out: number;
|
|
10
|
+
cost: number;
|
|
11
|
+
model: string;
|
|
12
|
+
latency_ms: number;
|
|
13
|
+
} | {
|
|
14
|
+
event: "compaction";
|
|
15
|
+
tokens_saved: number;
|
|
16
|
+
messages_before: number;
|
|
17
|
+
messages_after: number;
|
|
18
|
+
trigger: string;
|
|
19
|
+
} | {
|
|
20
|
+
event: "error";
|
|
21
|
+
source: string;
|
|
22
|
+
error: string;
|
|
23
|
+
tool?: string;
|
|
24
|
+
} | {
|
|
25
|
+
event: "session_start";
|
|
26
|
+
model: string;
|
|
27
|
+
tools: string[];
|
|
28
|
+
cwd: string;
|
|
29
|
+
} | {
|
|
30
|
+
event: "session_end";
|
|
31
|
+
duration_ms: number;
|
|
32
|
+
total_tool_calls: number;
|
|
33
|
+
total_tokens: number;
|
|
34
|
+
};
|
|
35
|
+
export declare function startSessionLog(sessionId: string, meta: {
|
|
36
|
+
model: string;
|
|
37
|
+
tools: string[];
|
|
38
|
+
cwd: string;
|
|
39
|
+
}): void;
|
|
40
|
+
export declare function logEvent(event: TelemetryEvent): void;
|
|
41
|
+
export declare function endSessionLog(stats: {
|
|
42
|
+
totalToolCalls: number;
|
|
43
|
+
totalTokens: number;
|
|
44
|
+
}): void;
|
|
45
|
+
export declare function getSessionLogs(sessionId: string): TelemetryEvent[];
|
|
46
|
+
export declare function listSessionLogs(): Array<{
|
|
47
|
+
sessionId: string;
|
|
48
|
+
size: number;
|
|
49
|
+
modified: string;
|
|
50
|
+
}>;
|
|
51
|
+
//# sourceMappingURL=logger.d.ts.map
|
|
@@ -0,0 +1,135 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __createBinding = (this && this.__createBinding) || (Object.create ? (function(o, m, k, k2) {
|
|
3
|
+
if (k2 === undefined) k2 = k;
|
|
4
|
+
var desc = Object.getOwnPropertyDescriptor(m, k);
|
|
5
|
+
if (!desc || ("get" in desc ? !m.__esModule : desc.writable || desc.configurable)) {
|
|
6
|
+
desc = { enumerable: true, get: function() { return m[k]; } };
|
|
7
|
+
}
|
|
8
|
+
Object.defineProperty(o, k2, desc);
|
|
9
|
+
}) : (function(o, m, k, k2) {
|
|
10
|
+
if (k2 === undefined) k2 = k;
|
|
11
|
+
o[k2] = m[k];
|
|
12
|
+
}));
|
|
13
|
+
var __setModuleDefault = (this && this.__setModuleDefault) || (Object.create ? (function(o, v) {
|
|
14
|
+
Object.defineProperty(o, "default", { enumerable: true, value: v });
|
|
15
|
+
}) : function(o, v) {
|
|
16
|
+
o["default"] = v;
|
|
17
|
+
});
|
|
18
|
+
var __importStar = (this && this.__importStar) || (function () {
|
|
19
|
+
var ownKeys = function(o) {
|
|
20
|
+
ownKeys = Object.getOwnPropertyNames || function (o) {
|
|
21
|
+
var ar = [];
|
|
22
|
+
for (var k in o) if (Object.prototype.hasOwnProperty.call(o, k)) ar[ar.length] = k;
|
|
23
|
+
return ar;
|
|
24
|
+
};
|
|
25
|
+
return ownKeys(o);
|
|
26
|
+
};
|
|
27
|
+
return function (mod) {
|
|
28
|
+
if (mod && mod.__esModule) return mod;
|
|
29
|
+
var result = {};
|
|
30
|
+
if (mod != null) for (var k = ownKeys(mod), i = 0; i < k.length; i++) if (k[i] !== "default") __createBinding(result, mod, k[i]);
|
|
31
|
+
__setModuleDefault(result, mod);
|
|
32
|
+
return result;
|
|
33
|
+
};
|
|
34
|
+
})();
|
|
35
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
36
|
+
exports.startSessionLog = startSessionLog;
|
|
37
|
+
exports.logEvent = logEvent;
|
|
38
|
+
exports.endSessionLog = endSessionLog;
|
|
39
|
+
exports.getSessionLogs = getSessionLogs;
|
|
40
|
+
exports.listSessionLogs = listSessionLogs;
|
|
41
|
+
const fs = __importStar(require("fs"));
|
|
42
|
+
const path = __importStar(require("path"));
|
|
43
|
+
const config_1 = require("../auth/config");
|
|
44
|
+
let currentSession = null;
|
|
45
|
+
let sessionStartTime = 0;
|
|
46
|
+
function getLogsDir() {
|
|
47
|
+
const base = process.env.LLMTUNE_LOGS_DIR || path.join((0, config_1.getConfigDir)(), "logs");
|
|
48
|
+
if (!fs.existsSync(base)) {
|
|
49
|
+
fs.mkdirSync(base, { recursive: true });
|
|
50
|
+
}
|
|
51
|
+
return base;
|
|
52
|
+
}
|
|
53
|
+
function getSessionLogPath(sessionId) {
|
|
54
|
+
return path.join(getLogsDir(), `${sessionId}.jsonl`);
|
|
55
|
+
}
|
|
56
|
+
function startSessionLog(sessionId, meta) {
|
|
57
|
+
currentSession = {
|
|
58
|
+
sessionId,
|
|
59
|
+
startedAt: new Date().toISOString(),
|
|
60
|
+
events: [],
|
|
61
|
+
};
|
|
62
|
+
sessionStartTime = Date.now();
|
|
63
|
+
logEvent({ event: "session_start", model: meta.model, tools: meta.tools, cwd: meta.cwd });
|
|
64
|
+
}
|
|
65
|
+
function logEvent(event) {
|
|
66
|
+
if (!currentSession)
|
|
67
|
+
return;
|
|
68
|
+
currentSession.events.push(event);
|
|
69
|
+
const entry = {
|
|
70
|
+
ts: new Date().toISOString(),
|
|
71
|
+
session_id: currentSession.sessionId,
|
|
72
|
+
...event,
|
|
73
|
+
};
|
|
74
|
+
try {
|
|
75
|
+
const logPath = getSessionLogPath(currentSession.sessionId);
|
|
76
|
+
fs.appendFileSync(logPath, JSON.stringify(entry) + "\n", "utf-8");
|
|
77
|
+
}
|
|
78
|
+
catch {
|
|
79
|
+
// Telemetry write failure is non-critical
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
function endSessionLog(stats) {
|
|
83
|
+
if (!currentSession)
|
|
84
|
+
return;
|
|
85
|
+
const durationMs = Date.now() - sessionStartTime;
|
|
86
|
+
logEvent({
|
|
87
|
+
event: "session_end",
|
|
88
|
+
duration_ms: durationMs,
|
|
89
|
+
total_tool_calls: stats.totalToolCalls,
|
|
90
|
+
total_tokens: stats.totalTokens,
|
|
91
|
+
});
|
|
92
|
+
currentSession = null;
|
|
93
|
+
}
|
|
94
|
+
function getSessionLogs(sessionId) {
|
|
95
|
+
const logPath = getSessionLogPath(sessionId);
|
|
96
|
+
try {
|
|
97
|
+
if (!fs.existsSync(logPath))
|
|
98
|
+
return [];
|
|
99
|
+
const lines = fs.readFileSync(logPath, "utf-8").split("\n").filter(Boolean);
|
|
100
|
+
return lines.map((line) => {
|
|
101
|
+
try {
|
|
102
|
+
return JSON.parse(line);
|
|
103
|
+
}
|
|
104
|
+
catch {
|
|
105
|
+
return null;
|
|
106
|
+
}
|
|
107
|
+
}).filter((e) => e !== null);
|
|
108
|
+
}
|
|
109
|
+
catch {
|
|
110
|
+
return [];
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
function listSessionLogs() {
|
|
114
|
+
const dir = getLogsDir();
|
|
115
|
+
try {
|
|
116
|
+
if (!fs.existsSync(dir))
|
|
117
|
+
return [];
|
|
118
|
+
return fs.readdirSync(dir)
|
|
119
|
+
.filter((f) => f.endsWith(".jsonl"))
|
|
120
|
+
.map((f) => {
|
|
121
|
+
const fullPath = path.join(dir, f);
|
|
122
|
+
const stat = fs.statSync(fullPath);
|
|
123
|
+
return {
|
|
124
|
+
sessionId: f.replace(".jsonl", ""),
|
|
125
|
+
size: stat.size,
|
|
126
|
+
modified: stat.mtime.toISOString(),
|
|
127
|
+
};
|
|
128
|
+
})
|
|
129
|
+
.sort((a, b) => b.modified.localeCompare(a.modified));
|
|
130
|
+
}
|
|
131
|
+
catch {
|
|
132
|
+
return [];
|
|
133
|
+
}
|
|
134
|
+
}
|
|
135
|
+
//# sourceMappingURL=logger.js.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
export type PermissionBehavior = "allow" | "deny" | "ask";
|
|
2
|
+
export interface PermissionCheckResult {
|
|
3
|
+
behavior: PermissionBehavior;
|
|
4
|
+
message?: string;
|
|
5
|
+
suggestion?: string;
|
|
6
|
+
updatedInput?: Record<string, unknown>;
|
|
7
|
+
}
|
|
8
|
+
export interface PermissionConfig {
|
|
9
|
+
allowedTools: Set<string>;
|
|
10
|
+
deniedTools: Set<string>;
|
|
11
|
+
sessionTrust: Map<string, boolean>;
|
|
12
|
+
}
|
|
13
|
+
export declare class PermissionManager {
|
|
14
|
+
private config;
|
|
15
|
+
constructor();
|
|
16
|
+
trustTool(toolName: string): void;
|
|
17
|
+
isTrusted(toolName: string): boolean;
|
|
18
|
+
check(toolName: string, input: Record<string, unknown>, isDestructive: boolean): Promise<PermissionCheckResult>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=permissions.d.ts.map
|
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
var __importDefault = (this && this.__importDefault) || function (mod) {
|
|
3
|
+
return (mod && mod.__esModule) ? mod : { "default": mod };
|
|
4
|
+
};
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.PermissionManager = void 0;
|
|
7
|
+
const prompts_1 = __importDefault(require("@inquirer/prompts"));
|
|
8
|
+
const chalk_1 = __importDefault(require("chalk"));
|
|
9
|
+
class PermissionManager {
|
|
10
|
+
config;
|
|
11
|
+
constructor() {
|
|
12
|
+
this.config = {
|
|
13
|
+
allowedTools: new Set(),
|
|
14
|
+
deniedTools: new Set(),
|
|
15
|
+
sessionTrust: new Map(),
|
|
16
|
+
};
|
|
17
|
+
}
|
|
18
|
+
trustTool(toolName) {
|
|
19
|
+
this.config.sessionTrust.set(toolName, true);
|
|
20
|
+
}
|
|
21
|
+
isTrusted(toolName) {
|
|
22
|
+
return this.config.sessionTrust.get(toolName) === true;
|
|
23
|
+
}
|
|
24
|
+
async check(toolName, input, isDestructive) {
|
|
25
|
+
if (this.isTrusted(toolName)) {
|
|
26
|
+
return { behavior: "allow" };
|
|
27
|
+
}
|
|
28
|
+
if (this.config.deniedTools.has(toolName)) {
|
|
29
|
+
return { behavior: "deny", message: `Tool '${toolName}' is denied` };
|
|
30
|
+
}
|
|
31
|
+
if (isDestructive) {
|
|
32
|
+
const command = toolName === "bash" ? input.command : "";
|
|
33
|
+
const preview = command
|
|
34
|
+
? command.slice(0, 80) + (command.length > 80 ? "..." : "")
|
|
35
|
+
: JSON.stringify(input).slice(0, 100);
|
|
36
|
+
console.log(chalk_1.default.yellow(`\n⚠ ${toolName} wants to execute:`));
|
|
37
|
+
console.log(chalk_1.default.dim(preview));
|
|
38
|
+
const confirmed = await prompts_1.default.confirm({
|
|
39
|
+
message: `Allow ${toolName}? (y/N)`,
|
|
40
|
+
default: false,
|
|
41
|
+
});
|
|
42
|
+
if (!confirmed) {
|
|
43
|
+
return { behavior: "deny", message: "User denied" };
|
|
44
|
+
}
|
|
45
|
+
const alwaysTrust = await prompts_1.default.confirm({
|
|
46
|
+
message: `Trust ${toolName} for this session? (y/N)`,
|
|
47
|
+
default: false,
|
|
48
|
+
});
|
|
49
|
+
if (alwaysTrust) {
|
|
50
|
+
this.trustTool(toolName);
|
|
51
|
+
}
|
|
52
|
+
return { behavior: "allow" };
|
|
53
|
+
}
|
|
54
|
+
return { behavior: "allow" };
|
|
55
|
+
}
|
|
56
|
+
}
|
|
57
|
+
exports.PermissionManager = PermissionManager;
|
|
58
|
+
//# sourceMappingURL=permissions.js.map
|
|
@@ -0,0 +1,22 @@
|
|
|
1
|
+
export interface ToolSpec {
|
|
2
|
+
name: string;
|
|
3
|
+
description: string;
|
|
4
|
+
inputSchema: Record<string, unknown>;
|
|
5
|
+
isReadOnly?: boolean;
|
|
6
|
+
isDestructive?: boolean;
|
|
7
|
+
}
|
|
8
|
+
export interface ToolResult {
|
|
9
|
+
name: string;
|
|
10
|
+
output: unknown;
|
|
11
|
+
isError: boolean;
|
|
12
|
+
toolUseId?: string;
|
|
13
|
+
}
|
|
14
|
+
export interface ToolContext {
|
|
15
|
+
cwd: string;
|
|
16
|
+
workspaceRoot: string;
|
|
17
|
+
}
|
|
18
|
+
export interface Tool {
|
|
19
|
+
spec(): ToolSpec;
|
|
20
|
+
run(input: Record<string, unknown>, ctx: ToolContext): ToolResult | Promise<ToolResult>;
|
|
21
|
+
}
|
|
22
|
+
//# sourceMappingURL=protocol.d.ts.map
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
import type { Tool, ToolSpec, ToolResult, ToolContext } from "./protocol";
|
|
2
|
+
export type { Tool, ToolSpec, ToolResult, ToolContext };
|
|
3
|
+
export interface ToolDefinition {
|
|
4
|
+
name: string;
|
|
5
|
+
description: string;
|
|
6
|
+
inputSchema: Record<string, unknown>;
|
|
7
|
+
isReadOnly?: boolean;
|
|
8
|
+
isDestructive?: boolean;
|
|
9
|
+
run: (input: Record<string, unknown>, ctx: ToolContext) => ToolResult | Promise<ToolResult>;
|
|
10
|
+
}
|
|
11
|
+
export declare function createTool(def: ToolDefinition): Tool;
|
|
12
|
+
export declare class ToolRegistry {
|
|
13
|
+
private tools;
|
|
14
|
+
register(tool: Tool): void;
|
|
15
|
+
listSpecs(): ToolSpec[];
|
|
16
|
+
get(name: string): Tool | undefined;
|
|
17
|
+
dispatch(name: string, input: Record<string, unknown>, ctx: ToolContext): ToolResult;
|
|
18
|
+
dispatchAsync(name: string, input: Record<string, unknown>, ctx: ToolContext): Promise<ToolResult>;
|
|
19
|
+
}
|
|
20
|
+
//# sourceMappingURL=registry.d.ts.map
|