praisonai 1.2.2 → 1.2.3
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/agent/simple.js +1 -1
- package/dist/cli/commands/auto.d.ts +12 -0
- package/dist/cli/commands/auto.js +109 -0
- package/dist/cli/commands/autonomy.d.ts +5 -0
- package/dist/cli/commands/autonomy.js +152 -0
- package/dist/cli/commands/cache.d.ts +9 -0
- package/dist/cli/commands/cache.js +143 -0
- package/dist/cli/commands/chat.d.ts +14 -0
- package/dist/cli/commands/chat.js +127 -0
- package/dist/cli/commands/checkpoints.d.ts +5 -0
- package/dist/cli/commands/checkpoints.js +236 -0
- package/dist/cli/commands/context.d.ts +11 -0
- package/dist/cli/commands/context.js +182 -0
- package/dist/cli/commands/cost.d.ts +5 -0
- package/dist/cli/commands/cost.js +146 -0
- package/dist/cli/commands/db.d.ts +9 -0
- package/dist/cli/commands/db.js +149 -0
- package/dist/cli/commands/eval.d.ts +17 -0
- package/dist/cli/commands/eval.js +247 -0
- package/dist/cli/commands/external-agents.d.ts +5 -0
- package/dist/cli/commands/external-agents.js +169 -0
- package/dist/cli/commands/fast-context.d.ts +5 -0
- package/dist/cli/commands/fast-context.js +126 -0
- package/dist/cli/commands/flow.d.ts +5 -0
- package/dist/cli/commands/flow.js +141 -0
- package/dist/cli/commands/git.d.ts +5 -0
- package/dist/cli/commands/git.js +178 -0
- package/dist/cli/commands/graph-rag.d.ts +9 -0
- package/dist/cli/commands/graph-rag.js +131 -0
- package/dist/cli/commands/guardrail.d.ts +11 -0
- package/dist/cli/commands/guardrail.js +156 -0
- package/dist/cli/commands/handoff.d.ts +9 -0
- package/dist/cli/commands/handoff.js +133 -0
- package/dist/cli/commands/help.d.ts +8 -0
- package/dist/cli/commands/help.js +167 -0
- package/dist/cli/commands/image.d.ts +13 -0
- package/dist/cli/commands/image.js +192 -0
- package/dist/cli/commands/interactive.d.ts +6 -0
- package/dist/cli/commands/interactive.js +79 -0
- package/dist/cli/commands/jobs.d.ts +5 -0
- package/dist/cli/commands/jobs.js +282 -0
- package/dist/cli/commands/knowledge.d.ts +9 -0
- package/dist/cli/commands/knowledge.js +226 -0
- package/dist/cli/commands/mcp.d.ts +9 -0
- package/dist/cli/commands/mcp.js +243 -0
- package/dist/cli/commands/memory.d.ts +10 -0
- package/dist/cli/commands/memory.js +198 -0
- package/dist/cli/commands/n8n.d.ts +5 -0
- package/dist/cli/commands/n8n.js +137 -0
- package/dist/cli/commands/observability.d.ts +9 -0
- package/dist/cli/commands/observability.js +145 -0
- package/dist/cli/commands/planning.d.ts +9 -0
- package/dist/cli/commands/planning.js +167 -0
- package/dist/cli/commands/prompt-expand.d.ts +11 -0
- package/dist/cli/commands/prompt-expand.js +100 -0
- package/dist/cli/commands/providers.d.ts +9 -0
- package/dist/cli/commands/providers.js +98 -0
- package/dist/cli/commands/query-rewrite.d.ts +12 -0
- package/dist/cli/commands/query-rewrite.js +102 -0
- package/dist/cli/commands/repo-map.d.ts +5 -0
- package/dist/cli/commands/repo-map.js +151 -0
- package/dist/cli/commands/reranker.d.ts +10 -0
- package/dist/cli/commands/reranker.js +144 -0
- package/dist/cli/commands/research.d.ts +12 -0
- package/dist/cli/commands/research.js +108 -0
- package/dist/cli/commands/router.d.ts +11 -0
- package/dist/cli/commands/router.js +142 -0
- package/dist/cli/commands/run.d.ts +14 -0
- package/dist/cli/commands/run.js +111 -0
- package/dist/cli/commands/sandbox.d.ts +5 -0
- package/dist/cli/commands/sandbox.js +135 -0
- package/dist/cli/commands/scheduler.d.ts +5 -0
- package/dist/cli/commands/scheduler.js +260 -0
- package/dist/cli/commands/session.d.ts +9 -0
- package/dist/cli/commands/session.js +238 -0
- package/dist/cli/commands/skills.d.ts +9 -0
- package/dist/cli/commands/skills.js +256 -0
- package/dist/cli/commands/telemetry.d.ts +9 -0
- package/dist/cli/commands/telemetry.js +146 -0
- package/dist/cli/commands/tools.d.ts +9 -0
- package/dist/cli/commands/tools.js +172 -0
- package/dist/cli/commands/vector.d.ts +10 -0
- package/dist/cli/commands/vector.js +171 -0
- package/dist/cli/commands/version.d.ts +8 -0
- package/dist/cli/commands/version.js +68 -0
- package/dist/cli/commands/voice.d.ts +10 -0
- package/dist/cli/commands/voice.js +162 -0
- package/dist/cli/commands/workflow.d.ts +13 -0
- package/dist/cli/commands/workflow.js +184 -0
- package/dist/cli/config/index.d.ts +6 -0
- package/dist/cli/config/index.js +22 -0
- package/dist/cli/config/load.d.ts +20 -0
- package/dist/cli/config/load.js +229 -0
- package/dist/cli/config/resolve.d.ts +28 -0
- package/dist/cli/config/resolve.js +70 -0
- package/dist/cli/config/schema.d.ts +15 -0
- package/dist/cli/config/schema.js +65 -0
- package/dist/cli/features/autonomy-mode.d.ts +98 -0
- package/dist/cli/features/autonomy-mode.js +266 -0
- package/dist/cli/features/background-jobs.d.ts +155 -0
- package/dist/cli/features/background-jobs.js +416 -0
- package/dist/cli/features/checkpoints.d.ts +126 -0
- package/dist/cli/features/checkpoints.js +288 -0
- package/dist/cli/features/cost-tracker.d.ts +101 -0
- package/dist/cli/features/cost-tracker.js +212 -0
- package/dist/cli/features/external-agents.d.ts +115 -0
- package/dist/cli/features/external-agents.js +294 -0
- package/dist/cli/features/fast-context.d.ts +126 -0
- package/dist/cli/features/fast-context.js +310 -0
- package/dist/cli/features/flow-display.d.ts +100 -0
- package/dist/cli/features/flow-display.js +254 -0
- package/dist/cli/features/git-integration.d.ts +138 -0
- package/dist/cli/features/git-integration.js +374 -0
- package/dist/cli/features/index.d.ts +17 -0
- package/dist/cli/features/index.js +102 -0
- package/dist/cli/features/interactive-tui.d.ts +114 -0
- package/dist/cli/features/interactive-tui.js +326 -0
- package/dist/cli/features/n8n-integration.d.ts +108 -0
- package/dist/cli/features/n8n-integration.js +296 -0
- package/dist/cli/features/repo-map.d.ts +101 -0
- package/dist/cli/features/repo-map.js +350 -0
- package/dist/cli/features/sandbox-executor.d.ts +89 -0
- package/dist/cli/features/sandbox-executor.js +314 -0
- package/dist/cli/features/scheduler.d.ts +111 -0
- package/dist/cli/features/scheduler.js +298 -0
- package/dist/cli/features/slash-commands.d.ts +77 -0
- package/dist/cli/features/slash-commands.js +316 -0
- package/dist/cli/index.d.ts +19 -15
- package/dist/cli/index.js +163 -123
- package/dist/cli/output/errors.d.ts +32 -0
- package/dist/cli/output/errors.js +72 -0
- package/dist/cli/output/index.d.ts +6 -0
- package/dist/cli/output/index.js +22 -0
- package/dist/cli/output/json.d.ts +17 -0
- package/dist/cli/output/json.js +54 -0
- package/dist/cli/output/pretty.d.ts +21 -0
- package/dist/cli/output/pretty.js +106 -0
- package/dist/cli/runtime/env.d.ts +12 -0
- package/dist/cli/runtime/env.js +49 -0
- package/dist/cli/runtime/exit.d.ts +11 -0
- package/dist/cli/runtime/exit.js +49 -0
- package/dist/cli/runtime/index.d.ts +6 -0
- package/dist/cli/runtime/index.js +22 -0
- package/dist/cli/runtime/lazy.d.ts +18 -0
- package/dist/cli/runtime/lazy.js +85 -0
- package/dist/cli/spec/cli-spec.d.ts +87 -0
- package/dist/cli/spec/cli-spec.js +478 -0
- package/dist/cli/spec/index.d.ts +4 -0
- package/dist/cli/spec/index.js +20 -0
- package/dist/index.d.ts +4 -1
- package/dist/index.js +100 -7
- package/dist/memory/auto-memory.d.ts +136 -0
- package/dist/memory/auto-memory.js +301 -0
- package/dist/memory/file-memory.d.ts +88 -0
- package/dist/memory/file-memory.js +287 -0
- package/dist/memory/index.d.ts +2 -0
- package/dist/memory/index.js +11 -1
- package/dist/workflows/loop.d.ts +0 -0
- package/dist/workflows/loop.js +1 -0
- package/package.json +1 -1
|
@@ -0,0 +1,298 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Agent Scheduler - Cron-like scheduling for agent tasks
|
|
4
|
+
*/
|
|
5
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
6
|
+
exports.cronExpressions = exports.Scheduler = void 0;
|
|
7
|
+
exports.createScheduler = createScheduler;
|
|
8
|
+
/**
|
|
9
|
+
* Parse cron expression (simplified: minute hour day month weekday)
|
|
10
|
+
*/
|
|
11
|
+
function parseCron(cron) {
|
|
12
|
+
const parts = cron.split(/\s+/);
|
|
13
|
+
if (parts.length !== 5) {
|
|
14
|
+
throw new Error('Invalid cron expression. Expected: minute hour day month weekday');
|
|
15
|
+
}
|
|
16
|
+
const parseField = (field, min, max) => {
|
|
17
|
+
if (field === '*') {
|
|
18
|
+
return Array.from({ length: max - min + 1 }, (_, i) => min + i);
|
|
19
|
+
}
|
|
20
|
+
if (field.includes('/')) {
|
|
21
|
+
const [, step] = field.split('/');
|
|
22
|
+
const stepNum = parseInt(step);
|
|
23
|
+
return Array.from({ length: Math.ceil((max - min + 1) / stepNum) }, (_, i) => min + i * stepNum);
|
|
24
|
+
}
|
|
25
|
+
if (field.includes(',')) {
|
|
26
|
+
return field.split(',').map(n => parseInt(n));
|
|
27
|
+
}
|
|
28
|
+
if (field.includes('-')) {
|
|
29
|
+
const [start, end] = field.split('-').map(n => parseInt(n));
|
|
30
|
+
return Array.from({ length: end - start + 1 }, (_, i) => start + i);
|
|
31
|
+
}
|
|
32
|
+
return [parseInt(field)];
|
|
33
|
+
};
|
|
34
|
+
return {
|
|
35
|
+
minute: parseField(parts[0], 0, 59),
|
|
36
|
+
hour: parseField(parts[1], 0, 23),
|
|
37
|
+
day: parseField(parts[2], 1, 31),
|
|
38
|
+
month: parseField(parts[3], 1, 12),
|
|
39
|
+
weekday: parseField(parts[4], 0, 6)
|
|
40
|
+
};
|
|
41
|
+
}
|
|
42
|
+
/**
|
|
43
|
+
* Get next run time from cron expression
|
|
44
|
+
*/
|
|
45
|
+
function getNextCronRun(cron, from = new Date()) {
|
|
46
|
+
const parsed = parseCron(cron);
|
|
47
|
+
const next = new Date(from);
|
|
48
|
+
next.setSeconds(0);
|
|
49
|
+
next.setMilliseconds(0);
|
|
50
|
+
next.setMinutes(next.getMinutes() + 1);
|
|
51
|
+
for (let i = 0; i < 366 * 24 * 60; i++) { // Max 1 year search
|
|
52
|
+
const minute = next.getMinutes();
|
|
53
|
+
const hour = next.getHours();
|
|
54
|
+
const day = next.getDate();
|
|
55
|
+
const month = next.getMonth() + 1;
|
|
56
|
+
const weekday = next.getDay();
|
|
57
|
+
if (parsed.minute.includes(minute) &&
|
|
58
|
+
parsed.hour.includes(hour) &&
|
|
59
|
+
parsed.day.includes(day) &&
|
|
60
|
+
parsed.month.includes(month) &&
|
|
61
|
+
parsed.weekday.includes(weekday)) {
|
|
62
|
+
return next;
|
|
63
|
+
}
|
|
64
|
+
next.setMinutes(next.getMinutes() + 1);
|
|
65
|
+
}
|
|
66
|
+
throw new Error('Could not find next run time');
|
|
67
|
+
}
|
|
68
|
+
/**
|
|
69
|
+
* Scheduler class
|
|
70
|
+
*/
|
|
71
|
+
class Scheduler {
|
|
72
|
+
constructor() {
|
|
73
|
+
this.tasks = new Map();
|
|
74
|
+
this.running = false;
|
|
75
|
+
this.stats = {
|
|
76
|
+
totalTasks: 0,
|
|
77
|
+
activeTasks: 0,
|
|
78
|
+
totalRuns: 0,
|
|
79
|
+
errors: 0
|
|
80
|
+
};
|
|
81
|
+
}
|
|
82
|
+
/**
|
|
83
|
+
* Add a scheduled task
|
|
84
|
+
*/
|
|
85
|
+
add(config) {
|
|
86
|
+
const id = config.id || `task_${Date.now()}_${Math.random().toString(36).substr(2, 9)}`;
|
|
87
|
+
const task = {
|
|
88
|
+
id,
|
|
89
|
+
name: config.name,
|
|
90
|
+
cron: config.cron,
|
|
91
|
+
interval: config.interval,
|
|
92
|
+
enabled: config.enabled ?? true,
|
|
93
|
+
runCount: 0,
|
|
94
|
+
maxRuns: config.maxRuns,
|
|
95
|
+
status: 'idle'
|
|
96
|
+
};
|
|
97
|
+
if (config.cron) {
|
|
98
|
+
task.nextRun = getNextCronRun(config.cron);
|
|
99
|
+
}
|
|
100
|
+
else if (config.interval) {
|
|
101
|
+
task.nextRun = new Date(Date.now() + config.interval);
|
|
102
|
+
}
|
|
103
|
+
this.tasks.set(id, { config, task });
|
|
104
|
+
this.stats.totalTasks++;
|
|
105
|
+
if (this.running && task.enabled) {
|
|
106
|
+
this.scheduleTask(id);
|
|
107
|
+
}
|
|
108
|
+
return id;
|
|
109
|
+
}
|
|
110
|
+
/**
|
|
111
|
+
* Remove a task
|
|
112
|
+
*/
|
|
113
|
+
remove(id) {
|
|
114
|
+
const entry = this.tasks.get(id);
|
|
115
|
+
if (!entry)
|
|
116
|
+
return false;
|
|
117
|
+
if (entry.timer) {
|
|
118
|
+
clearTimeout(entry.timer);
|
|
119
|
+
}
|
|
120
|
+
this.tasks.delete(id);
|
|
121
|
+
this.stats.totalTasks--;
|
|
122
|
+
return true;
|
|
123
|
+
}
|
|
124
|
+
/**
|
|
125
|
+
* Enable a task
|
|
126
|
+
*/
|
|
127
|
+
enable(id) {
|
|
128
|
+
const entry = this.tasks.get(id);
|
|
129
|
+
if (!entry)
|
|
130
|
+
return false;
|
|
131
|
+
entry.task.enabled = true;
|
|
132
|
+
if (this.running) {
|
|
133
|
+
this.scheduleTask(id);
|
|
134
|
+
}
|
|
135
|
+
return true;
|
|
136
|
+
}
|
|
137
|
+
/**
|
|
138
|
+
* Disable a task
|
|
139
|
+
*/
|
|
140
|
+
disable(id) {
|
|
141
|
+
const entry = this.tasks.get(id);
|
|
142
|
+
if (!entry)
|
|
143
|
+
return false;
|
|
144
|
+
entry.task.enabled = false;
|
|
145
|
+
if (entry.timer) {
|
|
146
|
+
clearTimeout(entry.timer);
|
|
147
|
+
entry.timer = undefined;
|
|
148
|
+
}
|
|
149
|
+
return true;
|
|
150
|
+
}
|
|
151
|
+
/**
|
|
152
|
+
* Start the scheduler
|
|
153
|
+
*/
|
|
154
|
+
start() {
|
|
155
|
+
if (this.running)
|
|
156
|
+
return;
|
|
157
|
+
this.running = true;
|
|
158
|
+
for (const [id, entry] of this.tasks) {
|
|
159
|
+
if (entry.task.enabled) {
|
|
160
|
+
this.scheduleTask(id);
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
}
|
|
164
|
+
/**
|
|
165
|
+
* Stop the scheduler
|
|
166
|
+
*/
|
|
167
|
+
stop() {
|
|
168
|
+
this.running = false;
|
|
169
|
+
for (const entry of this.tasks.values()) {
|
|
170
|
+
if (entry.timer) {
|
|
171
|
+
clearTimeout(entry.timer);
|
|
172
|
+
entry.timer = undefined;
|
|
173
|
+
}
|
|
174
|
+
}
|
|
175
|
+
}
|
|
176
|
+
/**
|
|
177
|
+
* Schedule a task's next run
|
|
178
|
+
*/
|
|
179
|
+
scheduleTask(id) {
|
|
180
|
+
const entry = this.tasks.get(id);
|
|
181
|
+
if (!entry || !entry.task.enabled || !this.running)
|
|
182
|
+
return;
|
|
183
|
+
// Check if max runs reached
|
|
184
|
+
if (entry.task.maxRuns && entry.task.runCount >= entry.task.maxRuns) {
|
|
185
|
+
entry.task.status = 'completed';
|
|
186
|
+
return;
|
|
187
|
+
}
|
|
188
|
+
let delay;
|
|
189
|
+
if (entry.config.cron) {
|
|
190
|
+
const nextRun = getNextCronRun(entry.config.cron);
|
|
191
|
+
entry.task.nextRun = nextRun;
|
|
192
|
+
delay = nextRun.getTime() - Date.now();
|
|
193
|
+
}
|
|
194
|
+
else if (entry.config.interval) {
|
|
195
|
+
entry.task.nextRun = new Date(Date.now() + entry.config.interval);
|
|
196
|
+
delay = entry.config.interval;
|
|
197
|
+
}
|
|
198
|
+
else {
|
|
199
|
+
return;
|
|
200
|
+
}
|
|
201
|
+
entry.timer = setTimeout(() => this.runTask(id), delay);
|
|
202
|
+
this.stats.activeTasks = Array.from(this.tasks.values()).filter(e => e.timer).length;
|
|
203
|
+
}
|
|
204
|
+
/**
|
|
205
|
+
* Run a task
|
|
206
|
+
*/
|
|
207
|
+
async runTask(id) {
|
|
208
|
+
const entry = this.tasks.get(id);
|
|
209
|
+
if (!entry)
|
|
210
|
+
return;
|
|
211
|
+
entry.task.status = 'running';
|
|
212
|
+
entry.task.lastRun = new Date();
|
|
213
|
+
try {
|
|
214
|
+
const result = await entry.config.task();
|
|
215
|
+
entry.task.runCount++;
|
|
216
|
+
entry.task.status = 'idle';
|
|
217
|
+
entry.task.lastError = undefined;
|
|
218
|
+
this.stats.totalRuns++;
|
|
219
|
+
entry.config.onComplete?.(result);
|
|
220
|
+
}
|
|
221
|
+
catch (error) {
|
|
222
|
+
entry.task.status = 'error';
|
|
223
|
+
entry.task.lastError = error.message;
|
|
224
|
+
this.stats.errors++;
|
|
225
|
+
entry.config.onError?.(error);
|
|
226
|
+
}
|
|
227
|
+
// Schedule next run
|
|
228
|
+
this.scheduleTask(id);
|
|
229
|
+
}
|
|
230
|
+
/**
|
|
231
|
+
* Run a task immediately
|
|
232
|
+
*/
|
|
233
|
+
async runNow(id) {
|
|
234
|
+
const entry = this.tasks.get(id);
|
|
235
|
+
if (!entry)
|
|
236
|
+
throw new Error(`Task ${id} not found`);
|
|
237
|
+
entry.task.status = 'running';
|
|
238
|
+
entry.task.lastRun = new Date();
|
|
239
|
+
try {
|
|
240
|
+
const result = await entry.config.task();
|
|
241
|
+
entry.task.runCount++;
|
|
242
|
+
entry.task.status = 'idle';
|
|
243
|
+
this.stats.totalRuns++;
|
|
244
|
+
return result;
|
|
245
|
+
}
|
|
246
|
+
catch (error) {
|
|
247
|
+
entry.task.status = 'error';
|
|
248
|
+
entry.task.lastError = error.message;
|
|
249
|
+
this.stats.errors++;
|
|
250
|
+
throw error;
|
|
251
|
+
}
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Get task info
|
|
255
|
+
*/
|
|
256
|
+
getTask(id) {
|
|
257
|
+
return this.tasks.get(id)?.task;
|
|
258
|
+
}
|
|
259
|
+
/**
|
|
260
|
+
* Get all tasks
|
|
261
|
+
*/
|
|
262
|
+
getAllTasks() {
|
|
263
|
+
return Array.from(this.tasks.values()).map(e => e.task);
|
|
264
|
+
}
|
|
265
|
+
/**
|
|
266
|
+
* Get scheduler stats
|
|
267
|
+
*/
|
|
268
|
+
getStats() {
|
|
269
|
+
return { ...this.stats };
|
|
270
|
+
}
|
|
271
|
+
/**
|
|
272
|
+
* Check if scheduler is running
|
|
273
|
+
*/
|
|
274
|
+
isRunning() {
|
|
275
|
+
return this.running;
|
|
276
|
+
}
|
|
277
|
+
}
|
|
278
|
+
exports.Scheduler = Scheduler;
|
|
279
|
+
/**
|
|
280
|
+
* Create a scheduler instance
|
|
281
|
+
*/
|
|
282
|
+
function createScheduler() {
|
|
283
|
+
return new Scheduler();
|
|
284
|
+
}
|
|
285
|
+
/**
|
|
286
|
+
* Helper to create common cron expressions
|
|
287
|
+
*/
|
|
288
|
+
exports.cronExpressions = {
|
|
289
|
+
everyMinute: '* * * * *',
|
|
290
|
+
every5Minutes: '*/5 * * * *',
|
|
291
|
+
every15Minutes: '*/15 * * * *',
|
|
292
|
+
everyHour: '0 * * * *',
|
|
293
|
+
everyDay: '0 0 * * *',
|
|
294
|
+
everyWeek: '0 0 * * 0',
|
|
295
|
+
everyMonth: '0 0 1 * *',
|
|
296
|
+
weekdays: '0 9 * * 1-5',
|
|
297
|
+
weekends: '0 10 * * 0,6'
|
|
298
|
+
};
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Slash Commands - Interactive command system for CLI
|
|
3
|
+
* Supports /help, /cost, /clear, /model, /tokens, /plan, /undo, /diff, /commit, /exit, /settings, /map
|
|
4
|
+
*/
|
|
5
|
+
export interface SlashCommand {
|
|
6
|
+
name: string;
|
|
7
|
+
aliases?: string[];
|
|
8
|
+
description: string;
|
|
9
|
+
usage?: string;
|
|
10
|
+
execute: (args: string[], context: SlashCommandContext) => Promise<SlashCommandResult>;
|
|
11
|
+
}
|
|
12
|
+
export interface SlashCommandContext {
|
|
13
|
+
sessionId?: string;
|
|
14
|
+
model?: string;
|
|
15
|
+
tokenCount?: number;
|
|
16
|
+
costTracker?: CostTracker;
|
|
17
|
+
history?: string[];
|
|
18
|
+
settings?: Record<string, any>;
|
|
19
|
+
onOutput?: (message: string) => void;
|
|
20
|
+
}
|
|
21
|
+
export interface SlashCommandResult {
|
|
22
|
+
success: boolean;
|
|
23
|
+
message?: string;
|
|
24
|
+
data?: any;
|
|
25
|
+
shouldExit?: boolean;
|
|
26
|
+
}
|
|
27
|
+
export interface CostTracker {
|
|
28
|
+
totalTokens: number;
|
|
29
|
+
totalCost: number;
|
|
30
|
+
requests: number;
|
|
31
|
+
addUsage(model: string, inputTokens: number, outputTokens: number, latencyMs?: number): any;
|
|
32
|
+
reset(): void;
|
|
33
|
+
getSummary(): string;
|
|
34
|
+
}
|
|
35
|
+
/**
|
|
36
|
+
* Slash Command Registry
|
|
37
|
+
*/
|
|
38
|
+
declare class SlashCommandRegistry {
|
|
39
|
+
private commands;
|
|
40
|
+
private aliases;
|
|
41
|
+
constructor();
|
|
42
|
+
register(command: SlashCommand): void;
|
|
43
|
+
get(name: string): SlashCommand | undefined;
|
|
44
|
+
getAll(): SlashCommand[];
|
|
45
|
+
has(name: string): boolean;
|
|
46
|
+
}
|
|
47
|
+
export declare function getRegistry(): SlashCommandRegistry;
|
|
48
|
+
export declare function registerCommand(command: SlashCommand): void;
|
|
49
|
+
/**
|
|
50
|
+
* Parse slash command from input
|
|
51
|
+
*/
|
|
52
|
+
export declare function parseSlashCommand(input: string): {
|
|
53
|
+
command: string;
|
|
54
|
+
args: string[];
|
|
55
|
+
} | null;
|
|
56
|
+
/**
|
|
57
|
+
* Execute a slash command
|
|
58
|
+
*/
|
|
59
|
+
export declare function executeSlashCommand(input: string, context: SlashCommandContext): Promise<SlashCommandResult>;
|
|
60
|
+
/**
|
|
61
|
+
* Check if input is a slash command
|
|
62
|
+
*/
|
|
63
|
+
export declare function isSlashCommand(input: string): boolean;
|
|
64
|
+
/**
|
|
65
|
+
* Slash Command Handler for CLI integration
|
|
66
|
+
*/
|
|
67
|
+
export declare class SlashCommandHandler {
|
|
68
|
+
private context;
|
|
69
|
+
constructor(initialContext?: Partial<SlashCommandContext>);
|
|
70
|
+
handle(input: string): Promise<SlashCommandResult>;
|
|
71
|
+
isCommand(input: string): boolean;
|
|
72
|
+
getContext(): SlashCommandContext;
|
|
73
|
+
updateContext(updates: Partial<SlashCommandContext>): void;
|
|
74
|
+
registerCommand(command: SlashCommand): void;
|
|
75
|
+
}
|
|
76
|
+
export declare function createSlashCommandHandler(context?: Partial<SlashCommandContext>): SlashCommandHandler;
|
|
77
|
+
export {};
|
|
@@ -0,0 +1,316 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
/**
|
|
3
|
+
* Slash Commands - Interactive command system for CLI
|
|
4
|
+
* Supports /help, /cost, /clear, /model, /tokens, /plan, /undo, /diff, /commit, /exit, /settings, /map
|
|
5
|
+
*/
|
|
6
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
7
|
+
exports.SlashCommandHandler = void 0;
|
|
8
|
+
exports.getRegistry = getRegistry;
|
|
9
|
+
exports.registerCommand = registerCommand;
|
|
10
|
+
exports.parseSlashCommand = parseSlashCommand;
|
|
11
|
+
exports.executeSlashCommand = executeSlashCommand;
|
|
12
|
+
exports.isSlashCommand = isSlashCommand;
|
|
13
|
+
exports.createSlashCommandHandler = createSlashCommandHandler;
|
|
14
|
+
/**
|
|
15
|
+
* Built-in slash commands
|
|
16
|
+
*/
|
|
17
|
+
const BUILTIN_COMMANDS = [
|
|
18
|
+
{
|
|
19
|
+
name: 'help',
|
|
20
|
+
aliases: ['h', '?'],
|
|
21
|
+
description: 'Show available commands',
|
|
22
|
+
execute: async (_args, context) => {
|
|
23
|
+
const commands = getRegistry().getAll();
|
|
24
|
+
const lines = ['Available commands:', ''];
|
|
25
|
+
for (const cmd of commands) {
|
|
26
|
+
const aliases = cmd.aliases ? ` (${cmd.aliases.map(a => '/' + a).join(', ')})` : '';
|
|
27
|
+
lines.push(` /${cmd.name}${aliases} - ${cmd.description}`);
|
|
28
|
+
if (cmd.usage) {
|
|
29
|
+
lines.push(` Usage: ${cmd.usage}`);
|
|
30
|
+
}
|
|
31
|
+
}
|
|
32
|
+
context.onOutput?.(lines.join('\n'));
|
|
33
|
+
return { success: true, message: lines.join('\n') };
|
|
34
|
+
}
|
|
35
|
+
},
|
|
36
|
+
{
|
|
37
|
+
name: 'cost',
|
|
38
|
+
aliases: ['c'],
|
|
39
|
+
description: 'Show token usage and cost',
|
|
40
|
+
execute: async (_args, context) => {
|
|
41
|
+
if (!context.costTracker) {
|
|
42
|
+
return { success: false, message: 'Cost tracking not enabled' };
|
|
43
|
+
}
|
|
44
|
+
const summary = context.costTracker.getSummary();
|
|
45
|
+
context.onOutput?.(summary);
|
|
46
|
+
return { success: true, message: summary };
|
|
47
|
+
}
|
|
48
|
+
},
|
|
49
|
+
{
|
|
50
|
+
name: 'clear',
|
|
51
|
+
description: 'Clear conversation history',
|
|
52
|
+
execute: async (_args, context) => {
|
|
53
|
+
if (context.history) {
|
|
54
|
+
context.history.length = 0;
|
|
55
|
+
}
|
|
56
|
+
context.onOutput?.('Conversation cleared');
|
|
57
|
+
return { success: true, message: 'Conversation cleared' };
|
|
58
|
+
}
|
|
59
|
+
},
|
|
60
|
+
{
|
|
61
|
+
name: 'model',
|
|
62
|
+
aliases: ['m'],
|
|
63
|
+
description: 'Show or change the current model',
|
|
64
|
+
usage: '/model [model-name]',
|
|
65
|
+
execute: async (args, context) => {
|
|
66
|
+
if (args.length === 0) {
|
|
67
|
+
const msg = `Current model: ${context.model || 'default'}`;
|
|
68
|
+
context.onOutput?.(msg);
|
|
69
|
+
return { success: true, message: msg, data: { model: context.model } };
|
|
70
|
+
}
|
|
71
|
+
const newModel = args[0];
|
|
72
|
+
context.model = newModel;
|
|
73
|
+
const msg = `Model changed to: ${newModel}`;
|
|
74
|
+
context.onOutput?.(msg);
|
|
75
|
+
return { success: true, message: msg, data: { model: newModel } };
|
|
76
|
+
}
|
|
77
|
+
},
|
|
78
|
+
{
|
|
79
|
+
name: 'tokens',
|
|
80
|
+
aliases: ['t'],
|
|
81
|
+
description: 'Show token count for current session',
|
|
82
|
+
execute: async (_args, context) => {
|
|
83
|
+
const count = context.tokenCount || 0;
|
|
84
|
+
const msg = `Token count: ${count}`;
|
|
85
|
+
context.onOutput?.(msg);
|
|
86
|
+
return { success: true, message: msg, data: { tokens: count } };
|
|
87
|
+
}
|
|
88
|
+
},
|
|
89
|
+
{
|
|
90
|
+
name: 'plan',
|
|
91
|
+
aliases: ['p'],
|
|
92
|
+
description: 'Show or manage task plan',
|
|
93
|
+
usage: '/plan [add|remove|clear] [task]',
|
|
94
|
+
execute: async (args, context) => {
|
|
95
|
+
const plans = context.settings?.plans || [];
|
|
96
|
+
if (args.length === 0) {
|
|
97
|
+
if (plans.length === 0) {
|
|
98
|
+
context.onOutput?.('No plans set');
|
|
99
|
+
return { success: true, message: 'No plans set' };
|
|
100
|
+
}
|
|
101
|
+
const msg = ['Current plan:', ...plans.map((p, i) => ` ${i + 1}. ${p}`)].join('\n');
|
|
102
|
+
context.onOutput?.(msg);
|
|
103
|
+
return { success: true, message: msg, data: { plans } };
|
|
104
|
+
}
|
|
105
|
+
const action = args[0];
|
|
106
|
+
const task = args.slice(1).join(' ');
|
|
107
|
+
if (action === 'add' && task) {
|
|
108
|
+
plans.push(task);
|
|
109
|
+
context.settings = { ...context.settings, plans };
|
|
110
|
+
context.onOutput?.(`Added: ${task}`);
|
|
111
|
+
return { success: true, message: `Added: ${task}` };
|
|
112
|
+
}
|
|
113
|
+
if (action === 'remove' && task) {
|
|
114
|
+
const index = parseInt(task) - 1;
|
|
115
|
+
if (index >= 0 && index < plans.length) {
|
|
116
|
+
const removed = plans.splice(index, 1)[0];
|
|
117
|
+
context.settings = { ...context.settings, plans };
|
|
118
|
+
context.onOutput?.(`Removed: ${removed}`);
|
|
119
|
+
return { success: true, message: `Removed: ${removed}` };
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
if (action === 'clear') {
|
|
123
|
+
context.settings = { ...context.settings, plans: [] };
|
|
124
|
+
context.onOutput?.('Plans cleared');
|
|
125
|
+
return { success: true, message: 'Plans cleared' };
|
|
126
|
+
}
|
|
127
|
+
return { success: false, message: 'Invalid plan command' };
|
|
128
|
+
}
|
|
129
|
+
},
|
|
130
|
+
{
|
|
131
|
+
name: 'undo',
|
|
132
|
+
aliases: ['u'],
|
|
133
|
+
description: 'Undo last action',
|
|
134
|
+
execute: async (_args, context) => {
|
|
135
|
+
if (context.history && context.history.length > 0) {
|
|
136
|
+
const removed = context.history.pop();
|
|
137
|
+
context.onOutput?.(`Undone: ${removed?.substring(0, 50)}...`);
|
|
138
|
+
return { success: true, message: 'Last action undone' };
|
|
139
|
+
}
|
|
140
|
+
return { success: false, message: 'Nothing to undo' };
|
|
141
|
+
}
|
|
142
|
+
},
|
|
143
|
+
{
|
|
144
|
+
name: 'diff',
|
|
145
|
+
aliases: ['d'],
|
|
146
|
+
description: 'Show pending changes',
|
|
147
|
+
execute: async (_args, context) => {
|
|
148
|
+
const diff = context.settings?.pendingDiff || 'No pending changes';
|
|
149
|
+
context.onOutput?.(diff);
|
|
150
|
+
return { success: true, message: diff };
|
|
151
|
+
}
|
|
152
|
+
},
|
|
153
|
+
{
|
|
154
|
+
name: 'commit',
|
|
155
|
+
description: 'Commit pending changes',
|
|
156
|
+
execute: async (args, context) => {
|
|
157
|
+
const message = args.join(' ') || 'Auto-commit';
|
|
158
|
+
context.onOutput?.(`Committed with message: ${message}`);
|
|
159
|
+
context.settings = { ...context.settings, pendingDiff: null };
|
|
160
|
+
return { success: true, message: `Committed: ${message}` };
|
|
161
|
+
}
|
|
162
|
+
},
|
|
163
|
+
{
|
|
164
|
+
name: 'exit',
|
|
165
|
+
aliases: ['quit', 'q'],
|
|
166
|
+
description: 'Exit the session',
|
|
167
|
+
execute: async (_args, context) => {
|
|
168
|
+
context.onOutput?.('Goodbye!');
|
|
169
|
+
return { success: true, message: 'Exiting', shouldExit: true };
|
|
170
|
+
}
|
|
171
|
+
},
|
|
172
|
+
{
|
|
173
|
+
name: 'settings',
|
|
174
|
+
aliases: ['s'],
|
|
175
|
+
description: 'Show or modify settings',
|
|
176
|
+
usage: '/settings [key] [value]',
|
|
177
|
+
execute: async (args, context) => {
|
|
178
|
+
if (args.length === 0) {
|
|
179
|
+
const settings = JSON.stringify(context.settings || {}, null, 2);
|
|
180
|
+
context.onOutput?.(settings);
|
|
181
|
+
return { success: true, message: settings, data: context.settings };
|
|
182
|
+
}
|
|
183
|
+
if (args.length === 1) {
|
|
184
|
+
const value = context.settings?.[args[0]];
|
|
185
|
+
const msg = `${args[0]}: ${JSON.stringify(value)}`;
|
|
186
|
+
context.onOutput?.(msg);
|
|
187
|
+
return { success: true, message: msg, data: { [args[0]]: value } };
|
|
188
|
+
}
|
|
189
|
+
const [key, ...valueParts] = args;
|
|
190
|
+
let value = valueParts.join(' ');
|
|
191
|
+
try {
|
|
192
|
+
value = JSON.parse(value);
|
|
193
|
+
}
|
|
194
|
+
catch {
|
|
195
|
+
// Keep as string
|
|
196
|
+
}
|
|
197
|
+
context.settings = { ...context.settings, [key]: value };
|
|
198
|
+
context.onOutput?.(`Set ${key} = ${JSON.stringify(value)}`);
|
|
199
|
+
return { success: true, message: `Set ${key}` };
|
|
200
|
+
}
|
|
201
|
+
},
|
|
202
|
+
{
|
|
203
|
+
name: 'map',
|
|
204
|
+
description: 'Show repository map',
|
|
205
|
+
execute: async (_args, context) => {
|
|
206
|
+
const map = context.settings?.repoMap || 'Repository map not available. Run /map refresh to generate.';
|
|
207
|
+
context.onOutput?.(map);
|
|
208
|
+
return { success: true, message: map };
|
|
209
|
+
}
|
|
210
|
+
}
|
|
211
|
+
];
|
|
212
|
+
/**
|
|
213
|
+
* Slash Command Registry
|
|
214
|
+
*/
|
|
215
|
+
class SlashCommandRegistry {
|
|
216
|
+
constructor() {
|
|
217
|
+
this.commands = new Map();
|
|
218
|
+
this.aliases = new Map();
|
|
219
|
+
// Register built-in commands
|
|
220
|
+
for (const cmd of BUILTIN_COMMANDS) {
|
|
221
|
+
this.register(cmd);
|
|
222
|
+
}
|
|
223
|
+
}
|
|
224
|
+
register(command) {
|
|
225
|
+
this.commands.set(command.name, command);
|
|
226
|
+
if (command.aliases) {
|
|
227
|
+
for (const alias of command.aliases) {
|
|
228
|
+
this.aliases.set(alias, command.name);
|
|
229
|
+
}
|
|
230
|
+
}
|
|
231
|
+
}
|
|
232
|
+
get(name) {
|
|
233
|
+
const resolved = this.aliases.get(name) || name;
|
|
234
|
+
return this.commands.get(resolved);
|
|
235
|
+
}
|
|
236
|
+
getAll() {
|
|
237
|
+
return Array.from(this.commands.values());
|
|
238
|
+
}
|
|
239
|
+
has(name) {
|
|
240
|
+
return this.commands.has(name) || this.aliases.has(name);
|
|
241
|
+
}
|
|
242
|
+
}
|
|
243
|
+
let registry = null;
|
|
244
|
+
function getRegistry() {
|
|
245
|
+
if (!registry) {
|
|
246
|
+
registry = new SlashCommandRegistry();
|
|
247
|
+
}
|
|
248
|
+
return registry;
|
|
249
|
+
}
|
|
250
|
+
function registerCommand(command) {
|
|
251
|
+
getRegistry().register(command);
|
|
252
|
+
}
|
|
253
|
+
/**
|
|
254
|
+
* Parse slash command from input
|
|
255
|
+
*/
|
|
256
|
+
function parseSlashCommand(input) {
|
|
257
|
+
const trimmed = input.trim();
|
|
258
|
+
if (!trimmed.startsWith('/')) {
|
|
259
|
+
return null;
|
|
260
|
+
}
|
|
261
|
+
const parts = trimmed.slice(1).split(/\s+/);
|
|
262
|
+
const command = parts[0].toLowerCase();
|
|
263
|
+
const args = parts.slice(1);
|
|
264
|
+
return { command, args };
|
|
265
|
+
}
|
|
266
|
+
/**
|
|
267
|
+
* Execute a slash command
|
|
268
|
+
*/
|
|
269
|
+
async function executeSlashCommand(input, context) {
|
|
270
|
+
const parsed = parseSlashCommand(input);
|
|
271
|
+
if (!parsed) {
|
|
272
|
+
return { success: false, message: 'Not a slash command' };
|
|
273
|
+
}
|
|
274
|
+
const command = getRegistry().get(parsed.command);
|
|
275
|
+
if (!command) {
|
|
276
|
+
return { success: false, message: `Unknown command: /${parsed.command}` };
|
|
277
|
+
}
|
|
278
|
+
return command.execute(parsed.args, context);
|
|
279
|
+
}
|
|
280
|
+
/**
|
|
281
|
+
* Check if input is a slash command
|
|
282
|
+
*/
|
|
283
|
+
function isSlashCommand(input) {
|
|
284
|
+
return input.trim().startsWith('/');
|
|
285
|
+
}
|
|
286
|
+
/**
|
|
287
|
+
* Slash Command Handler for CLI integration
|
|
288
|
+
*/
|
|
289
|
+
class SlashCommandHandler {
|
|
290
|
+
constructor(initialContext = {}) {
|
|
291
|
+
this.context = {
|
|
292
|
+
history: [],
|
|
293
|
+
settings: {},
|
|
294
|
+
...initialContext
|
|
295
|
+
};
|
|
296
|
+
}
|
|
297
|
+
async handle(input) {
|
|
298
|
+
return executeSlashCommand(input, this.context);
|
|
299
|
+
}
|
|
300
|
+
isCommand(input) {
|
|
301
|
+
return isSlashCommand(input);
|
|
302
|
+
}
|
|
303
|
+
getContext() {
|
|
304
|
+
return this.context;
|
|
305
|
+
}
|
|
306
|
+
updateContext(updates) {
|
|
307
|
+
this.context = { ...this.context, ...updates };
|
|
308
|
+
}
|
|
309
|
+
registerCommand(command) {
|
|
310
|
+
registerCommand(command);
|
|
311
|
+
}
|
|
312
|
+
}
|
|
313
|
+
exports.SlashCommandHandler = SlashCommandHandler;
|
|
314
|
+
function createSlashCommandHandler(context) {
|
|
315
|
+
return new SlashCommandHandler(context);
|
|
316
|
+
}
|