@pify/cli 0.2.2 → 0.3.1
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/README.md +4 -3
- package/catalog.json +52 -10
- package/dist/cli.js +47 -3
- package/dist/index.d.ts +16 -1
- package/dist/index.js +37 -1
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -24,6 +24,7 @@ pify setup --pi-version 0.84.4 # pin the version your team has tested
|
|
|
24
24
|
pify setup --installer # run pi's official interactive installer (ps1/sh)
|
|
25
25
|
pify list # show the @pify catalog with install state
|
|
26
26
|
pify install goal task # short names resolve to @pify/goal, @pify/task
|
|
27
|
+
pify install suite # the whole suite in one go (also: core, agents)
|
|
27
28
|
pify install goal -l -a # project scope, pre-approved (CI-friendly)
|
|
28
29
|
pify remove goal
|
|
29
30
|
pify update # update pi + every installed @pify package
|
|
@@ -63,14 +64,14 @@ pify completions powershell | Out-String | Invoke-Expression # add to $PROFILE
|
|
|
63
64
|
| `@pify/memory` | Persistent memory across pi sessions |
|
|
64
65
|
| `@pify/plan-mode` | Read-only planning mode with approve-then-execute gate |
|
|
65
66
|
| `@pify/pretty` | Prettier TUI rendering for tool calls, diffs, markdown |
|
|
66
|
-
| `@pify/subagent` | Spawn scoped subagents
|
|
67
|
+
| `@pify/subagent` | Spawn scoped subagents, including by `@agent` mention |
|
|
67
68
|
| `@pify/swarm` | Coordinate multiple pi agents working in parallel |
|
|
68
69
|
| `@pify/task` | Task tracking: dependency graph, evidence-gated completion, reminders |
|
|
69
70
|
| `@pify/todo` | Agent working-memory checklist: TodoWrite-style, next-item surfacing |
|
|
70
|
-
| `@pify/usage` | Token and cost reporting
|
|
71
|
+
| `@pify/usage` | Token and cost reporting, plus what is filling the context window |
|
|
71
72
|
| `@pify/workflow` | Deterministic agent orchestration: CC-style workflow scripts |
|
|
72
73
|
| `@pify/worktree` | Safe git-worktree management with safety rails and merge-back |
|
|
73
|
-
| `@pify/yolo` |
|
|
74
|
+
| `@pify/yolo` | A safety gradient from auto-approve to ask-about-anything, with an undo trail |
|
|
74
75
|
|
|
75
76
|
The catalog ships inside the CLI and refreshes (at most daily) from [`catalog.json` on `main`](https://github.com/pifydev/cli/blob/main/catalog.json), so newly published packages appear without a CLI update. A fetched catalog is validated before use — every entry must stay inside the `@pify` scope — and any invalid document is discarded entirely. Overrides: `PIFY_CATALOG_URL` (remote URL), `PIFY_OFFLINE=1` or `PI_OFFLINE=1` (skip all network lookups).
|
|
76
77
|
|
package/catalog.json
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
{
|
|
2
|
-
"version":
|
|
2
|
+
"version": 17,
|
|
3
3
|
"org": "pifydev",
|
|
4
4
|
"scope": "@pify",
|
|
5
5
|
"remote": "https://raw.githubusercontent.com/pifydev/cli/main/catalog.json",
|
|
@@ -8,7 +8,7 @@
|
|
|
8
8
|
"name": "ask-question",
|
|
9
9
|
"npm": "@pify/ask-question",
|
|
10
10
|
"repo": "https://github.com/pifydev/ask-question",
|
|
11
|
-
"description": "CC AskUserQuestion-shaped tool on built-in dialogs: 1-4 questions, multi-select, Other free-text",
|
|
11
|
+
"description": "CC AskUserQuestion-shaped tool on built-in dialogs: 1-4 questions, multi-select, Other free-text, /ask history",
|
|
12
12
|
"status": "published"
|
|
13
13
|
},
|
|
14
14
|
{
|
|
@@ -22,35 +22,35 @@
|
|
|
22
22
|
"name": "goal",
|
|
23
23
|
"npm": "@pify/goal",
|
|
24
24
|
"repo": "https://github.com/pifydev/goal",
|
|
25
|
-
"description": "Pin a session goal and keep the agent anchored
|
|
25
|
+
"description": "Pin a session goal and keep the agent anchored: ordered steps, safety limits, evidence-gated completion with an optional independent audit",
|
|
26
26
|
"status": "published"
|
|
27
27
|
},
|
|
28
28
|
{
|
|
29
29
|
"name": "memory",
|
|
30
30
|
"npm": "@pify/memory",
|
|
31
31
|
"repo": "https://github.com/pifydev/memory",
|
|
32
|
-
"description": "Persistent memory: two-tier markdown
|
|
32
|
+
"description": "Persistent memory across sessions: two-tier markdown, FTS5 search, secret-scanned writes, opt-in LLM consolidation",
|
|
33
33
|
"status": "published"
|
|
34
34
|
},
|
|
35
35
|
{
|
|
36
36
|
"name": "plan-mode",
|
|
37
37
|
"npm": "@pify/plan-mode",
|
|
38
38
|
"repo": "https://github.com/pifydev/plan-mode",
|
|
39
|
-
"description": "Read-only planning
|
|
39
|
+
"description": "Read-only planning with an approve-then-execute gate: enforced tool policy, tracked plan steps, saved-plan library, HTML export",
|
|
40
40
|
"status": "published"
|
|
41
41
|
},
|
|
42
42
|
{
|
|
43
43
|
"name": "pretty",
|
|
44
44
|
"npm": "@pify/pretty",
|
|
45
45
|
"repo": "https://github.com/pifydev/pretty",
|
|
46
|
-
"description": "Compact theme-aware rendering for built-in tools: summaries, highlighted reads, colorized diffs",
|
|
46
|
+
"description": "Compact theme-aware rendering for built-in tools: summaries, highlighted reads, colorized diffs, configurable caps",
|
|
47
47
|
"status": "published"
|
|
48
48
|
},
|
|
49
49
|
{
|
|
50
50
|
"name": "subagent",
|
|
51
51
|
"npm": "@pify/subagent",
|
|
52
52
|
"repo": "https://github.com/pifydev/subagent",
|
|
53
|
-
"description": "Spawn scoped subagents: agent_run/agent_result, custom agent types, turn caps and tool allowlists",
|
|
53
|
+
"description": "Spawn scoped subagents: agent_run/agent_result, @agent mentions, custom agent types, turn caps and tool allowlists",
|
|
54
54
|
"status": "published"
|
|
55
55
|
},
|
|
56
56
|
{
|
|
@@ -78,14 +78,14 @@
|
|
|
78
78
|
"name": "usage",
|
|
79
79
|
"npm": "@pify/usage",
|
|
80
80
|
"repo": "https://github.com/pifydev/usage",
|
|
81
|
-
"description": "Token and cost reporting: live footer, local-history dashboard with per-project costs,
|
|
81
|
+
"description": "Token and cost reporting: live footer, local-history dashboard with per-project costs, and /usage context showing what fills the window",
|
|
82
82
|
"status": "published"
|
|
83
83
|
},
|
|
84
84
|
{
|
|
85
85
|
"name": "workflow",
|
|
86
86
|
"npm": "@pify/workflow",
|
|
87
87
|
"repo": "https://github.com/pifydev/workflow",
|
|
88
|
-
"description": "Deterministic agent orchestration: CC-style
|
|
88
|
+
"description": "Deterministic agent orchestration: CC-style scripts with agent()/parallel()/pipeline(), schema-validated results, gates, and resume",
|
|
89
89
|
"status": "published"
|
|
90
90
|
},
|
|
91
91
|
{
|
|
@@ -99,8 +99,50 @@
|
|
|
99
99
|
"name": "yolo",
|
|
100
100
|
"npm": "@pify/yolo",
|
|
101
101
|
"repo": "https://github.com/pifydev/yolo",
|
|
102
|
-
"description": "
|
|
102
|
+
"description": "A safety gradient from auto-approve-everything to ask-about-anything: four modes, secret-file gate, undo trail with git checkpoints",
|
|
103
103
|
"status": "published"
|
|
104
104
|
}
|
|
105
|
+
],
|
|
106
|
+
"bundles": [
|
|
107
|
+
{
|
|
108
|
+
"name": "suite",
|
|
109
|
+
"description": "Every published @pify extension",
|
|
110
|
+
"packages": [
|
|
111
|
+
"ask-question",
|
|
112
|
+
"btw",
|
|
113
|
+
"goal",
|
|
114
|
+
"memory",
|
|
115
|
+
"plan-mode",
|
|
116
|
+
"pretty",
|
|
117
|
+
"subagent",
|
|
118
|
+
"swarm",
|
|
119
|
+
"task",
|
|
120
|
+
"todo",
|
|
121
|
+
"usage",
|
|
122
|
+
"workflow",
|
|
123
|
+
"worktree",
|
|
124
|
+
"yolo"
|
|
125
|
+
]
|
|
126
|
+
},
|
|
127
|
+
{
|
|
128
|
+
"name": "core",
|
|
129
|
+
"description": "The everyday four: task tracking, planning, memory, and a safety gate",
|
|
130
|
+
"packages": [
|
|
131
|
+
"todo",
|
|
132
|
+
"plan-mode",
|
|
133
|
+
"memory",
|
|
134
|
+
"yolo"
|
|
135
|
+
]
|
|
136
|
+
},
|
|
137
|
+
{
|
|
138
|
+
"name": "agents",
|
|
139
|
+
"description": "The agent stack: subagents, parallel fan-out, scripted workflows, worktrees",
|
|
140
|
+
"packages": [
|
|
141
|
+
"subagent",
|
|
142
|
+
"swarm",
|
|
143
|
+
"workflow",
|
|
144
|
+
"worktree"
|
|
145
|
+
]
|
|
146
|
+
}
|
|
105
147
|
]
|
|
106
148
|
}
|
package/dist/cli.js
CHANGED
|
@@ -492,8 +492,38 @@ function validateCatalog(data) {
|
|
|
492
492
|
if (typeof p.npm !== "string" || !p.npm.startsWith("@pify/")) return false;
|
|
493
493
|
if (p.status !== "published" && p.status !== "planned") return false;
|
|
494
494
|
}
|
|
495
|
+
if (c.bundles !== void 0) {
|
|
496
|
+
if (!Array.isArray(c.bundles)) return false;
|
|
497
|
+
const known = new Set(c.packages.map((p) => p.name));
|
|
498
|
+
for (const entry of c.bundles) {
|
|
499
|
+
if (typeof entry !== "object" || entry === null) return false;
|
|
500
|
+
const b = entry;
|
|
501
|
+
if (typeof b.name !== "string" || !/^[a-z0-9-]+$/.test(b.name)) return false;
|
|
502
|
+
if (typeof b.description !== "string") return false;
|
|
503
|
+
if (!Array.isArray(b.packages) || b.packages.length === 0) return false;
|
|
504
|
+
for (const member of b.packages) {
|
|
505
|
+
if (typeof member !== "string" || !known.has(member)) return false;
|
|
506
|
+
}
|
|
507
|
+
}
|
|
508
|
+
}
|
|
495
509
|
return true;
|
|
496
510
|
}
|
|
511
|
+
function findBundle(catalog, name) {
|
|
512
|
+
const wanted = name.trim().toLowerCase();
|
|
513
|
+
if (catalog.packages.some((p) => p.name === wanted)) return null;
|
|
514
|
+
return catalog.bundles?.find((b) => b.name === wanted) ?? null;
|
|
515
|
+
}
|
|
516
|
+
function expandBundles(catalog, names) {
|
|
517
|
+
const expanded = [];
|
|
518
|
+
for (const name of names) {
|
|
519
|
+
const bundle = findBundle(catalog, name);
|
|
520
|
+
const members = bundle ? bundle.packages : [name];
|
|
521
|
+
for (const member of members) {
|
|
522
|
+
if (!expanded.includes(member)) expanded.push(member);
|
|
523
|
+
}
|
|
524
|
+
}
|
|
525
|
+
return expanded;
|
|
526
|
+
}
|
|
497
527
|
async function loadCatalog(opts = {}) {
|
|
498
528
|
const bundled = loadBundledCatalog();
|
|
499
529
|
const cached = readCache();
|
|
@@ -659,7 +689,12 @@ async function install(names, opts) {
|
|
|
659
689
|
throw usageError("Missing package name.", "Usage: pify install <name...> [-l] [-a]");
|
|
660
690
|
}
|
|
661
691
|
const catalog = await loadCatalog();
|
|
662
|
-
const
|
|
692
|
+
for (const name of names) {
|
|
693
|
+
const bundle = findBundle(catalog, name);
|
|
694
|
+
if (bundle) step(`${bundle.name}: ${bundle.packages.length} packages \u2014 ${bundle.description}`);
|
|
695
|
+
}
|
|
696
|
+
const expanded = expandBundles(catalog, names);
|
|
697
|
+
const targets = expanded.map((name) => resolveInstallTarget(catalog, name));
|
|
663
698
|
for (const target of targets) {
|
|
664
699
|
if (target.explicit && (!target.inCatalog || target.status !== "published")) {
|
|
665
700
|
warn(`${target.npm} is not in the catalog (or not marked published); installing anyway.`);
|
|
@@ -1288,7 +1323,11 @@ function parseArgsOptionsFor(spec) {
|
|
|
1288
1323
|
|
|
1289
1324
|
// src/completions.ts
|
|
1290
1325
|
function packageNames() {
|
|
1291
|
-
|
|
1326
|
+
const catalog = loadBundledCatalog();
|
|
1327
|
+
return [
|
|
1328
|
+
...catalog.packages.map((p) => p.name),
|
|
1329
|
+
...(catalog.bundles ?? []).map((b) => b.name)
|
|
1330
|
+
];
|
|
1292
1331
|
}
|
|
1293
1332
|
function allNames(spec) {
|
|
1294
1333
|
return [spec.name, ...spec.aliases];
|
|
@@ -1451,7 +1490,7 @@ Usage:
|
|
|
1451
1490
|
|
|
1452
1491
|
Commands:
|
|
1453
1492
|
setup Install the pi coding agent (safe to re-run)
|
|
1454
|
-
install <name...> Install @pify packages
|
|
1493
|
+
install <name...> Install @pify packages, or a bundle (suite|core|agents)
|
|
1455
1494
|
remove <name...> Remove installed @pify packages
|
|
1456
1495
|
update [pi|<name...>] Update pi and installed @pify packages
|
|
1457
1496
|
list Show the @pify catalog with install state
|
|
@@ -1526,6 +1565,11 @@ Install @pify packages by short name. Names resolve against the Pify catalog
|
|
|
1526
1565
|
(goal -> npm:@pify/goal); the install itself is delegated to pi install.
|
|
1527
1566
|
Exact version pins are accepted (goal@0.3.0); range specifiers are refused.
|
|
1528
1567
|
|
|
1568
|
+
A bundle name installs several at once \u2014 pify install suite (everything),
|
|
1569
|
+
core (todo, plan-mode, memory, yolo), or agents (subagent, swarm, workflow,
|
|
1570
|
+
worktree). Bundle members are resolved exactly like typed names, and a
|
|
1571
|
+
package name always wins over a bundle with the same name.
|
|
1572
|
+
|
|
1529
1573
|
Options:
|
|
1530
1574
|
-l, --local Project scope (.pi/settings.json, .pi/npm)
|
|
1531
1575
|
-a, --approve Forward --approve to pi (scripted -l installs)
|
package/dist/index.d.ts
CHANGED
|
@@ -11,6 +11,12 @@ interface CatalogPackage {
|
|
|
11
11
|
/** "published" once it exists on the npm registry; "planned" before that. */
|
|
12
12
|
status: "published" | "planned";
|
|
13
13
|
}
|
|
14
|
+
/** A named set of packages installable in one go, e.g. `pify install suite`. */
|
|
15
|
+
interface CatalogBundle {
|
|
16
|
+
name: string;
|
|
17
|
+
description: string;
|
|
18
|
+
packages: string[];
|
|
19
|
+
}
|
|
14
20
|
interface Catalog {
|
|
15
21
|
version: number;
|
|
16
22
|
org: string;
|
|
@@ -18,6 +24,8 @@ interface Catalog {
|
|
|
18
24
|
/** URL of the always-current catalog on the org's main branch. */
|
|
19
25
|
remote: string;
|
|
20
26
|
packages: CatalogPackage[];
|
|
27
|
+
/** Optional (v0.3): older CLIs ignore this key and keep working. */
|
|
28
|
+
bundles?: CatalogBundle[];
|
|
21
29
|
}
|
|
22
30
|
declare function loadBundledCatalog(): Catalog;
|
|
23
31
|
/**
|
|
@@ -29,6 +37,13 @@ declare function loadBundledCatalog(): Catalog;
|
|
|
29
37
|
* radius of a compromised remote to "packages the org itself published".
|
|
30
38
|
*/
|
|
31
39
|
declare function validateCatalog(data: unknown): data is Catalog;
|
|
40
|
+
/** The bundle by that name, or null. Package names always win over bundles. */
|
|
41
|
+
declare function findBundle(catalog: Catalog, name: string): CatalogBundle | null;
|
|
42
|
+
/**
|
|
43
|
+
* Expand bundle names into their members, keeping order and dropping
|
|
44
|
+
* duplicates — installing `suite goal` must not install goal twice.
|
|
45
|
+
*/
|
|
46
|
+
declare function expandBundles(catalog: Catalog, names: string[]): string[];
|
|
32
47
|
/**
|
|
33
48
|
* Load the catalog. Resolution chain, newest `version` wins:
|
|
34
49
|
* bundled snapshot (offline floor) -> ~/.pify cache -> remote fetch.
|
|
@@ -244,4 +259,4 @@ declare class PifyError extends Error {
|
|
|
244
259
|
constructor(message: string, code?: ExitCodeValue, hint?: string);
|
|
245
260
|
}
|
|
246
261
|
|
|
247
|
-
export { COMMAND_SPECS, COMPLETION_SHELLS, type Catalog, type CatalogPackage, type CommandSpec, type CompletionShell, ExitCode, type FlagSpec, GLOBAL_FLAGS, INDEX_TS, type InstallSpec, type InstallTarget, type InstalledPifyPackage, NODE_FLOOR, PI_PACKAGE, type PiSettings, type PiStatus, PifyError, README_MD, TESTED_PI_VERSION, type TemplateVars, VERSION, agentDir, assertSafeArg, compareSemver, fetchLatestPiVersion, generateCompletion, installPi, installedPifyPackages, installedVersionOnDisk, interpolate, isOffline, loadBundledCatalog, loadCatalog, npmInstallPiArgs, officialInstallerCommand, packageJsonTemplate, parseArgsOptionsFor, parseInstallSpec, piStatus, readSettings, refreshCatalog, resolveInstallTarget, resolvePifyName, updatePi, validateCatalog, which };
|
|
262
|
+
export { COMMAND_SPECS, COMPLETION_SHELLS, type Catalog, type CatalogBundle, type CatalogPackage, type CommandSpec, type CompletionShell, ExitCode, type FlagSpec, GLOBAL_FLAGS, INDEX_TS, type InstallSpec, type InstallTarget, type InstalledPifyPackage, NODE_FLOOR, PI_PACKAGE, type PiSettings, type PiStatus, PifyError, README_MD, TESTED_PI_VERSION, type TemplateVars, VERSION, agentDir, assertSafeArg, compareSemver, expandBundles, fetchLatestPiVersion, findBundle, generateCompletion, installPi, installedPifyPackages, installedVersionOnDisk, interpolate, isOffline, loadBundledCatalog, loadCatalog, npmInstallPiArgs, officialInstallerCommand, packageJsonTemplate, parseArgsOptionsFor, parseInstallSpec, piStatus, readSettings, refreshCatalog, resolveInstallTarget, resolvePifyName, updatePi, validateCatalog, which };
|
package/dist/index.js
CHANGED
|
@@ -150,8 +150,38 @@ function validateCatalog(data) {
|
|
|
150
150
|
if (typeof p.npm !== "string" || !p.npm.startsWith("@pify/")) return false;
|
|
151
151
|
if (p.status !== "published" && p.status !== "planned") return false;
|
|
152
152
|
}
|
|
153
|
+
if (c.bundles !== void 0) {
|
|
154
|
+
if (!Array.isArray(c.bundles)) return false;
|
|
155
|
+
const known = new Set(c.packages.map((p) => p.name));
|
|
156
|
+
for (const entry of c.bundles) {
|
|
157
|
+
if (typeof entry !== "object" || entry === null) return false;
|
|
158
|
+
const b = entry;
|
|
159
|
+
if (typeof b.name !== "string" || !/^[a-z0-9-]+$/.test(b.name)) return false;
|
|
160
|
+
if (typeof b.description !== "string") return false;
|
|
161
|
+
if (!Array.isArray(b.packages) || b.packages.length === 0) return false;
|
|
162
|
+
for (const member of b.packages) {
|
|
163
|
+
if (typeof member !== "string" || !known.has(member)) return false;
|
|
164
|
+
}
|
|
165
|
+
}
|
|
166
|
+
}
|
|
153
167
|
return true;
|
|
154
168
|
}
|
|
169
|
+
function findBundle(catalog, name) {
|
|
170
|
+
const wanted = name.trim().toLowerCase();
|
|
171
|
+
if (catalog.packages.some((p) => p.name === wanted)) return null;
|
|
172
|
+
return catalog.bundles?.find((b) => b.name === wanted) ?? null;
|
|
173
|
+
}
|
|
174
|
+
function expandBundles(catalog, names) {
|
|
175
|
+
const expanded = [];
|
|
176
|
+
for (const name of names) {
|
|
177
|
+
const bundle = findBundle(catalog, name);
|
|
178
|
+
const members = bundle ? bundle.packages : [name];
|
|
179
|
+
for (const member of members) {
|
|
180
|
+
if (!expanded.includes(member)) expanded.push(member);
|
|
181
|
+
}
|
|
182
|
+
}
|
|
183
|
+
return expanded;
|
|
184
|
+
}
|
|
155
185
|
async function loadCatalog(opts = {}) {
|
|
156
186
|
const bundled = loadBundledCatalog();
|
|
157
187
|
const cached = readCache();
|
|
@@ -644,7 +674,11 @@ function parseArgsOptionsFor(spec) {
|
|
|
644
674
|
|
|
645
675
|
// src/completions.ts
|
|
646
676
|
function packageNames() {
|
|
647
|
-
|
|
677
|
+
const catalog = loadBundledCatalog();
|
|
678
|
+
return [
|
|
679
|
+
...catalog.packages.map((p) => p.name),
|
|
680
|
+
...(catalog.bundles ?? []).map((b) => b.name)
|
|
681
|
+
];
|
|
648
682
|
}
|
|
649
683
|
function allNames(spec) {
|
|
650
684
|
return [spec.name, ...spec.aliases];
|
|
@@ -921,7 +955,9 @@ export {
|
|
|
921
955
|
agentDir,
|
|
922
956
|
assertSafeArg,
|
|
923
957
|
compareSemver,
|
|
958
|
+
expandBundles,
|
|
924
959
|
fetchLatestPiVersion,
|
|
960
|
+
findBundle,
|
|
925
961
|
generateCompletion,
|
|
926
962
|
installPi,
|
|
927
963
|
installedPifyPackages,
|