@pikaa-ai/pikaa 0.3.23 → 0.3.25
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 +407 -219
- package/dist/index.js +7 -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
|
|
@@ -1910,6 +1910,12 @@ class WindowsSandbox {
|
|
|
1910
1910
|
return null;
|
|
1911
1911
|
}
|
|
1912
1912
|
try {
|
|
1913
|
+
if (this.jobObjectHandle) {
|
|
1914
|
+
try {
|
|
1915
|
+
this.kernel32.symbols.CloseHandle(this.jobObjectHandle);
|
|
1916
|
+
} catch {}
|
|
1917
|
+
this.jobObjectHandle = null;
|
|
1918
|
+
}
|
|
1913
1919
|
const jobHandle = this.kernel32.symbols.CreateJobObjectW(null, null);
|
|
1914
1920
|
if (!jobHandle || jobHandle === 0) {
|
|
1915
1921
|
return null;
|
|
@@ -5269,7 +5275,6 @@ class SessionPersistenceManager {
|
|
|
5269
5275
|
// src/skills/loader.ts
|
|
5270
5276
|
import { existsSync as existsSync16, readdirSync as readdirSync6, readFileSync as readFileSync9 } from "fs";
|
|
5271
5277
|
import { resolve as resolve13, join as join8 } from "path";
|
|
5272
|
-
import { homedir as homedir3 } from "os";
|
|
5273
5278
|
var __dirname = "/home/runner/work/agent-cli/agent-cli/src/skills";
|
|
5274
5279
|
|
|
5275
5280
|
class SkillsLoader {
|
|
@@ -5345,7 +5350,7 @@ class SkillsLoader {
|
|
|
5345
5350
|
}
|
|
5346
5351
|
}
|
|
5347
5352
|
if (this.includeGlobal) {
|
|
5348
|
-
roots.push(getGlobalSkillsDir()
|
|
5353
|
+
roots.push(getGlobalSkillsDir());
|
|
5349
5354
|
}
|
|
5350
5355
|
roots.push(...this.customRoots.map((r) => resolve13(r)));
|
|
5351
5356
|
return roots.filter((r) => existsSync16(r));
|
|
@@ -5491,9 +5496,77 @@ When tackling complex specialized tasks that match any of these skills, autonomo
|
|
|
5491
5496
|
}
|
|
5492
5497
|
}
|
|
5493
5498
|
|
|
5499
|
+
// src/skills/installer.ts
|
|
5500
|
+
import { existsSync as existsSync17, mkdirSync as mkdirSync10, writeFileSync as writeFileSync5, rmSync as rmSync2 } from "fs";
|
|
5501
|
+
import { resolve as resolve14, join as join9 } from "path";
|
|
5502
|
+
async function installSkill(skillName, options) {
|
|
5503
|
+
const cleanName = skillName.trim().toLowerCase().replace(/^@/, "");
|
|
5504
|
+
if (!cleanName) {
|
|
5505
|
+
throw new Error("Skill name cannot be empty.");
|
|
5506
|
+
}
|
|
5507
|
+
const credStore = new CredentialsStore;
|
|
5508
|
+
const creds = credStore.load();
|
|
5509
|
+
let backend = (options.backendUrl || process.env.PIKAA_BACKEND_URL || process.env.GROUPY_BACKEND_URL || creds?.baseUrl || "https://api.groupy-hub.store").replace(/\/+$/, "");
|
|
5510
|
+
if (backend.endsWith("/v1")) {
|
|
5511
|
+
backend = backend.slice(0, -3).replace(/\/+$/, "");
|
|
5512
|
+
}
|
|
5513
|
+
const endpoint = `${backend}/api/skills/${encodeURIComponent(cleanName)}`;
|
|
5514
|
+
let resp;
|
|
5515
|
+
try {
|
|
5516
|
+
resp = await fetch(endpoint, {
|
|
5517
|
+
headers: creds?.accessToken ? { Authorization: `Bearer ${creds.accessToken}` } : {}
|
|
5518
|
+
});
|
|
5519
|
+
} catch (netErr) {
|
|
5520
|
+
throw new Error(`Failed to connect to backend at ${backend}: ${netErr.message}`);
|
|
5521
|
+
}
|
|
5522
|
+
if (!resp.ok) {
|
|
5523
|
+
if (resp.status === 404) {
|
|
5524
|
+
throw new Error(`Skill '${cleanName}' not found in catalog (${endpoint}).`);
|
|
5525
|
+
}
|
|
5526
|
+
const errText = await resp.text();
|
|
5527
|
+
throw new Error(`Backend error (${resp.status}): ${errText}`);
|
|
5528
|
+
}
|
|
5529
|
+
const skillData = await resp.json();
|
|
5530
|
+
if (!skillData.content) {
|
|
5531
|
+
throw new Error(`Skill '${cleanName}' does not contain markdown content.`);
|
|
5532
|
+
}
|
|
5533
|
+
const scope = options.global ? "global" : "workspace";
|
|
5534
|
+
const targetDir = options.global ? resolve14(getGlobalSkillsDir(), cleanName) : resolve14(options.cwd, ".agents", "skills", cleanName);
|
|
5535
|
+
mkdirSync10(targetDir, { recursive: true });
|
|
5536
|
+
const targetFile = join9(targetDir, "SKILL.md");
|
|
5537
|
+
let fileContent = skillData.content;
|
|
5538
|
+
if (!fileContent.startsWith("---")) {
|
|
5539
|
+
const desc = skillData.description ? `description: "${skillData.description.replace(/"/g, "\\\"")}"
|
|
5540
|
+
` : "";
|
|
5541
|
+
fileContent = `---
|
|
5542
|
+
name: ${cleanName}
|
|
5543
|
+
${desc}---
|
|
5544
|
+
|
|
5545
|
+
${fileContent}`;
|
|
5546
|
+
}
|
|
5547
|
+
writeFileSync5(targetFile, fileContent, "utf-8");
|
|
5548
|
+
return {
|
|
5549
|
+
success: true,
|
|
5550
|
+
skillName: cleanName,
|
|
5551
|
+
title: skillData.title || cleanName,
|
|
5552
|
+
targetPath: targetFile,
|
|
5553
|
+
scope,
|
|
5554
|
+
message: `Installed skill '${skillData.title || cleanName}' (@${cleanName}) into ${scope} at ${targetFile}`
|
|
5555
|
+
};
|
|
5556
|
+
}
|
|
5557
|
+
function removeSkill(skillName, options) {
|
|
5558
|
+
const cleanName = skillName.trim().toLowerCase().replace(/^@/, "");
|
|
5559
|
+
const targetDir = options.global ? resolve14(getGlobalSkillsDir(), cleanName) : resolve14(options.cwd, ".agents", "skills", cleanName);
|
|
5560
|
+
if (!existsSync17(targetDir)) {
|
|
5561
|
+
return { success: false, targetDir, removed: false };
|
|
5562
|
+
}
|
|
5563
|
+
rmSync2(targetDir, { recursive: true, force: true });
|
|
5564
|
+
return { success: true, targetDir, removed: true };
|
|
5565
|
+
}
|
|
5566
|
+
|
|
5494
5567
|
// src/memories/store.ts
|
|
5495
|
-
import { existsSync as
|
|
5496
|
-
import { resolve as
|
|
5568
|
+
import { existsSync as existsSync18, readFileSync as readFileSync10, writeFileSync as writeFileSync6, mkdirSync as mkdirSync11, readdirSync as readdirSync7 } from "fs";
|
|
5569
|
+
import { resolve as resolve15, join as join10, basename, dirname as dirname8 } from "path";
|
|
5497
5570
|
import { createHash } from "crypto";
|
|
5498
5571
|
class MemoryStore {
|
|
5499
5572
|
globalPath;
|
|
@@ -5503,14 +5576,14 @@ class MemoryStore {
|
|
|
5503
5576
|
this.customWorkspacePath = options.workspacePath;
|
|
5504
5577
|
}
|
|
5505
5578
|
findProjectRoot(cwd) {
|
|
5506
|
-
let current =
|
|
5579
|
+
let current = resolve15(cwd);
|
|
5507
5580
|
while (true) {
|
|
5508
|
-
if (
|
|
5581
|
+
if (existsSync18(join10(current, ".git"))) {
|
|
5509
5582
|
return current;
|
|
5510
5583
|
}
|
|
5511
5584
|
const parent = dirname8(current);
|
|
5512
5585
|
if (parent === current) {
|
|
5513
|
-
return
|
|
5586
|
+
return resolve15(cwd);
|
|
5514
5587
|
}
|
|
5515
5588
|
current = parent;
|
|
5516
5589
|
}
|
|
@@ -5518,30 +5591,30 @@ class MemoryStore {
|
|
|
5518
5591
|
getProjectSlug(cwd) {
|
|
5519
5592
|
const root = this.findProjectRoot(cwd);
|
|
5520
5593
|
const folderName = basename(root).toLowerCase().replace(/[^a-z0-9_-]/g, "-") || "project";
|
|
5521
|
-
const hash = createHash("sha256").update(
|
|
5594
|
+
const hash = createHash("sha256").update(resolve15(root)).digest("hex").slice(0, 6);
|
|
5522
5595
|
return `${folderName}-${hash}`;
|
|
5523
5596
|
}
|
|
5524
5597
|
getProjectMemoryDir(cwd) {
|
|
5525
5598
|
if (this.customWorkspacePath) {
|
|
5526
|
-
const dir2 =
|
|
5527
|
-
if (!
|
|
5599
|
+
const dir2 = resolve15(this.customWorkspacePath);
|
|
5600
|
+
if (!existsSync18(dir2)) {
|
|
5528
5601
|
try {
|
|
5529
|
-
|
|
5602
|
+
mkdirSync11(dir2, { recursive: true });
|
|
5530
5603
|
} catch {}
|
|
5531
5604
|
}
|
|
5532
5605
|
return dir2;
|
|
5533
5606
|
}
|
|
5534
5607
|
const slug = this.getProjectSlug(cwd);
|
|
5535
|
-
const dir =
|
|
5536
|
-
if (!
|
|
5608
|
+
const dir = join10(getProjectsDir(), slug, "memory");
|
|
5609
|
+
if (!existsSync18(dir)) {
|
|
5537
5610
|
try {
|
|
5538
|
-
|
|
5611
|
+
mkdirSync11(dir, { recursive: true });
|
|
5539
5612
|
} catch {}
|
|
5540
5613
|
}
|
|
5541
5614
|
return dir;
|
|
5542
5615
|
}
|
|
5543
5616
|
getMemoryIndexPath(cwd) {
|
|
5544
|
-
return
|
|
5617
|
+
return join10(this.getProjectMemoryDir(cwd), "MEMORY.md");
|
|
5545
5618
|
}
|
|
5546
5619
|
normalizeCategory(raw) {
|
|
5547
5620
|
const cat = raw.toLowerCase().trim();
|
|
@@ -5560,7 +5633,7 @@ class MemoryStore {
|
|
|
5560
5633
|
const sanitizedName = params.name.toLowerCase().trim().replace(/[^a-z0-9_-]/g, "_").replace(/^_+|_+$/g, "") || `note_${Date.now()}`;
|
|
5561
5634
|
const memoryDir = this.getProjectMemoryDir(params.cwd);
|
|
5562
5635
|
const fileName = `${type}_${sanitizedName}.md`;
|
|
5563
|
-
const filePath =
|
|
5636
|
+
const filePath = join10(memoryDir, fileName);
|
|
5564
5637
|
const nowIso = new Date().toISOString();
|
|
5565
5638
|
const cleanContent = params.content.trim();
|
|
5566
5639
|
const desc = (params.description || cleanContent.split(`
|
|
@@ -5579,7 +5652,7 @@ class MemoryStore {
|
|
|
5579
5652
|
""
|
|
5580
5653
|
].join(`
|
|
5581
5654
|
`);
|
|
5582
|
-
|
|
5655
|
+
writeFileSync6(filePath, frontmatter, "utf8");
|
|
5583
5656
|
this.syncMemoryIndex(params.cwd);
|
|
5584
5657
|
return {
|
|
5585
5658
|
id: `mem_${sanitizedName}`,
|
|
@@ -5595,17 +5668,17 @@ class MemoryStore {
|
|
|
5595
5668
|
}
|
|
5596
5669
|
readTopicMemory(topicNameOrFile, cwd) {
|
|
5597
5670
|
const memoryDir = this.getProjectMemoryDir(cwd);
|
|
5598
|
-
let targetPath =
|
|
5599
|
-
if (!
|
|
5671
|
+
let targetPath = join10(memoryDir, topicNameOrFile);
|
|
5672
|
+
if (!existsSync18(targetPath)) {
|
|
5600
5673
|
if (!topicNameOrFile.endsWith(".md")) {
|
|
5601
|
-
targetPath =
|
|
5674
|
+
targetPath = join10(memoryDir, `${topicNameOrFile}.md`);
|
|
5602
5675
|
}
|
|
5603
5676
|
}
|
|
5604
|
-
if (!
|
|
5677
|
+
if (!existsSync18(targetPath)) {
|
|
5605
5678
|
const files = readdirSync7(memoryDir);
|
|
5606
5679
|
const match = files.find((f) => f.includes(topicNameOrFile));
|
|
5607
5680
|
if (match) {
|
|
5608
|
-
targetPath =
|
|
5681
|
+
targetPath = join10(memoryDir, match);
|
|
5609
5682
|
} else {
|
|
5610
5683
|
return null;
|
|
5611
5684
|
}
|
|
@@ -5666,12 +5739,12 @@ class MemoryStore {
|
|
|
5666
5739
|
}
|
|
5667
5740
|
syncMemoryIndex(cwd) {
|
|
5668
5741
|
const memoryDir = this.getProjectMemoryDir(cwd);
|
|
5669
|
-
const indexPath =
|
|
5670
|
-
const files =
|
|
5742
|
+
const indexPath = join10(memoryDir, "MEMORY.md");
|
|
5743
|
+
const files = existsSync18(memoryDir) ? readdirSync7(memoryDir).filter((f) => f.endsWith(".md") && f !== "MEMORY.md") : [];
|
|
5671
5744
|
const items = [];
|
|
5672
5745
|
for (const f of files) {
|
|
5673
5746
|
try {
|
|
5674
|
-
const full =
|
|
5747
|
+
const full = join10(memoryDir, f);
|
|
5675
5748
|
const parsed = this.parseTopicFile(readFileSync10(full, "utf8"), full);
|
|
5676
5749
|
items.push({
|
|
5677
5750
|
type: parsed.type,
|
|
@@ -5692,13 +5765,13 @@ class MemoryStore {
|
|
|
5692
5765
|
indexLines.push(`- [${item.type}] **${item.name}**: ${item.desc} (topic: ${item.file})`);
|
|
5693
5766
|
}
|
|
5694
5767
|
const boundedLines = indexLines.slice(0, 200);
|
|
5695
|
-
|
|
5768
|
+
writeFileSync6(indexPath, boundedLines.join(`
|
|
5696
5769
|
`) + `
|
|
5697
5770
|
`, "utf8");
|
|
5698
5771
|
}
|
|
5699
5772
|
loadMemoryIndex(cwd) {
|
|
5700
5773
|
const indexPath = this.getMemoryIndexPath(cwd);
|
|
5701
|
-
if (!
|
|
5774
|
+
if (!existsSync18(indexPath))
|
|
5702
5775
|
return "";
|
|
5703
5776
|
try {
|
|
5704
5777
|
const raw = readFileSync10(indexPath, "utf8");
|
|
@@ -5714,13 +5787,13 @@ class MemoryStore {
|
|
|
5714
5787
|
}
|
|
5715
5788
|
listProjectMemories(cwd) {
|
|
5716
5789
|
const memoryDir = this.getProjectMemoryDir(cwd);
|
|
5717
|
-
if (!
|
|
5790
|
+
if (!existsSync18(memoryDir))
|
|
5718
5791
|
return [];
|
|
5719
5792
|
const files = readdirSync7(memoryDir).filter((f) => f.endsWith(".md") && f !== "MEMORY.md");
|
|
5720
5793
|
const list = [];
|
|
5721
5794
|
for (const f of files) {
|
|
5722
5795
|
try {
|
|
5723
|
-
const full =
|
|
5796
|
+
const full = join10(memoryDir, f);
|
|
5724
5797
|
list.push(this.parseTopicFile(readFileSync10(full, "utf8"), full));
|
|
5725
5798
|
} catch {}
|
|
5726
5799
|
}
|
|
@@ -5772,11 +5845,11 @@ class MemoryStore {
|
|
|
5772
5845
|
}
|
|
5773
5846
|
|
|
5774
5847
|
// src/worktree/manager.ts
|
|
5775
|
-
import { resolve as
|
|
5776
|
-
import { existsSync as
|
|
5848
|
+
import { resolve as resolve17, join as join11 } from "path";
|
|
5849
|
+
import { existsSync as existsSync19, mkdirSync as mkdirSync12, writeFileSync as writeFileSync7, readFileSync as readFileSync11 } from "fs";
|
|
5777
5850
|
|
|
5778
5851
|
// src/worktree/git.ts
|
|
5779
|
-
import { resolve as
|
|
5852
|
+
import { resolve as resolve16 } from "path";
|
|
5780
5853
|
var NON_INHERITABLE_GIT_ENV = [
|
|
5781
5854
|
"GIT_DIR",
|
|
5782
5855
|
"GIT_WORK_TREE",
|
|
@@ -5820,13 +5893,13 @@ async function getRepoRoot(cwd) {
|
|
|
5820
5893
|
const res = await runGit(cwd, ["rev-parse", "--show-toplevel"]);
|
|
5821
5894
|
if (res.exitCode !== 0 || !res.stdout)
|
|
5822
5895
|
return null;
|
|
5823
|
-
return
|
|
5896
|
+
return resolve16(res.stdout);
|
|
5824
5897
|
}
|
|
5825
5898
|
async function getMainRepoRoot(cwd) {
|
|
5826
5899
|
const res = await runGit(cwd, ["rev-parse", "--path-format=absolute", "--git-common-dir"]);
|
|
5827
5900
|
if (res.exitCode === 0 && res.stdout) {
|
|
5828
|
-
const commonDir =
|
|
5829
|
-
return
|
|
5901
|
+
const commonDir = resolve16(cwd, res.stdout);
|
|
5902
|
+
return resolve16(commonDir, "..");
|
|
5830
5903
|
}
|
|
5831
5904
|
return getRepoRoot(cwd);
|
|
5832
5905
|
}
|
|
@@ -5856,7 +5929,7 @@ async function listWorktreesGit(repoRoot) {
|
|
|
5856
5929
|
let isLocked = false;
|
|
5857
5930
|
for (const line of lines) {
|
|
5858
5931
|
if (line.startsWith("worktree ")) {
|
|
5859
|
-
path =
|
|
5932
|
+
path = resolve16(line.slice(9).trim());
|
|
5860
5933
|
} else if (line.startsWith("HEAD ")) {
|
|
5861
5934
|
commitHash = line.slice(5).trim();
|
|
5862
5935
|
} else if (line.startsWith("branch ")) {
|
|
@@ -5921,19 +5994,19 @@ class WorktreeManager {
|
|
|
5921
5994
|
}
|
|
5922
5995
|
const taskId = `task_${Date.now().toString(36)}_${Math.random().toString(36).slice(2, 6)}`;
|
|
5923
5996
|
const branchName = options.branch || `groupy/${taskId}`;
|
|
5924
|
-
const targetDir = options.worktreePath || (this.baseStorageDir ?
|
|
5925
|
-
const worktreeParent =
|
|
5926
|
-
if (!
|
|
5927
|
-
|
|
5997
|
+
const targetDir = options.worktreePath || (this.baseStorageDir ? resolve17(this.baseStorageDir, branchName.replace(/\//g, "_")) : resolve17(repoRoot, ".groupy", "worktrees", branchName.replace(/\//g, "_")));
|
|
5998
|
+
const worktreeParent = resolve17(targetDir, "..");
|
|
5999
|
+
if (!existsSync19(worktreeParent)) {
|
|
6000
|
+
mkdirSync12(worktreeParent, { recursive: true });
|
|
5928
6001
|
}
|
|
5929
6002
|
const baseBranch = options.baseBranch || await getCurrentBranch(repoRoot);
|
|
5930
6003
|
const result = await createWorktreeGit(repoRoot, targetDir, branchName, baseBranch);
|
|
5931
6004
|
if (!result.success) {
|
|
5932
6005
|
throw new Error(`Failed to create git worktree: ${result.error}`);
|
|
5933
6006
|
}
|
|
5934
|
-
const metaPath =
|
|
6007
|
+
const metaPath = join11(targetDir, "groupy-thread.json");
|
|
5935
6008
|
try {
|
|
5936
|
-
|
|
6009
|
+
writeFileSync7(metaPath, JSON.stringify({
|
|
5937
6010
|
version: 1,
|
|
5938
6011
|
ownerThreadId: options.threadId || null,
|
|
5939
6012
|
branch: branchName,
|
|
@@ -5942,7 +6015,7 @@ class WorktreeManager {
|
|
|
5942
6015
|
}, null, 2), "utf8");
|
|
5943
6016
|
} catch {}
|
|
5944
6017
|
const worktrees = await listWorktreesGit(repoRoot);
|
|
5945
|
-
const created = worktrees.find((w) =>
|
|
6018
|
+
const created = worktrees.find((w) => resolve17(w.path) === resolve17(targetDir));
|
|
5946
6019
|
return created || {
|
|
5947
6020
|
path: targetDir,
|
|
5948
6021
|
branch: branchName,
|
|
@@ -5957,8 +6030,8 @@ class WorktreeManager {
|
|
|
5957
6030
|
return [];
|
|
5958
6031
|
const worktrees = await listWorktreesGit(repoRoot);
|
|
5959
6032
|
return worktrees.map((wt) => {
|
|
5960
|
-
const metaPath =
|
|
5961
|
-
if (
|
|
6033
|
+
const metaPath = join11(wt.path, "groupy-thread.json");
|
|
6034
|
+
if (existsSync19(metaPath)) {
|
|
5962
6035
|
try {
|
|
5963
6036
|
const raw = JSON.parse(readFileSync11(metaPath, "utf8"));
|
|
5964
6037
|
return { ...wt, threadId: raw.ownerThreadId || raw.threadId };
|
|
@@ -5968,7 +6041,7 @@ class WorktreeManager {
|
|
|
5968
6041
|
});
|
|
5969
6042
|
}
|
|
5970
6043
|
async mergeWorktree(worktreePath, options = {}) {
|
|
5971
|
-
const resolvedPath =
|
|
6044
|
+
const resolvedPath = resolve17(worktreePath);
|
|
5972
6045
|
const repoRoot = await getMainRepoRoot(resolvedPath);
|
|
5973
6046
|
if (!repoRoot) {
|
|
5974
6047
|
return { success: false, message: "Worktree path is not a valid git repository." };
|
|
@@ -6005,7 +6078,7 @@ class WorktreeManager {
|
|
|
6005
6078
|
};
|
|
6006
6079
|
}
|
|
6007
6080
|
async removeWorktree(worktreePath, deleteBranch = false) {
|
|
6008
|
-
const resolvedPath =
|
|
6081
|
+
const resolvedPath = resolve17(worktreePath);
|
|
6009
6082
|
const repoRoot = await getMainRepoRoot(resolvedPath);
|
|
6010
6083
|
if (!repoRoot)
|
|
6011
6084
|
return false;
|
|
@@ -6086,8 +6159,8 @@ class AuthClient {
|
|
|
6086
6159
|
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`;
|
|
6087
6160
|
let serverResolve;
|
|
6088
6161
|
let serverReject;
|
|
6089
|
-
const codePromise = new Promise((
|
|
6090
|
-
serverResolve =
|
|
6162
|
+
const codePromise = new Promise((resolve18, reject) => {
|
|
6163
|
+
serverResolve = resolve18;
|
|
6091
6164
|
serverReject = reject;
|
|
6092
6165
|
});
|
|
6093
6166
|
if (options.openBrowser !== false) {
|
|
@@ -6656,7 +6729,7 @@ function parsePatch(oldSrc, newSrc, contextLines = 3) {
|
|
|
6656
6729
|
// package.json
|
|
6657
6730
|
var package_default = {
|
|
6658
6731
|
name: "@pikaa-ai/pikaa",
|
|
6659
|
-
version: "0.3.
|
|
6732
|
+
version: "0.3.25",
|
|
6660
6733
|
description: "PIKAA CLI - AI coding agent that runs locally in your terminal.",
|
|
6661
6734
|
main: "./dist/index.js",
|
|
6662
6735
|
module: "./dist/index.js",
|
|
@@ -6672,7 +6745,6 @@ var package_default = {
|
|
|
6672
6745
|
"bin",
|
|
6673
6746
|
"templates",
|
|
6674
6747
|
"assets",
|
|
6675
|
-
"skills/**/SKILL.md",
|
|
6676
6748
|
"README.md",
|
|
6677
6749
|
"LICENSE"
|
|
6678
6750
|
],
|
|
@@ -6734,7 +6806,7 @@ function getCliVersion(options = {}) {
|
|
|
6734
6806
|
}
|
|
6735
6807
|
|
|
6736
6808
|
// src/cli/ui/animation/banner-animation.ts
|
|
6737
|
-
import { homedir as
|
|
6809
|
+
import { homedir as homedir3 } from "os";
|
|
6738
6810
|
import { execSync } from "child_process";
|
|
6739
6811
|
var ROSE = "\x1B[38;2;205;105;74m";
|
|
6740
6812
|
var ROSE_DIM = "\x1B[38;2;120;60;45m";
|
|
@@ -6744,7 +6816,7 @@ var BOLD = "\x1B[1m";
|
|
|
6744
6816
|
var ITALIC = "\x1B[3m";
|
|
6745
6817
|
var RESET = "\x1B[0m";
|
|
6746
6818
|
function shortenPath(cwd) {
|
|
6747
|
-
const home =
|
|
6819
|
+
const home = homedir3();
|
|
6748
6820
|
if (cwd.startsWith(home)) {
|
|
6749
6821
|
return `~${cwd.slice(home.length).replace(/\\/g, "/")}`;
|
|
6750
6822
|
}
|
|
@@ -7224,8 +7296,25 @@ import readline2 from "readline";
|
|
|
7224
7296
|
import readline from "readline";
|
|
7225
7297
|
var keypressEventsInitialized = false;
|
|
7226
7298
|
var listeners = new Set;
|
|
7299
|
+
var rawModeState = null;
|
|
7300
|
+
function ensureRawMode(active) {
|
|
7301
|
+
if (!process.stdin.isTTY)
|
|
7302
|
+
return;
|
|
7303
|
+
if (rawModeState === active)
|
|
7304
|
+
return;
|
|
7305
|
+
try {
|
|
7306
|
+
process.stdin.setRawMode(active);
|
|
7307
|
+
rawModeState = active;
|
|
7308
|
+
if (active) {
|
|
7309
|
+
process.stdin.resume();
|
|
7310
|
+
}
|
|
7311
|
+
} catch {}
|
|
7312
|
+
}
|
|
7227
7313
|
function initGlobalKeypress() {
|
|
7228
7314
|
if (!keypressEventsInitialized && process.stdin.isTTY) {
|
|
7315
|
+
try {
|
|
7316
|
+
process.stdin.on("error", () => {});
|
|
7317
|
+
} catch {}
|
|
7229
7318
|
readline.emitKeypressEvents(process.stdin);
|
|
7230
7319
|
keypressEventsInitialized = true;
|
|
7231
7320
|
process.stdin.on("keypress", (str, key) => {
|
|
@@ -7302,15 +7391,15 @@ class InteractiveLineEditor {
|
|
|
7302
7391
|
}
|
|
7303
7392
|
async readLine() {
|
|
7304
7393
|
if (!process.stdin.isTTY) {
|
|
7305
|
-
return new Promise((
|
|
7394
|
+
return new Promise((resolve18) => {
|
|
7306
7395
|
const rl = readline2.createInterface({ input: process.stdin, output: process.stdout });
|
|
7307
7396
|
rl.question(this.promptSymbol, (answer) => {
|
|
7308
7397
|
rl.close();
|
|
7309
|
-
|
|
7398
|
+
resolve18(answer);
|
|
7310
7399
|
});
|
|
7311
7400
|
});
|
|
7312
7401
|
}
|
|
7313
|
-
return new Promise((
|
|
7402
|
+
return new Promise((resolve18) => {
|
|
7314
7403
|
let buffer = "";
|
|
7315
7404
|
let cursor = 0;
|
|
7316
7405
|
let selectedIndex = 0;
|
|
@@ -7318,12 +7407,7 @@ class InteractiveLineEditor {
|
|
|
7318
7407
|
let popupDismissed = false;
|
|
7319
7408
|
let lastCursorRowFromTop = 0;
|
|
7320
7409
|
let unsubscribeKeypress = null;
|
|
7321
|
-
|
|
7322
|
-
try {
|
|
7323
|
-
process.stdin.setRawMode(true);
|
|
7324
|
-
} catch {}
|
|
7325
|
-
}
|
|
7326
|
-
process.stdin.resume();
|
|
7410
|
+
ensureRawMode(true);
|
|
7327
7411
|
const getMatchingCommands = () => {
|
|
7328
7412
|
if (!buffer.startsWith("/") || popupDismissed)
|
|
7329
7413
|
return [];
|
|
@@ -7357,7 +7441,7 @@ class InteractiveLineEditor {
|
|
|
7357
7441
|
};
|
|
7358
7442
|
const getRule = () => {
|
|
7359
7443
|
const cols = getTerminalCols();
|
|
7360
|
-
const ruleLen = Math.max(10, cols -
|
|
7444
|
+
const ruleLen = Math.max(10, cols - 6);
|
|
7361
7445
|
return "\u2500".repeat(ruleLen);
|
|
7362
7446
|
};
|
|
7363
7447
|
const ensureVisible = (totalItems, visibleRows) => {
|
|
@@ -7383,11 +7467,12 @@ class InteractiveLineEditor {
|
|
|
7383
7467
|
const redraw = () => {
|
|
7384
7468
|
const termCols = getTerminalCols();
|
|
7385
7469
|
const visiblePromptWidth = this.promptSymbol.replace(/\x1b\[[0-9;]*m/g, "").length;
|
|
7470
|
+
let frame = "";
|
|
7386
7471
|
if (lastCursorRowFromTop > 0) {
|
|
7387
|
-
|
|
7472
|
+
frame += `\x1B[${lastCursorRowFromTop}A`;
|
|
7388
7473
|
}
|
|
7389
|
-
|
|
7390
|
-
|
|
7474
|
+
frame += "\r\x1B[J";
|
|
7475
|
+
frame += `${this.promptSymbol}${buffer}`;
|
|
7391
7476
|
const totalPromptChars = visiblePromptWidth + buffer.length;
|
|
7392
7477
|
const promptRows = Math.max(1, Math.floor(totalPromptChars / termCols) + 1);
|
|
7393
7478
|
const slashMatches = getMatchingCommands();
|
|
@@ -7395,7 +7480,7 @@ class InteractiveLineEditor {
|
|
|
7395
7480
|
const fileMatches = activeFile ? getMatchingFiles(activeFile.query) : [];
|
|
7396
7481
|
let menuRows = 0;
|
|
7397
7482
|
if (buffer.startsWith("/") && !popupDismissed && slashMatches.length > 0) {
|
|
7398
|
-
const BOX_WIDTH = Math.max(20, Math.min(termCols -
|
|
7483
|
+
const BOX_WIDTH = Math.max(20, Math.min(termCols - 6, 120));
|
|
7399
7484
|
const maxVisible = Math.min(slashMatches.length, 7);
|
|
7400
7485
|
ensureVisible(slashMatches.length, maxVisible);
|
|
7401
7486
|
const visibleMatches = slashMatches.slice(scrollTop, scrollTop + maxVisible);
|
|
@@ -7422,12 +7507,12 @@ class InteractiveLineEditor {
|
|
|
7422
7507
|
}
|
|
7423
7508
|
menuLines.push(` ${RULE_COLOR2}${rule}${RESET2}`);
|
|
7424
7509
|
for (const line of menuLines) {
|
|
7425
|
-
|
|
7426
|
-
\x1B[2K${line}
|
|
7510
|
+
frame += `
|
|
7511
|
+
\x1B[2K${line}`;
|
|
7427
7512
|
}
|
|
7428
7513
|
menuRows = menuLines.length;
|
|
7429
7514
|
} else if (activeFile && !popupDismissed && fileMatches.length > 0) {
|
|
7430
|
-
const BOX_WIDTH = Math.max(20, Math.min(termCols -
|
|
7515
|
+
const BOX_WIDTH = Math.max(20, Math.min(termCols - 6, 120));
|
|
7431
7516
|
const maxVisible = Math.min(fileMatches.length, 7);
|
|
7432
7517
|
ensureVisible(fileMatches.length, maxVisible);
|
|
7433
7518
|
const visibleMatches = fileMatches.slice(scrollTop, scrollTop + maxVisible);
|
|
@@ -7459,31 +7544,34 @@ class InteractiveLineEditor {
|
|
|
7459
7544
|
menuLines.push(` ${style.dim("\u2502")}${style.dim(footerPadded)}${style.dim("\u2502")}`);
|
|
7460
7545
|
menuLines.push(` ${style.dim("\u2514" + "\u2500".repeat(BOX_WIDTH) + "\u2518")}`);
|
|
7461
7546
|
for (const line of menuLines) {
|
|
7462
|
-
|
|
7463
|
-
\x1B[2K${line}
|
|
7547
|
+
frame += `
|
|
7548
|
+
\x1B[2K${line}`;
|
|
7464
7549
|
}
|
|
7465
7550
|
menuRows = menuLines.length;
|
|
7466
7551
|
} else {
|
|
7467
7552
|
const RULE_COLOR2 = "\x1B[38;2;60;60;68m";
|
|
7468
7553
|
const bottomRule = ` ${RULE_COLOR2}${getRule()}\x1B[0m`;
|
|
7469
7554
|
const modeLine = this.getModeLine();
|
|
7470
|
-
|
|
7555
|
+
frame += `
|
|
7471
7556
|
\x1B[2K${bottomRule}
|
|
7472
|
-
\x1B[2K${modeLine}
|
|
7557
|
+
\x1B[2K${modeLine}`;
|
|
7473
7558
|
menuRows = 2;
|
|
7474
7559
|
}
|
|
7475
7560
|
const cursorCharsFromTop = visiblePromptWidth + cursor;
|
|
7476
7561
|
const cursorRow = Math.floor(cursorCharsFromTop / termCols);
|
|
7477
7562
|
const cursorCol = cursorCharsFromTop % termCols;
|
|
7478
|
-
const moveUpRows = promptRows - 1 - cursorRow + menuRows;
|
|
7563
|
+
const moveUpRows = Math.max(0, promptRows - 1 - cursorRow + menuRows);
|
|
7479
7564
|
if (moveUpRows > 0) {
|
|
7480
|
-
|
|
7565
|
+
frame += `\x1B[${moveUpRows}A`;
|
|
7481
7566
|
}
|
|
7482
|
-
|
|
7567
|
+
frame += "\r";
|
|
7483
7568
|
if (cursorCol > 0) {
|
|
7484
|
-
|
|
7569
|
+
frame += `\x1B[${cursorCol}C`;
|
|
7485
7570
|
}
|
|
7486
7571
|
lastCursorRowFromTop = cursorRow;
|
|
7572
|
+
try {
|
|
7573
|
+
process.stdout.write(frame);
|
|
7574
|
+
} catch {}
|
|
7487
7575
|
};
|
|
7488
7576
|
const onResize = () => {
|
|
7489
7577
|
redraw();
|
|
@@ -7499,24 +7587,24 @@ class InteractiveLineEditor {
|
|
|
7499
7587
|
unsubscribeKeypress();
|
|
7500
7588
|
unsubscribeKeypress = null;
|
|
7501
7589
|
}
|
|
7502
|
-
|
|
7503
|
-
|
|
7504
|
-
process.stdin.setRawMode(false);
|
|
7505
|
-
} catch {}
|
|
7506
|
-
}
|
|
7590
|
+
ensureRawMode(false);
|
|
7591
|
+
let cleanupFrame = "";
|
|
7507
7592
|
if (lastCursorRowFromTop > 0) {
|
|
7508
|
-
|
|
7593
|
+
cleanupFrame += `\x1B[${lastCursorRowFromTop}A`;
|
|
7509
7594
|
}
|
|
7510
|
-
|
|
7595
|
+
cleanupFrame += "\r\x1B[J";
|
|
7511
7596
|
if (result.trim().length > 0 && !result.startsWith("/")) {
|
|
7512
|
-
|
|
7597
|
+
cleanupFrame += `${CliFormatter.formatClaudeUserPrompt(result)}
|
|
7513
7598
|
|
|
7514
|
-
|
|
7599
|
+
`;
|
|
7515
7600
|
} else {
|
|
7516
|
-
|
|
7517
|
-
|
|
7601
|
+
cleanupFrame += `
|
|
7602
|
+
`;
|
|
7518
7603
|
}
|
|
7519
|
-
|
|
7604
|
+
try {
|
|
7605
|
+
process.stdout.write(cleanupFrame);
|
|
7606
|
+
} catch {}
|
|
7607
|
+
resolve18(result);
|
|
7520
7608
|
};
|
|
7521
7609
|
const onKeypress = (_str, key) => {
|
|
7522
7610
|
if (!key)
|
|
@@ -7704,7 +7792,7 @@ async function promptChoice(config) {
|
|
|
7704
7792
|
const def = choices[defaultIndex] || choices[0];
|
|
7705
7793
|
return def ? def.value : "";
|
|
7706
7794
|
}
|
|
7707
|
-
return new Promise((
|
|
7795
|
+
return new Promise((resolve18) => {
|
|
7708
7796
|
const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
|
|
7709
7797
|
const promptText = ` ${message} (${choices.map((c3) => `[${c3.key}] ${c3.label}`).join(", ")}): `;
|
|
7710
7798
|
rl.question(promptText, (answer) => {
|
|
@@ -7712,23 +7800,20 @@ async function promptChoice(config) {
|
|
|
7712
7800
|
const trimmed = answer.trim().toLowerCase();
|
|
7713
7801
|
const match = choices.find((c3) => c3.key.toLowerCase() === trimmed);
|
|
7714
7802
|
if (match) {
|
|
7715
|
-
|
|
7803
|
+
resolve18(match.value);
|
|
7716
7804
|
} else {
|
|
7717
7805
|
const def = choices[defaultIndex] || choices[0];
|
|
7718
|
-
|
|
7806
|
+
resolve18(def ? def.value : "");
|
|
7719
7807
|
}
|
|
7720
7808
|
});
|
|
7721
7809
|
});
|
|
7722
7810
|
}
|
|
7723
|
-
return new Promise((
|
|
7811
|
+
return new Promise((resolve18) => {
|
|
7724
7812
|
let selectedIndex = defaultIndex;
|
|
7725
7813
|
if (selectedIndex < 0 || selectedIndex >= choices.length)
|
|
7726
7814
|
selectedIndex = 0;
|
|
7727
|
-
const wasRaw = process.stdin.isRaw;
|
|
7728
|
-
|
|
7729
|
-
process.stdin.setRawMode(true);
|
|
7730
|
-
} catch {}
|
|
7731
|
-
process.stdin.resume();
|
|
7815
|
+
const wasRaw = process.stdin.isRaw ?? false;
|
|
7816
|
+
ensureRawMode(true);
|
|
7732
7817
|
const render = () => {
|
|
7733
7818
|
const parts = choices.map((choice, idx) => {
|
|
7734
7819
|
const isSelected = idx === selectedIndex;
|
|
@@ -7747,12 +7832,10 @@ async function promptChoice(config) {
|
|
|
7747
7832
|
unsubscribe();
|
|
7748
7833
|
unsubscribe = null;
|
|
7749
7834
|
}
|
|
7750
|
-
|
|
7751
|
-
process.stdin.setRawMode(wasRaw ?? false);
|
|
7752
|
-
} catch {}
|
|
7835
|
+
ensureRawMode(wasRaw);
|
|
7753
7836
|
process.stdout.write(`\r\x1B[1A\r\x1B[2K ${style.bold(message)} ${style.cyan(`[${confirmedChoice.key}] ${confirmedChoice.label}`)}
|
|
7754
7837
|
\r\x1B[2K`);
|
|
7755
|
-
|
|
7838
|
+
resolve18(confirmedChoice.value);
|
|
7756
7839
|
};
|
|
7757
7840
|
const onKeypress = (_str, key) => {
|
|
7758
7841
|
if (!key)
|
|
@@ -7818,13 +7901,10 @@ async function promptToolApproval(params) {
|
|
|
7818
7901
|
renderCard(1);
|
|
7819
7902
|
return "yes";
|
|
7820
7903
|
}
|
|
7821
|
-
return new Promise((
|
|
7904
|
+
return new Promise((resolve18) => {
|
|
7822
7905
|
let selectedIndex = 1;
|
|
7823
|
-
const wasRaw = process.stdin.isRaw;
|
|
7824
|
-
|
|
7825
|
-
process.stdin.setRawMode(true);
|
|
7826
|
-
} catch {}
|
|
7827
|
-
process.stdin.resume();
|
|
7906
|
+
const wasRaw = process.stdin.isRaw ?? false;
|
|
7907
|
+
ensureRawMode(true);
|
|
7828
7908
|
const render = () => {
|
|
7829
7909
|
renderCard(selectedIndex);
|
|
7830
7910
|
};
|
|
@@ -7834,11 +7914,9 @@ async function promptToolApproval(params) {
|
|
|
7834
7914
|
unsubscribe();
|
|
7835
7915
|
unsubscribe = null;
|
|
7836
7916
|
}
|
|
7837
|
-
|
|
7838
|
-
process.stdin.setRawMode(wasRaw ?? false);
|
|
7839
|
-
} catch {}
|
|
7917
|
+
ensureRawMode(wasRaw);
|
|
7840
7918
|
console.log();
|
|
7841
|
-
|
|
7919
|
+
resolve18(val);
|
|
7842
7920
|
};
|
|
7843
7921
|
const onKeypress = (_str, key) => {
|
|
7844
7922
|
if (!key)
|
|
@@ -7921,7 +7999,7 @@ async function promptUserQuestion(params) {
|
|
|
7921
7999
|
if (!process.stdin.isTTY || false || !process.stdin.readable) {
|
|
7922
8000
|
return options[0] || "yes";
|
|
7923
8001
|
}
|
|
7924
|
-
return new Promise((
|
|
8002
|
+
return new Promise((resolve18) => {
|
|
7925
8003
|
const rl = readline3.createInterface({ input: process.stdin, output: process.stdout });
|
|
7926
8004
|
const promptLabel = options.length > 0 ? `Select [1-${options.length}] or type custom response: ` : `Your response: `;
|
|
7927
8005
|
rl.question(` ${style.bold(promptLabel)}`, (answer) => {
|
|
@@ -7931,7 +8009,7 @@ async function promptUserQuestion(params) {
|
|
|
7931
8009
|
const fallback = options[0] || "";
|
|
7932
8010
|
console.log(style.dim(` \u21B3 Default: ${fallback || "(empty)"}
|
|
7933
8011
|
`));
|
|
7934
|
-
|
|
8012
|
+
resolve18(fallback);
|
|
7935
8013
|
return;
|
|
7936
8014
|
}
|
|
7937
8015
|
const num = parseInt(trimmed, 10);
|
|
@@ -7939,26 +8017,26 @@ async function promptUserQuestion(params) {
|
|
|
7939
8017
|
const picked = options[num - 1];
|
|
7940
8018
|
console.log(style.green(` \u2714 Selected: ${picked}
|
|
7941
8019
|
`));
|
|
7942
|
-
|
|
8020
|
+
resolve18(picked);
|
|
7943
8021
|
return;
|
|
7944
8022
|
}
|
|
7945
8023
|
if (options.length === 2) {
|
|
7946
8024
|
if (/^(y|yes)$/i.test(trimmed)) {
|
|
7947
8025
|
console.log(style.green(` \u2714 Selected: ${options[0]}
|
|
7948
8026
|
`));
|
|
7949
|
-
|
|
8027
|
+
resolve18(options[0]);
|
|
7950
8028
|
return;
|
|
7951
8029
|
}
|
|
7952
8030
|
if (/^(n|no)$/i.test(trimmed)) {
|
|
7953
8031
|
console.log(style.green(` \u2714 Selected: ${options[1]}
|
|
7954
8032
|
`));
|
|
7955
|
-
|
|
8033
|
+
resolve18(options[1]);
|
|
7956
8034
|
return;
|
|
7957
8035
|
}
|
|
7958
8036
|
}
|
|
7959
8037
|
console.log(style.green(` \u2714 Answer: ${trimmed}
|
|
7960
8038
|
`));
|
|
7961
|
-
|
|
8039
|
+
resolve18(trimmed);
|
|
7962
8040
|
});
|
|
7963
8041
|
});
|
|
7964
8042
|
}
|
|
@@ -7987,15 +8065,12 @@ async function promptInteractiveList(config) {
|
|
|
7987
8065
|
`);
|
|
7988
8066
|
return { selectedIndex: -1, action: "close" };
|
|
7989
8067
|
}
|
|
7990
|
-
return new Promise((
|
|
8068
|
+
return new Promise((resolve18) => {
|
|
7991
8069
|
let selectedIndex = Math.max(0, Math.min(defaultIndex, items.length - 1));
|
|
7992
8070
|
let scrollTop = 0;
|
|
7993
8071
|
let renderedLines = 0;
|
|
7994
|
-
const wasRaw = process.stdin.isRaw;
|
|
7995
|
-
|
|
7996
|
-
process.stdin.setRawMode(true);
|
|
7997
|
-
} catch {}
|
|
7998
|
-
process.stdin.resume();
|
|
8072
|
+
const wasRaw = process.stdin.isRaw ?? false;
|
|
8073
|
+
ensureRawMode(true);
|
|
7999
8074
|
process.stdout.write("\x1B[?25l");
|
|
8000
8075
|
const BOX_WIDTH = Math.min(process.stdout.columns ?? 80, 76);
|
|
8001
8076
|
const ensureVisible = () => {
|
|
@@ -8079,10 +8154,8 @@ async function promptInteractiveList(config) {
|
|
|
8079
8154
|
unsubscribe();
|
|
8080
8155
|
unsubscribe = null;
|
|
8081
8156
|
}
|
|
8082
|
-
|
|
8083
|
-
|
|
8084
|
-
} catch {}
|
|
8085
|
-
resolve17(res);
|
|
8157
|
+
ensureRawMode(wasRaw);
|
|
8158
|
+
resolve18(res);
|
|
8086
8159
|
};
|
|
8087
8160
|
const onKeypress = async (_str, key) => {
|
|
8088
8161
|
if (!key)
|
|
@@ -8153,8 +8226,8 @@ async function promptInteractiveList(config) {
|
|
|
8153
8226
|
}
|
|
8154
8227
|
|
|
8155
8228
|
// src/security/scanner.ts
|
|
8156
|
-
import { existsSync as
|
|
8157
|
-
import { join as
|
|
8229
|
+
import { existsSync as existsSync20, readdirSync as readdirSync8, readFileSync as readFileSync12, statSync as statSync5 } from "fs";
|
|
8230
|
+
import { join as join12, relative as relative2, resolve as resolve18 } from "path";
|
|
8158
8231
|
var SECURITY_RULES = [
|
|
8159
8232
|
{
|
|
8160
8233
|
id: "SEC-001",
|
|
@@ -8286,13 +8359,13 @@ var IGNORED_FILES = new Set([
|
|
|
8286
8359
|
]);
|
|
8287
8360
|
async function runSecurityScan(targetDir, options = {}) {
|
|
8288
8361
|
const startTime = performance.now();
|
|
8289
|
-
const root =
|
|
8362
|
+
const root = resolve18(targetDir);
|
|
8290
8363
|
const isDirectTestDir = targetDir.includes("test") || Boolean(options.includeTests);
|
|
8291
8364
|
const maxFiles = options.maxFiles || 2000;
|
|
8292
8365
|
const findings = [];
|
|
8293
8366
|
let scannedCount = 0;
|
|
8294
8367
|
function walk(current) {
|
|
8295
|
-
if (scannedCount >= maxFiles || !
|
|
8368
|
+
if (scannedCount >= maxFiles || !existsSync20(current))
|
|
8296
8369
|
return;
|
|
8297
8370
|
let entries;
|
|
8298
8371
|
try {
|
|
@@ -8303,7 +8376,7 @@ async function runSecurityScan(targetDir, options = {}) {
|
|
|
8303
8376
|
for (const entry of entries) {
|
|
8304
8377
|
if (scannedCount >= maxFiles)
|
|
8305
8378
|
break;
|
|
8306
|
-
const fullPath =
|
|
8379
|
+
const fullPath = join12(current, entry);
|
|
8307
8380
|
let stat;
|
|
8308
8381
|
try {
|
|
8309
8382
|
stat = statSync5(fullPath);
|
|
@@ -8381,38 +8454,38 @@ async function runSecurityScan(targetDir, options = {}) {
|
|
|
8381
8454
|
}
|
|
8382
8455
|
|
|
8383
8456
|
// src/mcp/servers/chrome-devtools/index.ts
|
|
8384
|
-
import { resolve as
|
|
8457
|
+
import { resolve as resolve19 } from "path";
|
|
8385
8458
|
|
|
8386
8459
|
// src/mcp/servers/chrome-devtools/server.ts
|
|
8387
8460
|
if (false) {}
|
|
8388
8461
|
|
|
8389
8462
|
// src/mcp/servers/chrome-devtools/index.ts
|
|
8390
8463
|
var __dirname = "/home/runner/work/agent-cli/agent-cli/src/mcp/servers/chrome-devtools";
|
|
8391
|
-
var CHROME_DEVTOOLS_MCP_SERVER_PATH =
|
|
8464
|
+
var CHROME_DEVTOOLS_MCP_SERVER_PATH = resolve19(__dirname, "server.ts");
|
|
8392
8465
|
|
|
8393
8466
|
// src/mcp/servers/web-search/index.ts
|
|
8394
|
-
import { resolve as
|
|
8467
|
+
import { resolve as resolve20 } from "path";
|
|
8395
8468
|
|
|
8396
8469
|
// src/mcp/servers/web-search/server.ts
|
|
8397
8470
|
if (false) {}
|
|
8398
8471
|
|
|
8399
8472
|
// src/mcp/servers/web-search/index.ts
|
|
8400
8473
|
var __dirname = "/home/runner/work/agent-cli/agent-cli/src/mcp/servers/web-search";
|
|
8401
|
-
var WEB_SEARCH_MCP_SERVER_PATH =
|
|
8474
|
+
var WEB_SEARCH_MCP_SERVER_PATH = resolve20(__dirname, "server.ts");
|
|
8402
8475
|
|
|
8403
8476
|
// src/mcp/servers/sqlite/index.ts
|
|
8404
|
-
import { resolve as
|
|
8477
|
+
import { resolve as resolve21 } from "path";
|
|
8405
8478
|
|
|
8406
8479
|
// src/mcp/servers/sqlite/server.ts
|
|
8407
8480
|
if (false) {}
|
|
8408
8481
|
|
|
8409
8482
|
// src/mcp/servers/sqlite/index.ts
|
|
8410
8483
|
var __dirname = "/home/runner/work/agent-cli/agent-cli/src/mcp/servers/sqlite";
|
|
8411
|
-
var SQLITE_MCP_SERVER_PATH =
|
|
8484
|
+
var SQLITE_MCP_SERVER_PATH = resolve21(__dirname, "server.ts");
|
|
8412
8485
|
|
|
8413
8486
|
// src/init/project-analyzer.ts
|
|
8414
|
-
import { existsSync as
|
|
8415
|
-
import { join as
|
|
8487
|
+
import { existsSync as existsSync21, readFileSync as readFileSync13, readdirSync as readdirSync9 } from "fs";
|
|
8488
|
+
import { join as join13, basename as basename3 } from "path";
|
|
8416
8489
|
|
|
8417
8490
|
class ProjectAnalyzer {
|
|
8418
8491
|
cwd;
|
|
@@ -8430,8 +8503,8 @@ class ProjectAnalyzer {
|
|
|
8430
8503
|
const architectureNotes = [];
|
|
8431
8504
|
const codeConventions = [];
|
|
8432
8505
|
let description = readmeInfo.description;
|
|
8433
|
-
const pkgPath =
|
|
8434
|
-
if (
|
|
8506
|
+
const pkgPath = join13(this.cwd, "package.json");
|
|
8507
|
+
if (existsSync21(pkgPath)) {
|
|
8435
8508
|
try {
|
|
8436
8509
|
const pkg = JSON.parse(readFileSync13(pkgPath, "utf8"));
|
|
8437
8510
|
if (!description && pkg.description)
|
|
@@ -8504,8 +8577,8 @@ class ProjectAnalyzer {
|
|
|
8504
8577
|
}
|
|
8505
8578
|
} catch {}
|
|
8506
8579
|
}
|
|
8507
|
-
const tsconfigPath =
|
|
8508
|
-
if (
|
|
8580
|
+
const tsconfigPath = join13(this.cwd, "tsconfig.json");
|
|
8581
|
+
if (existsSync21(tsconfigPath)) {
|
|
8509
8582
|
try {
|
|
8510
8583
|
const tsconfig = JSON.parse(readFileSync13(tsconfigPath, "utf8"));
|
|
8511
8584
|
if (tsconfig.compilerOptions?.strict) {
|
|
@@ -8516,8 +8589,8 @@ class ProjectAnalyzer {
|
|
|
8516
8589
|
}
|
|
8517
8590
|
} catch {}
|
|
8518
8591
|
}
|
|
8519
|
-
const cargoPath =
|
|
8520
|
-
if (
|
|
8592
|
+
const cargoPath = join13(this.cwd, "Cargo.toml");
|
|
8593
|
+
if (existsSync21(cargoPath)) {
|
|
8521
8594
|
try {
|
|
8522
8595
|
commands.dev = commands.dev || "cargo run";
|
|
8523
8596
|
commands.build = commands.build || "cargo build";
|
|
@@ -8526,8 +8599,8 @@ class ProjectAnalyzer {
|
|
|
8526
8599
|
frameworks.push("Rust Cargo");
|
|
8527
8600
|
} catch {}
|
|
8528
8601
|
}
|
|
8529
|
-
const goModPath =
|
|
8530
|
-
if (
|
|
8602
|
+
const goModPath = join13(this.cwd, "go.mod");
|
|
8603
|
+
if (existsSync21(goModPath)) {
|
|
8531
8604
|
try {
|
|
8532
8605
|
commands.dev = commands.dev || "go run .";
|
|
8533
8606
|
commands.build = commands.build || "go build ./...";
|
|
@@ -8536,37 +8609,37 @@ class ProjectAnalyzer {
|
|
|
8536
8609
|
frameworks.push("Go Modules");
|
|
8537
8610
|
} catch {}
|
|
8538
8611
|
}
|
|
8539
|
-
const pyprojectPath =
|
|
8540
|
-
const requirementsPath =
|
|
8541
|
-
if (
|
|
8612
|
+
const pyprojectPath = join13(this.cwd, "pyproject.toml");
|
|
8613
|
+
const requirementsPath = join13(this.cwd, "requirements.txt");
|
|
8614
|
+
if (existsSync21(pyprojectPath) || existsSync21(requirementsPath)) {
|
|
8542
8615
|
commands.test = commands.test || "pytest";
|
|
8543
8616
|
commands.lint = commands.lint || "ruff check .";
|
|
8544
|
-
if (
|
|
8617
|
+
if (existsSync21(join13(this.cwd, "uv.lock"))) {
|
|
8545
8618
|
frameworks.push("uv");
|
|
8546
8619
|
commands.test = "uv run pytest";
|
|
8547
|
-
} else if (
|
|
8620
|
+
} else if (existsSync21(join13(this.cwd, "poetry.lock"))) {
|
|
8548
8621
|
frameworks.push("Poetry");
|
|
8549
8622
|
commands.test = "poetry run pytest";
|
|
8550
8623
|
}
|
|
8551
8624
|
}
|
|
8552
|
-
if (
|
|
8625
|
+
if (existsSync21(join13(this.cwd, "Dockerfile"))) {
|
|
8553
8626
|
infrastructure.push("Docker");
|
|
8554
8627
|
const sanitizedName = projectName.toLowerCase().replace(/[^a-z0-9_-]/g, "-").replace(/^-+|-+$/g, "");
|
|
8555
8628
|
commands.dockerBuild = `docker build -t ${sanitizedName || "app"} .`;
|
|
8556
8629
|
}
|
|
8557
|
-
if (
|
|
8630
|
+
if (existsSync21(join13(this.cwd, "nginx.conf"))) {
|
|
8558
8631
|
infrastructure.push("Nginx");
|
|
8559
8632
|
}
|
|
8560
|
-
if (
|
|
8633
|
+
if (existsSync21(join13(this.cwd, "src/api.ts")) || existsSync21(join13(this.cwd, "src/api"))) {
|
|
8561
8634
|
architectureNotes.push("Backend API endpoints and network client logic are centralized in `src/api`.");
|
|
8562
8635
|
}
|
|
8563
|
-
if (
|
|
8636
|
+
if (existsSync21(join13(this.cwd, "src/components"))) {
|
|
8564
8637
|
architectureNotes.push("Reusable UI presentation components live in `src/components/`.");
|
|
8565
8638
|
}
|
|
8566
|
-
if (
|
|
8639
|
+
if (existsSync21(join13(this.cwd, "src/types.ts")) || existsSync21(join13(this.cwd, "src/types"))) {
|
|
8567
8640
|
architectureNotes.push("Shared TypeScript data models and interfaces are defined in `src/types`.");
|
|
8568
8641
|
}
|
|
8569
|
-
if (
|
|
8642
|
+
if (existsSync21(join13(this.cwd, ".env.example"))) {
|
|
8570
8643
|
architectureNotes.push("Environment configuration template is in `.env.example`.");
|
|
8571
8644
|
}
|
|
8572
8645
|
if (commands.typecheck || commands.lint || commands.test) {
|
|
@@ -8583,7 +8656,7 @@ class ProjectAnalyzer {
|
|
|
8583
8656
|
let hasExistingInstructions = false;
|
|
8584
8657
|
let existingInstructionFile;
|
|
8585
8658
|
for (const f of instructionFiles) {
|
|
8586
|
-
if (
|
|
8659
|
+
if (existsSync21(join13(this.cwd, f))) {
|
|
8587
8660
|
hasExistingInstructions = true;
|
|
8588
8661
|
existingInstructionFile = f;
|
|
8589
8662
|
break;
|
|
@@ -8664,8 +8737,8 @@ class ProjectAnalyzer {
|
|
|
8664
8737
|
extractReadmeMetadata() {
|
|
8665
8738
|
const readmeFiles = ["README.md", "readme.md", "README.MD"];
|
|
8666
8739
|
for (const file of readmeFiles) {
|
|
8667
|
-
const fullPath =
|
|
8668
|
-
if (
|
|
8740
|
+
const fullPath = join13(this.cwd, file);
|
|
8741
|
+
if (existsSync21(fullPath)) {
|
|
8669
8742
|
try {
|
|
8670
8743
|
const content = readFileSync13(fullPath, "utf8");
|
|
8671
8744
|
const lines = content.split(`
|
|
@@ -8690,8 +8763,8 @@ class ProjectAnalyzer {
|
|
|
8690
8763
|
return {};
|
|
8691
8764
|
}
|
|
8692
8765
|
detectProjectName() {
|
|
8693
|
-
const pkgPath =
|
|
8694
|
-
if (
|
|
8766
|
+
const pkgPath = join13(this.cwd, "package.json");
|
|
8767
|
+
if (existsSync21(pkgPath)) {
|
|
8695
8768
|
try {
|
|
8696
8769
|
const pkg = JSON.parse(readFileSync13(pkgPath, "utf8"));
|
|
8697
8770
|
if (pkg.name && pkg.name !== "frontend" && pkg.name !== "backend" && pkg.name !== "app") {
|
|
@@ -8699,16 +8772,16 @@ class ProjectAnalyzer {
|
|
|
8699
8772
|
}
|
|
8700
8773
|
} catch {}
|
|
8701
8774
|
}
|
|
8702
|
-
const cargoPath =
|
|
8703
|
-
if (
|
|
8775
|
+
const cargoPath = join13(this.cwd, "Cargo.toml");
|
|
8776
|
+
if (existsSync21(cargoPath)) {
|
|
8704
8777
|
try {
|
|
8705
8778
|
const match = readFileSync13(cargoPath, "utf8").match(/name\s*=\s*"([^"]+)"/);
|
|
8706
8779
|
if (match?.[1])
|
|
8707
8780
|
return match[1];
|
|
8708
8781
|
} catch {}
|
|
8709
8782
|
}
|
|
8710
|
-
const goModPath =
|
|
8711
|
-
if (
|
|
8783
|
+
const goModPath = join13(this.cwd, "go.mod");
|
|
8784
|
+
if (existsSync21(goModPath)) {
|
|
8712
8785
|
try {
|
|
8713
8786
|
const match = readFileSync13(goModPath, "utf8").match(/module\s+([^\s]+)/);
|
|
8714
8787
|
if (match?.[1])
|
|
@@ -8719,47 +8792,47 @@ class ProjectAnalyzer {
|
|
|
8719
8792
|
}
|
|
8720
8793
|
detectLanguages() {
|
|
8721
8794
|
const langs = new Set;
|
|
8722
|
-
if (
|
|
8795
|
+
if (existsSync21(join13(this.cwd, "tsconfig.json")) || this.hasFileWithExtension(".ts", ".tsx")) {
|
|
8723
8796
|
langs.add("TypeScript");
|
|
8724
8797
|
}
|
|
8725
|
-
if (
|
|
8798
|
+
if (existsSync21(join13(this.cwd, "package.json")) || this.hasFileWithExtension(".js", ".jsx", ".mjs")) {
|
|
8726
8799
|
langs.add("JavaScript");
|
|
8727
8800
|
}
|
|
8728
|
-
if (
|
|
8801
|
+
if (existsSync21(join13(this.cwd, "Cargo.toml")) || this.hasFileWithExtension(".rs")) {
|
|
8729
8802
|
langs.add("Rust");
|
|
8730
8803
|
}
|
|
8731
|
-
if (
|
|
8804
|
+
if (existsSync21(join13(this.cwd, "go.mod")) || this.hasFileWithExtension(".go")) {
|
|
8732
8805
|
langs.add("Go");
|
|
8733
8806
|
}
|
|
8734
|
-
if (
|
|
8807
|
+
if (existsSync21(join13(this.cwd, "pyproject.toml")) || existsSync21(join13(this.cwd, "requirements.txt")) || this.hasFileWithExtension(".py")) {
|
|
8735
8808
|
langs.add("Python");
|
|
8736
8809
|
}
|
|
8737
|
-
if (
|
|
8810
|
+
if (existsSync21(join13(this.cwd, "pom.xml")) || existsSync21(join13(this.cwd, "build.gradle")) || this.hasFileWithExtension(".java")) {
|
|
8738
8811
|
langs.add("Java");
|
|
8739
8812
|
}
|
|
8740
|
-
if (
|
|
8813
|
+
if (existsSync21(join13(this.cwd, "CMakeLists.txt")) || this.hasFileWithExtension(".cpp", ".c", ".h", ".hpp")) {
|
|
8741
8814
|
langs.add("C/C++");
|
|
8742
8815
|
}
|
|
8743
8816
|
return Array.from(langs);
|
|
8744
8817
|
}
|
|
8745
8818
|
detectPackageManager() {
|
|
8746
|
-
if (
|
|
8819
|
+
if (existsSync21(join13(this.cwd, "bun.lockb")) || existsSync21(join13(this.cwd, "bun.lock")))
|
|
8747
8820
|
return "bun";
|
|
8748
|
-
if (
|
|
8821
|
+
if (existsSync21(join13(this.cwd, "pnpm-lock.yaml")))
|
|
8749
8822
|
return "pnpm";
|
|
8750
|
-
if (
|
|
8823
|
+
if (existsSync21(join13(this.cwd, "yarn.lock")))
|
|
8751
8824
|
return "yarn";
|
|
8752
|
-
if (
|
|
8825
|
+
if (existsSync21(join13(this.cwd, "package-lock.json")))
|
|
8753
8826
|
return "npm";
|
|
8754
|
-
if (
|
|
8827
|
+
if (existsSync21(join13(this.cwd, "Cargo.lock")) || existsSync21(join13(this.cwd, "Cargo.toml")))
|
|
8755
8828
|
return "cargo";
|
|
8756
|
-
if (
|
|
8829
|
+
if (existsSync21(join13(this.cwd, "uv.lock")))
|
|
8757
8830
|
return "uv";
|
|
8758
|
-
if (
|
|
8831
|
+
if (existsSync21(join13(this.cwd, "poetry.lock")))
|
|
8759
8832
|
return "poetry";
|
|
8760
|
-
if (
|
|
8833
|
+
if (existsSync21(join13(this.cwd, "go.sum")) || existsSync21(join13(this.cwd, "go.mod")))
|
|
8761
8834
|
return "go";
|
|
8762
|
-
if (
|
|
8835
|
+
if (existsSync21(join13(this.cwd, "package.json")))
|
|
8763
8836
|
return "npm";
|
|
8764
8837
|
return;
|
|
8765
8838
|
}
|
|
@@ -8773,17 +8846,17 @@ class ProjectAnalyzer {
|
|
|
8773
8846
|
}
|
|
8774
8847
|
}
|
|
8775
8848
|
// src/init/init-command.ts
|
|
8776
|
-
import { existsSync as
|
|
8777
|
-
import { join as
|
|
8849
|
+
import { existsSync as existsSync22, writeFileSync as writeFileSync8 } from "fs";
|
|
8850
|
+
import { join as join14 } from "path";
|
|
8778
8851
|
function runProjectInit(options = {}) {
|
|
8779
8852
|
const cwd = options.cwd || process.cwd();
|
|
8780
8853
|
const filename = options.filename || "AGENTS.md";
|
|
8781
|
-
const targetPath =
|
|
8854
|
+
const targetPath = join14(cwd, filename);
|
|
8782
8855
|
const analyzer = new ProjectAnalyzer(cwd);
|
|
8783
8856
|
const analysis = analyzer.analyze();
|
|
8784
8857
|
const content = analyzer.generateAgentsMarkdown(analysis);
|
|
8785
|
-
const alreadyExists =
|
|
8786
|
-
|
|
8858
|
+
const alreadyExists = existsSync22(targetPath);
|
|
8859
|
+
writeFileSync8(targetPath, content, "utf8");
|
|
8787
8860
|
return {
|
|
8788
8861
|
success: true,
|
|
8789
8862
|
filePath: targetPath,
|
|
@@ -8855,7 +8928,7 @@ var AVAILABLE_SLASH_COMMANDS = [
|
|
|
8855
8928
|
{ name: "/manual", description: "Switch to Manual Mode (all tools require user confirmation)" },
|
|
8856
8929
|
{ name: "/accept-edits", description: "Switch to Accept Edits Mode (file edits auto-approved, shell prompts)" },
|
|
8857
8930
|
{ name: "/plan", description: "Switch to Plan Mode (read-only planning, mutations blocked)" },
|
|
8858
|
-
{ name: "/skills", description: "
|
|
8931
|
+
{ name: "/skills", description: "Manage domain skills (/skills, /skill add <name>, /skill remove <name>)" },
|
|
8859
8932
|
{ name: "/memories", description: "View learned preferences & memories" },
|
|
8860
8933
|
{ name: "/worktrees", description: "List active isolated Git Worktrees" },
|
|
8861
8934
|
{ name: "/resume", description: "Resume a previous conversation session (/resume [id])" },
|
|
@@ -9358,6 +9431,46 @@ async function handleSkillsCommand(ctx, args) {
|
|
|
9358
9431
|
}
|
|
9359
9432
|
const sub = (args[0] || "").toLowerCase();
|
|
9360
9433
|
const target = (args[1] || "").toLowerCase();
|
|
9434
|
+
if (sub === "install" || sub === "add") {
|
|
9435
|
+
if (!target) {
|
|
9436
|
+
console.log(style.yellow("Usage: /skill add <skill-name> [--global]"));
|
|
9437
|
+
return;
|
|
9438
|
+
}
|
|
9439
|
+
const isGlobal = args.includes("--global") || args.includes("-g");
|
|
9440
|
+
try {
|
|
9441
|
+
console.log(style.dim(`
|
|
9442
|
+
Fetching skill '${target}' from catalog...`));
|
|
9443
|
+
const res = await installSkill(target, { cwd: ctx.session.cwd, global: isGlobal });
|
|
9444
|
+
loader.clearCache();
|
|
9445
|
+
console.log(style.green(`
|
|
9446
|
+
\u2713 ${res.message}
|
|
9447
|
+
`));
|
|
9448
|
+
} catch (err) {
|
|
9449
|
+
console.log(style.red(`
|
|
9450
|
+
\u2715 Failed to install skill: ${err.message}
|
|
9451
|
+
`));
|
|
9452
|
+
}
|
|
9453
|
+
return;
|
|
9454
|
+
}
|
|
9455
|
+
if (sub === "remove" || sub === "uninstall" || sub === "rm") {
|
|
9456
|
+
if (!target) {
|
|
9457
|
+
console.log(style.yellow("Usage: /skill remove <skill-name> [--global]"));
|
|
9458
|
+
return;
|
|
9459
|
+
}
|
|
9460
|
+
const isGlobal = args.includes("--global") || args.includes("-g");
|
|
9461
|
+
const res = removeSkill(target, { cwd: ctx.session.cwd, global: isGlobal });
|
|
9462
|
+
loader.clearCache();
|
|
9463
|
+
if (res.removed) {
|
|
9464
|
+
console.log(style.green(`
|
|
9465
|
+
\u2713 Skill '${target}' removed from ${res.targetDir}
|
|
9466
|
+
`));
|
|
9467
|
+
} else {
|
|
9468
|
+
console.log(style.yellow(`
|
|
9469
|
+
\u2715 Skill '${target}' was not found in ${res.targetDir}
|
|
9470
|
+
`));
|
|
9471
|
+
}
|
|
9472
|
+
return;
|
|
9473
|
+
}
|
|
9361
9474
|
if (sub === "disable" || sub === "off") {
|
|
9362
9475
|
if (!target) {
|
|
9363
9476
|
console.log(style.yellow("Usage: /skills disable <skill-name>"));
|
|
@@ -10328,9 +10441,9 @@ class MarkdownHighlighter {
|
|
|
10328
10441
|
}
|
|
10329
10442
|
|
|
10330
10443
|
// src/cli/update-checker.ts
|
|
10331
|
-
import { existsSync as
|
|
10332
|
-
import { homedir as
|
|
10333
|
-
import { join as
|
|
10444
|
+
import { existsSync as existsSync23, mkdirSync as mkdirSync13, readFileSync as readFileSync14, writeFileSync as writeFileSync9 } from "fs";
|
|
10445
|
+
import { homedir as homedir4 } from "os";
|
|
10446
|
+
import { join as join15 } from "path";
|
|
10334
10447
|
var CHECK_INTERVAL_MS = 12 * 60 * 60 * 1000;
|
|
10335
10448
|
function parseSemver(v) {
|
|
10336
10449
|
const clean = v.replace(/^v/, "").trim();
|
|
@@ -10351,8 +10464,8 @@ function isNewerVersion(current, remote) {
|
|
|
10351
10464
|
return remPatch > curPatch;
|
|
10352
10465
|
}
|
|
10353
10466
|
function getUpdateCachePath() {
|
|
10354
|
-
const baseDir = process.env.PIKAA_HOME || process.env.GROUPY_HOME ||
|
|
10355
|
-
return
|
|
10467
|
+
const baseDir = process.env.PIKAA_HOME || process.env.GROUPY_HOME || join15(homedir4(), ".pikaa");
|
|
10468
|
+
return join15(baseDir, "update-cache.json");
|
|
10356
10469
|
}
|
|
10357
10470
|
async function fetchLatestNpmVersion(packageName, timeoutMs = 1500) {
|
|
10358
10471
|
const url = `https://registry.npmjs.org/${encodeURIComponent(packageName)}/latest`;
|
|
@@ -10385,7 +10498,7 @@ async function checkForUpdates(options = {}) {
|
|
|
10385
10498
|
const cachePath = options.cachePath || getUpdateCachePath();
|
|
10386
10499
|
const now = Date.now();
|
|
10387
10500
|
let cached = null;
|
|
10388
|
-
if (!options.force &&
|
|
10501
|
+
if (!options.force && existsSync23(cachePath)) {
|
|
10389
10502
|
try {
|
|
10390
10503
|
const raw = JSON.parse(readFileSync14(cachePath, "utf8"));
|
|
10391
10504
|
if (raw && typeof raw.lastChecked === "number" && typeof raw.latestVersion === "string") {
|
|
@@ -10415,16 +10528,16 @@ async function checkForUpdates(options = {}) {
|
|
|
10415
10528
|
return null;
|
|
10416
10529
|
}
|
|
10417
10530
|
try {
|
|
10418
|
-
const parentDir =
|
|
10419
|
-
if (!
|
|
10420
|
-
|
|
10531
|
+
const parentDir = join15(cachePath, "..");
|
|
10532
|
+
if (!existsSync23(parentDir)) {
|
|
10533
|
+
mkdirSync13(parentDir, { recursive: true });
|
|
10421
10534
|
}
|
|
10422
10535
|
const cacheData = {
|
|
10423
10536
|
lastChecked: now,
|
|
10424
10537
|
latestVersion,
|
|
10425
10538
|
packageName
|
|
10426
10539
|
};
|
|
10427
|
-
|
|
10540
|
+
writeFileSync9(cachePath, JSON.stringify(cacheData, null, 2), "utf8");
|
|
10428
10541
|
} catch {}
|
|
10429
10542
|
const updateAvailable = isNewerVersion(currentVersion, latestVersion);
|
|
10430
10543
|
return updateAvailable ? {
|
|
@@ -10590,9 +10703,9 @@ class CliRepl {
|
|
|
10590
10703
|
filesModified: Array.from(this.turnFilesModified)
|
|
10591
10704
|
});
|
|
10592
10705
|
if (this.turnDoneResolver) {
|
|
10593
|
-
const
|
|
10706
|
+
const resolve22 = this.turnDoneResolver;
|
|
10594
10707
|
this.turnDoneResolver = undefined;
|
|
10595
|
-
|
|
10708
|
+
resolve22();
|
|
10596
10709
|
}
|
|
10597
10710
|
break;
|
|
10598
10711
|
case "Error":
|
|
@@ -10608,9 +10721,9 @@ class CliRepl {
|
|
|
10608
10721
|
console.error(style.red(`Error: ${msg.message}
|
|
10609
10722
|
`));
|
|
10610
10723
|
if (this.turnDoneResolver) {
|
|
10611
|
-
const
|
|
10724
|
+
const resolve22 = this.turnDoneResolver;
|
|
10612
10725
|
this.turnDoneResolver = undefined;
|
|
10613
|
-
|
|
10726
|
+
resolve22();
|
|
10614
10727
|
}
|
|
10615
10728
|
break;
|
|
10616
10729
|
}
|
|
@@ -10680,15 +10793,21 @@ class CliRepl {
|
|
|
10680
10793
|
`));
|
|
10681
10794
|
this.isProcessing = false;
|
|
10682
10795
|
if (this.turnDoneResolver) {
|
|
10683
|
-
const
|
|
10796
|
+
const resolve22 = this.turnDoneResolver;
|
|
10684
10797
|
this.turnDoneResolver = undefined;
|
|
10685
|
-
|
|
10798
|
+
resolve22();
|
|
10686
10799
|
}
|
|
10687
10800
|
}
|
|
10688
10801
|
}
|
|
10689
10802
|
}
|
|
10690
10803
|
});
|
|
10691
10804
|
while (!this.isClosed) {
|
|
10805
|
+
await new Promise((resolve22) => setTimeout(resolve22, 20));
|
|
10806
|
+
if (typeof Bun !== "undefined" && typeof Bun.gc === "function") {
|
|
10807
|
+
try {
|
|
10808
|
+
Bun.gc(false);
|
|
10809
|
+
} catch {}
|
|
10810
|
+
}
|
|
10692
10811
|
let rawLine;
|
|
10693
10812
|
try {
|
|
10694
10813
|
rawLine = await editor.readLine();
|
|
@@ -10719,8 +10838,8 @@ class CliRepl {
|
|
|
10719
10838
|
}
|
|
10720
10839
|
async submitTurn(text) {
|
|
10721
10840
|
try {
|
|
10722
|
-
const turnPromise = new Promise((
|
|
10723
|
-
this.turnDoneResolver =
|
|
10841
|
+
const turnPromise = new Promise((resolve22) => {
|
|
10842
|
+
this.turnDoneResolver = resolve22;
|
|
10724
10843
|
});
|
|
10725
10844
|
await this.session.submit({
|
|
10726
10845
|
type: "TurnInput",
|
|
@@ -10786,9 +10905,22 @@ async function main() {
|
|
|
10786
10905
|
} else if (arg === "list" || arg === "sessions" || arg === "--list") {
|
|
10787
10906
|
printSessionsList(storageManager);
|
|
10788
10907
|
process.exit(0);
|
|
10789
|
-
} else if (arg === "skills") {
|
|
10790
|
-
|
|
10791
|
-
|
|
10908
|
+
} else if (arg === "skills" || arg === "skill") {
|
|
10909
|
+
const subAction = args[i + 1];
|
|
10910
|
+
const target = args[i + 2];
|
|
10911
|
+
const isGlobal = args.includes("--global") || args.includes("-g");
|
|
10912
|
+
if (subAction && !subAction.startsWith("-")) {
|
|
10913
|
+
await handleSkillCliCommand(subAction, target, {
|
|
10914
|
+
cwd,
|
|
10915
|
+
isGlobal,
|
|
10916
|
+
baseUrl,
|
|
10917
|
+
loader: skillsLoader
|
|
10918
|
+
});
|
|
10919
|
+
process.exit(0);
|
|
10920
|
+
} else {
|
|
10921
|
+
printSkillsList(skillsLoader, cwd);
|
|
10922
|
+
process.exit(0);
|
|
10923
|
+
}
|
|
10792
10924
|
} else if (arg === "memories" || arg === "memory") {
|
|
10793
10925
|
printMemoriesList(memoryStore, cwd);
|
|
10794
10926
|
process.exit(0);
|
|
@@ -10810,7 +10942,7 @@ async function main() {
|
|
|
10810
10942
|
explicitApiKey = args[++i];
|
|
10811
10943
|
apiKey = explicitApiKey || apiKey;
|
|
10812
10944
|
} else if (arg === "--cwd" || arg === "-C") {
|
|
10813
|
-
cwd =
|
|
10945
|
+
cwd = resolve22(args[++i] || cwd);
|
|
10814
10946
|
} else if (arg === "--role" || arg === "-r") {
|
|
10815
10947
|
role = args[++i] || role;
|
|
10816
10948
|
} else if (arg === "--mcp") {
|
|
@@ -10836,11 +10968,11 @@ async function main() {
|
|
|
10836
10968
|
const mcpManager = new McpManager;
|
|
10837
10969
|
const candidateConfigs = [
|
|
10838
10970
|
mcpConfigFile,
|
|
10839
|
-
|
|
10840
|
-
|
|
10971
|
+
resolve22(cwd, ".mcp.json"),
|
|
10972
|
+
resolve22(cwd, "mcp_config.json")
|
|
10841
10973
|
].filter(Boolean);
|
|
10842
10974
|
for (const cfg of candidateConfigs) {
|
|
10843
|
-
if (
|
|
10975
|
+
if (existsSync24(cfg)) {
|
|
10844
10976
|
try {
|
|
10845
10977
|
await mcpManager.loadConfigFile(cfg);
|
|
10846
10978
|
mcpManager.registerToolsIntoRouter(tools4);
|
|
@@ -11043,6 +11175,62 @@ Resume a session with: ${style.bold("groupy --resume <thread_id>")}`);
|
|
|
11043
11175
|
}
|
|
11044
11176
|
console.log();
|
|
11045
11177
|
}
|
|
11178
|
+
async function handleSkillCliCommand(action, targetName, options) {
|
|
11179
|
+
const act = action.toLowerCase();
|
|
11180
|
+
if (act === "add" || act === "install") {
|
|
11181
|
+
if (!targetName) {
|
|
11182
|
+
console.error(style.yellow(`
|
|
11183
|
+
Usage: pikaa skill add <skill-name> [--global]
|
|
11184
|
+
`));
|
|
11185
|
+
process.exit(1);
|
|
11186
|
+
}
|
|
11187
|
+
try {
|
|
11188
|
+
console.log(style.dim(`
|
|
11189
|
+
Fetching skill '${targetName}' from catalog...`));
|
|
11190
|
+
const res = await installSkill(targetName, {
|
|
11191
|
+
cwd: options.cwd,
|
|
11192
|
+
global: options.isGlobal,
|
|
11193
|
+
backendUrl: options.baseUrl
|
|
11194
|
+
});
|
|
11195
|
+
console.log(style.green(`
|
|
11196
|
+
\u2713 ${res.message}`));
|
|
11197
|
+
console.log(style.dim(` To start using this skill in an AI coding session, simply run: pikaa
|
|
11198
|
+
`));
|
|
11199
|
+
} catch (err) {
|
|
11200
|
+
console.error(style.red(`
|
|
11201
|
+
\u2715 Failed to install skill: ${err.message}
|
|
11202
|
+
`));
|
|
11203
|
+
process.exit(1);
|
|
11204
|
+
}
|
|
11205
|
+
} else if (act === "remove" || act === "uninstall" || act === "rm") {
|
|
11206
|
+
if (!targetName) {
|
|
11207
|
+
console.error(style.yellow(`
|
|
11208
|
+
Usage: pikaa skill remove <skill-name> [--global]
|
|
11209
|
+
`));
|
|
11210
|
+
process.exit(1);
|
|
11211
|
+
}
|
|
11212
|
+
const res = removeSkill(targetName, { cwd: options.cwd, global: options.isGlobal });
|
|
11213
|
+
if (res.removed) {
|
|
11214
|
+
console.log(style.green(`
|
|
11215
|
+
\u2713 Skill '${targetName}' removed from ${res.targetDir}
|
|
11216
|
+
`));
|
|
11217
|
+
} else {
|
|
11218
|
+
console.log(style.yellow(`
|
|
11219
|
+
\u2715 Skill '${targetName}' was not found in ${res.targetDir}
|
|
11220
|
+
`));
|
|
11221
|
+
}
|
|
11222
|
+
} else if (act === "list" || act === "ls") {
|
|
11223
|
+
printSkillsList(options.loader, options.cwd);
|
|
11224
|
+
} else {
|
|
11225
|
+
if (act && !targetName) {
|
|
11226
|
+
return handleSkillCliCommand("add", act, options);
|
|
11227
|
+
}
|
|
11228
|
+
console.error(style.yellow(`
|
|
11229
|
+
Unknown skill action '${action}'. Available: add, remove, list
|
|
11230
|
+
`));
|
|
11231
|
+
process.exit(1);
|
|
11232
|
+
}
|
|
11233
|
+
}
|
|
11046
11234
|
function printSkillsList(loader, cwd) {
|
|
11047
11235
|
const skills = loader.discoverSkills(cwd);
|
|
11048
11236
|
console.log();
|