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/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
- await runSessionLoop(s);
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' +
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "kiosapi",
3
- "version": "0.1.27",
3
+ "version": "0.1.29",
4
4
  "type": "module",
5
5
  "description": "CLI Kiosapi.id berbahasa Indonesia — bangun aplikasimu pakai API key Kiosapi (agen + multimodal).",
6
6
  "keywords": [