@pikaa-ai/pikaa 0.3.22 → 0.3.24
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/assets/brand/orbit-logo-option4-whale.jpg +0 -0
- package/assets/brand/orbit-logo.jpg +0 -0
- package/assets/brand/orbit-logo.png +0 -0
- package/assets/brand/orbit-logo.svg +3 -0
- package/dist/cli.js +448 -181
- package/dist/index.js +22 -2
- package/package.json +1 -2
- package/skills/adaptyv/SKILL.md +0 -240
- package/skills/aeon/SKILL.md +0 -402
- package/skills/analytical-method-validation/SKILL.md +0 -299
- package/skills/anndata/SKILL.md +0 -431
- package/skills/arbor/SKILL.md +0 -152
- package/skills/arboreto/SKILL.md +0 -267
- package/skills/astropy/SKILL.md +0 -353
- package/skills/autoskill/SKILL.md +0 -233
- package/skills/benchling-integration/SKILL.md +0 -229
- package/skills/bgpt-paper-search/SKILL.md +0 -75
- package/skills/bids/SKILL.md +0 -237
- package/skills/biopython/SKILL.md +0 -472
- package/skills/bioservices/SKILL.md +0 -399
- package/skills/bulk-rnaseq/SKILL.md +0 -198
- package/skills/cellxgene-census/SKILL.md +0 -283
- package/skills/cirq/SKILL.md +0 -370
- package/skills/citation-management/SKILL.md +0 -329
- package/skills/clinical-decision-support/SKILL.md +0 -238
- package/skills/clinical-decision-support/references/README.md +0 -62
- package/skills/clinical-reports/SKILL.md +0 -248
- package/skills/clinical-reports/references/README.md +0 -34
- package/skills/cobrapy/SKILL.md +0 -496
- package/skills/consciousness-council/SKILL.md +0 -151
- package/skills/dask/SKILL.md +0 -482
- package/skills/database-lookup/SKILL.md +0 -386
- package/skills/datamol/SKILL.md +0 -200
- package/skills/deepchem/SKILL.md +0 -244
- package/skills/deepspot-m/SKILL.md +0 -175
- package/skills/deeptools/SKILL.md +0 -412
- package/skills/depmap/SKILL.md +0 -301
- package/skills/dhdna-profiler/SKILL.md +0 -184
- package/skills/diffdock/SKILL.md +0 -488
- package/skills/dnanexus-integration/SKILL.md +0 -325
- package/skills/docx/SKILL.md +0 -99
- package/skills/esm/SKILL.md +0 -334
- package/skills/etetoolkit/SKILL.md +0 -327
- package/skills/exa-search/SKILL.md +0 -102
- package/skills/executing-plans/SKILL.md +0 -14
- package/skills/experimental-design/SKILL.md +0 -234
- package/skills/exploratory-data-analysis/SKILL.md +0 -280
- package/skills/flowio/SKILL.md +0 -310
- package/skills/fluidsim/SKILL.md +0 -279
- package/skills/frontend-design/SKILL.md +0 -100
- package/skills/generate-image/SKILL.md +0 -304
- package/skills/geniml/SKILL.md +0 -310
- package/skills/genomic-coordinates/SKILL.md +0 -189
- package/skills/genomic-intelligence/SKILL.md +0 -243
- package/skills/geomaster/README.md +0 -105
- package/skills/geomaster/SKILL.md +0 -366
- package/skills/geopandas/SKILL.md +0 -250
- package/skills/get-available-resources/SKILL.md +0 -260
- package/skills/gget/SKILL.md +0 -153
- package/skills/ginkgo-cloud-lab/SKILL.md +0 -106
- package/skills/glycoengineering/SKILL.md +0 -339
- package/skills/gtars/SKILL.md +0 -282
- package/skills/guardian-rails/SKILL.md +0 -54
- package/skills/histolab/SKILL.md +0 -243
- package/skills/hugging-science/SKILL.md +0 -132
- package/skills/hypogenic/SKILL.md +0 -290
- package/skills/hypothesis-generation/SKILL.md +0 -264
- package/skills/imaging-data-commons/SKILL.md +0 -496
- package/skills/infographics/SKILL.md +0 -315
- package/skills/iso-standards-readiness/SKILL.md +0 -352
- package/skills/lab-hardware-cad/SKILL.md +0 -372
- package/skills/labarchive-integration/SKILL.md +0 -216
- package/skills/lamindb/SKILL.md +0 -408
- package/skills/latchbio-integration/SKILL.md +0 -227
- package/skills/latex-posters/SKILL.md +0 -369
- package/skills/latex-posters/references/README.md +0 -439
- package/skills/liteparse/SKILL.md +0 -295
- package/skills/literature-review/SKILL.md +0 -263
- package/skills/markdown-mermaid-writing/SKILL.md +0 -322
- package/skills/market-research-reports/SKILL.md +0 -337
- package/skills/markitdown/SKILL.md +0 -264
- package/skills/matchms/SKILL.md +0 -276
- package/skills/matlab/SKILL.md +0 -274
- package/skills/matplotlib/SKILL.md +0 -378
- package/skills/medchem/SKILL.md +0 -321
- package/skills/modal/SKILL.md +0 -468
- package/skills/molecular-dynamics/SKILL.md +0 -458
- package/skills/molfeat/SKILL.md +0 -348
- package/skills/ncats-arax/SKILL.md +0 -178
- package/skills/networkx/SKILL.md +0 -440
- package/skills/neurokit2/SKILL.md +0 -323
- package/skills/neuropixels-analysis/SKILL.md +0 -412
- package/skills/nextflow/SKILL.md +0 -195
- package/skills/omero-integration/SKILL.md +0 -222
- package/skills/onekgpd/SKILL.md +0 -371
- package/skills/ontology-term-resolution/SKILL.md +0 -147
- package/skills/open-notebook/SKILL.md +0 -297
- package/skills/openpiv/SKILL.md +0 -469
- package/skills/opentrons-integration/SKILL.md +0 -322
- package/skills/optimize-for-gpu/SKILL.md +0 -176
- package/skills/owasp-top10/SKILL.md +0 -48
- package/skills/pacsomatic/LICENSE +0 -21
- package/skills/pacsomatic/SKILL.md +0 -150
- package/skills/paper-lookup/SKILL.md +0 -263
- package/skills/paperclip/SKILL.md +0 -413
- package/skills/paperzilla/SKILL.md +0 -159
- package/skills/parallel-web/SKILL.md +0 -128
- package/skills/pathml/SKILL.md +0 -222
- package/skills/pathogen-variant-surveillance/SKILL.md +0 -208
- package/skills/pathway-enrichment/SKILL.md +0 -194
- package/skills/pdf/SKILL.md +0 -322
- package/skills/peer-review/SKILL.md +0 -288
- package/skills/penetration-testing/SKILL.md +0 -31
- package/skills/pennylane/SKILL.md +0 -240
- package/skills/phylogenetics/SKILL.md +0 -409
- package/skills/pi-agent/SKILL.md +0 -83
- package/skills/pkpd-modeling/SKILL.md +0 -381
- package/skills/polars/SKILL.md +0 -393
- package/skills/polars-bio/SKILL.md +0 -379
- package/skills/ponytail/SKILL.md +0 -31
- package/skills/ponytail-audit/SKILL.md +0 -18
- package/skills/pptx/SKILL.md +0 -246
- package/skills/pptx-posters/SKILL.md +0 -258
- package/skills/primekg/SKILL.md +0 -99
- package/skills/protocolsio-integration/SKILL.md +0 -236
- package/skills/pufferlib/SKILL.md +0 -328
- package/skills/pydeseq2/SKILL.md +0 -369
- package/skills/pydicom/SKILL.md +0 -381
- package/skills/pyhealth/SKILL.md +0 -124
- package/skills/pylabrobot/SKILL.md +0 -216
- package/skills/pymatgen/SKILL.md +0 -404
- package/skills/pymc/SKILL.md +0 -310
- package/skills/pymoo/SKILL.md +0 -276
- package/skills/pyopenms/SKILL.md +0 -179
- package/skills/pysam/SKILL.md +0 -330
- package/skills/pytdc/SKILL.md +0 -297
- package/skills/pytorch-lightning/SKILL.md +0 -191
- package/skills/pyzotero/SKILL.md +0 -137
- package/skills/qiskit/SKILL.md +0 -259
- package/skills/qutip/SKILL.md +0 -317
- package/skills/rdkit/SKILL.md +0 -94
- package/skills/relsa-severity-assessment/SKILL.md +0 -354
- package/skills/research-grants/SKILL.md +0 -296
- package/skills/research-grants/references/README.md +0 -287
- package/skills/research-lookup/README.md +0 -106
- package/skills/research-lookup/SKILL.md +0 -338
- package/skills/rowan/SKILL.md +0 -398
- package/skills/scanpy/SKILL.md +0 -303
- package/skills/scholar-evaluation/SKILL.md +0 -296
- package/skills/scientific-brainstorming/SKILL.md +0 -282
- package/skills/scientific-critical-thinking/SKILL.md +0 -180
- package/skills/scientific-schematics/SKILL.md +0 -370
- package/skills/scientific-slides/SKILL.md +0 -379
- package/skills/scientific-visualization/SKILL.md +0 -285
- package/skills/scientific-writing/SKILL.md +0 -356
- package/skills/scikit-bio/SKILL.md +0 -470
- package/skills/scikit-learn/SKILL.md +0 -324
- package/skills/scikit-survival/SKILL.md +0 -313
- package/skills/scvelo/SKILL.md +0 -328
- package/skills/scvi-tools/SKILL.md +0 -201
- package/skills/seaborn/SKILL.md +0 -254
- package/skills/security-auditor/SKILL.md +0 -37
- package/skills/shap/SKILL.md +0 -282
- package/skills/simpy/SKILL.md +0 -283
- package/skills/stable-baselines3/SKILL.md +0 -325
- package/skills/statistical-analysis/SKILL.md +0 -446
- package/skills/statistical-power/SKILL.md +0 -200
- package/skills/statsmodels/SKILL.md +0 -238
- package/skills/sympy/SKILL.md +0 -354
- package/skills/systematic-debugging/SKILL.md +0 -35
- package/skills/tamarind/SKILL.md +0 -285
- package/skills/tdd/SKILL.md +0 -26
- package/skills/tiledbvcf/SKILL.md +0 -456
- package/skills/timesfm-forecasting/SKILL.md +0 -408
- package/skills/timesfm-forecasting/examples/global-temperature/README.md +0 -178
- package/skills/torch-geometric/SKILL.md +0 -458
- package/skills/torchdrug/SKILL.md +0 -241
- package/skills/transformers/SKILL.md +0 -195
- package/skills/treatment-plans/SKILL.md +0 -174
- package/skills/treatment-plans/references/README.md +0 -19
- package/skills/umap-learn/SKILL.md +0 -488
- package/skills/uncertainty-and-units/SKILL.md +0 -384
- package/skills/usfiscaldata/SKILL.md +0 -171
- package/skills/vaex/SKILL.md +0 -204
- package/skills/venue-templates/SKILL.md +0 -269
- package/skills/verification-before-completion/SKILL.md +0 -22
- package/skills/waypoint-bio/SKILL.md +0 -273
- package/skills/what-if-oracle/SKILL.md +0 -184
- package/skills/writing-plans/SKILL.md +0 -15
- package/skills/xlsx/SKILL.md +0 -110
- package/skills/zarr-python/SKILL.md +0 -241
package/dist/cli.js
CHANGED
|
@@ -2,8 +2,8 @@
|
|
|
2
2
|
// @bun
|
|
3
3
|
|
|
4
4
|
// src/cli/index.ts
|
|
5
|
-
import { resolve as
|
|
6
|
-
import { existsSync as
|
|
5
|
+
import { resolve as resolve22 } from "path";
|
|
6
|
+
import { existsSync as existsSync24 } from "fs";
|
|
7
7
|
import { createInterface } from "readline";
|
|
8
8
|
|
|
9
9
|
// src/auth/store.ts
|
|
@@ -5228,6 +5228,27 @@ class SessionPersistenceManager {
|
|
|
5228
5228
|
return null;
|
|
5229
5229
|
}
|
|
5230
5230
|
}
|
|
5231
|
+
unbindSession() {
|
|
5232
|
+
for (const unsub of this.unsubscribers) {
|
|
5233
|
+
try {
|
|
5234
|
+
unsub();
|
|
5235
|
+
} catch {}
|
|
5236
|
+
}
|
|
5237
|
+
this.unsubscribers = [];
|
|
5238
|
+
}
|
|
5239
|
+
resumeIntoSession(session, threadId) {
|
|
5240
|
+
const restored = this.loadSession(threadId);
|
|
5241
|
+
if (!restored)
|
|
5242
|
+
return null;
|
|
5243
|
+
this.unbindSession();
|
|
5244
|
+
session.threadId = restored.thread.id;
|
|
5245
|
+
session.setHistory(restored.items);
|
|
5246
|
+
if (restored.thread.model) {
|
|
5247
|
+
session.model = restored.thread.model;
|
|
5248
|
+
}
|
|
5249
|
+
this.bindSession(session, restored.thread.role);
|
|
5250
|
+
return restored;
|
|
5251
|
+
}
|
|
5231
5252
|
listSessions(options) {
|
|
5232
5253
|
return this.store.listThreads(options);
|
|
5233
5254
|
}
|
|
@@ -5248,7 +5269,6 @@ class SessionPersistenceManager {
|
|
|
5248
5269
|
// src/skills/loader.ts
|
|
5249
5270
|
import { existsSync as existsSync16, readdirSync as readdirSync6, readFileSync as readFileSync9 } from "fs";
|
|
5250
5271
|
import { resolve as resolve13, join as join8 } from "path";
|
|
5251
|
-
import { homedir as homedir3 } from "os";
|
|
5252
5272
|
var __dirname = "/home/runner/work/agent-cli/agent-cli/src/skills";
|
|
5253
5273
|
|
|
5254
5274
|
class SkillsLoader {
|
|
@@ -5324,7 +5344,7 @@ class SkillsLoader {
|
|
|
5324
5344
|
}
|
|
5325
5345
|
}
|
|
5326
5346
|
if (this.includeGlobal) {
|
|
5327
|
-
roots.push(getGlobalSkillsDir()
|
|
5347
|
+
roots.push(getGlobalSkillsDir());
|
|
5328
5348
|
}
|
|
5329
5349
|
roots.push(...this.customRoots.map((r) => resolve13(r)));
|
|
5330
5350
|
return roots.filter((r) => existsSync16(r));
|
|
@@ -5470,9 +5490,77 @@ When tackling complex specialized tasks that match any of these skills, autonomo
|
|
|
5470
5490
|
}
|
|
5471
5491
|
}
|
|
5472
5492
|
|
|
5493
|
+
// src/skills/installer.ts
|
|
5494
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync10, writeFileSync as writeFileSync5, rmSync as rmSync2 } from "fs";
|
|
5495
|
+
import { resolve as resolve14, join as join9 } from "path";
|
|
5496
|
+
async function installSkill(skillName, options) {
|
|
5497
|
+
const cleanName = skillName.trim().toLowerCase().replace(/^@/, "");
|
|
5498
|
+
if (!cleanName) {
|
|
5499
|
+
throw new Error("Skill name cannot be empty.");
|
|
5500
|
+
}
|
|
5501
|
+
const credStore = new CredentialsStore;
|
|
5502
|
+
const creds = credStore.load();
|
|
5503
|
+
let backend = (options.backendUrl || process.env.PIKAA_BACKEND_URL || process.env.GROUPY_BACKEND_URL || creds?.baseUrl || "https://api.groupy-hub.store").replace(/\/+$/, "");
|
|
5504
|
+
if (backend.endsWith("/v1")) {
|
|
5505
|
+
backend = backend.slice(0, -3).replace(/\/+$/, "");
|
|
5506
|
+
}
|
|
5507
|
+
const endpoint = `${backend}/api/skills/${encodeURIComponent(cleanName)}`;
|
|
5508
|
+
let resp;
|
|
5509
|
+
try {
|
|
5510
|
+
resp = await fetch(endpoint, {
|
|
5511
|
+
headers: creds?.accessToken ? { Authorization: `Bearer ${creds.accessToken}` } : {}
|
|
5512
|
+
});
|
|
5513
|
+
} catch (netErr) {
|
|
5514
|
+
throw new Error(`Failed to connect to backend at ${backend}: ${netErr.message}`);
|
|
5515
|
+
}
|
|
5516
|
+
if (!resp.ok) {
|
|
5517
|
+
if (resp.status === 404) {
|
|
5518
|
+
throw new Error(`Skill '${cleanName}' not found in catalog (${endpoint}).`);
|
|
5519
|
+
}
|
|
5520
|
+
const errText = await resp.text();
|
|
5521
|
+
throw new Error(`Backend error (${resp.status}): ${errText}`);
|
|
5522
|
+
}
|
|
5523
|
+
const skillData = await resp.json();
|
|
5524
|
+
if (!skillData.content) {
|
|
5525
|
+
throw new Error(`Skill '${cleanName}' does not contain markdown content.`);
|
|
5526
|
+
}
|
|
5527
|
+
const scope = options.global ? "global" : "workspace";
|
|
5528
|
+
const targetDir = options.global ? resolve14(getGlobalSkillsDir(), cleanName) : resolve14(options.cwd, ".agents", "skills", cleanName);
|
|
5529
|
+
mkdirSync10(targetDir, { recursive: true });
|
|
5530
|
+
const targetFile = join9(targetDir, "SKILL.md");
|
|
5531
|
+
let fileContent = skillData.content;
|
|
5532
|
+
if (!fileContent.startsWith("---")) {
|
|
5533
|
+
const desc = skillData.description ? `description: "${skillData.description.replace(/"/g, "\\\"")}"
|
|
5534
|
+
` : "";
|
|
5535
|
+
fileContent = `---
|
|
5536
|
+
name: ${cleanName}
|
|
5537
|
+
${desc}---
|
|
5538
|
+
|
|
5539
|
+
${fileContent}`;
|
|
5540
|
+
}
|
|
5541
|
+
writeFileSync5(targetFile, fileContent, "utf-8");
|
|
5542
|
+
return {
|
|
5543
|
+
success: true,
|
|
5544
|
+
skillName: cleanName,
|
|
5545
|
+
title: skillData.title || cleanName,
|
|
5546
|
+
targetPath: targetFile,
|
|
5547
|
+
scope,
|
|
5548
|
+
message: `Installed skill '${skillData.title || cleanName}' (@${cleanName}) into ${scope} at ${targetFile}`
|
|
5549
|
+
};
|
|
5550
|
+
}
|
|
5551
|
+
function removeSkill(skillName, options) {
|
|
5552
|
+
const cleanName = skillName.trim().toLowerCase().replace(/^@/, "");
|
|
5553
|
+
const targetDir = options.global ? resolve14(getGlobalSkillsDir(), cleanName) : resolve14(options.cwd, ".agents", "skills", cleanName);
|
|
5554
|
+
if (!existsSync17(targetDir)) {
|
|
5555
|
+
return { success: false, targetDir, removed: false };
|
|
5556
|
+
}
|
|
5557
|
+
rmSync2(targetDir, { recursive: true, force: true });
|
|
5558
|
+
return { success: true, targetDir, removed: true };
|
|
5559
|
+
}
|
|
5560
|
+
|
|
5473
5561
|
// src/memories/store.ts
|
|
5474
|
-
import { existsSync as
|
|
5475
|
-
import { resolve as
|
|
5562
|
+
import { existsSync as existsSync18, readFileSync as readFileSync10, writeFileSync as writeFileSync6, mkdirSync as mkdirSync11, readdirSync as readdirSync7 } from "fs";
|
|
5563
|
+
import { resolve as resolve15, join as join10, basename, dirname as dirname8 } from "path";
|
|
5476
5564
|
import { createHash } from "crypto";
|
|
5477
5565
|
class MemoryStore {
|
|
5478
5566
|
globalPath;
|
|
@@ -5482,14 +5570,14 @@ class MemoryStore {
|
|
|
5482
5570
|
this.customWorkspacePath = options.workspacePath;
|
|
5483
5571
|
}
|
|
5484
5572
|
findProjectRoot(cwd) {
|
|
5485
|
-
let current =
|
|
5573
|
+
let current = resolve15(cwd);
|
|
5486
5574
|
while (true) {
|
|
5487
|
-
if (
|
|
5575
|
+
if (existsSync18(join10(current, ".git"))) {
|
|
5488
5576
|
return current;
|
|
5489
5577
|
}
|
|
5490
5578
|
const parent = dirname8(current);
|
|
5491
5579
|
if (parent === current) {
|
|
5492
|
-
return
|
|
5580
|
+
return resolve15(cwd);
|
|
5493
5581
|
}
|
|
5494
5582
|
current = parent;
|
|
5495
5583
|
}
|
|
@@ -5497,30 +5585,30 @@ class MemoryStore {
|
|
|
5497
5585
|
getProjectSlug(cwd) {
|
|
5498
5586
|
const root = this.findProjectRoot(cwd);
|
|
5499
5587
|
const folderName = basename(root).toLowerCase().replace(/[^a-z0-9_-]/g, "-") || "project";
|
|
5500
|
-
const hash = createHash("sha256").update(
|
|
5588
|
+
const hash = createHash("sha256").update(resolve15(root)).digest("hex").slice(0, 6);
|
|
5501
5589
|
return `${folderName}-${hash}`;
|
|
5502
5590
|
}
|
|
5503
5591
|
getProjectMemoryDir(cwd) {
|
|
5504
5592
|
if (this.customWorkspacePath) {
|
|
5505
|
-
const dir2 =
|
|
5506
|
-
if (!
|
|
5593
|
+
const dir2 = resolve15(this.customWorkspacePath);
|
|
5594
|
+
if (!existsSync18(dir2)) {
|
|
5507
5595
|
try {
|
|
5508
|
-
|
|
5596
|
+
mkdirSync11(dir2, { recursive: true });
|
|
5509
5597
|
} catch {}
|
|
5510
5598
|
}
|
|
5511
5599
|
return dir2;
|
|
5512
5600
|
}
|
|
5513
5601
|
const slug = this.getProjectSlug(cwd);
|
|
5514
|
-
const dir =
|
|
5515
|
-
if (!
|
|
5602
|
+
const dir = join10(getProjectsDir(), slug, "memory");
|
|
5603
|
+
if (!existsSync18(dir)) {
|
|
5516
5604
|
try {
|
|
5517
|
-
|
|
5605
|
+
mkdirSync11(dir, { recursive: true });
|
|
5518
5606
|
} catch {}
|
|
5519
5607
|
}
|
|
5520
5608
|
return dir;
|
|
5521
5609
|
}
|
|
5522
5610
|
getMemoryIndexPath(cwd) {
|
|
5523
|
-
return
|
|
5611
|
+
return join10(this.getProjectMemoryDir(cwd), "MEMORY.md");
|
|
5524
5612
|
}
|
|
5525
5613
|
normalizeCategory(raw) {
|
|
5526
5614
|
const cat = raw.toLowerCase().trim();
|
|
@@ -5539,7 +5627,7 @@ class MemoryStore {
|
|
|
5539
5627
|
const sanitizedName = params.name.toLowerCase().trim().replace(/[^a-z0-9_-]/g, "_").replace(/^_+|_+$/g, "") || `note_${Date.now()}`;
|
|
5540
5628
|
const memoryDir = this.getProjectMemoryDir(params.cwd);
|
|
5541
5629
|
const fileName = `${type}_${sanitizedName}.md`;
|
|
5542
|
-
const filePath =
|
|
5630
|
+
const filePath = join10(memoryDir, fileName);
|
|
5543
5631
|
const nowIso = new Date().toISOString();
|
|
5544
5632
|
const cleanContent = params.content.trim();
|
|
5545
5633
|
const desc = (params.description || cleanContent.split(`
|
|
@@ -5558,7 +5646,7 @@ class MemoryStore {
|
|
|
5558
5646
|
""
|
|
5559
5647
|
].join(`
|
|
5560
5648
|
`);
|
|
5561
|
-
|
|
5649
|
+
writeFileSync6(filePath, frontmatter, "utf8");
|
|
5562
5650
|
this.syncMemoryIndex(params.cwd);
|
|
5563
5651
|
return {
|
|
5564
5652
|
id: `mem_${sanitizedName}`,
|
|
@@ -5574,17 +5662,17 @@ class MemoryStore {
|
|
|
5574
5662
|
}
|
|
5575
5663
|
readTopicMemory(topicNameOrFile, cwd) {
|
|
5576
5664
|
const memoryDir = this.getProjectMemoryDir(cwd);
|
|
5577
|
-
let targetPath =
|
|
5578
|
-
if (!
|
|
5665
|
+
let targetPath = join10(memoryDir, topicNameOrFile);
|
|
5666
|
+
if (!existsSync18(targetPath)) {
|
|
5579
5667
|
if (!topicNameOrFile.endsWith(".md")) {
|
|
5580
|
-
targetPath =
|
|
5668
|
+
targetPath = join10(memoryDir, `${topicNameOrFile}.md`);
|
|
5581
5669
|
}
|
|
5582
5670
|
}
|
|
5583
|
-
if (!
|
|
5671
|
+
if (!existsSync18(targetPath)) {
|
|
5584
5672
|
const files = readdirSync7(memoryDir);
|
|
5585
5673
|
const match = files.find((f) => f.includes(topicNameOrFile));
|
|
5586
5674
|
if (match) {
|
|
5587
|
-
targetPath =
|
|
5675
|
+
targetPath = join10(memoryDir, match);
|
|
5588
5676
|
} else {
|
|
5589
5677
|
return null;
|
|
5590
5678
|
}
|
|
@@ -5645,12 +5733,12 @@ class MemoryStore {
|
|
|
5645
5733
|
}
|
|
5646
5734
|
syncMemoryIndex(cwd) {
|
|
5647
5735
|
const memoryDir = this.getProjectMemoryDir(cwd);
|
|
5648
|
-
const indexPath =
|
|
5649
|
-
const files =
|
|
5736
|
+
const indexPath = join10(memoryDir, "MEMORY.md");
|
|
5737
|
+
const files = existsSync18(memoryDir) ? readdirSync7(memoryDir).filter((f) => f.endsWith(".md") && f !== "MEMORY.md") : [];
|
|
5650
5738
|
const items = [];
|
|
5651
5739
|
for (const f of files) {
|
|
5652
5740
|
try {
|
|
5653
|
-
const full =
|
|
5741
|
+
const full = join10(memoryDir, f);
|
|
5654
5742
|
const parsed = this.parseTopicFile(readFileSync10(full, "utf8"), full);
|
|
5655
5743
|
items.push({
|
|
5656
5744
|
type: parsed.type,
|
|
@@ -5671,13 +5759,13 @@ class MemoryStore {
|
|
|
5671
5759
|
indexLines.push(`- [${item.type}] **${item.name}**: ${item.desc} (topic: ${item.file})`);
|
|
5672
5760
|
}
|
|
5673
5761
|
const boundedLines = indexLines.slice(0, 200);
|
|
5674
|
-
|
|
5762
|
+
writeFileSync6(indexPath, boundedLines.join(`
|
|
5675
5763
|
`) + `
|
|
5676
5764
|
`, "utf8");
|
|
5677
5765
|
}
|
|
5678
5766
|
loadMemoryIndex(cwd) {
|
|
5679
5767
|
const indexPath = this.getMemoryIndexPath(cwd);
|
|
5680
|
-
if (!
|
|
5768
|
+
if (!existsSync18(indexPath))
|
|
5681
5769
|
return "";
|
|
5682
5770
|
try {
|
|
5683
5771
|
const raw = readFileSync10(indexPath, "utf8");
|
|
@@ -5693,13 +5781,13 @@ class MemoryStore {
|
|
|
5693
5781
|
}
|
|
5694
5782
|
listProjectMemories(cwd) {
|
|
5695
5783
|
const memoryDir = this.getProjectMemoryDir(cwd);
|
|
5696
|
-
if (!
|
|
5784
|
+
if (!existsSync18(memoryDir))
|
|
5697
5785
|
return [];
|
|
5698
5786
|
const files = readdirSync7(memoryDir).filter((f) => f.endsWith(".md") && f !== "MEMORY.md");
|
|
5699
5787
|
const list = [];
|
|
5700
5788
|
for (const f of files) {
|
|
5701
5789
|
try {
|
|
5702
|
-
const full =
|
|
5790
|
+
const full = join10(memoryDir, f);
|
|
5703
5791
|
list.push(this.parseTopicFile(readFileSync10(full, "utf8"), full));
|
|
5704
5792
|
} catch {}
|
|
5705
5793
|
}
|
|
@@ -5751,11 +5839,11 @@ class MemoryStore {
|
|
|
5751
5839
|
}
|
|
5752
5840
|
|
|
5753
5841
|
// src/worktree/manager.ts
|
|
5754
|
-
import { resolve as
|
|
5755
|
-
import { existsSync as
|
|
5842
|
+
import { resolve as resolve17, join as join11 } from "path";
|
|
5843
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync12, writeFileSync as writeFileSync7, readFileSync as readFileSync11 } from "fs";
|
|
5756
5844
|
|
|
5757
5845
|
// src/worktree/git.ts
|
|
5758
|
-
import { resolve as
|
|
5846
|
+
import { resolve as resolve16 } from "path";
|
|
5759
5847
|
var NON_INHERITABLE_GIT_ENV = [
|
|
5760
5848
|
"GIT_DIR",
|
|
5761
5849
|
"GIT_WORK_TREE",
|
|
@@ -5799,13 +5887,13 @@ async function getRepoRoot(cwd) {
|
|
|
5799
5887
|
const res = await runGit(cwd, ["rev-parse", "--show-toplevel"]);
|
|
5800
5888
|
if (res.exitCode !== 0 || !res.stdout)
|
|
5801
5889
|
return null;
|
|
5802
|
-
return
|
|
5890
|
+
return resolve16(res.stdout);
|
|
5803
5891
|
}
|
|
5804
5892
|
async function getMainRepoRoot(cwd) {
|
|
5805
5893
|
const res = await runGit(cwd, ["rev-parse", "--path-format=absolute", "--git-common-dir"]);
|
|
5806
5894
|
if (res.exitCode === 0 && res.stdout) {
|
|
5807
|
-
const commonDir =
|
|
5808
|
-
return
|
|
5895
|
+
const commonDir = resolve16(cwd, res.stdout);
|
|
5896
|
+
return resolve16(commonDir, "..");
|
|
5809
5897
|
}
|
|
5810
5898
|
return getRepoRoot(cwd);
|
|
5811
5899
|
}
|
|
@@ -5835,7 +5923,7 @@ async function listWorktreesGit(repoRoot) {
|
|
|
5835
5923
|
let isLocked = false;
|
|
5836
5924
|
for (const line of lines) {
|
|
5837
5925
|
if (line.startsWith("worktree ")) {
|
|
5838
|
-
path =
|
|
5926
|
+
path = resolve16(line.slice(9).trim());
|
|
5839
5927
|
} else if (line.startsWith("HEAD ")) {
|
|
5840
5928
|
commitHash = line.slice(5).trim();
|
|
5841
5929
|
} else if (line.startsWith("branch ")) {
|
|
@@ -5900,19 +5988,19 @@ class WorktreeManager {
|
|
|
5900
5988
|
}
|
|
5901
5989
|
const taskId = `task_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 6)}`;
|
|
5902
5990
|
const branchName = options.branch || `groupy/${taskId}`;
|
|
5903
|
-
const targetDir = options.worktreePath || (this.baseStorageDir ?
|
|
5904
|
-
const worktreeParent =
|
|
5905
|
-
if (!
|
|
5906
|
-
|
|
5991
|
+
const targetDir = options.worktreePath || (this.baseStorageDir ? resolve17(this.baseStorageDir, branchName.replace(/\//g, "_")) : resolve17(repoRoot, ".groupy", "worktrees", branchName.replace(/\//g, "_")));
|
|
5992
|
+
const worktreeParent = resolve17(targetDir, "..");
|
|
5993
|
+
if (!existsSync19(worktreeParent)) {
|
|
5994
|
+
mkdirSync12(worktreeParent, { recursive: true });
|
|
5907
5995
|
}
|
|
5908
5996
|
const baseBranch = options.baseBranch || await getCurrentBranch(repoRoot);
|
|
5909
5997
|
const result = await createWorktreeGit(repoRoot, targetDir, branchName, baseBranch);
|
|
5910
5998
|
if (!result.success) {
|
|
5911
5999
|
throw new Error(`Failed to create git worktree: ${result.error}`);
|
|
5912
6000
|
}
|
|
5913
|
-
const metaPath =
|
|
6001
|
+
const metaPath = join11(targetDir, "groupy-thread.json");
|
|
5914
6002
|
try {
|
|
5915
|
-
|
|
6003
|
+
writeFileSync7(metaPath, JSON.stringify({
|
|
5916
6004
|
version: 1,
|
|
5917
6005
|
ownerThreadId: options.threadId || null,
|
|
5918
6006
|
branch: branchName,
|
|
@@ -5921,7 +6009,7 @@ class WorktreeManager {
|
|
|
5921
6009
|
}, null, 2), "utf8");
|
|
5922
6010
|
} catch {}
|
|
5923
6011
|
const worktrees = await listWorktreesGit(repoRoot);
|
|
5924
|
-
const created = worktrees.find((w) =>
|
|
6012
|
+
const created = worktrees.find((w) => resolve17(w.path) === resolve17(targetDir));
|
|
5925
6013
|
return created || {
|
|
5926
6014
|
path: targetDir,
|
|
5927
6015
|
branch: branchName,
|
|
@@ -5936,8 +6024,8 @@ class WorktreeManager {
|
|
|
5936
6024
|
return [];
|
|
5937
6025
|
const worktrees = await listWorktreesGit(repoRoot);
|
|
5938
6026
|
return worktrees.map((wt) => {
|
|
5939
|
-
const metaPath =
|
|
5940
|
-
if (
|
|
6027
|
+
const metaPath = join11(wt.path, "groupy-thread.json");
|
|
6028
|
+
if (existsSync19(metaPath)) {
|
|
5941
6029
|
try {
|
|
5942
6030
|
const raw = JSON.parse(readFileSync11(metaPath, "utf8"));
|
|
5943
6031
|
return { ...wt, threadId: raw.ownerThreadId || raw.threadId };
|
|
@@ -5947,7 +6035,7 @@ class WorktreeManager {
|
|
|
5947
6035
|
});
|
|
5948
6036
|
}
|
|
5949
6037
|
async mergeWorktree(worktreePath, options = {}) {
|
|
5950
|
-
const resolvedPath =
|
|
6038
|
+
const resolvedPath = resolve17(worktreePath);
|
|
5951
6039
|
const repoRoot = await getMainRepoRoot(resolvedPath);
|
|
5952
6040
|
if (!repoRoot) {
|
|
5953
6041
|
return { success: false, message: "Worktree path is not a valid git repository." };
|
|
@@ -5984,7 +6072,7 @@ class WorktreeManager {
|
|
|
5984
6072
|
};
|
|
5985
6073
|
}
|
|
5986
6074
|
async removeWorktree(worktreePath, deleteBranch = false) {
|
|
5987
|
-
const resolvedPath =
|
|
6075
|
+
const resolvedPath = resolve17(worktreePath);
|
|
5988
6076
|
const repoRoot = await getMainRepoRoot(resolvedPath);
|
|
5989
6077
|
if (!repoRoot)
|
|
5990
6078
|
return false;
|
|
@@ -6065,8 +6153,8 @@ class AuthClient {
|
|
|
6065
6153
|
const authUrl = `${backendUrl}/api/auth/authorize?response_type=code&client_id=groupy-cli&redirect_uri=${encodeURIComponent(redirectUri)}&code_challenge=${encodeURIComponent(codeChallenge)}&code_challenge_method=S256&state=${state}&direct=1`;
|
|
6066
6154
|
let serverResolve;
|
|
6067
6155
|
let serverReject;
|
|
6068
|
-
const codePromise = new Promise((
|
|
6069
|
-
serverResolve =
|
|
6156
|
+
const codePromise = new Promise((resolve18, reject) => {
|
|
6157
|
+
serverResolve = resolve18;
|
|
6070
6158
|
serverReject = reject;
|
|
6071
6159
|
});
|
|
6072
6160
|
if (options.openBrowser !== false) {
|
|
@@ -6635,7 +6723,7 @@ function parsePatch(oldSrc, newSrc, contextLines = 3) {
|
|
|
6635
6723
|
// package.json
|
|
6636
6724
|
var package_default = {
|
|
6637
6725
|
name: "@pikaa-ai/pikaa",
|
|
6638
|
-
version: "0.3.
|
|
6726
|
+
version: "0.3.24",
|
|
6639
6727
|
description: "PIKAA CLI - AI coding agent that runs locally in your terminal.",
|
|
6640
6728
|
main: "./dist/index.js",
|
|
6641
6729
|
module: "./dist/index.js",
|
|
@@ -6651,7 +6739,6 @@ var package_default = {
|
|
|
6651
6739
|
"bin",
|
|
6652
6740
|
"templates",
|
|
6653
6741
|
"assets",
|
|
6654
|
-
"skills/**/SKILL.md",
|
|
6655
6742
|
"README.md",
|
|
6656
6743
|
"LICENSE"
|
|
6657
6744
|
],
|
|
@@ -6713,7 +6800,7 @@ function getCliVersion(options = {}) {
|
|
|
6713
6800
|
}
|
|
6714
6801
|
|
|
6715
6802
|
// src/cli/ui/animation/banner-animation.ts
|
|
6716
|
-
import { homedir as
|
|
6803
|
+
import { homedir as homedir3 } from "os";
|
|
6717
6804
|
import { execSync } from "child_process";
|
|
6718
6805
|
var ROSE = "\x1B[38;2;205;105;74m";
|
|
6719
6806
|
var ROSE_DIM = "\x1B[38;2;120;60;45m";
|
|
@@ -6723,7 +6810,7 @@ var BOLD = "\x1B[1m";
|
|
|
6723
6810
|
var ITALIC = "\x1B[3m";
|
|
6724
6811
|
var RESET = "\x1B[0m";
|
|
6725
6812
|
function shortenPath(cwd) {
|
|
6726
|
-
const home =
|
|
6813
|
+
const home = homedir3();
|
|
6727
6814
|
if (cwd.startsWith(home)) {
|
|
6728
6815
|
return `~${cwd.slice(home.length).replace(/\\/g, "/")}`;
|
|
6729
6816
|
}
|
|
@@ -7281,15 +7368,15 @@ class InteractiveLineEditor {
|
|
|
7281
7368
|
}
|
|
7282
7369
|
async readLine() {
|
|
7283
7370
|
if (!process.stdin.isTTY) {
|
|
7284
|
-
return new Promise((
|
|
7371
|
+
return new Promise((resolve18) => {
|
|
7285
7372
|
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
7286
7373
|
rl.question(this.promptSymbol, (answer) => {
|
|
7287
7374
|
rl.close();
|
|
7288
|
-
|
|
7375
|
+
resolve18(answer);
|
|
7289
7376
|
});
|
|
7290
7377
|
});
|
|
7291
7378
|
}
|
|
7292
|
-
return new Promise((
|
|
7379
|
+
return new Promise((resolve18) => {
|
|
7293
7380
|
let buffer = "";
|
|
7294
7381
|
let cursor = 0;
|
|
7295
7382
|
let selectedIndex = 0;
|
|
@@ -7495,7 +7582,7 @@ class InteractiveLineEditor {
|
|
|
7495
7582
|
process.stdout.write(`
|
|
7496
7583
|
`);
|
|
7497
7584
|
}
|
|
7498
|
-
|
|
7585
|
+
resolve18(result);
|
|
7499
7586
|
};
|
|
7500
7587
|
const onKeypress = (_str, key) => {
|
|
7501
7588
|
if (!key)
|
|
@@ -7683,7 +7770,7 @@ async function promptChoice(config) {
|
|
|
7683
7770
|
const def = choices[defaultIndex] || choices[0];
|
|
7684
7771
|
return def ? def.value : "";
|
|
7685
7772
|
}
|
|
7686
|
-
return new Promise((
|
|
7773
|
+
return new Promise((resolve18) => {
|
|
7687
7774
|
const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
|
|
7688
7775
|
const promptText = ` ${message} (${choices.map((c3) => `[${c3.key}] ${c3.label}`).join(", ")}): `;
|
|
7689
7776
|
rl.question(promptText, (answer) => {
|
|
@@ -7691,15 +7778,15 @@ async function promptChoice(config) {
|
|
|
7691
7778
|
const trimmed = answer.trim().toLowerCase();
|
|
7692
7779
|
const match = choices.find((c3) => c3.key.toLowerCase() === trimmed);
|
|
7693
7780
|
if (match) {
|
|
7694
|
-
|
|
7781
|
+
resolve18(match.value);
|
|
7695
7782
|
} else {
|
|
7696
7783
|
const def = choices[defaultIndex] || choices[0];
|
|
7697
|
-
|
|
7784
|
+
resolve18(def ? def.value : "");
|
|
7698
7785
|
}
|
|
7699
7786
|
});
|
|
7700
7787
|
});
|
|
7701
7788
|
}
|
|
7702
|
-
return new Promise((
|
|
7789
|
+
return new Promise((resolve18) => {
|
|
7703
7790
|
let selectedIndex = defaultIndex;
|
|
7704
7791
|
if (selectedIndex < 0 || selectedIndex >= choices.length)
|
|
7705
7792
|
selectedIndex = 0;
|
|
@@ -7731,7 +7818,7 @@ async function promptChoice(config) {
|
|
|
7731
7818
|
} catch {}
|
|
7732
7819
|
process.stdout.write(`\r\x1B[1A\r\x1B[2K ${style.bold(message)} ${style.cyan(`[${confirmedChoice.key}] ${confirmedChoice.label}`)}
|
|
7733
7820
|
\r\x1B[2K`);
|
|
7734
|
-
|
|
7821
|
+
resolve18(confirmedChoice.value);
|
|
7735
7822
|
};
|
|
7736
7823
|
const onKeypress = (_str, key) => {
|
|
7737
7824
|
if (!key)
|
|
@@ -7797,7 +7884,7 @@ async function promptToolApproval(params) {
|
|
|
7797
7884
|
renderCard(1);
|
|
7798
7885
|
return "yes";
|
|
7799
7886
|
}
|
|
7800
|
-
return new Promise((
|
|
7887
|
+
return new Promise((resolve18) => {
|
|
7801
7888
|
let selectedIndex = 1;
|
|
7802
7889
|
const wasRaw = process.stdin.isRaw;
|
|
7803
7890
|
try {
|
|
@@ -7817,7 +7904,7 @@ async function promptToolApproval(params) {
|
|
|
7817
7904
|
process.stdin.setRawMode(wasRaw ?? false);
|
|
7818
7905
|
} catch {}
|
|
7819
7906
|
console.log();
|
|
7820
|
-
|
|
7907
|
+
resolve18(val);
|
|
7821
7908
|
};
|
|
7822
7909
|
const onKeypress = (_str, key) => {
|
|
7823
7910
|
if (!key)
|
|
@@ -7900,7 +7987,7 @@ async function promptUserQuestion(params) {
|
|
|
7900
7987
|
if (!process.stdin.isTTY || false || !process.stdin.readable) {
|
|
7901
7988
|
return options[0] || "yes";
|
|
7902
7989
|
}
|
|
7903
|
-
return new Promise((
|
|
7990
|
+
return new Promise((resolve18) => {
|
|
7904
7991
|
const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
|
|
7905
7992
|
const promptLabel = options.length > 0 ? `Select [1-${options.length}] or type custom response: ` : `Your response: `;
|
|
7906
7993
|
rl.question(` ${style.bold(promptLabel)}`, (answer) => {
|
|
@@ -7910,7 +7997,7 @@ async function promptUserQuestion(params) {
|
|
|
7910
7997
|
const fallback = options[0] || "";
|
|
7911
7998
|
console.log(style.dim(` \u21B3 Default: ${fallback || "(empty)"}
|
|
7912
7999
|
`));
|
|
7913
|
-
|
|
8000
|
+
resolve18(fallback);
|
|
7914
8001
|
return;
|
|
7915
8002
|
}
|
|
7916
8003
|
const num = parseInt(trimmed, 10);
|
|
@@ -7918,26 +8005,26 @@ async function promptUserQuestion(params) {
|
|
|
7918
8005
|
const picked = options[num - 1];
|
|
7919
8006
|
console.log(style.green(` \u2714 Selected: ${picked}
|
|
7920
8007
|
`));
|
|
7921
|
-
|
|
8008
|
+
resolve18(picked);
|
|
7922
8009
|
return;
|
|
7923
8010
|
}
|
|
7924
8011
|
if (options.length === 2) {
|
|
7925
8012
|
if (/^(y|yes)$/i.test(trimmed)) {
|
|
7926
8013
|
console.log(style.green(` \u2714 Selected: ${options[0]}
|
|
7927
8014
|
`));
|
|
7928
|
-
|
|
8015
|
+
resolve18(options[0]);
|
|
7929
8016
|
return;
|
|
7930
8017
|
}
|
|
7931
8018
|
if (/^(n|no)$/i.test(trimmed)) {
|
|
7932
8019
|
console.log(style.green(` \u2714 Selected: ${options[1]}
|
|
7933
8020
|
`));
|
|
7934
|
-
|
|
8021
|
+
resolve18(options[1]);
|
|
7935
8022
|
return;
|
|
7936
8023
|
}
|
|
7937
8024
|
}
|
|
7938
8025
|
console.log(style.green(` \u2714 Answer: ${trimmed}
|
|
7939
8026
|
`));
|
|
7940
|
-
|
|
8027
|
+
resolve18(trimmed);
|
|
7941
8028
|
});
|
|
7942
8029
|
});
|
|
7943
8030
|
}
|
|
@@ -7966,7 +8053,7 @@ async function promptInteractiveList(config) {
|
|
|
7966
8053
|
`);
|
|
7967
8054
|
return { selectedIndex: -1, action: "close" };
|
|
7968
8055
|
}
|
|
7969
|
-
return new Promise((
|
|
8056
|
+
return new Promise((resolve18) => {
|
|
7970
8057
|
let selectedIndex = Math.max(0, Math.min(defaultIndex, items.length - 1));
|
|
7971
8058
|
let scrollTop = 0;
|
|
7972
8059
|
let renderedLines = 0;
|
|
@@ -8061,7 +8148,7 @@ async function promptInteractiveList(config) {
|
|
|
8061
8148
|
try {
|
|
8062
8149
|
process.stdin.setRawMode(wasRaw ?? false);
|
|
8063
8150
|
} catch {}
|
|
8064
|
-
|
|
8151
|
+
resolve18(res);
|
|
8065
8152
|
};
|
|
8066
8153
|
const onKeypress = async (_str, key) => {
|
|
8067
8154
|
if (!key)
|
|
@@ -8132,8 +8219,8 @@ async function promptInteractiveList(config) {
|
|
|
8132
8219
|
}
|
|
8133
8220
|
|
|
8134
8221
|
// src/security/scanner.ts
|
|
8135
|
-
import { existsSync as
|
|
8136
|
-
import { join as
|
|
8222
|
+
import { existsSync as existsSync20, readdirSync as readdirSync8, readFileSync as readFileSync12, statSync as statSync5 } from "fs";
|
|
8223
|
+
import { join as join12, relative as relative2, resolve as resolve18 } from "path";
|
|
8137
8224
|
var SECURITY_RULES = [
|
|
8138
8225
|
{
|
|
8139
8226
|
id: "SEC-001",
|
|
@@ -8265,13 +8352,13 @@ var IGNORED_FILES = new Set([
|
|
|
8265
8352
|
]);
|
|
8266
8353
|
async function runSecurityScan(targetDir, options = {}) {
|
|
8267
8354
|
const startTime = performance.now();
|
|
8268
|
-
const root =
|
|
8355
|
+
const root = resolve18(targetDir);
|
|
8269
8356
|
const isDirectTestDir = targetDir.includes("test") || Boolean(options.includeTests);
|
|
8270
8357
|
const maxFiles = options.maxFiles || 2000;
|
|
8271
8358
|
const findings = [];
|
|
8272
8359
|
let scannedCount = 0;
|
|
8273
8360
|
function walk(current) {
|
|
8274
|
-
if (scannedCount >= maxFiles || !
|
|
8361
|
+
if (scannedCount >= maxFiles || !existsSync20(current))
|
|
8275
8362
|
return;
|
|
8276
8363
|
let entries;
|
|
8277
8364
|
try {
|
|
@@ -8282,7 +8369,7 @@ async function runSecurityScan(targetDir, options = {}) {
|
|
|
8282
8369
|
for (const entry of entries) {
|
|
8283
8370
|
if (scannedCount >= maxFiles)
|
|
8284
8371
|
break;
|
|
8285
|
-
const fullPath =
|
|
8372
|
+
const fullPath = join12(current, entry);
|
|
8286
8373
|
let stat;
|
|
8287
8374
|
try {
|
|
8288
8375
|
stat = statSync5(fullPath);
|
|
@@ -8360,38 +8447,38 @@ async function runSecurityScan(targetDir, options = {}) {
|
|
|
8360
8447
|
}
|
|
8361
8448
|
|
|
8362
8449
|
// src/mcp/servers/chrome-devtools/index.ts
|
|
8363
|
-
import { resolve as
|
|
8450
|
+
import { resolve as resolve19 } from "path";
|
|
8364
8451
|
|
|
8365
8452
|
// src/mcp/servers/chrome-devtools/server.ts
|
|
8366
8453
|
if (false) {}
|
|
8367
8454
|
|
|
8368
8455
|
// src/mcp/servers/chrome-devtools/index.ts
|
|
8369
8456
|
var __dirname = "/home/runner/work/agent-cli/agent-cli/src/mcp/servers/chrome-devtools";
|
|
8370
|
-
var CHROME_DEVTOOLS_MCP_SERVER_PATH =
|
|
8457
|
+
var CHROME_DEVTOOLS_MCP_SERVER_PATH = resolve19(__dirname, "server.ts");
|
|
8371
8458
|
|
|
8372
8459
|
// src/mcp/servers/web-search/index.ts
|
|
8373
|
-
import { resolve as
|
|
8460
|
+
import { resolve as resolve20 } from "path";
|
|
8374
8461
|
|
|
8375
8462
|
// src/mcp/servers/web-search/server.ts
|
|
8376
8463
|
if (false) {}
|
|
8377
8464
|
|
|
8378
8465
|
// src/mcp/servers/web-search/index.ts
|
|
8379
8466
|
var __dirname = "/home/runner/work/agent-cli/agent-cli/src/mcp/servers/web-search";
|
|
8380
|
-
var WEB_SEARCH_MCP_SERVER_PATH =
|
|
8467
|
+
var WEB_SEARCH_MCP_SERVER_PATH = resolve20(__dirname, "server.ts");
|
|
8381
8468
|
|
|
8382
8469
|
// src/mcp/servers/sqlite/index.ts
|
|
8383
|
-
import { resolve as
|
|
8470
|
+
import { resolve as resolve21 } from "path";
|
|
8384
8471
|
|
|
8385
8472
|
// src/mcp/servers/sqlite/server.ts
|
|
8386
8473
|
if (false) {}
|
|
8387
8474
|
|
|
8388
8475
|
// src/mcp/servers/sqlite/index.ts
|
|
8389
8476
|
var __dirname = "/home/runner/work/agent-cli/agent-cli/src/mcp/servers/sqlite";
|
|
8390
|
-
var SQLITE_MCP_SERVER_PATH =
|
|
8477
|
+
var SQLITE_MCP_SERVER_PATH = resolve21(__dirname, "server.ts");
|
|
8391
8478
|
|
|
8392
8479
|
// src/init/project-analyzer.ts
|
|
8393
|
-
import { existsSync as
|
|
8394
|
-
import { join as
|
|
8480
|
+
import { existsSync as existsSync21, readFileSync as readFileSync13, readdirSync as readdirSync9 } from "fs";
|
|
8481
|
+
import { join as join13, basename as basename3 } from "path";
|
|
8395
8482
|
|
|
8396
8483
|
class ProjectAnalyzer {
|
|
8397
8484
|
cwd;
|
|
@@ -8409,8 +8496,8 @@ class ProjectAnalyzer {
|
|
|
8409
8496
|
const architectureNotes = [];
|
|
8410
8497
|
const codeConventions = [];
|
|
8411
8498
|
let description = readmeInfo.description;
|
|
8412
|
-
const pkgPath =
|
|
8413
|
-
if (
|
|
8499
|
+
const pkgPath = join13(this.cwd, "package.json");
|
|
8500
|
+
if (existsSync21(pkgPath)) {
|
|
8414
8501
|
try {
|
|
8415
8502
|
const pkg = JSON.parse(readFileSync13(pkgPath, "utf8"));
|
|
8416
8503
|
if (!description && pkg.description)
|
|
@@ -8483,8 +8570,8 @@ class ProjectAnalyzer {
|
|
|
8483
8570
|
}
|
|
8484
8571
|
} catch {}
|
|
8485
8572
|
}
|
|
8486
|
-
const tsconfigPath =
|
|
8487
|
-
if (
|
|
8573
|
+
const tsconfigPath = join13(this.cwd, "tsconfig.json");
|
|
8574
|
+
if (existsSync21(tsconfigPath)) {
|
|
8488
8575
|
try {
|
|
8489
8576
|
const tsconfig = JSON.parse(readFileSync13(tsconfigPath, "utf8"));
|
|
8490
8577
|
if (tsconfig.compilerOptions?.strict) {
|
|
@@ -8495,8 +8582,8 @@ class ProjectAnalyzer {
|
|
|
8495
8582
|
}
|
|
8496
8583
|
} catch {}
|
|
8497
8584
|
}
|
|
8498
|
-
const cargoPath =
|
|
8499
|
-
if (
|
|
8585
|
+
const cargoPath = join13(this.cwd, "Cargo.toml");
|
|
8586
|
+
if (existsSync21(cargoPath)) {
|
|
8500
8587
|
try {
|
|
8501
8588
|
commands.dev = commands.dev || "cargo run";
|
|
8502
8589
|
commands.build = commands.build || "cargo build";
|
|
@@ -8505,8 +8592,8 @@ class ProjectAnalyzer {
|
|
|
8505
8592
|
frameworks.push("Rust Cargo");
|
|
8506
8593
|
} catch {}
|
|
8507
8594
|
}
|
|
8508
|
-
const goModPath =
|
|
8509
|
-
if (
|
|
8595
|
+
const goModPath = join13(this.cwd, "go.mod");
|
|
8596
|
+
if (existsSync21(goModPath)) {
|
|
8510
8597
|
try {
|
|
8511
8598
|
commands.dev = commands.dev || "go run .";
|
|
8512
8599
|
commands.build = commands.build || "go build ./...";
|
|
@@ -8515,37 +8602,37 @@ class ProjectAnalyzer {
|
|
|
8515
8602
|
frameworks.push("Go Modules");
|
|
8516
8603
|
} catch {}
|
|
8517
8604
|
}
|
|
8518
|
-
const pyprojectPath =
|
|
8519
|
-
const requirementsPath =
|
|
8520
|
-
if (
|
|
8605
|
+
const pyprojectPath = join13(this.cwd, "pyproject.toml");
|
|
8606
|
+
const requirementsPath = join13(this.cwd, "requirements.txt");
|
|
8607
|
+
if (existsSync21(pyprojectPath) || existsSync21(requirementsPath)) {
|
|
8521
8608
|
commands.test = commands.test || "pytest";
|
|
8522
8609
|
commands.lint = commands.lint || "ruff check .";
|
|
8523
|
-
if (
|
|
8610
|
+
if (existsSync21(join13(this.cwd, "uv.lock"))) {
|
|
8524
8611
|
frameworks.push("uv");
|
|
8525
8612
|
commands.test = "uv run pytest";
|
|
8526
|
-
} else if (
|
|
8613
|
+
} else if (existsSync21(join13(this.cwd, "poetry.lock"))) {
|
|
8527
8614
|
frameworks.push("Poetry");
|
|
8528
8615
|
commands.test = "poetry run pytest";
|
|
8529
8616
|
}
|
|
8530
8617
|
}
|
|
8531
|
-
if (
|
|
8618
|
+
if (existsSync21(join13(this.cwd, "Dockerfile"))) {
|
|
8532
8619
|
infrastructure.push("Docker");
|
|
8533
8620
|
const sanitizedName = projectName.toLowerCase().replace(/[^a-z0-9_-]/g, "-").replace(/^-+|-+$/g, "");
|
|
8534
8621
|
commands.dockerBuild = `docker build -t ${sanitizedName || "app"} .`;
|
|
8535
8622
|
}
|
|
8536
|
-
if (
|
|
8623
|
+
if (existsSync21(join13(this.cwd, "nginx.conf"))) {
|
|
8537
8624
|
infrastructure.push("Nginx");
|
|
8538
8625
|
}
|
|
8539
|
-
if (
|
|
8626
|
+
if (existsSync21(join13(this.cwd, "src/api.ts")) || existsSync21(join13(this.cwd, "src/api"))) {
|
|
8540
8627
|
architectureNotes.push("Backend API endpoints and network client logic are centralized in `src/api`.");
|
|
8541
8628
|
}
|
|
8542
|
-
if (
|
|
8629
|
+
if (existsSync21(join13(this.cwd, "src/components"))) {
|
|
8543
8630
|
architectureNotes.push("Reusable UI presentation components live in `src/components/`.");
|
|
8544
8631
|
}
|
|
8545
|
-
if (
|
|
8632
|
+
if (existsSync21(join13(this.cwd, "src/types.ts")) || existsSync21(join13(this.cwd, "src/types"))) {
|
|
8546
8633
|
architectureNotes.push("Shared TypeScript data models and interfaces are defined in `src/types`.");
|
|
8547
8634
|
}
|
|
8548
|
-
if (
|
|
8635
|
+
if (existsSync21(join13(this.cwd, ".env.example"))) {
|
|
8549
8636
|
architectureNotes.push("Environment configuration template is in `.env.example`.");
|
|
8550
8637
|
}
|
|
8551
8638
|
if (commands.typecheck || commands.lint || commands.test) {
|
|
@@ -8562,7 +8649,7 @@ class ProjectAnalyzer {
|
|
|
8562
8649
|
let hasExistingInstructions = false;
|
|
8563
8650
|
let existingInstructionFile;
|
|
8564
8651
|
for (const f of instructionFiles) {
|
|
8565
|
-
if (
|
|
8652
|
+
if (existsSync21(join13(this.cwd, f))) {
|
|
8566
8653
|
hasExistingInstructions = true;
|
|
8567
8654
|
existingInstructionFile = f;
|
|
8568
8655
|
break;
|
|
@@ -8643,8 +8730,8 @@ class ProjectAnalyzer {
|
|
|
8643
8730
|
extractReadmeMetadata() {
|
|
8644
8731
|
const readmeFiles = ["README.md", "readme.md", "README.MD"];
|
|
8645
8732
|
for (const file of readmeFiles) {
|
|
8646
|
-
const fullPath =
|
|
8647
|
-
if (
|
|
8733
|
+
const fullPath = join13(this.cwd, file);
|
|
8734
|
+
if (existsSync21(fullPath)) {
|
|
8648
8735
|
try {
|
|
8649
8736
|
const content = readFileSync13(fullPath, "utf8");
|
|
8650
8737
|
const lines = content.split(`
|
|
@@ -8669,8 +8756,8 @@ class ProjectAnalyzer {
|
|
|
8669
8756
|
return {};
|
|
8670
8757
|
}
|
|
8671
8758
|
detectProjectName() {
|
|
8672
|
-
const pkgPath =
|
|
8673
|
-
if (
|
|
8759
|
+
const pkgPath = join13(this.cwd, "package.json");
|
|
8760
|
+
if (existsSync21(pkgPath)) {
|
|
8674
8761
|
try {
|
|
8675
8762
|
const pkg = JSON.parse(readFileSync13(pkgPath, "utf8"));
|
|
8676
8763
|
if (pkg.name && pkg.name !== "frontend" && pkg.name !== "backend" && pkg.name !== "app") {
|
|
@@ -8678,16 +8765,16 @@ class ProjectAnalyzer {
|
|
|
8678
8765
|
}
|
|
8679
8766
|
} catch {}
|
|
8680
8767
|
}
|
|
8681
|
-
const cargoPath =
|
|
8682
|
-
if (
|
|
8768
|
+
const cargoPath = join13(this.cwd, "Cargo.toml");
|
|
8769
|
+
if (existsSync21(cargoPath)) {
|
|
8683
8770
|
try {
|
|
8684
8771
|
const match = readFileSync13(cargoPath, "utf8").match(/name\s*=\s*"([^"]+)"/);
|
|
8685
8772
|
if (match?.[1])
|
|
8686
8773
|
return match[1];
|
|
8687
8774
|
} catch {}
|
|
8688
8775
|
}
|
|
8689
|
-
const goModPath =
|
|
8690
|
-
if (
|
|
8776
|
+
const goModPath = join13(this.cwd, "go.mod");
|
|
8777
|
+
if (existsSync21(goModPath)) {
|
|
8691
8778
|
try {
|
|
8692
8779
|
const match = readFileSync13(goModPath, "utf8").match(/module\s+([^\s]+)/);
|
|
8693
8780
|
if (match?.[1])
|
|
@@ -8698,47 +8785,47 @@ class ProjectAnalyzer {
|
|
|
8698
8785
|
}
|
|
8699
8786
|
detectLanguages() {
|
|
8700
8787
|
const langs = new Set;
|
|
8701
|
-
if (
|
|
8788
|
+
if (existsSync21(join13(this.cwd, "tsconfig.json")) || this.hasFileWithExtension(".ts", ".tsx")) {
|
|
8702
8789
|
langs.add("TypeScript");
|
|
8703
8790
|
}
|
|
8704
|
-
if (
|
|
8791
|
+
if (existsSync21(join13(this.cwd, "package.json")) || this.hasFileWithExtension(".js", ".jsx", ".mjs")) {
|
|
8705
8792
|
langs.add("JavaScript");
|
|
8706
8793
|
}
|
|
8707
|
-
if (
|
|
8794
|
+
if (existsSync21(join13(this.cwd, "Cargo.toml")) || this.hasFileWithExtension(".rs")) {
|
|
8708
8795
|
langs.add("Rust");
|
|
8709
8796
|
}
|
|
8710
|
-
if (
|
|
8797
|
+
if (existsSync21(join13(this.cwd, "go.mod")) || this.hasFileWithExtension(".go")) {
|
|
8711
8798
|
langs.add("Go");
|
|
8712
8799
|
}
|
|
8713
|
-
if (
|
|
8800
|
+
if (existsSync21(join13(this.cwd, "pyproject.toml")) || existsSync21(join13(this.cwd, "requirements.txt")) || this.hasFileWithExtension(".py")) {
|
|
8714
8801
|
langs.add("Python");
|
|
8715
8802
|
}
|
|
8716
|
-
if (
|
|
8803
|
+
if (existsSync21(join13(this.cwd, "pom.xml")) || existsSync21(join13(this.cwd, "build.gradle")) || this.hasFileWithExtension(".java")) {
|
|
8717
8804
|
langs.add("Java");
|
|
8718
8805
|
}
|
|
8719
|
-
if (
|
|
8806
|
+
if (existsSync21(join13(this.cwd, "CMakeLists.txt")) || this.hasFileWithExtension(".cpp", ".c", ".h", ".hpp")) {
|
|
8720
8807
|
langs.add("C/C++");
|
|
8721
8808
|
}
|
|
8722
8809
|
return Array.from(langs);
|
|
8723
8810
|
}
|
|
8724
8811
|
detectPackageManager() {
|
|
8725
|
-
if (
|
|
8812
|
+
if (existsSync21(join13(this.cwd, "bun.lockb")) || existsSync21(join13(this.cwd, "bun.lock")))
|
|
8726
8813
|
return "bun";
|
|
8727
|
-
if (
|
|
8814
|
+
if (existsSync21(join13(this.cwd, "pnpm-lock.yaml")))
|
|
8728
8815
|
return "pnpm";
|
|
8729
|
-
if (
|
|
8816
|
+
if (existsSync21(join13(this.cwd, "yarn.lock")))
|
|
8730
8817
|
return "yarn";
|
|
8731
|
-
if (
|
|
8818
|
+
if (existsSync21(join13(this.cwd, "package-lock.json")))
|
|
8732
8819
|
return "npm";
|
|
8733
|
-
if (
|
|
8820
|
+
if (existsSync21(join13(this.cwd, "Cargo.lock")) || existsSync21(join13(this.cwd, "Cargo.toml")))
|
|
8734
8821
|
return "cargo";
|
|
8735
|
-
if (
|
|
8822
|
+
if (existsSync21(join13(this.cwd, "uv.lock")))
|
|
8736
8823
|
return "uv";
|
|
8737
|
-
if (
|
|
8824
|
+
if (existsSync21(join13(this.cwd, "poetry.lock")))
|
|
8738
8825
|
return "poetry";
|
|
8739
|
-
if (
|
|
8826
|
+
if (existsSync21(join13(this.cwd, "go.sum")) || existsSync21(join13(this.cwd, "go.mod")))
|
|
8740
8827
|
return "go";
|
|
8741
|
-
if (
|
|
8828
|
+
if (existsSync21(join13(this.cwd, "package.json")))
|
|
8742
8829
|
return "npm";
|
|
8743
8830
|
return;
|
|
8744
8831
|
}
|
|
@@ -8752,17 +8839,17 @@ class ProjectAnalyzer {
|
|
|
8752
8839
|
}
|
|
8753
8840
|
}
|
|
8754
8841
|
// src/init/init-command.ts
|
|
8755
|
-
import { existsSync as
|
|
8756
|
-
import { join as
|
|
8842
|
+
import { existsSync as existsSync22, writeFileSync as writeFileSync8 } from "fs";
|
|
8843
|
+
import { join as join14 } from "path";
|
|
8757
8844
|
function runProjectInit(options = {}) {
|
|
8758
8845
|
const cwd = options.cwd || process.cwd();
|
|
8759
8846
|
const filename = options.filename || "AGENTS.md";
|
|
8760
|
-
const targetPath =
|
|
8847
|
+
const targetPath = join14(cwd, filename);
|
|
8761
8848
|
const analyzer = new ProjectAnalyzer(cwd);
|
|
8762
8849
|
const analysis = analyzer.analyze();
|
|
8763
8850
|
const content = analyzer.generateAgentsMarkdown(analysis);
|
|
8764
|
-
const alreadyExists =
|
|
8765
|
-
|
|
8851
|
+
const alreadyExists = existsSync22(targetPath);
|
|
8852
|
+
writeFileSync8(targetPath, content, "utf8");
|
|
8766
8853
|
return {
|
|
8767
8854
|
success: true,
|
|
8768
8855
|
filePath: targetPath,
|
|
@@ -8834,10 +8921,11 @@ var AVAILABLE_SLASH_COMMANDS = [
|
|
|
8834
8921
|
{ name: "/manual", description: "Switch to Manual Mode (all tools require user confirmation)" },
|
|
8835
8922
|
{ name: "/accept-edits", description: "Switch to Accept Edits Mode (file edits auto-approved, shell prompts)" },
|
|
8836
8923
|
{ name: "/plan", description: "Switch to Plan Mode (read-only planning, mutations blocked)" },
|
|
8837
|
-
{ name: "/skills", description: "
|
|
8924
|
+
{ name: "/skills", description: "Manage domain skills (/skills, /skill add <name>, /skill remove <name>)" },
|
|
8838
8925
|
{ name: "/memories", description: "View learned preferences & memories" },
|
|
8839
8926
|
{ name: "/worktrees", description: "List active isolated Git Worktrees" },
|
|
8840
|
-
{ name: "/
|
|
8927
|
+
{ name: "/resume", description: "Resume a previous conversation session (/resume [id])" },
|
|
8928
|
+
{ name: "/sessions", description: "List and manage saved past sessions" },
|
|
8841
8929
|
{ name: "/role", description: "Select and inspect specialized agent roles & personas" },
|
|
8842
8930
|
{ name: "/security", description: "Scan codebase for vulnerabilities & secrets (Strix)" },
|
|
8843
8931
|
{ name: "/agents", description: "List active sub-agents & execution status" },
|
|
@@ -8945,9 +9033,10 @@ async function handleSlashCommand(input, ctx) {
|
|
|
8945
9033
|
case "/worktree":
|
|
8946
9034
|
await printWorktrees(ctx);
|
|
8947
9035
|
return true;
|
|
9036
|
+
case "/resume":
|
|
8948
9037
|
case "/sessions":
|
|
8949
9038
|
case "/session":
|
|
8950
|
-
await
|
|
9039
|
+
await handleResumeCommand(ctx, args);
|
|
8951
9040
|
return true;
|
|
8952
9041
|
case "/security":
|
|
8953
9042
|
case "/audit":
|
|
@@ -9335,6 +9424,46 @@ async function handleSkillsCommand(ctx, args) {
|
|
|
9335
9424
|
}
|
|
9336
9425
|
const sub = (args[0] || "").toLowerCase();
|
|
9337
9426
|
const target = (args[1] || "").toLowerCase();
|
|
9427
|
+
if (sub === "install" || sub === "add") {
|
|
9428
|
+
if (!target) {
|
|
9429
|
+
console.log(style.yellow("Usage: /skill add <skill-name> [--global]"));
|
|
9430
|
+
return;
|
|
9431
|
+
}
|
|
9432
|
+
const isGlobal = args.includes("--global") || args.includes("-g");
|
|
9433
|
+
try {
|
|
9434
|
+
console.log(style.dim(`
|
|
9435
|
+
Fetching skill '${target}' from catalog...`));
|
|
9436
|
+
const res = await installSkill(target, { cwd: ctx.session.cwd, global: isGlobal });
|
|
9437
|
+
loader.clearCache();
|
|
9438
|
+
console.log(style.green(`
|
|
9439
|
+
\u2713 ${res.message}
|
|
9440
|
+
`));
|
|
9441
|
+
} catch (err) {
|
|
9442
|
+
console.log(style.red(`
|
|
9443
|
+
\u2715 Failed to install skill: ${err.message}
|
|
9444
|
+
`));
|
|
9445
|
+
}
|
|
9446
|
+
return;
|
|
9447
|
+
}
|
|
9448
|
+
if (sub === "remove" || sub === "uninstall" || sub === "rm") {
|
|
9449
|
+
if (!target) {
|
|
9450
|
+
console.log(style.yellow("Usage: /skill remove <skill-name> [--global]"));
|
|
9451
|
+
return;
|
|
9452
|
+
}
|
|
9453
|
+
const isGlobal = args.includes("--global") || args.includes("-g");
|
|
9454
|
+
const res = removeSkill(target, { cwd: ctx.session.cwd, global: isGlobal });
|
|
9455
|
+
loader.clearCache();
|
|
9456
|
+
if (res.removed) {
|
|
9457
|
+
console.log(style.green(`
|
|
9458
|
+
\u2713 Skill '${target}' removed from ${res.targetDir}
|
|
9459
|
+
`));
|
|
9460
|
+
} else {
|
|
9461
|
+
console.log(style.yellow(`
|
|
9462
|
+
\u2715 Skill '${target}' was not found in ${res.targetDir}
|
|
9463
|
+
`));
|
|
9464
|
+
}
|
|
9465
|
+
return;
|
|
9466
|
+
}
|
|
9338
9467
|
if (sub === "disable" || sub === "off") {
|
|
9339
9468
|
if (!target) {
|
|
9340
9469
|
console.log(style.yellow("Usage: /skills disable <skill-name>"));
|
|
@@ -9482,41 +9611,104 @@ function printMemories(ctx) {
|
|
|
9482
9611
|
}
|
|
9483
9612
|
console.log();
|
|
9484
9613
|
}
|
|
9485
|
-
|
|
9614
|
+
function formatRelativeTime(timestamp) {
|
|
9615
|
+
const diffMs = Math.max(0, Date.now() - timestamp);
|
|
9616
|
+
const diffSec = Math.floor(diffMs / 1000);
|
|
9617
|
+
if (diffSec < 60)
|
|
9618
|
+
return "just now";
|
|
9619
|
+
const diffMin = Math.floor(diffSec / 60);
|
|
9620
|
+
if (diffMin < 60)
|
|
9621
|
+
return `${diffMin}m ago`;
|
|
9622
|
+
const diffHours = Math.floor(diffMin / 60);
|
|
9623
|
+
if (diffHours < 24)
|
|
9624
|
+
return `${diffHours}h ago`;
|
|
9625
|
+
const diffDays = Math.floor(diffHours / 24);
|
|
9626
|
+
if (diffDays < 30)
|
|
9627
|
+
return `${diffDays}d ago`;
|
|
9628
|
+
return new Date(timestamp).toLocaleDateString();
|
|
9629
|
+
}
|
|
9630
|
+
function printRecentConversation(items) {
|
|
9631
|
+
if (!items || items.length === 0)
|
|
9632
|
+
return;
|
|
9633
|
+
const dialog = items.filter((i) => i.type === "user_message" || i.type === "agent_message" || i.role === "user" || i.role === "assistant").slice(-3);
|
|
9634
|
+
if (dialog.length === 0)
|
|
9635
|
+
return;
|
|
9636
|
+
console.log(style.dim(" Recent context:"));
|
|
9637
|
+
for (const item of dialog) {
|
|
9638
|
+
const isUser = item.role === "user" || item.type === "user_message";
|
|
9639
|
+
const text = typeof item.content === "string" ? item.content : item.text || "";
|
|
9640
|
+
const singleLine = text.trim().replace(/\s+/g, " ");
|
|
9641
|
+
const preview = singleLine.length > 85 ? singleLine.slice(0, 82) + "..." : singleLine;
|
|
9642
|
+
const badge = isUser ? style.brand(" \u276F User:") : style.cyan(" \u25CF Assistant:");
|
|
9643
|
+
console.log(`${badge} ${style.dim(preview)}`);
|
|
9644
|
+
}
|
|
9645
|
+
console.log();
|
|
9646
|
+
}
|
|
9647
|
+
async function handleResumeCommand(ctx, args = []) {
|
|
9486
9648
|
const storage = ctx.storageManager;
|
|
9487
9649
|
if (!storage) {
|
|
9488
|
-
console.log(style.yellow(
|
|
9650
|
+
console.log(style.yellow(`
|
|
9651
|
+
Session persistence manager not active.
|
|
9652
|
+
`));
|
|
9489
9653
|
return;
|
|
9490
9654
|
}
|
|
9491
|
-
const
|
|
9492
|
-
if (
|
|
9655
|
+
const rawThreads = storage.listSessions();
|
|
9656
|
+
if (rawThreads.length === 0) {
|
|
9493
9657
|
console.log(style.dim(`
|
|
9494
|
-
No saved sessions in SQLite database.
|
|
9658
|
+
No saved conversation sessions found in SQLite database.
|
|
9495
9659
|
`));
|
|
9496
9660
|
return;
|
|
9497
9661
|
}
|
|
9662
|
+
const threads = [...rawThreads].sort((a, b) => b.updatedAt - a.updatedAt);
|
|
9663
|
+
const filterArg = args[0]?.trim();
|
|
9664
|
+
let defaultIdx = 0;
|
|
9665
|
+
if (filterArg) {
|
|
9666
|
+
const foundIdx = threads.findIndex((t) => t.id === filterArg || t.id.toLowerCase().startsWith(filterArg.toLowerCase()));
|
|
9667
|
+
if (foundIdx !== -1) {
|
|
9668
|
+
defaultIdx = foundIdx;
|
|
9669
|
+
}
|
|
9670
|
+
}
|
|
9498
9671
|
if (!process.stdin.isTTY || false || !process.stdin.readable) {
|
|
9672
|
+
if (filterArg) {
|
|
9673
|
+
const match = threads[defaultIdx];
|
|
9674
|
+
const restored = storage.resumeIntoSession(ctx.session, match.id);
|
|
9675
|
+
if (restored) {
|
|
9676
|
+
console.log(style.green(`
|
|
9677
|
+
\u2713 Resumed past session: ${style.bold(match.id)} (${restored.items.length} items, model: ${restored.thread.model || ctx.session.model})
|
|
9678
|
+
`));
|
|
9679
|
+
printRecentConversation(restored.items);
|
|
9680
|
+
} else {
|
|
9681
|
+
console.log(style.red(`
|
|
9682
|
+
\u2715 Failed to load session '${match.id}'.
|
|
9683
|
+
`));
|
|
9684
|
+
}
|
|
9685
|
+
return;
|
|
9686
|
+
}
|
|
9499
9687
|
console.log();
|
|
9500
9688
|
console.log(style.bold(" Saved Sessions in SQLite Store:"));
|
|
9501
9689
|
for (const t of threads) {
|
|
9502
|
-
const
|
|
9503
|
-
|
|
9690
|
+
const timeStr = formatRelativeTime(t.updatedAt);
|
|
9691
|
+
const titleStr = t.title && t.title !== "New Session" ? ` - "${t.title}"` : "";
|
|
9692
|
+
console.log(` \u2022 ${style.cyan(t.id)} [${style.dim(t.model)}]${titleStr} - ${style.dim(timeStr)} (${t.itemsCount ?? 0} items)`);
|
|
9504
9693
|
}
|
|
9505
9694
|
console.log();
|
|
9506
9695
|
return;
|
|
9507
9696
|
}
|
|
9508
9697
|
const items = threads.map((t) => {
|
|
9509
|
-
const
|
|
9698
|
+
const timeStr = formatRelativeTime(t.updatedAt);
|
|
9699
|
+
const titlePart = t.title && t.title !== "New Session" ? `"${t.title.slice(0, 36)}"` : undefined;
|
|
9510
9700
|
return {
|
|
9511
9701
|
id: t.id,
|
|
9512
9702
|
label: t.id,
|
|
9513
|
-
|
|
9703
|
+
badge: t.model,
|
|
9704
|
+
description: [titlePart, `${t.itemsCount ?? 0} items`, timeStr].filter(Boolean).join(" \xB7 ")
|
|
9514
9705
|
};
|
|
9515
9706
|
});
|
|
9516
9707
|
const res = await promptInteractiveList({
|
|
9517
|
-
title: `\uD83D\uDDC4\uFE0F
|
|
9708
|
+
title: `\uD83D\uDDC4\uFE0F Resume Past Conversation (${threads.length} saved)`,
|
|
9518
9709
|
items,
|
|
9519
9710
|
mode: "select",
|
|
9711
|
+
defaultIndex: defaultIdx,
|
|
9520
9712
|
onAction: (key, item, idx) => {
|
|
9521
9713
|
if (key === "d") {
|
|
9522
9714
|
storage.deleteSession(item.id);
|
|
@@ -9526,18 +9718,24 @@ async function printSessions(ctx) {
|
|
|
9526
9718
|
}
|
|
9527
9719
|
return false;
|
|
9528
9720
|
},
|
|
9529
|
-
customKeyHints: "\u2191/\u2193: navigate \xB7 Enter: resume
|
|
9721
|
+
customKeyHints: "\u2191/\u2193: navigate \xB7 Enter: resume conversation \xB7 d: delete \xB7 Esc: cancel"
|
|
9530
9722
|
});
|
|
9531
9723
|
if (res.action === "select" && res.selectedItem) {
|
|
9532
|
-
const
|
|
9533
|
-
if (
|
|
9534
|
-
ctx.session.setHistory(session.items);
|
|
9535
|
-
if (session.thread.model)
|
|
9536
|
-
ctx.session.model = session.thread.model;
|
|
9724
|
+
const restored = storage.resumeIntoSession(ctx.session, res.selectedItem.id);
|
|
9725
|
+
if (restored) {
|
|
9537
9726
|
console.log(style.green(`
|
|
9538
|
-
\u2713 Resumed past
|
|
9727
|
+
\u2713 Resumed past conversation: ${style.bold(res.selectedItem.id)} (${restored.items.length} items, model: ${restored.thread.model || ctx.session.model})
|
|
9728
|
+
`));
|
|
9729
|
+
printRecentConversation(restored.items);
|
|
9730
|
+
} else {
|
|
9731
|
+
console.log(style.red(`
|
|
9732
|
+
\u2715 Failed to load session '${res.selectedItem.id}'.
|
|
9539
9733
|
`));
|
|
9540
9734
|
}
|
|
9735
|
+
} else {
|
|
9736
|
+
console.log(style.dim(`
|
|
9737
|
+
Session resume cancelled.
|
|
9738
|
+
`));
|
|
9541
9739
|
}
|
|
9542
9740
|
}
|
|
9543
9741
|
function printSessionStats(ctx) {
|
|
@@ -10236,9 +10434,9 @@ class MarkdownHighlighter {
|
|
|
10236
10434
|
}
|
|
10237
10435
|
|
|
10238
10436
|
// src/cli/update-checker.ts
|
|
10239
|
-
import { existsSync as
|
|
10240
|
-
import { homedir as
|
|
10241
|
-
import { join as
|
|
10437
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync13, readFileSync as readFileSync14, writeFileSync as writeFileSync9 } from "fs";
|
|
10438
|
+
import { homedir as homedir4 } from "os";
|
|
10439
|
+
import { join as join15 } from "path";
|
|
10242
10440
|
var CHECK_INTERVAL_MS = 12 * 60 * 60 * 1000;
|
|
10243
10441
|
function parseSemver(v) {
|
|
10244
10442
|
const clean = v.replace(/^v/, "").trim();
|
|
@@ -10259,8 +10457,8 @@ function isNewerVersion(current, remote) {
|
|
|
10259
10457
|
return remPatch > curPatch;
|
|
10260
10458
|
}
|
|
10261
10459
|
function getUpdateCachePath() {
|
|
10262
|
-
const baseDir = process.env.PIKAA_HOME || process.env.GROUPY_HOME ||
|
|
10263
|
-
return
|
|
10460
|
+
const baseDir = process.env.PIKAA_HOME || process.env.GROUPY_HOME || join15(homedir4(), ".pikaa");
|
|
10461
|
+
return join15(baseDir, "update-cache.json");
|
|
10264
10462
|
}
|
|
10265
10463
|
async function fetchLatestNpmVersion(packageName, timeoutMs = 1500) {
|
|
10266
10464
|
const url = `https://registry.npmjs.org/${encodeURIComponent(packageName)}/latest`;
|
|
@@ -10293,7 +10491,7 @@ async function checkForUpdates(options = {}) {
|
|
|
10293
10491
|
const cachePath = options.cachePath || getUpdateCachePath();
|
|
10294
10492
|
const now = Date.now();
|
|
10295
10493
|
let cached = null;
|
|
10296
|
-
if (!options.force &&
|
|
10494
|
+
if (!options.force && existsSync23(cachePath)) {
|
|
10297
10495
|
try {
|
|
10298
10496
|
const raw = JSON.parse(readFileSync14(cachePath, "utf8"));
|
|
10299
10497
|
if (raw && typeof raw.lastChecked === "number" && typeof raw.latestVersion === "string") {
|
|
@@ -10323,16 +10521,16 @@ async function checkForUpdates(options = {}) {
|
|
|
10323
10521
|
return null;
|
|
10324
10522
|
}
|
|
10325
10523
|
try {
|
|
10326
|
-
const parentDir =
|
|
10327
|
-
if (!
|
|
10328
|
-
|
|
10524
|
+
const parentDir = join15(cachePath, "..");
|
|
10525
|
+
if (!existsSync23(parentDir)) {
|
|
10526
|
+
mkdirSync13(parentDir, { recursive: true });
|
|
10329
10527
|
}
|
|
10330
10528
|
const cacheData = {
|
|
10331
10529
|
lastChecked: now,
|
|
10332
10530
|
latestVersion,
|
|
10333
10531
|
packageName
|
|
10334
10532
|
};
|
|
10335
|
-
|
|
10533
|
+
writeFileSync9(cachePath, JSON.stringify(cacheData, null, 2), "utf8");
|
|
10336
10534
|
} catch {}
|
|
10337
10535
|
const updateAvailable = isNewerVersion(currentVersion, latestVersion);
|
|
10338
10536
|
return updateAvailable ? {
|
|
@@ -10498,9 +10696,9 @@ class CliRepl {
|
|
|
10498
10696
|
filesModified: Array.from(this.turnFilesModified)
|
|
10499
10697
|
});
|
|
10500
10698
|
if (this.turnDoneResolver) {
|
|
10501
|
-
const
|
|
10699
|
+
const resolve22 = this.turnDoneResolver;
|
|
10502
10700
|
this.turnDoneResolver = undefined;
|
|
10503
|
-
|
|
10701
|
+
resolve22();
|
|
10504
10702
|
}
|
|
10505
10703
|
break;
|
|
10506
10704
|
case "Error":
|
|
@@ -10516,9 +10714,9 @@ class CliRepl {
|
|
|
10516
10714
|
console.error(style.red(`Error: ${msg.message}
|
|
10517
10715
|
`));
|
|
10518
10716
|
if (this.turnDoneResolver) {
|
|
10519
|
-
const
|
|
10717
|
+
const resolve22 = this.turnDoneResolver;
|
|
10520
10718
|
this.turnDoneResolver = undefined;
|
|
10521
|
-
|
|
10719
|
+
resolve22();
|
|
10522
10720
|
}
|
|
10523
10721
|
break;
|
|
10524
10722
|
}
|
|
@@ -10588,9 +10786,9 @@ class CliRepl {
|
|
|
10588
10786
|
`));
|
|
10589
10787
|
this.isProcessing = false;
|
|
10590
10788
|
if (this.turnDoneResolver) {
|
|
10591
|
-
const
|
|
10789
|
+
const resolve22 = this.turnDoneResolver;
|
|
10592
10790
|
this.turnDoneResolver = undefined;
|
|
10593
|
-
|
|
10791
|
+
resolve22();
|
|
10594
10792
|
}
|
|
10595
10793
|
}
|
|
10596
10794
|
}
|
|
@@ -10627,8 +10825,8 @@ class CliRepl {
|
|
|
10627
10825
|
}
|
|
10628
10826
|
async submitTurn(text) {
|
|
10629
10827
|
try {
|
|
10630
|
-
const turnPromise = new Promise((
|
|
10631
|
-
this.turnDoneResolver =
|
|
10828
|
+
const turnPromise = new Promise((resolve22) => {
|
|
10829
|
+
this.turnDoneResolver = resolve22;
|
|
10632
10830
|
});
|
|
10633
10831
|
await this.session.submit({
|
|
10634
10832
|
type: "TurnInput",
|
|
@@ -10694,9 +10892,22 @@ async function main() {
|
|
|
10694
10892
|
} else if (arg === "list" || arg === "sessions" || arg === "--list") {
|
|
10695
10893
|
printSessionsList(storageManager);
|
|
10696
10894
|
process.exit(0);
|
|
10697
|
-
} else if (arg === "skills") {
|
|
10698
|
-
|
|
10699
|
-
|
|
10895
|
+
} else if (arg === "skills" || arg === "skill") {
|
|
10896
|
+
const subAction = args[i + 1];
|
|
10897
|
+
const target = args[i + 2];
|
|
10898
|
+
const isGlobal = args.includes("--global") || args.includes("-g");
|
|
10899
|
+
if (subAction && !subAction.startsWith("-")) {
|
|
10900
|
+
await handleSkillCliCommand(subAction, target, {
|
|
10901
|
+
cwd,
|
|
10902
|
+
isGlobal,
|
|
10903
|
+
baseUrl,
|
|
10904
|
+
loader: skillsLoader
|
|
10905
|
+
});
|
|
10906
|
+
process.exit(0);
|
|
10907
|
+
} else {
|
|
10908
|
+
printSkillsList(skillsLoader, cwd);
|
|
10909
|
+
process.exit(0);
|
|
10910
|
+
}
|
|
10700
10911
|
} else if (arg === "memories" || arg === "memory") {
|
|
10701
10912
|
printMemoriesList(memoryStore, cwd);
|
|
10702
10913
|
process.exit(0);
|
|
@@ -10718,7 +10929,7 @@ async function main() {
|
|
|
10718
10929
|
explicitApiKey = args[++i];
|
|
10719
10930
|
apiKey = explicitApiKey || apiKey;
|
|
10720
10931
|
} else if (arg === "--cwd" || arg === "-C") {
|
|
10721
|
-
cwd =
|
|
10932
|
+
cwd = resolve22(args[++i] || cwd);
|
|
10722
10933
|
} else if (arg === "--role" || arg === "-r") {
|
|
10723
10934
|
role = args[++i] || role;
|
|
10724
10935
|
} else if (arg === "--mcp") {
|
|
@@ -10744,11 +10955,11 @@ async function main() {
|
|
|
10744
10955
|
const mcpManager = new McpManager;
|
|
10745
10956
|
const candidateConfigs = [
|
|
10746
10957
|
mcpConfigFile,
|
|
10747
|
-
|
|
10748
|
-
|
|
10958
|
+
resolve22(cwd, ".mcp.json"),
|
|
10959
|
+
resolve22(cwd, "mcp_config.json")
|
|
10749
10960
|
].filter(Boolean);
|
|
10750
10961
|
for (const cfg of candidateConfigs) {
|
|
10751
|
-
if (
|
|
10962
|
+
if (existsSync24(cfg)) {
|
|
10752
10963
|
try {
|
|
10753
10964
|
await mcpManager.loadConfigFile(cfg);
|
|
10754
10965
|
mcpManager.registerToolsIntoRouter(tools4);
|
|
@@ -10951,6 +11162,62 @@ Resume a session with: ${style.bold("groupy --resume <thread_id>")}`);
|
|
|
10951
11162
|
}
|
|
10952
11163
|
console.log();
|
|
10953
11164
|
}
|
|
11165
|
+
async function handleSkillCliCommand(action, targetName, options) {
|
|
11166
|
+
const act = action.toLowerCase();
|
|
11167
|
+
if (act === "add" || act === "install") {
|
|
11168
|
+
if (!targetName) {
|
|
11169
|
+
console.error(style.yellow(`
|
|
11170
|
+
Usage: pikaa skill add <skill-name> [--global]
|
|
11171
|
+
`));
|
|
11172
|
+
process.exit(1);
|
|
11173
|
+
}
|
|
11174
|
+
try {
|
|
11175
|
+
console.log(style.dim(`
|
|
11176
|
+
Fetching skill '${targetName}' from catalog...`));
|
|
11177
|
+
const res = await installSkill(targetName, {
|
|
11178
|
+
cwd: options.cwd,
|
|
11179
|
+
global: options.isGlobal,
|
|
11180
|
+
backendUrl: options.baseUrl
|
|
11181
|
+
});
|
|
11182
|
+
console.log(style.green(`
|
|
11183
|
+
\u2713 ${res.message}`));
|
|
11184
|
+
console.log(style.dim(` To start using this skill in an AI coding session, simply run: pikaa
|
|
11185
|
+
`));
|
|
11186
|
+
} catch (err) {
|
|
11187
|
+
console.error(style.red(`
|
|
11188
|
+
\u2715 Failed to install skill: ${err.message}
|
|
11189
|
+
`));
|
|
11190
|
+
process.exit(1);
|
|
11191
|
+
}
|
|
11192
|
+
} else if (act === "remove" || act === "uninstall" || act === "rm") {
|
|
11193
|
+
if (!targetName) {
|
|
11194
|
+
console.error(style.yellow(`
|
|
11195
|
+
Usage: pikaa skill remove <skill-name> [--global]
|
|
11196
|
+
`));
|
|
11197
|
+
process.exit(1);
|
|
11198
|
+
}
|
|
11199
|
+
const res = removeSkill(targetName, { cwd: options.cwd, global: options.isGlobal });
|
|
11200
|
+
if (res.removed) {
|
|
11201
|
+
console.log(style.green(`
|
|
11202
|
+
\u2713 Skill '${targetName}' removed from ${res.targetDir}
|
|
11203
|
+
`));
|
|
11204
|
+
} else {
|
|
11205
|
+
console.log(style.yellow(`
|
|
11206
|
+
\u2715 Skill '${targetName}' was not found in ${res.targetDir}
|
|
11207
|
+
`));
|
|
11208
|
+
}
|
|
11209
|
+
} else if (act === "list" || act === "ls") {
|
|
11210
|
+
printSkillsList(options.loader, options.cwd);
|
|
11211
|
+
} else {
|
|
11212
|
+
if (act && !targetName) {
|
|
11213
|
+
return handleSkillCliCommand("add", act, options);
|
|
11214
|
+
}
|
|
11215
|
+
console.error(style.yellow(`
|
|
11216
|
+
Unknown skill action '${action}'. Available: add, remove, list
|
|
11217
|
+
`));
|
|
11218
|
+
process.exit(1);
|
|
11219
|
+
}
|
|
11220
|
+
}
|
|
10954
11221
|
function printSkillsList(loader, cwd) {
|
|
10955
11222
|
const skills = loader.discoverSkills(cwd);
|
|
10956
11223
|
console.log();
|