kiosapi 0.1.27 → 0.1.29
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/mcp.js +205 -0
- package/dist/agent/run.js +110 -25
- package/dist/agent/skills.js +84 -0
- package/dist/agent/team.js +136 -56
- package/dist/commands.js +223 -3
- package/dist/config.js +73 -1
- package/dist/help.js +19 -0
- package/dist/index.js +4 -1
- package/dist/session.js +125 -3
- package/package.json +1 -1
package/dist/session.js
CHANGED
|
@@ -1,10 +1,12 @@
|
|
|
1
1
|
import { spawnSync } from 'node:child_process';
|
|
2
|
+
import { McpManager } from './agent/mcp.js';
|
|
2
3
|
import { clearCheckpoint, loadCheckpoint, newSession, resetSession, runTurn, undoLastTurn, } from './agent/run.js';
|
|
4
|
+
import { listSkills, loadSkill } from './agent/skills.js';
|
|
3
5
|
import { runCustomTeam, runTeam } from './agent/team.js';
|
|
4
6
|
import { expandAtMentions } from './agent/tools.js';
|
|
5
7
|
import { resolveModel, streamChat } from './api.js';
|
|
6
|
-
import { cmdGambar, cmdIsi, cmdLihat, cmdMasuk, cmdPakai, cmdPerbarui, cmdSaldo, cmdVideo, maybeNotifyUpdate, pickModel, warnIfNoTools, } from './commands.js';
|
|
7
|
-
import { listTeamConfigs, loadConfig, loadProjectConfig, loadTeamConfig, saveTeamConfig, } from './config.js';
|
|
8
|
+
import { cmdGambar, cmdIsi, cmdLihat, cmdMasuk, cmdPakai, cmdPerbarui, cmdSaldo, cmdSkill, cmdVideo, maybeNotifyUpdate, pickModel, warnIfNoTools, } from './commands.js';
|
|
9
|
+
import { clearTimCheckpoint, listTeamConfigs, loadConfig, loadMcpServers, loadProjectConfig, loadTeamConfig, loadTimCheckpoint, saveTeamConfig, } from './config.js';
|
|
8
10
|
import { bold, cyan, dim, green, idn, prompt, red, thinking, yellow } from './ui.js';
|
|
9
11
|
const MODES = ['rencana', 'edit', 'buat'];
|
|
10
12
|
/** The prompt indicator shows the active mode, turn count, accumulated tokens, and ⚡ for auto. */
|
|
@@ -23,6 +25,8 @@ ${dim('Ketik tugasmu langsung. Perintah meta diawali "/". /bantuan untuk daftar,
|
|
|
23
25
|
}
|
|
24
26
|
function slashHelp() {
|
|
25
27
|
console.log(`${bold('Perintah sesi:')}
|
|
28
|
+
/skills Lihat semua skill tersimpan
|
|
29
|
+
/skill <nama> [konteks] Jalankan skill (project atau global)
|
|
26
30
|
/tim <tugas> Multi-agen bawaan (perencana→pengkode→peninjau)
|
|
27
31
|
/tim --pakai <nama> <tugas> Jalankan tim kustom tersimpan
|
|
28
32
|
/peran [peran] [model] Atur model per peran tim (atau lihat/reset)
|
|
@@ -65,6 +69,64 @@ async function runSlash(line, s) {
|
|
|
65
69
|
case '?':
|
|
66
70
|
slashHelp();
|
|
67
71
|
return false;
|
|
72
|
+
case 'skills':
|
|
73
|
+
case 'skill-daftar': {
|
|
74
|
+
const all = listSkills();
|
|
75
|
+
if (all.length === 0) {
|
|
76
|
+
console.log(dim('Belum ada skill. Buat dengan: kiosapi skill buat <nama>'));
|
|
77
|
+
}
|
|
78
|
+
else {
|
|
79
|
+
for (const sk of all) {
|
|
80
|
+
const scopeTag = sk.source === 'project' ? '[project]' : '[global]';
|
|
81
|
+
const desc = sk.description ? ` — ${sk.description}` : '';
|
|
82
|
+
console.log(` ${cyan(sk.name)} ${dim(scopeTag)}${dim(desc)} ${dim(`[${sk.mode}]`)}`);
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return false;
|
|
86
|
+
}
|
|
87
|
+
case 'skill': {
|
|
88
|
+
const skillName = rest[0];
|
|
89
|
+
if (!skillName) {
|
|
90
|
+
// No name → show list
|
|
91
|
+
const all = listSkills();
|
|
92
|
+
if (all.length === 0) {
|
|
93
|
+
console.log(dim('Belum ada skill. Buat dengan: kiosapi skill buat <nama>'));
|
|
94
|
+
}
|
|
95
|
+
else {
|
|
96
|
+
for (const sk of all) {
|
|
97
|
+
const desc = sk.description ? dim(` — ${sk.description}`) : '';
|
|
98
|
+
console.log(` ${cyan(sk.name)}${desc} ${dim(`[${sk.mode}]`)}`);
|
|
99
|
+
}
|
|
100
|
+
}
|
|
101
|
+
return false;
|
|
102
|
+
}
|
|
103
|
+
const sk = loadSkill(skillName);
|
|
104
|
+
if (!sk) {
|
|
105
|
+
console.log(red(`Skill "${skillName}" tidak ditemukan.`));
|
|
106
|
+
console.log(dim(' Buat: kiosapi skill buat <nama> | Lihat: /skills'));
|
|
107
|
+
return false;
|
|
108
|
+
}
|
|
109
|
+
const extra = rest.slice(1).join(' ').trim();
|
|
110
|
+
const rawPrompt = extra ? `${sk.prompt}\n\n${extra}` : sk.prompt;
|
|
111
|
+
const expanded = await expandAtMentions(rawPrompt);
|
|
112
|
+
// Apply skill's model/mode/otomatis to the current session for this turn only
|
|
113
|
+
const prevModel = s.model;
|
|
114
|
+
const prevMode = s.mode;
|
|
115
|
+
const prevOto = s.otomatis;
|
|
116
|
+
if (sk.model)
|
|
117
|
+
s.model = sk.model;
|
|
118
|
+
s.mode = sk.mode;
|
|
119
|
+
if (sk.otomatis)
|
|
120
|
+
s.otomatis = true;
|
|
121
|
+
const scopeLabel = sk.source === 'project' ? dim(' [project]') : dim(' [global]');
|
|
122
|
+
console.log(`${bold(`▶ skill: ${sk.name}`)}${scopeLabel}`);
|
|
123
|
+
await runTurn(s, expanded);
|
|
124
|
+
// Restore session settings after skill run
|
|
125
|
+
s.model = prevModel;
|
|
126
|
+
s.mode = prevMode;
|
|
127
|
+
s.otomatis = prevOto;
|
|
128
|
+
return false;
|
|
129
|
+
}
|
|
68
130
|
case 'mode': {
|
|
69
131
|
const m = rest[0]?.toLowerCase();
|
|
70
132
|
if (!m) {
|
|
@@ -483,7 +545,22 @@ export async function startSession() {
|
|
|
483
545
|
}
|
|
484
546
|
banner(s);
|
|
485
547
|
await warnIfNoTools(model);
|
|
486
|
-
|
|
548
|
+
const mcpServers = loadMcpServers();
|
|
549
|
+
let mcpManager;
|
|
550
|
+
if (Object.keys(mcpServers).length > 0) {
|
|
551
|
+
mcpManager = new McpManager();
|
|
552
|
+
await mcpManager.connect(mcpServers, (w) => console.log(yellow(w)));
|
|
553
|
+
if (mcpManager.toolCount > 0) {
|
|
554
|
+
console.log(dim(` MCP: ${mcpManager.toolCount} tool dari ${mcpManager.serverCount} server`));
|
|
555
|
+
}
|
|
556
|
+
s.mcpManager = mcpManager;
|
|
557
|
+
}
|
|
558
|
+
try {
|
|
559
|
+
await runSessionLoop(s);
|
|
560
|
+
}
|
|
561
|
+
finally {
|
|
562
|
+
mcpManager?.disconnect();
|
|
563
|
+
}
|
|
487
564
|
}
|
|
488
565
|
/**
|
|
489
566
|
* Resume a checkpointed session interactively: load the saved state, show a preamble, ask for a
|
|
@@ -492,6 +569,51 @@ export async function startSession() {
|
|
|
492
569
|
*/
|
|
493
570
|
export async function resumeFromCheckpoint(args) {
|
|
494
571
|
await maybeNotifyUpdate();
|
|
572
|
+
// Tim checkpoint takes priority — it stores multi-step pipeline progress
|
|
573
|
+
const timCp = loadTimCheckpoint();
|
|
574
|
+
if (timCp) {
|
|
575
|
+
console.log(bold('Sesi tim tersimpan ditemukan'));
|
|
576
|
+
console.log(` Tugas : ${timCp.task.slice(0, 80)}${timCp.task.length > 80 ? '…' : ''}`);
|
|
577
|
+
console.log(` Progress : ${timCp.completedStepCount}/${timCp.plan.langkah.length} langkah selesai`);
|
|
578
|
+
console.log(` Disimpan : ${new Date(timCp.savedAt).toLocaleString('id-ID')}`);
|
|
579
|
+
if (timCp.completedStepCount > 0) {
|
|
580
|
+
console.log(dim(' Langkah selesai:'));
|
|
581
|
+
for (const [i, step] of timCp.plan.langkah.entries()) {
|
|
582
|
+
if (i >= timCp.completedStepCount)
|
|
583
|
+
break;
|
|
584
|
+
console.log(dim(` ✓ ${i + 1}. ${step.tugas}`));
|
|
585
|
+
}
|
|
586
|
+
}
|
|
587
|
+
const remaining = timCp.plan.langkah.length - timCp.completedStepCount;
|
|
588
|
+
console.log(`\n Sisa : ${remaining} langkah belum dikerjakan`);
|
|
589
|
+
if (timCp.cwd !== process.cwd()) {
|
|
590
|
+
console.log(yellow(`\n⚠ Sesi ini disimpan di direktori berbeda: ${timCp.cwd}`));
|
|
591
|
+
}
|
|
592
|
+
if (!loadConfig().apiKey) {
|
|
593
|
+
console.log(dim('Belum masuk — masukkan API key dulu.'));
|
|
594
|
+
await cmdMasuk();
|
|
595
|
+
if (!loadConfig().apiKey)
|
|
596
|
+
return;
|
|
597
|
+
}
|
|
598
|
+
const ans = (await prompt('Lanjutkan sesi tim ini? (y/t) ')).trim().toLowerCase();
|
|
599
|
+
if (ans === 'y' || ans === 'ya') {
|
|
600
|
+
const resume = {
|
|
601
|
+
startFromStep: timCp.completedStepCount,
|
|
602
|
+
stepResults: timCp.stepResults,
|
|
603
|
+
plan: timCp.plan,
|
|
604
|
+
};
|
|
605
|
+
await runTeam(timCp.task, { models: timCp.models, otomatis: timCp.otomatis }, resume);
|
|
606
|
+
}
|
|
607
|
+
else {
|
|
608
|
+
console.log(dim('Sesi tim dibatalkan.'));
|
|
609
|
+
const clearAns = (await prompt('Hapus checkpoint tim ini? (y/t) ')).trim().toLowerCase();
|
|
610
|
+
if (clearAns === 'y' || clearAns === 'ya') {
|
|
611
|
+
clearTimCheckpoint();
|
|
612
|
+
console.log(dim('Checkpoint tim dihapus.'));
|
|
613
|
+
}
|
|
614
|
+
}
|
|
615
|
+
return;
|
|
616
|
+
}
|
|
495
617
|
const cp = loadCheckpoint();
|
|
496
618
|
if (!cp) {
|
|
497
619
|
throw new Error('Tidak ada sesi tersimpan. Mulai dengan: kiosapi buat "tugas"\n' +
|