pi-agent-toolkit 0.1.2 → 0.3.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/index.js +441 -265
- package/package.json +5 -3
package/dist/index.js
CHANGED
|
@@ -1,6 +1,9 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
3
|
// src/index.ts
|
|
4
|
+
import { readFileSync as readFileSync2 } from "fs";
|
|
5
|
+
import { dirname as dirname3, resolve as resolve5 } from "path";
|
|
6
|
+
import { fileURLToPath as fileURLToPath2 } from "url";
|
|
4
7
|
import { defineCommand, runMain } from "citty";
|
|
5
8
|
|
|
6
9
|
// src/commands/install.ts
|
|
@@ -185,8 +188,7 @@ var extensions = [
|
|
|
185
188
|
group: "tools",
|
|
186
189
|
description: "Intercepts pip/python calls and redirects to uv",
|
|
187
190
|
method: "copy",
|
|
188
|
-
source: "extensions/uv.ts"
|
|
189
|
-
recommends: ["intercepted-commands"]
|
|
191
|
+
source: "extensions/uv.ts"
|
|
190
192
|
},
|
|
191
193
|
{
|
|
192
194
|
name: "execute-command",
|
|
@@ -536,18 +538,22 @@ var registry = [
|
|
|
536
538
|
...externalSkills,
|
|
537
539
|
...packages,
|
|
538
540
|
...configs
|
|
541
|
+
// Placeholders: no items yet, but the categories are ready for content.
|
|
542
|
+
// Add prompts, agents, and themes entries here as they're created.
|
|
539
543
|
];
|
|
540
544
|
function getByCategory(category) {
|
|
541
545
|
return registry.filter((c) => c.category === category);
|
|
542
546
|
}
|
|
543
547
|
function getExtensionGroups() {
|
|
544
|
-
|
|
545
|
-
|
|
546
|
-
|
|
547
|
-
|
|
548
|
-
|
|
549
|
-
|
|
550
|
-
|
|
548
|
+
return getByCategory("extensions").reduce(
|
|
549
|
+
(acc, ext) => {
|
|
550
|
+
const key = ext.group ?? "tools";
|
|
551
|
+
if (!acc[key]) acc[key] = [];
|
|
552
|
+
acc[key].push(ext);
|
|
553
|
+
return acc;
|
|
554
|
+
},
|
|
555
|
+
{}
|
|
556
|
+
);
|
|
551
557
|
}
|
|
552
558
|
var GROUP_LABELS = {
|
|
553
559
|
safety: "Safety",
|
|
@@ -561,19 +567,21 @@ var GROUP_LABELS = {
|
|
|
561
567
|
|
|
562
568
|
// src/lib/warnings.ts
|
|
563
569
|
import * as p from "@clack/prompts";
|
|
564
|
-
|
|
570
|
+
function findMissingRecommendations(selected) {
|
|
565
571
|
const selectedNames = new Set(selected.map((c) => c.name));
|
|
566
572
|
const warnings = [];
|
|
567
573
|
for (const component of selected) {
|
|
568
574
|
if (!component.recommends) continue;
|
|
569
575
|
for (const rec of component.recommends) {
|
|
570
576
|
if (!selectedNames.has(rec)) {
|
|
571
|
-
warnings.push(
|
|
572
|
-
`${component.name} works best with ${rec}, which you didn't select.`
|
|
573
|
-
);
|
|
577
|
+
warnings.push(`${component.name} works best with ${rec}, which you didn't select.`);
|
|
574
578
|
}
|
|
575
579
|
}
|
|
576
580
|
}
|
|
581
|
+
return warnings;
|
|
582
|
+
}
|
|
583
|
+
async function checkRecommendations(selected) {
|
|
584
|
+
const warnings = findMissingRecommendations(selected);
|
|
577
585
|
if (warnings.length === 0) return true;
|
|
578
586
|
p.log.warn("Some selected components have recommendations:");
|
|
579
587
|
for (const warning of warnings) {
|
|
@@ -594,12 +602,11 @@ async function checkRecommendations(selected) {
|
|
|
594
602
|
import {
|
|
595
603
|
cpSync,
|
|
596
604
|
existsSync as existsSync2,
|
|
597
|
-
mkdirSync as mkdirSync2,
|
|
598
|
-
symlinkSync,
|
|
599
605
|
lstatSync,
|
|
600
|
-
|
|
606
|
+
mkdirSync as mkdirSync2,
|
|
601
607
|
readdirSync,
|
|
602
608
|
statSync,
|
|
609
|
+
symlinkSync,
|
|
603
610
|
unlinkSync
|
|
604
611
|
} from "fs";
|
|
605
612
|
import { resolve as resolve2, basename } from "path";
|
|
@@ -618,6 +625,9 @@ var AGENTS_SKILLS_DIR = resolve(homedir(), ".agents", "skills");
|
|
|
618
625
|
var MANIFEST_PATH = resolve(PI_AGENT_DIR, ".pi-toolkit.json");
|
|
619
626
|
var PI_EXTENSIONS_DIR = resolve(PI_AGENT_DIR, "extensions");
|
|
620
627
|
var PI_SKILLS_DIR = resolve(PI_AGENT_DIR, "skills");
|
|
628
|
+
var PI_PROMPTS_DIR = resolve(PI_AGENT_DIR, "prompts");
|
|
629
|
+
var PI_AGENTS_DIR = resolve(PI_AGENT_DIR, "agents");
|
|
630
|
+
var PI_THEMES_DIR = resolve(PI_AGENT_DIR, "themes");
|
|
621
631
|
|
|
622
632
|
// src/lib/manifest.ts
|
|
623
633
|
import { readFileSync, writeFileSync, existsSync, mkdirSync } from "fs";
|
|
@@ -628,6 +638,9 @@ function emptyManifest() {
|
|
|
628
638
|
installed: {
|
|
629
639
|
extensions: [],
|
|
630
640
|
skills: { bundled: [], external: [] },
|
|
641
|
+
prompts: [],
|
|
642
|
+
agents: [],
|
|
643
|
+
themes: [],
|
|
631
644
|
packages: [],
|
|
632
645
|
configs: []
|
|
633
646
|
},
|
|
@@ -635,51 +648,73 @@ function emptyManifest() {
|
|
|
635
648
|
updatedAt: ""
|
|
636
649
|
};
|
|
637
650
|
}
|
|
638
|
-
function readManifest() {
|
|
639
|
-
if (!existsSync(
|
|
651
|
+
function readManifest(path = MANIFEST_PATH) {
|
|
652
|
+
if (!existsSync(path)) return emptyManifest();
|
|
640
653
|
try {
|
|
641
|
-
const raw = readFileSync(
|
|
642
|
-
|
|
654
|
+
const raw = readFileSync(path, "utf-8");
|
|
655
|
+
const parsed = JSON.parse(raw);
|
|
656
|
+
const defaults = emptyManifest();
|
|
657
|
+
const installed = parsed.installed ?? {};
|
|
658
|
+
return {
|
|
659
|
+
version: parsed.version ?? defaults.version,
|
|
660
|
+
installed: {
|
|
661
|
+
extensions: installed.extensions ?? defaults.installed.extensions,
|
|
662
|
+
skills: {
|
|
663
|
+
bundled: installed.skills?.bundled ?? defaults.installed.skills.bundled,
|
|
664
|
+
external: installed.skills?.external ?? defaults.installed.skills.external
|
|
665
|
+
},
|
|
666
|
+
prompts: installed.prompts ?? defaults.installed.prompts,
|
|
667
|
+
agents: installed.agents ?? defaults.installed.agents,
|
|
668
|
+
themes: installed.themes ?? defaults.installed.themes,
|
|
669
|
+
packages: installed.packages ?? defaults.installed.packages,
|
|
670
|
+
configs: installed.configs ?? defaults.installed.configs
|
|
671
|
+
},
|
|
672
|
+
installedAt: parsed.installedAt ?? defaults.installedAt,
|
|
673
|
+
updatedAt: parsed.updatedAt ?? defaults.updatedAt
|
|
674
|
+
};
|
|
643
675
|
} catch {
|
|
644
676
|
return emptyManifest();
|
|
645
677
|
}
|
|
646
678
|
}
|
|
647
|
-
function writeManifest(manifest) {
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
writeFileSync(MANIFEST_PATH, JSON.stringify(manifest, null, 2) + "\n");
|
|
679
|
+
function writeManifest(manifest, path = MANIFEST_PATH) {
|
|
680
|
+
mkdirSync(dirname2(path), { recursive: true });
|
|
681
|
+
writeFileSync(path, JSON.stringify(manifest, null, 2) + "\n");
|
|
651
682
|
}
|
|
652
|
-
function
|
|
653
|
-
|
|
683
|
+
function getList(manifest, category) {
|
|
684
|
+
switch (category) {
|
|
685
|
+
case "extensions":
|
|
686
|
+
return manifest.installed.extensions;
|
|
687
|
+
case "skills-bundled":
|
|
688
|
+
return manifest.installed.skills.bundled;
|
|
689
|
+
case "skills-external":
|
|
690
|
+
return manifest.installed.skills.external;
|
|
691
|
+
case "packages":
|
|
692
|
+
return manifest.installed.packages;
|
|
693
|
+
case "prompts":
|
|
694
|
+
return manifest.installed.prompts;
|
|
695
|
+
case "agents":
|
|
696
|
+
return manifest.installed.agents;
|
|
697
|
+
case "themes":
|
|
698
|
+
return manifest.installed.themes;
|
|
699
|
+
case "configs":
|
|
700
|
+
return manifest.installed.configs;
|
|
701
|
+
default:
|
|
702
|
+
return null;
|
|
703
|
+
}
|
|
704
|
+
}
|
|
705
|
+
function recordInstall(names, category, cliVersion, path = MANIFEST_PATH) {
|
|
706
|
+
const manifest = readManifest(path);
|
|
654
707
|
const now = (/* @__PURE__ */ new Date()).toISOString();
|
|
655
708
|
if (!manifest.installedAt) manifest.installedAt = now;
|
|
656
709
|
manifest.updatedAt = now;
|
|
657
710
|
manifest.version = cliVersion;
|
|
658
|
-
|
|
659
|
-
|
|
660
|
-
|
|
661
|
-
|
|
662
|
-
manifest.installed.extensions.push(name);
|
|
663
|
-
break;
|
|
664
|
-
case "skills-bundled":
|
|
665
|
-
if (!manifest.installed.skills.bundled.includes(name))
|
|
666
|
-
manifest.installed.skills.bundled.push(name);
|
|
667
|
-
break;
|
|
668
|
-
case "skills-external":
|
|
669
|
-
if (!manifest.installed.skills.external.includes(name))
|
|
670
|
-
manifest.installed.skills.external.push(name);
|
|
671
|
-
break;
|
|
672
|
-
case "packages":
|
|
673
|
-
if (!manifest.installed.packages.includes(name))
|
|
674
|
-
manifest.installed.packages.push(name);
|
|
675
|
-
break;
|
|
676
|
-
case "configs":
|
|
677
|
-
if (!manifest.installed.configs.includes(name))
|
|
678
|
-
manifest.installed.configs.push(name);
|
|
679
|
-
break;
|
|
711
|
+
const list2 = getList(manifest, category);
|
|
712
|
+
if (list2) {
|
|
713
|
+
for (const name of names) {
|
|
714
|
+
if (!list2.includes(name)) list2.push(name);
|
|
680
715
|
}
|
|
681
716
|
}
|
|
682
|
-
writeManifest(manifest);
|
|
717
|
+
writeManifest(manifest, path);
|
|
683
718
|
}
|
|
684
719
|
|
|
685
720
|
// src/lib/installer.ts
|
|
@@ -704,6 +739,14 @@ function resolveTarget(component) {
|
|
|
704
739
|
}
|
|
705
740
|
return resolve2(PI_SKILLS_DIR, component.name);
|
|
706
741
|
}
|
|
742
|
+
case "prompts":
|
|
743
|
+
return resolve2(PI_PROMPTS_DIR, component.name);
|
|
744
|
+
case "agents":
|
|
745
|
+
return resolve2(PI_AGENTS_DIR, component.name);
|
|
746
|
+
case "themes": {
|
|
747
|
+
const themeName = (component.source ?? component.name).endsWith(".json") ? basename(component.source ?? component.name) : component.name + ".json";
|
|
748
|
+
return resolve2(PI_THEMES_DIR, themeName);
|
|
749
|
+
}
|
|
707
750
|
case "configs": {
|
|
708
751
|
const name = (component.source ?? component.name).replace(".template", "");
|
|
709
752
|
return resolve2(PI_AGENT_DIR, name);
|
|
@@ -712,42 +755,24 @@ function resolveTarget(component) {
|
|
|
712
755
|
return resolve2(PI_AGENT_DIR, component.name);
|
|
713
756
|
}
|
|
714
757
|
}
|
|
715
|
-
function copyComponent(source, target
|
|
716
|
-
|
|
717
|
-
|
|
718
|
-
if (isDirectory) {
|
|
719
|
-
cpSync(source, target, { recursive: true });
|
|
720
|
-
} else {
|
|
721
|
-
cpSync(source, target);
|
|
722
|
-
}
|
|
758
|
+
function copyComponent(source, target) {
|
|
759
|
+
mkdirSync2(resolve2(target, ".."), { recursive: true });
|
|
760
|
+
cpSync(source, target, { recursive: true });
|
|
723
761
|
}
|
|
724
762
|
function linkComponent(source, target) {
|
|
725
763
|
const targetDir = resolve2(target, "..");
|
|
726
764
|
mkdirSync2(targetDir, { recursive: true });
|
|
727
|
-
if (
|
|
728
|
-
unlinkSync(target);
|
|
729
|
-
}
|
|
765
|
+
if (targetExists(target)) unlinkSync(target);
|
|
730
766
|
symlinkSync(source, target);
|
|
731
767
|
}
|
|
732
|
-
function
|
|
768
|
+
function targetExists(path) {
|
|
733
769
|
try {
|
|
734
770
|
lstatSync(path);
|
|
735
|
-
return
|
|
771
|
+
return true;
|
|
736
772
|
} catch {
|
|
737
773
|
return false;
|
|
738
774
|
}
|
|
739
775
|
}
|
|
740
|
-
function targetExists(target) {
|
|
741
|
-
if (isSymlink(target)) {
|
|
742
|
-
try {
|
|
743
|
-
readlinkSync(target);
|
|
744
|
-
return true;
|
|
745
|
-
} catch {
|
|
746
|
-
return false;
|
|
747
|
-
}
|
|
748
|
-
}
|
|
749
|
-
return existsSync2(target);
|
|
750
|
-
}
|
|
751
776
|
function installLocal(component, options) {
|
|
752
777
|
const source = resolveSource(component, options);
|
|
753
778
|
const target = resolveTarget(component);
|
|
@@ -762,7 +787,7 @@ function installLocal(component, options) {
|
|
|
762
787
|
linkComponent(source, target);
|
|
763
788
|
return { success: true, message: "linked" };
|
|
764
789
|
} else {
|
|
765
|
-
copyComponent(source, target
|
|
790
|
+
copyComponent(source, target);
|
|
766
791
|
return { success: true, message: "copied" };
|
|
767
792
|
}
|
|
768
793
|
} catch (err) {
|
|
@@ -806,14 +831,21 @@ function installViaPi(component) {
|
|
|
806
831
|
}
|
|
807
832
|
async function installComponents(components, options) {
|
|
808
833
|
if (components.length === 0) return;
|
|
809
|
-
|
|
810
|
-
|
|
811
|
-
|
|
812
|
-
|
|
813
|
-
|
|
834
|
+
for (const dir of [
|
|
835
|
+
PI_AGENT_DIR,
|
|
836
|
+
PI_EXTENSIONS_DIR,
|
|
837
|
+
PI_SKILLS_DIR,
|
|
838
|
+
PI_PROMPTS_DIR,
|
|
839
|
+
PI_AGENTS_DIR,
|
|
840
|
+
PI_THEMES_DIR,
|
|
841
|
+
AGENTS_SKILLS_DIR
|
|
842
|
+
]) {
|
|
843
|
+
mkdirSync2(dir, { recursive: true });
|
|
844
|
+
}
|
|
845
|
+
const spinner3 = p2.spinner();
|
|
814
846
|
const results = [];
|
|
815
847
|
for (const component of components) {
|
|
816
|
-
|
|
848
|
+
spinner3.start(`Installing ${component.name}...`);
|
|
817
849
|
let result;
|
|
818
850
|
switch (component.method) {
|
|
819
851
|
case "copy":
|
|
@@ -831,9 +863,9 @@ async function installComponents(components, options) {
|
|
|
831
863
|
}
|
|
832
864
|
results.push({ name: component.name, ...result });
|
|
833
865
|
if (result.success) {
|
|
834
|
-
|
|
866
|
+
spinner3.stop(`${component.name}: ${result.message}`);
|
|
835
867
|
} else {
|
|
836
|
-
|
|
868
|
+
spinner3.stop(`${component.name}: FAILED - ${result.message}`);
|
|
837
869
|
}
|
|
838
870
|
}
|
|
839
871
|
const successByCategory = /* @__PURE__ */ new Map();
|
|
@@ -841,19 +873,17 @@ async function installComponents(components, options) {
|
|
|
841
873
|
if (!r.success) continue;
|
|
842
874
|
const component = components.find((c) => c.name === r.name);
|
|
843
875
|
if (!component) continue;
|
|
844
|
-
const
|
|
845
|
-
|
|
846
|
-
successByCategory.
|
|
876
|
+
const list2 = successByCategory.get(component.category) ?? [];
|
|
877
|
+
list2.push(r.name);
|
|
878
|
+
successByCategory.set(component.category, list2);
|
|
847
879
|
}
|
|
848
880
|
for (const [category, names] of successByCategory) {
|
|
849
881
|
recordInstall(names, category, options.cliVersion);
|
|
850
882
|
}
|
|
851
883
|
const succeeded = results.filter((r) => r.success).length;
|
|
852
|
-
const failed = results.
|
|
884
|
+
const failed = results.length - succeeded;
|
|
853
885
|
if (failed > 0) {
|
|
854
|
-
p2.log.warn(
|
|
855
|
-
`Installed ${succeeded}/${results.length} components. ${failed} failed:`
|
|
856
|
-
);
|
|
886
|
+
p2.log.warn(`Installed ${succeeded}/${results.length} components. ${failed} failed:`);
|
|
857
887
|
for (const r of results.filter((r2) => !r2.success)) {
|
|
858
888
|
p2.log.error(` ${r.name}: ${r.message}`);
|
|
859
889
|
}
|
|
@@ -868,130 +898,93 @@ function installExtensionDeps() {
|
|
|
868
898
|
for (const entry of entries) {
|
|
869
899
|
const fullPath = resolve2(extDir, entry);
|
|
870
900
|
try {
|
|
871
|
-
if (statSync(fullPath).isDirectory()
|
|
872
|
-
|
|
873
|
-
execSync("npm install --silent", { cwd: fullPath, stdio: "pipe" });
|
|
901
|
+
if (!statSync(fullPath).isDirectory() || !existsSync2(resolve2(fullPath, "package.json"))) {
|
|
902
|
+
continue;
|
|
874
903
|
}
|
|
875
904
|
} catch {
|
|
905
|
+
continue;
|
|
906
|
+
}
|
|
907
|
+
try {
|
|
908
|
+
p2.log.info(`Installing dependencies for ${entry}...`);
|
|
909
|
+
execSync("npm install --silent", { cwd: fullPath, stdio: "pipe" });
|
|
910
|
+
} catch (err) {
|
|
911
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
912
|
+
p2.log.error(`Failed to install dependencies for ${entry}: ${msg}`);
|
|
876
913
|
}
|
|
877
914
|
}
|
|
878
915
|
}
|
|
879
916
|
|
|
880
917
|
// src/commands/install.ts
|
|
881
|
-
|
|
882
|
-
|
|
883
|
-
|
|
884
|
-
|
|
885
|
-
|
|
886
|
-
|
|
887
|
-
}
|
|
888
|
-
|
|
889
|
-
|
|
890
|
-
|
|
891
|
-
|
|
892
|
-
|
|
893
|
-
|
|
894
|
-
if (!components?.length) continue;
|
|
895
|
-
extensionOptions.push({
|
|
896
|
-
value: `__separator_${group}`,
|
|
897
|
-
label: pc.dim(`--- ${GROUP_LABELS[group]} ---`),
|
|
898
|
-
hint: ""
|
|
899
|
-
});
|
|
900
|
-
extensionOptions.push(...componentOptions(components));
|
|
901
|
-
}
|
|
902
|
-
const extResult = await p3.multiselect({
|
|
903
|
-
message: "Select extensions to install:",
|
|
904
|
-
options: extensionOptions.filter((o) => !o.value.startsWith("__separator")),
|
|
918
|
+
var SELECT_ALL = "__all__";
|
|
919
|
+
async function selectComponents(message, components) {
|
|
920
|
+
if (components.length === 0) return [];
|
|
921
|
+
const result = await p3.multiselect({
|
|
922
|
+
message,
|
|
923
|
+
options: [
|
|
924
|
+
{ value: SELECT_ALL, label: "* Select all", hint: `all ${components.length} items` },
|
|
925
|
+
...components.map((c) => ({
|
|
926
|
+
value: c.name,
|
|
927
|
+
label: c.name,
|
|
928
|
+
hint: c.description
|
|
929
|
+
}))
|
|
930
|
+
],
|
|
905
931
|
required: false
|
|
906
932
|
});
|
|
907
|
-
if (p3.isCancel(
|
|
933
|
+
if (p3.isCancel(result)) {
|
|
908
934
|
p3.cancel("Installation cancelled.");
|
|
909
935
|
process.exit(0);
|
|
910
936
|
}
|
|
911
|
-
selected
|
|
912
|
-
|
|
913
|
-
|
|
914
|
-
const skillResult = await p3.multiselect({
|
|
915
|
-
message: "Select bundled skills to install:",
|
|
916
|
-
options: componentOptions(bundledSkills2),
|
|
917
|
-
required: false
|
|
918
|
-
});
|
|
919
|
-
if (p3.isCancel(skillResult)) {
|
|
920
|
-
p3.cancel("Installation cancelled.");
|
|
921
|
-
process.exit(0);
|
|
922
|
-
}
|
|
923
|
-
selected.push(...skillResult);
|
|
937
|
+
const selected = result;
|
|
938
|
+
if (selected.includes(SELECT_ALL)) {
|
|
939
|
+
return components.map((c) => c.name);
|
|
924
940
|
}
|
|
925
|
-
|
|
926
|
-
|
|
927
|
-
|
|
941
|
+
return selected;
|
|
942
|
+
}
|
|
943
|
+
async function interactivePicker() {
|
|
944
|
+
const selected = [];
|
|
945
|
+
const steps = [
|
|
946
|
+
{ message: "Select extensions to install:", components: getByCategory("extensions") },
|
|
947
|
+
{ message: "Select bundled skills to install:", components: getByCategory("skills-bundled") },
|
|
948
|
+
{
|
|
928
949
|
message: "Select external skills to install (fetched from source repos):",
|
|
929
|
-
|
|
930
|
-
|
|
931
|
-
}
|
|
932
|
-
|
|
933
|
-
|
|
934
|
-
|
|
935
|
-
|
|
936
|
-
|
|
937
|
-
|
|
938
|
-
const pkgs = getByCategory("packages");
|
|
939
|
-
if (pkgs.length > 0) {
|
|
940
|
-
const pkgResult = await p3.multiselect({
|
|
941
|
-
message: "Select pi packages to install:",
|
|
942
|
-
options: componentOptions(pkgs),
|
|
943
|
-
required: false
|
|
944
|
-
});
|
|
945
|
-
if (p3.isCancel(pkgResult)) {
|
|
946
|
-
p3.cancel("Installation cancelled.");
|
|
947
|
-
process.exit(0);
|
|
948
|
-
}
|
|
949
|
-
selected.push(...pkgResult);
|
|
950
|
-
}
|
|
951
|
-
const configs2 = getByCategory("configs");
|
|
952
|
-
if (configs2.length > 0) {
|
|
953
|
-
const configResult = await p3.multiselect({
|
|
954
|
-
message: "Select starter configs to install (copied as templates, won't overwrite existing):",
|
|
955
|
-
options: componentOptions(configs2),
|
|
956
|
-
required: false
|
|
957
|
-
});
|
|
958
|
-
if (p3.isCancel(configResult)) {
|
|
959
|
-
p3.cancel("Installation cancelled.");
|
|
960
|
-
process.exit(0);
|
|
950
|
+
components: getByCategory("skills-external")
|
|
951
|
+
},
|
|
952
|
+
{ message: "Select prompts to install:", components: getByCategory("prompts") },
|
|
953
|
+
{ message: "Select agents to install:", components: getByCategory("agents") },
|
|
954
|
+
{ message: "Select themes to install:", components: getByCategory("themes") },
|
|
955
|
+
{ message: "Select pi packages to install:", components: getByCategory("packages") },
|
|
956
|
+
{
|
|
957
|
+
message: "Select starter configs (copied as templates, won't overwrite existing):",
|
|
958
|
+
components: getByCategory("configs")
|
|
961
959
|
}
|
|
962
|
-
|
|
960
|
+
];
|
|
961
|
+
for (const step of steps) {
|
|
962
|
+
const names = await selectComponents(step.message, step.components);
|
|
963
|
+
selected.push(...names);
|
|
963
964
|
}
|
|
964
965
|
return registry.filter((c) => selected.includes(c.name));
|
|
965
966
|
}
|
|
966
967
|
function resolveFromFlags(args) {
|
|
967
|
-
const names = /* @__PURE__ */ new Set(
|
|
968
|
-
|
|
969
|
-
|
|
970
|
-
|
|
971
|
-
|
|
972
|
-
for (const name of args.skills) names.add(name);
|
|
973
|
-
}
|
|
974
|
-
if (args.packages) {
|
|
975
|
-
for (const name of args.packages) names.add(name);
|
|
976
|
-
}
|
|
968
|
+
const names = /* @__PURE__ */ new Set([
|
|
969
|
+
...args.extensions ?? [],
|
|
970
|
+
...args.skills ?? [],
|
|
971
|
+
...args.packages ?? []
|
|
972
|
+
]);
|
|
977
973
|
const resolved = [];
|
|
978
974
|
const notFound = [];
|
|
979
975
|
for (const name of names) {
|
|
980
976
|
const component = registry.find((c) => c.name === name);
|
|
981
|
-
if (component)
|
|
982
|
-
|
|
983
|
-
} else {
|
|
984
|
-
notFound.push(name);
|
|
985
|
-
}
|
|
977
|
+
if (component) resolved.push(component);
|
|
978
|
+
else notFound.push(name);
|
|
986
979
|
}
|
|
987
980
|
if (notFound.length > 0) {
|
|
988
981
|
p3.log.warn(`Unknown components: ${notFound.join(", ")}`);
|
|
989
|
-
p3.log.info('Run "pi-toolkit list" to see available components.');
|
|
982
|
+
p3.log.info('Run "pi-agent-toolkit list" to see available components.');
|
|
990
983
|
}
|
|
991
984
|
return resolved;
|
|
992
985
|
}
|
|
993
986
|
async function runInstall(args) {
|
|
994
|
-
p3.intro(pc.bold("pi-toolkit install"));
|
|
987
|
+
p3.intro(pc.bold("pi-agent-toolkit install"));
|
|
995
988
|
if (args.link && !args.repoPath) {
|
|
996
989
|
p3.log.error("--link requires --repo-path to be set.");
|
|
997
990
|
p3.log.info("Example: pi-toolkit install --link --repo-path ~/Code/pi-toolkit");
|
|
@@ -1011,18 +1004,17 @@ async function runInstall(args) {
|
|
|
1011
1004
|
p3.outro("Done.");
|
|
1012
1005
|
return;
|
|
1013
1006
|
}
|
|
1014
|
-
const
|
|
1015
|
-
|
|
1016
|
-
(c) => c.category
|
|
1017
|
-
|
|
1018
|
-
|
|
1019
|
-
|
|
1020
|
-
|
|
1021
|
-
|
|
1022
|
-
|
|
1023
|
-
|
|
1024
|
-
|
|
1025
|
-
p3.log.info(`Will install: ${parts.join(", ")}`);
|
|
1007
|
+
const counts = [
|
|
1008
|
+
["extension", components.filter((c) => c.category === "extensions").length],
|
|
1009
|
+
["skill", components.filter((c) => c.category.startsWith("skills-")).length],
|
|
1010
|
+
["prompt", components.filter((c) => c.category === "prompts").length],
|
|
1011
|
+
["agent", components.filter((c) => c.category === "agents").length],
|
|
1012
|
+
["theme", components.filter((c) => c.category === "themes").length],
|
|
1013
|
+
["package", components.filter((c) => c.category === "packages").length],
|
|
1014
|
+
["config", components.filter((c) => c.category === "configs").length]
|
|
1015
|
+
];
|
|
1016
|
+
const summary = counts.filter(([, n]) => n > 0).map(([label, n]) => `${n} ${label}${n > 1 ? "s" : ""}`).join(", ");
|
|
1017
|
+
p3.log.info(`Will install: ${summary}`);
|
|
1026
1018
|
if (args.link) {
|
|
1027
1019
|
p3.log.info(`Mode: symlink (repo: ${args.repoPath})`);
|
|
1028
1020
|
}
|
|
@@ -1052,9 +1044,20 @@ async function runInstall(args) {
|
|
|
1052
1044
|
|
|
1053
1045
|
// src/commands/list.ts
|
|
1054
1046
|
import pc2 from "picocolors";
|
|
1047
|
+
function printSection(category, title, subtitle) {
|
|
1048
|
+
const items = getByCategory(category);
|
|
1049
|
+
if (items.length === 0) return;
|
|
1050
|
+
const header = subtitle ? pc2.bold(pc2.cyan(title)) + pc2.dim(` (${subtitle})`) : pc2.bold(pc2.cyan(title));
|
|
1051
|
+
console.log(header);
|
|
1052
|
+
for (const c of items) {
|
|
1053
|
+
const suffix = c.remote ? pc2.dim(` [${c.remote}]`) : "";
|
|
1054
|
+
console.log(` ${pc2.green(c.name.padEnd(38))} ${pc2.dim(c.description)}${suffix}`);
|
|
1055
|
+
}
|
|
1056
|
+
console.log();
|
|
1057
|
+
}
|
|
1055
1058
|
function runList() {
|
|
1056
1059
|
console.log();
|
|
1057
|
-
console.log(pc2.bold("pi-toolkit: available components"));
|
|
1060
|
+
console.log(pc2.bold("pi-agent-toolkit: available components"));
|
|
1058
1061
|
console.log();
|
|
1059
1062
|
console.log(pc2.bold(pc2.cyan("Extensions")));
|
|
1060
1063
|
const groups = getExtensionGroups();
|
|
@@ -1067,43 +1070,17 @@ function runList() {
|
|
|
1067
1070
|
}
|
|
1068
1071
|
}
|
|
1069
1072
|
console.log();
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1075
|
-
|
|
1076
|
-
|
|
1077
|
-
}
|
|
1078
|
-
const external = getByCategory("skills-external");
|
|
1079
|
-
if (external.length > 0) {
|
|
1080
|
-
console.log(pc2.bold(pc2.cyan("External Skills")) + pc2.dim(" (installed from source repos)"));
|
|
1081
|
-
for (const c of external) {
|
|
1082
|
-
const source = c.remote ? pc2.dim(` [${c.remote}]`) : "";
|
|
1083
|
-
console.log(` ${pc2.green(c.name.padEnd(38))} ${pc2.dim(c.description)}${source}`);
|
|
1084
|
-
}
|
|
1085
|
-
console.log();
|
|
1086
|
-
}
|
|
1087
|
-
const pkgs = getByCategory("packages");
|
|
1088
|
-
if (pkgs.length > 0) {
|
|
1089
|
-
console.log(pc2.bold(pc2.cyan("Packages")) + pc2.dim(" (installed via pi install)"));
|
|
1090
|
-
for (const c of pkgs) {
|
|
1091
|
-
console.log(` ${pc2.green(c.name.padEnd(38))} ${pc2.dim(c.description)}`);
|
|
1092
|
-
}
|
|
1093
|
-
console.log();
|
|
1094
|
-
}
|
|
1095
|
-
const configs2 = getByCategory("configs");
|
|
1096
|
-
if (configs2.length > 0) {
|
|
1097
|
-
console.log(pc2.bold(pc2.cyan("Starter Configs")) + pc2.dim(" (copied as templates)"));
|
|
1098
|
-
for (const c of configs2) {
|
|
1099
|
-
console.log(` ${pc2.green(c.name.padEnd(38))} ${pc2.dim(c.description)}`);
|
|
1100
|
-
}
|
|
1101
|
-
console.log();
|
|
1102
|
-
}
|
|
1073
|
+
printSection("skills-bundled", "Bundled Skills");
|
|
1074
|
+
printSection("skills-external", "External Skills", "installed from source repos");
|
|
1075
|
+
printSection("prompts", "Prompts", "custom prompt templates");
|
|
1076
|
+
printSection("agents", "Agents", "custom agent definitions");
|
|
1077
|
+
printSection("themes", "Themes", "TUI color themes");
|
|
1078
|
+
printSection("packages", "Packages", "installed via pi install");
|
|
1079
|
+
printSection("configs", "Starter Configs", "copied as templates");
|
|
1103
1080
|
}
|
|
1104
1081
|
|
|
1105
1082
|
// src/commands/status.ts
|
|
1106
|
-
import { existsSync as existsSync3, lstatSync as lstatSync2, readlinkSync
|
|
1083
|
+
import { existsSync as existsSync3, lstatSync as lstatSync2, readlinkSync } from "fs";
|
|
1107
1084
|
import { resolve as resolve3, basename as basename2 } from "path";
|
|
1108
1085
|
import pc3 from "picocolors";
|
|
1109
1086
|
function expectedPath(component) {
|
|
@@ -1121,10 +1098,17 @@ function expectedPath(component) {
|
|
|
1121
1098
|
case "skills-external": {
|
|
1122
1099
|
const piPath = resolve3(PI_SKILLS_DIR, component.name);
|
|
1123
1100
|
const agentsPath = resolve3(AGENTS_SKILLS_DIR, component.name);
|
|
1124
|
-
if (existsSync3(piPath)
|
|
1125
|
-
if (existsSync3(agentsPath) || isSymlink2(agentsPath)) return agentsPath;
|
|
1101
|
+
if (existsSync3(piPath)) return piPath;
|
|
1126
1102
|
return agentsPath;
|
|
1127
1103
|
}
|
|
1104
|
+
case "prompts":
|
|
1105
|
+
return resolve3(PI_PROMPTS_DIR, component.name);
|
|
1106
|
+
case "agents":
|
|
1107
|
+
return resolve3(PI_AGENTS_DIR, component.name);
|
|
1108
|
+
case "themes": {
|
|
1109
|
+
const themeName = (component.source ?? component.name).endsWith(".json") ? basename2(component.source ?? component.name) : component.name + ".json";
|
|
1110
|
+
return resolve3(PI_THEMES_DIR, themeName);
|
|
1111
|
+
}
|
|
1128
1112
|
case "packages":
|
|
1129
1113
|
return null;
|
|
1130
1114
|
// Can't easily check pi packages on disk
|
|
@@ -1136,49 +1120,44 @@ function expectedPath(component) {
|
|
|
1136
1120
|
return null;
|
|
1137
1121
|
}
|
|
1138
1122
|
}
|
|
1139
|
-
function
|
|
1123
|
+
function checkFile(path) {
|
|
1140
1124
|
try {
|
|
1141
|
-
|
|
1125
|
+
const stats = lstatSync2(path);
|
|
1126
|
+
if (stats.isSymbolicLink()) {
|
|
1127
|
+
const target = readlinkSync(path);
|
|
1128
|
+
const dangling = !existsSync3(path);
|
|
1129
|
+
return {
|
|
1130
|
+
exists: !dangling,
|
|
1131
|
+
detail: dangling ? `dangling symlink -> ${target}` : `symlink -> ${target}`
|
|
1132
|
+
};
|
|
1133
|
+
}
|
|
1134
|
+
return { exists: true };
|
|
1142
1135
|
} catch {
|
|
1143
|
-
return false;
|
|
1144
|
-
}
|
|
1145
|
-
}
|
|
1146
|
-
function checkFile(path) {
|
|
1147
|
-
if (isSymlink2(path)) {
|
|
1148
|
-
const target = readlinkSync2(path);
|
|
1149
|
-
const dangling = !existsSync3(path);
|
|
1150
|
-
return {
|
|
1151
|
-
exists: !dangling,
|
|
1152
|
-
detail: dangling ? `dangling symlink -> ${target}` : `symlink -> ${target}`
|
|
1153
|
-
};
|
|
1136
|
+
return { exists: false };
|
|
1154
1137
|
}
|
|
1155
|
-
return { exists: existsSync3(path) };
|
|
1156
1138
|
}
|
|
1157
1139
|
function runStatus() {
|
|
1158
1140
|
const manifest = readManifest();
|
|
1159
1141
|
console.log();
|
|
1160
|
-
console.log(pc3.bold("pi-toolkit status"));
|
|
1142
|
+
console.log(pc3.bold("pi-agent-toolkit status"));
|
|
1161
1143
|
console.log();
|
|
1162
1144
|
if (!manifest.installedAt) {
|
|
1163
1145
|
console.log(pc3.dim("No pi-toolkit manifest found. Nothing has been installed yet."));
|
|
1164
|
-
console.log(pc3.dim('Run "pi-toolkit install" to get started.'));
|
|
1146
|
+
console.log(pc3.dim('Run "pi-agent-toolkit install" to get started.'));
|
|
1165
1147
|
console.log();
|
|
1166
1148
|
return;
|
|
1167
1149
|
}
|
|
1168
|
-
console.log(
|
|
1169
|
-
|
|
1170
|
-
);
|
|
1171
|
-
console.log(
|
|
1172
|
-
`${pc3.dim("Installed at:")} ${manifest.installedAt}`
|
|
1173
|
-
);
|
|
1174
|
-
console.log(
|
|
1175
|
-
`${pc3.dim("Updated at:")} ${manifest.updatedAt}`
|
|
1176
|
-
);
|
|
1150
|
+
console.log(`${pc3.dim("CLI version:")} ${manifest.version || "unknown"}`);
|
|
1151
|
+
console.log(`${pc3.dim("Installed at:")} ${manifest.installedAt}`);
|
|
1152
|
+
console.log(`${pc3.dim("Updated at:")} ${manifest.updatedAt}`);
|
|
1177
1153
|
console.log();
|
|
1178
1154
|
const installedNames = /* @__PURE__ */ new Set([
|
|
1179
1155
|
...manifest.installed.extensions,
|
|
1180
1156
|
...manifest.installed.skills.bundled,
|
|
1181
1157
|
...manifest.installed.skills.external,
|
|
1158
|
+
...manifest.installed.prompts,
|
|
1159
|
+
...manifest.installed.agents,
|
|
1160
|
+
...manifest.installed.themes,
|
|
1182
1161
|
...manifest.installed.packages,
|
|
1183
1162
|
...manifest.installed.configs
|
|
1184
1163
|
]);
|
|
@@ -1215,6 +1194,9 @@ function runStatus() {
|
|
|
1215
1194
|
{ key: "extensions", label: "Extensions" },
|
|
1216
1195
|
{ key: "skills-bundled", label: "Bundled Skills" },
|
|
1217
1196
|
{ key: "skills-external", label: "External Skills" },
|
|
1197
|
+
{ key: "prompts", label: "Prompts" },
|
|
1198
|
+
{ key: "agents", label: "Agents" },
|
|
1199
|
+
{ key: "themes", label: "Themes" },
|
|
1218
1200
|
{ key: "packages", label: "Packages" },
|
|
1219
1201
|
{ key: "configs", label: "Configs" }
|
|
1220
1202
|
];
|
|
@@ -1241,21 +1223,190 @@ function runStatus() {
|
|
|
1241
1223
|
}
|
|
1242
1224
|
const missing = entries.filter((e) => e.status === "missing");
|
|
1243
1225
|
if (missing.length > 0) {
|
|
1244
|
-
console.log(
|
|
1245
|
-
pc3.yellow(
|
|
1246
|
-
`${missing.length} component(s) in manifest but missing from disk:`
|
|
1247
|
-
)
|
|
1248
|
-
);
|
|
1226
|
+
console.log(pc3.yellow(`${missing.length} component(s) in manifest but missing from disk:`));
|
|
1249
1227
|
for (const m of missing) {
|
|
1250
1228
|
console.log(pc3.yellow(` - ${m.name}`));
|
|
1251
1229
|
}
|
|
1252
|
-
console.log(pc3.dim('Re-run "pi-toolkit install" to restore them.'));
|
|
1230
|
+
console.log(pc3.dim('Re-run "pi-agent-toolkit install" to restore them.'));
|
|
1253
1231
|
console.log();
|
|
1254
1232
|
}
|
|
1255
1233
|
}
|
|
1256
1234
|
|
|
1235
|
+
// src/commands/sync.ts
|
|
1236
|
+
import {
|
|
1237
|
+
cpSync as cpSync2,
|
|
1238
|
+
existsSync as existsSync4,
|
|
1239
|
+
lstatSync as lstatSync3,
|
|
1240
|
+
mkdirSync as mkdirSync3,
|
|
1241
|
+
readdirSync as readdirSync2,
|
|
1242
|
+
rmSync,
|
|
1243
|
+
statSync as statSync2,
|
|
1244
|
+
symlinkSync as symlinkSync2,
|
|
1245
|
+
unlinkSync as unlinkSync2
|
|
1246
|
+
} from "fs";
|
|
1247
|
+
import { resolve as resolve4 } from "path";
|
|
1248
|
+
import * as p4 from "@clack/prompts";
|
|
1249
|
+
import pc4 from "picocolors";
|
|
1250
|
+
function getExternalSkillNames() {
|
|
1251
|
+
return new Set(getByCategory("skills-external").map((c) => c.name));
|
|
1252
|
+
}
|
|
1253
|
+
function isSymlink(path) {
|
|
1254
|
+
try {
|
|
1255
|
+
return lstatSync3(path).isSymbolicLink();
|
|
1256
|
+
} catch {
|
|
1257
|
+
return false;
|
|
1258
|
+
}
|
|
1259
|
+
}
|
|
1260
|
+
function findUnmanaged(scanDir, targetDir, category, skipNames) {
|
|
1261
|
+
if (!existsSync4(scanDir)) return [];
|
|
1262
|
+
const items = [];
|
|
1263
|
+
const entries = readdirSync2(scanDir);
|
|
1264
|
+
for (const entry of entries) {
|
|
1265
|
+
const fullPath = resolve4(scanDir, entry);
|
|
1266
|
+
if (isSymlink(fullPath)) continue;
|
|
1267
|
+
if (skipNames.has(entry) || skipNames.has(entry.replace(/\.ts$/, ""))) continue;
|
|
1268
|
+
if (entry === "node_modules" || entry.startsWith(".")) continue;
|
|
1269
|
+
let isDir;
|
|
1270
|
+
try {
|
|
1271
|
+
isDir = statSync2(fullPath).isDirectory();
|
|
1272
|
+
} catch {
|
|
1273
|
+
continue;
|
|
1274
|
+
}
|
|
1275
|
+
if (category === "extensions") {
|
|
1276
|
+
if (!isDir && !entry.endsWith(".ts")) continue;
|
|
1277
|
+
} else {
|
|
1278
|
+
if (!isDir) continue;
|
|
1279
|
+
}
|
|
1280
|
+
items.push({
|
|
1281
|
+
name: entry,
|
|
1282
|
+
sourcePath: fullPath,
|
|
1283
|
+
targetDir,
|
|
1284
|
+
category,
|
|
1285
|
+
isDirectory: isDir
|
|
1286
|
+
});
|
|
1287
|
+
}
|
|
1288
|
+
return items;
|
|
1289
|
+
}
|
|
1290
|
+
function absorbItem(item) {
|
|
1291
|
+
const targetPath = resolve4(item.targetDir, item.name);
|
|
1292
|
+
try {
|
|
1293
|
+
mkdirSync3(item.targetDir, { recursive: true });
|
|
1294
|
+
if (item.isDirectory) {
|
|
1295
|
+
cpSync2(item.sourcePath, targetPath, { recursive: true });
|
|
1296
|
+
rmSync(item.sourcePath, { recursive: true, force: true });
|
|
1297
|
+
} else {
|
|
1298
|
+
cpSync2(item.sourcePath, targetPath);
|
|
1299
|
+
unlinkSync2(item.sourcePath);
|
|
1300
|
+
}
|
|
1301
|
+
symlinkSync2(targetPath, item.sourcePath);
|
|
1302
|
+
return { success: true, message: "absorbed and symlinked" };
|
|
1303
|
+
} catch (err) {
|
|
1304
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
1305
|
+
return { success: false, message: msg };
|
|
1306
|
+
}
|
|
1307
|
+
}
|
|
1308
|
+
async function runSync(options) {
|
|
1309
|
+
p4.intro(pc4.bold("pi-agent-toolkit sync"));
|
|
1310
|
+
const repoPath = resolve4(options.repoPath);
|
|
1311
|
+
const dotfilesPath = resolve4(repoPath, "dotfiles");
|
|
1312
|
+
if (!existsSync4(dotfilesPath)) {
|
|
1313
|
+
p4.log.error(`dotfiles/ not found at ${dotfilesPath}`);
|
|
1314
|
+
p4.log.info("Make sure --repo-path points to your pi-toolkit repo clone.");
|
|
1315
|
+
process.exit(1);
|
|
1316
|
+
}
|
|
1317
|
+
p4.log.info(`Repo: ${repoPath}`);
|
|
1318
|
+
p4.log.info("Scanning for unmanaged components...");
|
|
1319
|
+
const externalSkills2 = getExternalSkillNames();
|
|
1320
|
+
function knownNames(subdir) {
|
|
1321
|
+
const dir = resolve4(dotfilesPath, subdir);
|
|
1322
|
+
if (!existsSync4(dir)) return /* @__PURE__ */ new Set();
|
|
1323
|
+
return new Set(readdirSync2(dir));
|
|
1324
|
+
}
|
|
1325
|
+
const scanTargets = [
|
|
1326
|
+
[PI_EXTENSIONS_DIR, "extensions", "extensions", knownNames("extensions")],
|
|
1327
|
+
[
|
|
1328
|
+
PI_SKILLS_DIR,
|
|
1329
|
+
"agent-skills",
|
|
1330
|
+
"agent-skills",
|
|
1331
|
+
/* @__PURE__ */ new Set([...knownNames("agent-skills"), ...externalSkills2])
|
|
1332
|
+
],
|
|
1333
|
+
[
|
|
1334
|
+
AGENTS_SKILLS_DIR,
|
|
1335
|
+
"global-skills",
|
|
1336
|
+
"global-skills",
|
|
1337
|
+
/* @__PURE__ */ new Set([...knownNames("global-skills"), ...externalSkills2])
|
|
1338
|
+
],
|
|
1339
|
+
[PI_PROMPTS_DIR, "prompts", "prompts", knownNames("prompts")],
|
|
1340
|
+
[PI_AGENTS_DIR, "agents", "agents", knownNames("agents")],
|
|
1341
|
+
[PI_THEMES_DIR, "themes", "themes", knownNames("themes")]
|
|
1342
|
+
];
|
|
1343
|
+
const found = scanTargets.flatMap(
|
|
1344
|
+
([scanDir, dotfilesSub, category, skipNames]) => findUnmanaged(scanDir, resolve4(dotfilesPath, dotfilesSub), category, skipNames)
|
|
1345
|
+
);
|
|
1346
|
+
if (found.length === 0) {
|
|
1347
|
+
p4.log.success("No unmanaged components found. Everything is in sync.");
|
|
1348
|
+
p4.outro("Done.");
|
|
1349
|
+
return;
|
|
1350
|
+
}
|
|
1351
|
+
p4.log.info(`Found ${found.length} unmanaged item(s):`);
|
|
1352
|
+
for (const item of found) {
|
|
1353
|
+
const suffix = item.isDirectory ? "/" : "";
|
|
1354
|
+
p4.log.message(` ${pc4.yellow(item.name + suffix)} ${pc4.dim(`(${item.category})`)}`);
|
|
1355
|
+
}
|
|
1356
|
+
let toAbsorb;
|
|
1357
|
+
if (options.all) {
|
|
1358
|
+
toAbsorb = found;
|
|
1359
|
+
} else {
|
|
1360
|
+
const selected = await p4.multiselect({
|
|
1361
|
+
message: "Select items to absorb into the repo:",
|
|
1362
|
+
options: found.map((item) => ({
|
|
1363
|
+
value: item.name,
|
|
1364
|
+
label: item.name + (item.isDirectory ? "/" : ""),
|
|
1365
|
+
hint: `${item.category} -> dotfiles/${item.category}/${item.name}`
|
|
1366
|
+
})),
|
|
1367
|
+
required: false
|
|
1368
|
+
});
|
|
1369
|
+
if (p4.isCancel(selected)) {
|
|
1370
|
+
p4.cancel("Sync cancelled.");
|
|
1371
|
+
process.exit(0);
|
|
1372
|
+
}
|
|
1373
|
+
const selectedNames = new Set(selected);
|
|
1374
|
+
toAbsorb = found.filter((item) => selectedNames.has(item.name));
|
|
1375
|
+
}
|
|
1376
|
+
if (toAbsorb.length === 0) {
|
|
1377
|
+
p4.log.warn("Nothing selected to absorb.");
|
|
1378
|
+
p4.outro("Done.");
|
|
1379
|
+
return;
|
|
1380
|
+
}
|
|
1381
|
+
const spinner3 = p4.spinner();
|
|
1382
|
+
let succeeded = 0;
|
|
1383
|
+
let failed = 0;
|
|
1384
|
+
for (const item of toAbsorb) {
|
|
1385
|
+
spinner3.start(`Absorbing ${item.name}...`);
|
|
1386
|
+
const result = absorbItem(item);
|
|
1387
|
+
if (result.success) {
|
|
1388
|
+
spinner3.stop(`${item.name}: ${result.message}`);
|
|
1389
|
+
succeeded++;
|
|
1390
|
+
} else {
|
|
1391
|
+
spinner3.stop(`${item.name}: FAILED - ${result.message}`);
|
|
1392
|
+
failed++;
|
|
1393
|
+
}
|
|
1394
|
+
}
|
|
1395
|
+
if (failed > 0) {
|
|
1396
|
+
p4.log.warn(`Absorbed ${succeeded}/${toAbsorb.length}. ${failed} failed.`);
|
|
1397
|
+
} else {
|
|
1398
|
+
p4.log.success(`All ${succeeded} item(s) absorbed into the repo.`);
|
|
1399
|
+
}
|
|
1400
|
+
p4.outro(
|
|
1401
|
+
pc4.green("Next steps: review the new files in dotfiles/, add to registry.ts, then commit.")
|
|
1402
|
+
);
|
|
1403
|
+
}
|
|
1404
|
+
|
|
1257
1405
|
// src/index.ts
|
|
1258
|
-
var
|
|
1406
|
+
var __dirname2 = dirname3(fileURLToPath2(import.meta.url));
|
|
1407
|
+
var CLI_VERSION = JSON.parse(
|
|
1408
|
+
readFileSync2(resolve5(__dirname2, "..", "package.json"), "utf-8")
|
|
1409
|
+
).version;
|
|
1259
1410
|
var install = defineCommand({
|
|
1260
1411
|
meta: {
|
|
1261
1412
|
name: "install",
|
|
@@ -1329,6 +1480,30 @@ var status = defineCommand({
|
|
|
1329
1480
|
runStatus();
|
|
1330
1481
|
}
|
|
1331
1482
|
});
|
|
1483
|
+
var sync = defineCommand({
|
|
1484
|
+
meta: {
|
|
1485
|
+
name: "sync",
|
|
1486
|
+
description: "Absorb unmanaged extensions and skills from pi into the repo"
|
|
1487
|
+
},
|
|
1488
|
+
args: {
|
|
1489
|
+
"repo-path": {
|
|
1490
|
+
type: "string",
|
|
1491
|
+
description: "Path to local pi-toolkit repo clone",
|
|
1492
|
+
required: true
|
|
1493
|
+
},
|
|
1494
|
+
all: {
|
|
1495
|
+
type: "boolean",
|
|
1496
|
+
description: "Absorb all unmanaged items without prompting",
|
|
1497
|
+
default: false
|
|
1498
|
+
}
|
|
1499
|
+
},
|
|
1500
|
+
run({ args }) {
|
|
1501
|
+
return runSync({
|
|
1502
|
+
repoPath: args["repo-path"],
|
|
1503
|
+
all: args.all
|
|
1504
|
+
});
|
|
1505
|
+
}
|
|
1506
|
+
});
|
|
1332
1507
|
var main = defineCommand({
|
|
1333
1508
|
meta: {
|
|
1334
1509
|
name: "pi-agent-toolkit",
|
|
@@ -1338,7 +1513,8 @@ var main = defineCommand({
|
|
|
1338
1513
|
subCommands: {
|
|
1339
1514
|
install,
|
|
1340
1515
|
list,
|
|
1341
|
-
status
|
|
1516
|
+
status,
|
|
1517
|
+
sync
|
|
1342
1518
|
}
|
|
1343
1519
|
});
|
|
1344
1520
|
runMain(main);
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "pi-agent-toolkit",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.3.0",
|
|
4
4
|
"description": "CLI to selectively install curated extensions, skills, and configs for the pi coding agent",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"pi",
|
|
@@ -27,11 +27,13 @@
|
|
|
27
27
|
"scripts": {
|
|
28
28
|
"build": "tsup",
|
|
29
29
|
"dev": "tsup --watch",
|
|
30
|
+
"test": "node --experimental-strip-types --test src/**/*.test.ts",
|
|
31
|
+
"typecheck": "tsc",
|
|
30
32
|
"prepack": "npm run build"
|
|
31
33
|
},
|
|
32
34
|
"dependencies": {
|
|
33
|
-
"@clack/prompts": "^0.
|
|
34
|
-
"citty": "^0.1
|
|
35
|
+
"@clack/prompts": "^0.11.0",
|
|
36
|
+
"citty": "^0.2.1",
|
|
35
37
|
"picocolors": "^1.1.1"
|
|
36
38
|
},
|
|
37
39
|
"devDependencies": {
|