gemkit-cli 0.2.3 → 0.3.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 +141 -7
- package/dist/commands/agent/index.d.ts +9 -0
- package/dist/commands/agent/index.js +1329 -0
- package/dist/commands/cache/index.d.ts +5 -0
- package/dist/commands/cache/index.js +43 -0
- package/dist/commands/catalog/index.d.ts +2 -0
- package/dist/commands/catalog/index.js +57 -0
- package/dist/commands/config/index.d.ts +7 -0
- package/dist/commands/config/index.js +122 -0
- package/dist/commands/convert/index.d.ts +8 -0
- package/dist/commands/convert/index.js +391 -0
- package/dist/commands/doctor/index.d.ts +2 -0
- package/dist/commands/doctor/index.js +243 -0
- package/dist/commands/extension/index.d.ts +5 -0
- package/dist/commands/extension/index.js +52 -0
- package/dist/commands/index.d.ts +5 -0
- package/dist/commands/index.js +37 -0
- package/dist/commands/init/index.d.ts +6 -0
- package/dist/commands/init/index.js +345 -0
- package/dist/commands/new/index.d.ts +5 -0
- package/dist/commands/new/index.js +49 -0
- package/dist/commands/office/index.d.ts +5 -0
- package/dist/commands/office/index.js +283 -0
- package/dist/commands/paste/index.d.ts +10 -0
- package/dist/commands/paste/index.js +533 -0
- package/dist/commands/plan/index.d.ts +8 -0
- package/dist/commands/plan/index.js +247 -0
- package/dist/commands/session/index.d.ts +8 -0
- package/dist/commands/session/index.js +289 -0
- package/dist/commands/tokens/index.d.ts +6 -0
- package/dist/commands/tokens/index.js +148 -0
- package/dist/commands/update/index.d.ts +26 -0
- package/dist/commands/update/index.js +199 -0
- package/dist/commands/versions/index.d.ts +5 -0
- package/dist/commands/versions/index.js +39 -0
- package/dist/domains/agent/index.d.ts +8 -0
- package/dist/domains/agent/index.js +8 -0
- package/dist/domains/agent/mappings.d.ts +32 -0
- package/dist/domains/agent/mappings.js +164 -0
- package/dist/domains/agent/profile.d.ts +26 -0
- package/dist/domains/agent/profile.js +225 -0
- package/dist/domains/agent/pty-context.d.ts +11 -0
- package/dist/domains/agent/pty-context.js +83 -0
- package/dist/domains/agent/pty-providers.d.ts +18 -0
- package/dist/domains/agent/pty-providers.js +66 -0
- package/dist/domains/agent/pty-session.d.ts +33 -0
- package/dist/domains/agent/pty-session.js +82 -0
- package/dist/domains/agent/pty-types.d.ts +127 -0
- package/dist/domains/agent/pty-types.js +4 -0
- package/dist/domains/agent/search.d.ts +45 -0
- package/dist/domains/agent/search.js +614 -0
- package/dist/domains/agent/types.d.ts +78 -0
- package/dist/domains/agent/types.js +5 -0
- package/dist/domains/agent-office/documents-scanner.d.ts +9 -0
- package/dist/domains/agent-office/documents-scanner.js +143 -0
- package/dist/domains/agent-office/event-emitter.d.ts +43 -0
- package/dist/domains/agent-office/event-emitter.js +86 -0
- package/dist/domains/agent-office/file-watcher.d.ts +40 -0
- package/dist/domains/agent-office/file-watcher.js +173 -0
- package/dist/domains/agent-office/icons.d.ts +11 -0
- package/dist/domains/agent-office/icons.js +36 -0
- package/dist/domains/agent-office/index.d.ts +12 -0
- package/dist/domains/agent-office/index.js +20 -0
- package/dist/domains/agent-office/renderer/web/assets.d.ts +11 -0
- package/dist/domains/agent-office/renderer/web/assets.js +3419 -0
- package/dist/domains/agent-office/renderer/web/server.d.ts +42 -0
- package/dist/domains/agent-office/renderer/web/server.js +228 -0
- package/dist/domains/agent-office/renderer/web.d.ts +30 -0
- package/dist/domains/agent-office/renderer/web.js +111 -0
- package/dist/domains/agent-office/session-bridge.d.ts +23 -0
- package/dist/domains/agent-office/session-bridge.js +171 -0
- package/dist/domains/agent-office/state-machine.d.ts +5 -0
- package/dist/domains/agent-office/state-machine.js +82 -0
- package/dist/domains/agent-office/types.d.ts +91 -0
- package/dist/domains/agent-office/types.js +4 -0
- package/dist/domains/cache/index.d.ts +1 -0
- package/dist/domains/cache/index.js +1 -0
- package/dist/domains/cache/manager.d.ts +22 -0
- package/dist/domains/cache/manager.js +84 -0
- package/dist/domains/config/index.d.ts +5 -0
- package/dist/domains/config/index.js +5 -0
- package/dist/domains/config/manager.d.ts +24 -0
- package/dist/domains/config/manager.js +85 -0
- package/dist/domains/config/schema.d.ts +17 -0
- package/dist/domains/config/schema.js +96 -0
- package/dist/domains/convert/converter.d.ts +78 -0
- package/dist/domains/convert/converter.js +471 -0
- package/dist/domains/convert/index.d.ts +5 -0
- package/dist/domains/convert/index.js +5 -0
- package/dist/domains/convert/types.d.ts +88 -0
- package/dist/domains/convert/types.js +18 -0
- package/dist/domains/github/download.d.ts +12 -0
- package/dist/domains/github/download.js +51 -0
- package/dist/domains/github/index.d.ts +2 -0
- package/dist/domains/github/index.js +2 -0
- package/dist/domains/github/releases.d.ts +16 -0
- package/dist/domains/github/releases.js +68 -0
- package/dist/domains/installation/conflict.d.ts +13 -0
- package/dist/domains/installation/conflict.js +38 -0
- package/dist/domains/installation/file-sync.d.ts +16 -0
- package/dist/domains/installation/file-sync.js +77 -0
- package/dist/domains/installation/index.d.ts +3 -0
- package/dist/domains/installation/index.js +3 -0
- package/dist/domains/installation/metadata.d.ts +20 -0
- package/dist/domains/installation/metadata.js +52 -0
- package/dist/domains/plan/index.d.ts +2 -0
- package/dist/domains/plan/index.js +2 -0
- package/dist/domains/plan/resolver.d.ts +24 -0
- package/dist/domains/plan/resolver.js +164 -0
- package/dist/domains/plan/types.d.ts +13 -0
- package/dist/domains/plan/types.js +4 -0
- package/dist/domains/session/env.d.ts +51 -0
- package/dist/domains/session/env.js +118 -0
- package/dist/domains/session/index.d.ts +8 -0
- package/dist/domains/session/index.js +8 -0
- package/dist/domains/session/manager.d.ts +56 -0
- package/dist/domains/session/manager.js +205 -0
- package/dist/domains/session/paths.d.ts +6 -0
- package/dist/domains/session/paths.js +6 -0
- package/dist/domains/session/types.d.ts +121 -0
- package/dist/domains/session/types.js +5 -0
- package/dist/domains/session/writer.d.ts +82 -0
- package/dist/domains/session/writer.js +431 -0
- package/dist/domains/tokens/index.d.ts +5 -0
- package/dist/domains/tokens/index.js +5 -0
- package/dist/domains/tokens/pricing.d.ts +38 -0
- package/dist/domains/tokens/pricing.js +129 -0
- package/dist/domains/tokens/scanner.d.ts +42 -0
- package/dist/domains/tokens/scanner.js +168 -0
- package/dist/index.d.ts +5 -0
- package/dist/index.js +90 -59
- package/dist/services/aipty.d.ts +76 -0
- package/dist/services/aipty.js +276 -0
- package/dist/services/archive.d.ts +22 -0
- package/dist/services/archive.js +53 -0
- package/dist/services/auto-update.d.ts +26 -0
- package/dist/services/auto-update.js +117 -0
- package/dist/services/hash.d.ts +36 -0
- package/dist/services/hash.js +63 -0
- package/dist/services/logger.d.ts +28 -0
- package/dist/services/logger.js +102 -0
- package/dist/services/music.d.ts +67 -0
- package/dist/services/music.js +290 -0
- package/dist/services/npm.d.ts +22 -0
- package/dist/services/npm.js +65 -0
- package/dist/services/pty-client.d.ts +66 -0
- package/dist/services/pty-client.js +154 -0
- package/dist/services/pty-server.d.ts +102 -0
- package/dist/services/pty-server.js +613 -0
- package/dist/types/index.d.ts +155 -0
- package/dist/types/index.js +4 -0
- package/dist/utils/colors.d.ts +43 -0
- package/dist/utils/colors.js +98 -0
- package/dist/utils/errors.d.ts +24 -0
- package/dist/utils/errors.js +56 -0
- package/dist/utils/paths.d.ts +46 -0
- package/dist/utils/paths.js +89 -0
- package/dist/utils/platform.d.ts +11 -0
- package/dist/utils/platform.js +31 -0
- package/package.json +55 -54
|
@@ -0,0 +1,225 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent profile loading
|
|
3
|
+
*/
|
|
4
|
+
import { existsSync, readFileSync, readdirSync } from 'fs';
|
|
5
|
+
import { join, basename } from 'path';
|
|
6
|
+
import { getAgentsDir } from '../../utils/paths.js';
|
|
7
|
+
import { getAgentPaths, mapModel, mapTools } from './mappings.js';
|
|
8
|
+
/**
|
|
9
|
+
* Load a single agent profile by name
|
|
10
|
+
*/
|
|
11
|
+
export function loadAgentProfile(name, projectDir) {
|
|
12
|
+
const agentsDir = getAgentsDir(projectDir);
|
|
13
|
+
const filePath = join(agentsDir, `${name}.md`);
|
|
14
|
+
if (!existsSync(filePath)) {
|
|
15
|
+
return null;
|
|
16
|
+
}
|
|
17
|
+
return parseAgentProfile(filePath);
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* List all available agent profiles
|
|
21
|
+
*/
|
|
22
|
+
export function listAgentProfiles(projectDir) {
|
|
23
|
+
const agentsDir = getAgentsDir(projectDir);
|
|
24
|
+
if (!existsSync(agentsDir)) {
|
|
25
|
+
return [];
|
|
26
|
+
}
|
|
27
|
+
const files = readdirSync(agentsDir).filter(f => f.endsWith('.md'));
|
|
28
|
+
const profiles = [];
|
|
29
|
+
for (const file of files) {
|
|
30
|
+
const filePath = join(agentsDir, file);
|
|
31
|
+
const profile = parseAgentProfile(filePath);
|
|
32
|
+
if (profile) {
|
|
33
|
+
profiles.push(profile);
|
|
34
|
+
}
|
|
35
|
+
}
|
|
36
|
+
return profiles;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Parse YAML frontmatter from markdown
|
|
40
|
+
*/
|
|
41
|
+
function parseFrontmatter(content) {
|
|
42
|
+
const match = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
|
|
43
|
+
if (!match)
|
|
44
|
+
return null;
|
|
45
|
+
const fm = {};
|
|
46
|
+
for (const line of match[1].split(/\r?\n/)) {
|
|
47
|
+
const idx = line.indexOf(':');
|
|
48
|
+
if (idx === -1)
|
|
49
|
+
continue;
|
|
50
|
+
const key = line.slice(0, idx).trim();
|
|
51
|
+
let val = line.slice(idx + 1).trim();
|
|
52
|
+
if ((val.startsWith('"') && val.endsWith('"')) || (val.startsWith("'") && val.endsWith("'"))) {
|
|
53
|
+
val = val.slice(1, -1);
|
|
54
|
+
}
|
|
55
|
+
fm[key] = val;
|
|
56
|
+
}
|
|
57
|
+
return fm;
|
|
58
|
+
}
|
|
59
|
+
/**
|
|
60
|
+
* Parse skills - handles single/multiple/array formats:
|
|
61
|
+
* - "research" -> ["research"]
|
|
62
|
+
* - "skill1, skill2" -> ["skill1", "skill2"]
|
|
63
|
+
* - "[skill1, skill2]" -> ["skill1", "skill2"]
|
|
64
|
+
*/
|
|
65
|
+
function parseSkills(value) {
|
|
66
|
+
if (!value)
|
|
67
|
+
return [];
|
|
68
|
+
let v = value.trim();
|
|
69
|
+
if (v.startsWith('[') && v.endsWith(']'))
|
|
70
|
+
v = v.slice(1, -1);
|
|
71
|
+
return v.split(',').map(s => s.trim().replace(/['"]/g, '')).filter(Boolean);
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Parse tools - handles single/multiple/array formats:
|
|
75
|
+
* - "read_file" -> ["read_file"]
|
|
76
|
+
* - "tool1, tool2" -> ["tool1", "tool2"]
|
|
77
|
+
* - "[tool1, tool2]" -> ["tool1", "tool2"]
|
|
78
|
+
*/
|
|
79
|
+
function parseTools(value) {
|
|
80
|
+
if (!value)
|
|
81
|
+
return [];
|
|
82
|
+
let v = value.trim();
|
|
83
|
+
if (v.startsWith('[') && v.endsWith(']'))
|
|
84
|
+
v = v.slice(1, -1);
|
|
85
|
+
return v.split(',').map(s => s.trim().replace(/['"]/g, '')).filter(Boolean);
|
|
86
|
+
}
|
|
87
|
+
/**
|
|
88
|
+
* Parse agent profile from markdown file
|
|
89
|
+
*/
|
|
90
|
+
function parseAgentProfile(filePath) {
|
|
91
|
+
if (!existsSync(filePath)) {
|
|
92
|
+
return null;
|
|
93
|
+
}
|
|
94
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
95
|
+
const name = basename(filePath, '.md');
|
|
96
|
+
let description = '';
|
|
97
|
+
let model = 'gemini-2.5-flash';
|
|
98
|
+
let skills = [];
|
|
99
|
+
let tools = [];
|
|
100
|
+
// Parse YAML frontmatter
|
|
101
|
+
const fm = parseFrontmatter(content);
|
|
102
|
+
let cleanContent = content;
|
|
103
|
+
if (fm) {
|
|
104
|
+
if (fm.description)
|
|
105
|
+
description = fm.description;
|
|
106
|
+
if (fm.model)
|
|
107
|
+
model = fm.model;
|
|
108
|
+
skills = parseSkills(fm.skills);
|
|
109
|
+
tools = parseTools(fm.tools);
|
|
110
|
+
// Strip frontmatter from content to avoid duplication
|
|
111
|
+
cleanContent = content.replace(/^---\r?\n[\s\S]*?\r?\n---\r?\n?/, '').trim();
|
|
112
|
+
}
|
|
113
|
+
else {
|
|
114
|
+
// Fallback: parse from content body
|
|
115
|
+
const lines = content.split('\n');
|
|
116
|
+
for (const line of lines) {
|
|
117
|
+
if (line.startsWith('# ')) {
|
|
118
|
+
description = line.substring(2).trim();
|
|
119
|
+
break;
|
|
120
|
+
}
|
|
121
|
+
if (line.trim() && !line.startsWith('#')) {
|
|
122
|
+
description = line.trim();
|
|
123
|
+
break;
|
|
124
|
+
}
|
|
125
|
+
}
|
|
126
|
+
const modelMatch = content.match(/model:\s*(.+)/i);
|
|
127
|
+
if (modelMatch)
|
|
128
|
+
model = modelMatch[1].trim();
|
|
129
|
+
const skillsMatch = content.match(/skills:\s*(.+)/i);
|
|
130
|
+
if (skillsMatch)
|
|
131
|
+
skills = parseSkills(skillsMatch[1]);
|
|
132
|
+
const toolsMatch = content.match(/tools:\s*(.+)/i);
|
|
133
|
+
if (toolsMatch)
|
|
134
|
+
tools = parseTools(toolsMatch[1]);
|
|
135
|
+
}
|
|
136
|
+
return {
|
|
137
|
+
name,
|
|
138
|
+
description,
|
|
139
|
+
model,
|
|
140
|
+
skills,
|
|
141
|
+
tools,
|
|
142
|
+
content: cleanContent,
|
|
143
|
+
filePath,
|
|
144
|
+
};
|
|
145
|
+
}
|
|
146
|
+
/**
|
|
147
|
+
* Get agent profile details as formatted string
|
|
148
|
+
*/
|
|
149
|
+
export function formatAgentProfile(profile) {
|
|
150
|
+
let output = `Agent: ${profile.name}\n`;
|
|
151
|
+
output += `Description: ${profile.description}\n`;
|
|
152
|
+
output += `Model: ${profile.model}\n`;
|
|
153
|
+
if (profile.skills && profile.skills.length > 0) {
|
|
154
|
+
output += `Skills: ${profile.skills.join(', ')}\n`;
|
|
155
|
+
}
|
|
156
|
+
if (profile.tools && profile.tools.length > 0) {
|
|
157
|
+
output += `Tools: ${profile.tools.join(', ')}\n`;
|
|
158
|
+
}
|
|
159
|
+
output += `Path: ${profile.filePath}\n`;
|
|
160
|
+
return output;
|
|
161
|
+
}
|
|
162
|
+
/**
|
|
163
|
+
* Load agent profile with fallback between providers
|
|
164
|
+
* Tries primary provider's folder first, then falls back to the other provider's folder
|
|
165
|
+
* Maps model and tools to target provider when using fallback
|
|
166
|
+
*/
|
|
167
|
+
export function loadAgentProfileWithFallback(name, targetProvider, projectDir) {
|
|
168
|
+
const cwd = projectDir || process.cwd();
|
|
169
|
+
const agentPaths = getAgentPaths(targetProvider);
|
|
170
|
+
for (const relPath of agentPaths) {
|
|
171
|
+
const filePath = join(cwd, relPath, `${name}.md`);
|
|
172
|
+
if (existsSync(filePath)) {
|
|
173
|
+
const profile = parseAgentProfile(filePath);
|
|
174
|
+
if (profile) {
|
|
175
|
+
// Check if this is from the fallback path (not the primary)
|
|
176
|
+
const isPrimaryPath = relPath === agentPaths[0];
|
|
177
|
+
if (!isPrimaryPath) {
|
|
178
|
+
// Map model and tools to target provider
|
|
179
|
+
profile.model = mapModel(profile.model, targetProvider);
|
|
180
|
+
if (profile.tools && profile.tools.length > 0) {
|
|
181
|
+
profile.tools = mapTools(profile.tools, targetProvider);
|
|
182
|
+
}
|
|
183
|
+
}
|
|
184
|
+
return profile;
|
|
185
|
+
}
|
|
186
|
+
}
|
|
187
|
+
}
|
|
188
|
+
return null;
|
|
189
|
+
}
|
|
190
|
+
/**
|
|
191
|
+
* List all available agent profiles with fallback between providers
|
|
192
|
+
*/
|
|
193
|
+
export function listAgentProfilesWithFallback(targetProvider, projectDir) {
|
|
194
|
+
const cwd = projectDir || process.cwd();
|
|
195
|
+
const agentPaths = getAgentPaths(targetProvider);
|
|
196
|
+
const profiles = [];
|
|
197
|
+
const seenNames = new Set();
|
|
198
|
+
for (const relPath of agentPaths) {
|
|
199
|
+
const agentsDir = join(cwd, relPath);
|
|
200
|
+
if (!existsSync(agentsDir))
|
|
201
|
+
continue;
|
|
202
|
+
const files = readdirSync(agentsDir).filter(f => f.endsWith('.md'));
|
|
203
|
+
const isPrimaryPath = relPath === agentPaths[0];
|
|
204
|
+
for (const file of files) {
|
|
205
|
+
const name = basename(file, '.md');
|
|
206
|
+
// Skip if already found in primary path
|
|
207
|
+
if (seenNames.has(name))
|
|
208
|
+
continue;
|
|
209
|
+
seenNames.add(name);
|
|
210
|
+
const filePath = join(agentsDir, file);
|
|
211
|
+
const profile = parseAgentProfile(filePath);
|
|
212
|
+
if (profile) {
|
|
213
|
+
if (!isPrimaryPath) {
|
|
214
|
+
// Map model and tools to target provider
|
|
215
|
+
profile.model = mapModel(profile.model, targetProvider);
|
|
216
|
+
if (profile.tools && profile.tools.length > 0) {
|
|
217
|
+
profile.tools = mapTools(profile.tools, targetProvider);
|
|
218
|
+
}
|
|
219
|
+
}
|
|
220
|
+
profiles.push(profile);
|
|
221
|
+
}
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
return profiles;
|
|
225
|
+
}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PTY Context Builder
|
|
3
|
+
* Builds enriched prompt for first send in interactive mode
|
|
4
|
+
* Reuses the same format as handleSpawn() for consistency
|
|
5
|
+
*/
|
|
6
|
+
import type { PtySessionState } from './pty-types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Build enriched prompt for first send
|
|
9
|
+
* Wraps task with agent, skills, and context - same format as spawn
|
|
10
|
+
*/
|
|
11
|
+
export declare function buildFirstSendPrompt(task: string, sessionState: PtySessionState): string;
|
|
@@ -0,0 +1,83 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PTY Context Builder
|
|
3
|
+
* Builds enriched prompt for first send in interactive mode
|
|
4
|
+
* Reuses the same format as handleSpawn() for consistency
|
|
5
|
+
*/
|
|
6
|
+
/**
|
|
7
|
+
* Build subagent context string
|
|
8
|
+
*/
|
|
9
|
+
function buildSubagentContext(options) {
|
|
10
|
+
const { agentRole = 'Assistant', projectDir = null } = options;
|
|
11
|
+
const lines = [
|
|
12
|
+
`Agent Type: Interactive Session`,
|
|
13
|
+
`Agent Role: ${agentRole}`,
|
|
14
|
+
];
|
|
15
|
+
if (projectDir) {
|
|
16
|
+
lines.push(`Project: ${projectDir}`);
|
|
17
|
+
}
|
|
18
|
+
return lines.join('\n');
|
|
19
|
+
}
|
|
20
|
+
/**
|
|
21
|
+
* Format context files section
|
|
22
|
+
*/
|
|
23
|
+
function formatContext(contextItems) {
|
|
24
|
+
if (!contextItems || contextItems.length === 0) {
|
|
25
|
+
return '';
|
|
26
|
+
}
|
|
27
|
+
let contextSection = '<context>\n';
|
|
28
|
+
contextSection += 'The following documents provide additional context for this task:\n\n';
|
|
29
|
+
contextItems.forEach((ctx, index) => {
|
|
30
|
+
contextSection += `## Document ${index + 1}: ${ctx.name}\n`;
|
|
31
|
+
contextSection += `Source: ${ctx.originalRef}\n\n`;
|
|
32
|
+
contextSection += ctx.content;
|
|
33
|
+
contextSection += '\n\n---\n\n';
|
|
34
|
+
});
|
|
35
|
+
contextSection += '</context>\n';
|
|
36
|
+
return contextSection;
|
|
37
|
+
}
|
|
38
|
+
/**
|
|
39
|
+
* Build enriched prompt for first send
|
|
40
|
+
* Wraps task with agent, skills, and context - same format as spawn
|
|
41
|
+
*/
|
|
42
|
+
export function buildFirstSendPrompt(task, sessionState) {
|
|
43
|
+
const promptParts = [];
|
|
44
|
+
// Add subagent context
|
|
45
|
+
const subagentContext = buildSubagentContext({
|
|
46
|
+
agentRole: sessionState.context.agentName || 'Assistant',
|
|
47
|
+
projectDir: process.cwd()
|
|
48
|
+
});
|
|
49
|
+
promptParts.push('<subagent-context>');
|
|
50
|
+
promptParts.push(subagentContext);
|
|
51
|
+
promptParts.push('</subagent-context>\n');
|
|
52
|
+
// Add task/prompt
|
|
53
|
+
promptParts.push('<task>');
|
|
54
|
+
promptParts.push(task);
|
|
55
|
+
promptParts.push('</task>\n');
|
|
56
|
+
// Add agent profile content
|
|
57
|
+
if (sessionState.context.agentName && sessionState.context.agentContent) {
|
|
58
|
+
promptParts.push('<agent>');
|
|
59
|
+
promptParts.push(`# Agent: ${sessionState.context.agentName}\n`);
|
|
60
|
+
promptParts.push('## Role & Responsibilities');
|
|
61
|
+
promptParts.push(sessionState.context.agentContent);
|
|
62
|
+
promptParts.push('</agent>\n');
|
|
63
|
+
}
|
|
64
|
+
// Add skills content
|
|
65
|
+
if (sessionState.context.skills.length > 0) {
|
|
66
|
+
promptParts.push('<skills>');
|
|
67
|
+
promptParts.push('You have access to the following skills and capabilities:\n');
|
|
68
|
+
sessionState.context.skills.forEach((skill, i) => {
|
|
69
|
+
const content = sessionState.context.skillContents[skill];
|
|
70
|
+
if (content) {
|
|
71
|
+
promptParts.push(`## Skill ${i + 1}: ${skill}`);
|
|
72
|
+
promptParts.push(content);
|
|
73
|
+
promptParts.push('---\n');
|
|
74
|
+
}
|
|
75
|
+
});
|
|
76
|
+
promptParts.push('</skills>\n');
|
|
77
|
+
}
|
|
78
|
+
// Add context section
|
|
79
|
+
if (sessionState.context.contextFiles.length > 0) {
|
|
80
|
+
promptParts.push(formatContext(sessionState.context.contextFiles));
|
|
81
|
+
}
|
|
82
|
+
return promptParts.join('\n');
|
|
83
|
+
}
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PTY Provider Configurations
|
|
3
|
+
* Claude Code and Gemini CLI specific settings
|
|
4
|
+
*/
|
|
5
|
+
import type { PtyProviderConfig } from './pty-types.js';
|
|
6
|
+
import type { CliProvider } from './types.js';
|
|
7
|
+
/**
|
|
8
|
+
* Provider-specific configurations for PTY management
|
|
9
|
+
*/
|
|
10
|
+
export declare const PTY_PROVIDERS: Record<CliProvider, PtyProviderConfig>;
|
|
11
|
+
/**
|
|
12
|
+
* Get provider config by name
|
|
13
|
+
*/
|
|
14
|
+
export declare function getProviderConfig(provider: CliProvider): PtyProviderConfig;
|
|
15
|
+
/**
|
|
16
|
+
* Build CLI arguments for starting a PTY session
|
|
17
|
+
*/
|
|
18
|
+
export declare function buildPtyArgs(provider: CliProvider, model: string, tools: string[]): string[];
|
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PTY Provider Configurations
|
|
3
|
+
* Claude Code and Gemini CLI specific settings
|
|
4
|
+
*/
|
|
5
|
+
/**
|
|
6
|
+
* Provider-specific configurations for PTY management
|
|
7
|
+
*/
|
|
8
|
+
export const PTY_PROVIDERS = {
|
|
9
|
+
claude: {
|
|
10
|
+
name: 'Claude Code',
|
|
11
|
+
command: 'claude',
|
|
12
|
+
modelFlag: '--model',
|
|
13
|
+
toolsFlag: '--allowedTools',
|
|
14
|
+
toolsFormat: 'csv', // Claude: --allowedTools Read,Write,Bash
|
|
15
|
+
pipeFlag: '-p', // Claude needs -p for stdin mode
|
|
16
|
+
readyIndicator: '❯', // Claude prompt indicator
|
|
17
|
+
responseMarker: '●', // Claude response marker
|
|
18
|
+
exitCommand: '/exit\r'
|
|
19
|
+
},
|
|
20
|
+
gemini: {
|
|
21
|
+
name: 'Gemini CLI',
|
|
22
|
+
command: 'gemini',
|
|
23
|
+
modelFlag: '-m',
|
|
24
|
+
toolsFlag: '--allowed-tools',
|
|
25
|
+
toolsFormat: 'json', // Gemini: --allowed-tools ["read_file","write_file"]
|
|
26
|
+
pipeFlag: undefined, // Gemini doesn't need -p
|
|
27
|
+
readyIndicator: '>', // Gemini prompt indicator
|
|
28
|
+
responseMarker: '✦', // Gemini response marker
|
|
29
|
+
exitCommand: '/exit\r'
|
|
30
|
+
}
|
|
31
|
+
};
|
|
32
|
+
/**
|
|
33
|
+
* Get provider config by name
|
|
34
|
+
*/
|
|
35
|
+
export function getProviderConfig(provider) {
|
|
36
|
+
const config = PTY_PROVIDERS[provider];
|
|
37
|
+
if (!config) {
|
|
38
|
+
throw new Error(`Unknown provider: ${provider}. Use 'claude' or 'gemini'`);
|
|
39
|
+
}
|
|
40
|
+
return config;
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Build CLI arguments for starting a PTY session
|
|
44
|
+
*/
|
|
45
|
+
export function buildPtyArgs(provider, model, tools) {
|
|
46
|
+
const config = PTY_PROVIDERS[provider];
|
|
47
|
+
const args = [];
|
|
48
|
+
// Add pipe flag if needed (Claude)
|
|
49
|
+
if (config.pipeFlag) {
|
|
50
|
+
args.push(config.pipeFlag);
|
|
51
|
+
}
|
|
52
|
+
// Add model flag
|
|
53
|
+
args.push(config.modelFlag, model);
|
|
54
|
+
// Add tools if any
|
|
55
|
+
if (tools.length > 0) {
|
|
56
|
+
if (config.toolsFormat === 'json') {
|
|
57
|
+
// Gemini: --allowed-tools ["tool1","tool2"]
|
|
58
|
+
args.push(config.toolsFlag, JSON.stringify(tools));
|
|
59
|
+
}
|
|
60
|
+
else {
|
|
61
|
+
// Claude: --allowedTools tool1,tool2
|
|
62
|
+
args.push(config.toolsFlag, tools.join(','));
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
return args;
|
|
66
|
+
}
|
|
@@ -0,0 +1,33 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PTY Session State Management
|
|
3
|
+
* Handles persistence of interactive session state
|
|
4
|
+
*/
|
|
5
|
+
import type { PtySessionState } from './pty-types.js';
|
|
6
|
+
/**
|
|
7
|
+
* Get the session file path
|
|
8
|
+
*/
|
|
9
|
+
export declare function getSessionFilePath(cwd?: string): string;
|
|
10
|
+
/**
|
|
11
|
+
* Load session state from file
|
|
12
|
+
*/
|
|
13
|
+
export declare function loadSession(cwd?: string): PtySessionState | null;
|
|
14
|
+
/**
|
|
15
|
+
* Save session state to file
|
|
16
|
+
*/
|
|
17
|
+
export declare function saveSession(state: PtySessionState, cwd?: string): void;
|
|
18
|
+
/**
|
|
19
|
+
* Clear session state file
|
|
20
|
+
*/
|
|
21
|
+
export declare function clearSession(cwd?: string): void;
|
|
22
|
+
/**
|
|
23
|
+
* Check if a session is currently active (process running)
|
|
24
|
+
*/
|
|
25
|
+
export declare function isSessionActive(cwd?: string): boolean;
|
|
26
|
+
/**
|
|
27
|
+
* Mark first send as complete
|
|
28
|
+
*/
|
|
29
|
+
export declare function markFirstSendComplete(cwd?: string): void;
|
|
30
|
+
/**
|
|
31
|
+
* Update session PID after server starts
|
|
32
|
+
*/
|
|
33
|
+
export declare function updateSessionPid(pid: number, cwd?: string): void;
|
|
@@ -0,0 +1,82 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PTY Session State Management
|
|
3
|
+
* Handles persistence of interactive session state
|
|
4
|
+
*/
|
|
5
|
+
import { existsSync, readFileSync, writeFileSync, unlinkSync } from 'fs';
|
|
6
|
+
import { join } from 'path';
|
|
7
|
+
const SESSION_FILE = '.gk-interactive-session.json';
|
|
8
|
+
/**
|
|
9
|
+
* Get the session file path
|
|
10
|
+
*/
|
|
11
|
+
export function getSessionFilePath(cwd) {
|
|
12
|
+
return join(cwd || process.cwd(), SESSION_FILE);
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Load session state from file
|
|
16
|
+
*/
|
|
17
|
+
export function loadSession(cwd) {
|
|
18
|
+
const filePath = getSessionFilePath(cwd);
|
|
19
|
+
if (!existsSync(filePath))
|
|
20
|
+
return null;
|
|
21
|
+
try {
|
|
22
|
+
const content = readFileSync(filePath, 'utf-8');
|
|
23
|
+
return JSON.parse(content);
|
|
24
|
+
}
|
|
25
|
+
catch {
|
|
26
|
+
return null;
|
|
27
|
+
}
|
|
28
|
+
}
|
|
29
|
+
/**
|
|
30
|
+
* Save session state to file
|
|
31
|
+
*/
|
|
32
|
+
export function saveSession(state, cwd) {
|
|
33
|
+
const filePath = getSessionFilePath(cwd);
|
|
34
|
+
writeFileSync(filePath, JSON.stringify(state, null, 2));
|
|
35
|
+
}
|
|
36
|
+
/**
|
|
37
|
+
* Clear session state file
|
|
38
|
+
*/
|
|
39
|
+
export function clearSession(cwd) {
|
|
40
|
+
const filePath = getSessionFilePath(cwd);
|
|
41
|
+
if (existsSync(filePath)) {
|
|
42
|
+
unlinkSync(filePath);
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
/**
|
|
46
|
+
* Check if a session is currently active (process running)
|
|
47
|
+
*/
|
|
48
|
+
export function isSessionActive(cwd) {
|
|
49
|
+
const session = loadSession(cwd);
|
|
50
|
+
if (!session)
|
|
51
|
+
return false;
|
|
52
|
+
// Check if process is still running
|
|
53
|
+
try {
|
|
54
|
+
process.kill(session.pid, 0);
|
|
55
|
+
return true;
|
|
56
|
+
}
|
|
57
|
+
catch {
|
|
58
|
+
// Process not running, clean up stale session
|
|
59
|
+
clearSession(cwd);
|
|
60
|
+
return false;
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
/**
|
|
64
|
+
* Mark first send as complete
|
|
65
|
+
*/
|
|
66
|
+
export function markFirstSendComplete(cwd) {
|
|
67
|
+
const session = loadSession(cwd);
|
|
68
|
+
if (session) {
|
|
69
|
+
session.isFirstSend = false;
|
|
70
|
+
saveSession(session, cwd);
|
|
71
|
+
}
|
|
72
|
+
}
|
|
73
|
+
/**
|
|
74
|
+
* Update session PID after server starts
|
|
75
|
+
*/
|
|
76
|
+
export function updateSessionPid(pid, cwd) {
|
|
77
|
+
const session = loadSession(cwd);
|
|
78
|
+
if (session) {
|
|
79
|
+
session.pid = pid;
|
|
80
|
+
saveSession(session, cwd);
|
|
81
|
+
}
|
|
82
|
+
}
|
|
@@ -0,0 +1,127 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* PTY Types for Interactive Mode
|
|
3
|
+
*/
|
|
4
|
+
import type { CliProvider } from './types.js';
|
|
5
|
+
/**
|
|
6
|
+
* Provider-specific PTY configuration
|
|
7
|
+
*/
|
|
8
|
+
export interface PtyProviderConfig {
|
|
9
|
+
name: string;
|
|
10
|
+
command: string;
|
|
11
|
+
modelFlag: string;
|
|
12
|
+
toolsFlag: string;
|
|
13
|
+
toolsFormat: 'json' | 'csv';
|
|
14
|
+
pipeFlag?: string;
|
|
15
|
+
readyIndicator: string;
|
|
16
|
+
responseMarker: string;
|
|
17
|
+
exitCommand: string;
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Loaded context file
|
|
21
|
+
*/
|
|
22
|
+
export interface LoadedContext {
|
|
23
|
+
type: 'context';
|
|
24
|
+
name: string;
|
|
25
|
+
path: string;
|
|
26
|
+
content: string;
|
|
27
|
+
originalRef: string;
|
|
28
|
+
relativePath?: string;
|
|
29
|
+
}
|
|
30
|
+
/**
|
|
31
|
+
* Session state stored in .gk-interactive-session.json
|
|
32
|
+
*/
|
|
33
|
+
export interface PtySessionState {
|
|
34
|
+
provider: CliProvider;
|
|
35
|
+
model: string;
|
|
36
|
+
port: number;
|
|
37
|
+
pid: number;
|
|
38
|
+
isFirstSend: boolean;
|
|
39
|
+
context: {
|
|
40
|
+
agentName: string | null;
|
|
41
|
+
agentContent: string | null;
|
|
42
|
+
skills: string[];
|
|
43
|
+
skillContents: Record<string, string>;
|
|
44
|
+
contextFiles: LoadedContext[];
|
|
45
|
+
tools: string[];
|
|
46
|
+
};
|
|
47
|
+
startedAt: string;
|
|
48
|
+
}
|
|
49
|
+
/**
|
|
50
|
+
* Structured exchange output
|
|
51
|
+
*/
|
|
52
|
+
export interface PtyExchange {
|
|
53
|
+
id: string;
|
|
54
|
+
timestamp: string;
|
|
55
|
+
prompt: string;
|
|
56
|
+
answer: string;
|
|
57
|
+
pending: PtyPendingTool[];
|
|
58
|
+
toolResults: PtyToolResult[];
|
|
59
|
+
status: 'complete' | 'waiting_confirmation' | 'streaming';
|
|
60
|
+
}
|
|
61
|
+
/**
|
|
62
|
+
* Pending tool awaiting confirmation
|
|
63
|
+
*/
|
|
64
|
+
export interface PtyPendingTool {
|
|
65
|
+
type: 'shell' | 'write_file' | 'read_file' | 'read_folder' | 'edit_file' | 'apply_change';
|
|
66
|
+
detail?: string;
|
|
67
|
+
command?: string;
|
|
68
|
+
path?: string;
|
|
69
|
+
waiting: boolean;
|
|
70
|
+
options?: string[];
|
|
71
|
+
actionRequired?: {
|
|
72
|
+
current: number;
|
|
73
|
+
total: number;
|
|
74
|
+
};
|
|
75
|
+
}
|
|
76
|
+
/**
|
|
77
|
+
* Tool execution result
|
|
78
|
+
*/
|
|
79
|
+
export interface PtyToolResult {
|
|
80
|
+
type: string;
|
|
81
|
+
detail: string;
|
|
82
|
+
status: 'completed' | 'failed' | 'in_progress';
|
|
83
|
+
}
|
|
84
|
+
/**
|
|
85
|
+
* Real-time event from PTY stream
|
|
86
|
+
*/
|
|
87
|
+
export interface PtyEvent {
|
|
88
|
+
type: 'stream_started' | 'tool_in_progress' | 'tool_completed' | 'tool_failed' | 'tool_confirmation_required' | 'action_required' | 'waiting_confirmation' | 'response_chunk' | 'prompt_ready';
|
|
89
|
+
tool?: string;
|
|
90
|
+
detail?: string;
|
|
91
|
+
command?: string;
|
|
92
|
+
current?: number;
|
|
93
|
+
total?: number;
|
|
94
|
+
}
|
|
95
|
+
/**
|
|
96
|
+
* Server status response
|
|
97
|
+
*/
|
|
98
|
+
export interface PtyServerStatus {
|
|
99
|
+
running: boolean;
|
|
100
|
+
ready: boolean;
|
|
101
|
+
provider: CliProvider;
|
|
102
|
+
outputLength: number;
|
|
103
|
+
}
|
|
104
|
+
/**
|
|
105
|
+
* Send command response
|
|
106
|
+
*/
|
|
107
|
+
export interface PtySendResponse {
|
|
108
|
+
ok: boolean;
|
|
109
|
+
exchangeId?: string;
|
|
110
|
+
error?: string;
|
|
111
|
+
}
|
|
112
|
+
/**
|
|
113
|
+
* Completion check response
|
|
114
|
+
*/
|
|
115
|
+
export interface PtyCompleteResponse {
|
|
116
|
+
complete: boolean;
|
|
117
|
+
reason?: 'streaming' | 'no_response' | 'pending_tool' | 'waiting_content' | 'unknown';
|
|
118
|
+
hint?: string;
|
|
119
|
+
}
|
|
120
|
+
/**
|
|
121
|
+
* Pending tools response
|
|
122
|
+
*/
|
|
123
|
+
export interface PtyPendingResponse {
|
|
124
|
+
hasPending: boolean;
|
|
125
|
+
tools: PtyPendingTool[];
|
|
126
|
+
hint?: string;
|
|
127
|
+
}
|
|
@@ -0,0 +1,45 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Agent-Skill Composer Search - BM25 search engine for Agent+Skills combinations
|
|
3
|
+
* Ported from Python core.py with same logic
|
|
4
|
+
*/
|
|
5
|
+
import { SearchResult, Intent, Domain, Complexity, SkillInfo } from './types.js';
|
|
6
|
+
declare const COMPLEXITY_MAX_SKILLS: Record<Complexity, number>;
|
|
7
|
+
declare const INTENT_AGENT_MAP: Record<Intent, string>;
|
|
8
|
+
declare const DOMAIN_SKILL_MAP: Record<string, string[]>;
|
|
9
|
+
declare function loadSynonyms(): Map<string, string[]>;
|
|
10
|
+
declare function expandQuery(query: string, synonyms?: Map<string, string[]>): string;
|
|
11
|
+
export declare function detectComplexity(query: string): Complexity;
|
|
12
|
+
export declare function detectIntent(query: string): Intent;
|
|
13
|
+
export declare function detectDomain(query: string): Domain;
|
|
14
|
+
export declare function searchCombinations(query: string, maxResults?: number, expand?: boolean): {
|
|
15
|
+
query: string;
|
|
16
|
+
expandedQuery?: string;
|
|
17
|
+
detectedIntent: Intent;
|
|
18
|
+
detectedDomain: Domain;
|
|
19
|
+
detectedComplexity: Complexity;
|
|
20
|
+
count: number;
|
|
21
|
+
results: Array<Record<string, any>>;
|
|
22
|
+
};
|
|
23
|
+
export declare function searchCombinationsFiltered(query: string, intentFilter?: Intent, domainFilter?: Domain, maxResults?: number, expand?: boolean): {
|
|
24
|
+
results: Array<Record<string, any>>;
|
|
25
|
+
count: number;
|
|
26
|
+
};
|
|
27
|
+
export declare function getBestCombination(query: string): SearchResult;
|
|
28
|
+
/**
|
|
29
|
+
* Main search function - returns multiple results
|
|
30
|
+
*/
|
|
31
|
+
export declare function searchAgentSkillCombination(task: string, options?: {
|
|
32
|
+
top?: number;
|
|
33
|
+
forceIntent?: Intent;
|
|
34
|
+
forceDomain?: Domain;
|
|
35
|
+
maxSkills?: number;
|
|
36
|
+
}): SearchResult[];
|
|
37
|
+
/**
|
|
38
|
+
* List all available skills from extensions
|
|
39
|
+
*/
|
|
40
|
+
export declare function listAllSkills(projectDir?: string): SkillInfo[];
|
|
41
|
+
/**
|
|
42
|
+
* Load skill content by name
|
|
43
|
+
*/
|
|
44
|
+
export declare function loadSkillContent(skillName: string, projectDir?: string): string | null;
|
|
45
|
+
export { loadSynonyms, expandQuery, INTENT_AGENT_MAP, DOMAIN_SKILL_MAP, COMPLEXITY_MAX_SKILLS };
|