gemkit-cli 0.2.3 → 0.3.0

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.
Files changed (160) hide show
  1. package/README.md +141 -7
  2. package/dist/commands/agent/index.d.ts +9 -0
  3. package/dist/commands/agent/index.js +1329 -0
  4. package/dist/commands/cache/index.d.ts +5 -0
  5. package/dist/commands/cache/index.js +43 -0
  6. package/dist/commands/catalog/index.d.ts +2 -0
  7. package/dist/commands/catalog/index.js +57 -0
  8. package/dist/commands/config/index.d.ts +7 -0
  9. package/dist/commands/config/index.js +122 -0
  10. package/dist/commands/convert/index.d.ts +8 -0
  11. package/dist/commands/convert/index.js +391 -0
  12. package/dist/commands/doctor/index.d.ts +2 -0
  13. package/dist/commands/doctor/index.js +243 -0
  14. package/dist/commands/extension/index.d.ts +5 -0
  15. package/dist/commands/extension/index.js +52 -0
  16. package/dist/commands/index.d.ts +5 -0
  17. package/dist/commands/index.js +37 -0
  18. package/dist/commands/init/index.d.ts +6 -0
  19. package/dist/commands/init/index.js +345 -0
  20. package/dist/commands/new/index.d.ts +5 -0
  21. package/dist/commands/new/index.js +49 -0
  22. package/dist/commands/office/index.d.ts +5 -0
  23. package/dist/commands/office/index.js +283 -0
  24. package/dist/commands/paste/index.d.ts +10 -0
  25. package/dist/commands/paste/index.js +533 -0
  26. package/dist/commands/plan/index.d.ts +8 -0
  27. package/dist/commands/plan/index.js +247 -0
  28. package/dist/commands/session/index.d.ts +8 -0
  29. package/dist/commands/session/index.js +289 -0
  30. package/dist/commands/tokens/index.d.ts +6 -0
  31. package/dist/commands/tokens/index.js +148 -0
  32. package/dist/commands/update/index.d.ts +26 -0
  33. package/dist/commands/update/index.js +199 -0
  34. package/dist/commands/versions/index.d.ts +5 -0
  35. package/dist/commands/versions/index.js +39 -0
  36. package/dist/domains/agent/index.d.ts +8 -0
  37. package/dist/domains/agent/index.js +8 -0
  38. package/dist/domains/agent/mappings.d.ts +32 -0
  39. package/dist/domains/agent/mappings.js +164 -0
  40. package/dist/domains/agent/profile.d.ts +26 -0
  41. package/dist/domains/agent/profile.js +225 -0
  42. package/dist/domains/agent/pty-context.d.ts +11 -0
  43. package/dist/domains/agent/pty-context.js +83 -0
  44. package/dist/domains/agent/pty-providers.d.ts +18 -0
  45. package/dist/domains/agent/pty-providers.js +66 -0
  46. package/dist/domains/agent/pty-session.d.ts +33 -0
  47. package/dist/domains/agent/pty-session.js +82 -0
  48. package/dist/domains/agent/pty-types.d.ts +127 -0
  49. package/dist/domains/agent/pty-types.js +4 -0
  50. package/dist/domains/agent/search.d.ts +45 -0
  51. package/dist/domains/agent/search.js +614 -0
  52. package/dist/domains/agent/types.d.ts +78 -0
  53. package/dist/domains/agent/types.js +5 -0
  54. package/dist/domains/agent-office/documents-scanner.d.ts +9 -0
  55. package/dist/domains/agent-office/documents-scanner.js +143 -0
  56. package/dist/domains/agent-office/event-emitter.d.ts +43 -0
  57. package/dist/domains/agent-office/event-emitter.js +86 -0
  58. package/dist/domains/agent-office/file-watcher.d.ts +40 -0
  59. package/dist/domains/agent-office/file-watcher.js +173 -0
  60. package/dist/domains/agent-office/icons.d.ts +11 -0
  61. package/dist/domains/agent-office/icons.js +36 -0
  62. package/dist/domains/agent-office/index.d.ts +12 -0
  63. package/dist/domains/agent-office/index.js +20 -0
  64. package/dist/domains/agent-office/renderer/web/assets.d.ts +11 -0
  65. package/dist/domains/agent-office/renderer/web/assets.js +3419 -0
  66. package/dist/domains/agent-office/renderer/web/server.d.ts +42 -0
  67. package/dist/domains/agent-office/renderer/web/server.js +228 -0
  68. package/dist/domains/agent-office/renderer/web.d.ts +30 -0
  69. package/dist/domains/agent-office/renderer/web.js +111 -0
  70. package/dist/domains/agent-office/session-bridge.d.ts +23 -0
  71. package/dist/domains/agent-office/session-bridge.js +171 -0
  72. package/dist/domains/agent-office/state-machine.d.ts +5 -0
  73. package/dist/domains/agent-office/state-machine.js +82 -0
  74. package/dist/domains/agent-office/types.d.ts +91 -0
  75. package/dist/domains/agent-office/types.js +4 -0
  76. package/dist/domains/cache/index.d.ts +1 -0
  77. package/dist/domains/cache/index.js +1 -0
  78. package/dist/domains/cache/manager.d.ts +22 -0
  79. package/dist/domains/cache/manager.js +84 -0
  80. package/dist/domains/config/index.d.ts +5 -0
  81. package/dist/domains/config/index.js +5 -0
  82. package/dist/domains/config/manager.d.ts +24 -0
  83. package/dist/domains/config/manager.js +85 -0
  84. package/dist/domains/config/schema.d.ts +17 -0
  85. package/dist/domains/config/schema.js +96 -0
  86. package/dist/domains/convert/converter.d.ts +78 -0
  87. package/dist/domains/convert/converter.js +471 -0
  88. package/dist/domains/convert/index.d.ts +5 -0
  89. package/dist/domains/convert/index.js +5 -0
  90. package/dist/domains/convert/types.d.ts +88 -0
  91. package/dist/domains/convert/types.js +18 -0
  92. package/dist/domains/github/download.d.ts +12 -0
  93. package/dist/domains/github/download.js +51 -0
  94. package/dist/domains/github/index.d.ts +2 -0
  95. package/dist/domains/github/index.js +2 -0
  96. package/dist/domains/github/releases.d.ts +16 -0
  97. package/dist/domains/github/releases.js +68 -0
  98. package/dist/domains/installation/conflict.d.ts +13 -0
  99. package/dist/domains/installation/conflict.js +38 -0
  100. package/dist/domains/installation/file-sync.d.ts +16 -0
  101. package/dist/domains/installation/file-sync.js +77 -0
  102. package/dist/domains/installation/index.d.ts +3 -0
  103. package/dist/domains/installation/index.js +3 -0
  104. package/dist/domains/installation/metadata.d.ts +20 -0
  105. package/dist/domains/installation/metadata.js +52 -0
  106. package/dist/domains/plan/index.d.ts +2 -0
  107. package/dist/domains/plan/index.js +2 -0
  108. package/dist/domains/plan/resolver.d.ts +24 -0
  109. package/dist/domains/plan/resolver.js +164 -0
  110. package/dist/domains/plan/types.d.ts +13 -0
  111. package/dist/domains/plan/types.js +4 -0
  112. package/dist/domains/session/env.d.ts +51 -0
  113. package/dist/domains/session/env.js +118 -0
  114. package/dist/domains/session/index.d.ts +8 -0
  115. package/dist/domains/session/index.js +8 -0
  116. package/dist/domains/session/manager.d.ts +56 -0
  117. package/dist/domains/session/manager.js +205 -0
  118. package/dist/domains/session/paths.d.ts +6 -0
  119. package/dist/domains/session/paths.js +6 -0
  120. package/dist/domains/session/types.d.ts +121 -0
  121. package/dist/domains/session/types.js +5 -0
  122. package/dist/domains/session/writer.d.ts +82 -0
  123. package/dist/domains/session/writer.js +431 -0
  124. package/dist/domains/tokens/index.d.ts +5 -0
  125. package/dist/domains/tokens/index.js +5 -0
  126. package/dist/domains/tokens/pricing.d.ts +38 -0
  127. package/dist/domains/tokens/pricing.js +129 -0
  128. package/dist/domains/tokens/scanner.d.ts +42 -0
  129. package/dist/domains/tokens/scanner.js +168 -0
  130. package/dist/index.d.ts +5 -0
  131. package/dist/index.js +87 -58
  132. package/dist/services/aipty.d.ts +76 -0
  133. package/dist/services/aipty.js +276 -0
  134. package/dist/services/archive.d.ts +22 -0
  135. package/dist/services/archive.js +53 -0
  136. package/dist/services/auto-update.d.ts +26 -0
  137. package/dist/services/auto-update.js +117 -0
  138. package/dist/services/hash.d.ts +36 -0
  139. package/dist/services/hash.js +63 -0
  140. package/dist/services/logger.d.ts +28 -0
  141. package/dist/services/logger.js +102 -0
  142. package/dist/services/music.d.ts +67 -0
  143. package/dist/services/music.js +290 -0
  144. package/dist/services/npm.d.ts +22 -0
  145. package/dist/services/npm.js +65 -0
  146. package/dist/services/pty-client.d.ts +66 -0
  147. package/dist/services/pty-client.js +154 -0
  148. package/dist/services/pty-server.d.ts +102 -0
  149. package/dist/services/pty-server.js +613 -0
  150. package/dist/types/index.d.ts +155 -0
  151. package/dist/types/index.js +4 -0
  152. package/dist/utils/colors.d.ts +43 -0
  153. package/dist/utils/colors.js +98 -0
  154. package/dist/utils/errors.d.ts +24 -0
  155. package/dist/utils/errors.js +56 -0
  156. package/dist/utils/paths.d.ts +46 -0
  157. package/dist/utils/paths.js +89 -0
  158. package/dist/utils/platform.d.ts +11 -0
  159. package/dist/utils/platform.js +31 -0
  160. 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,4 @@
1
+ /**
2
+ * PTY Types for Interactive Mode
3
+ */
4
+ export {};
@@ -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 };