@jaybeeuu/agent-cortex 1.41.1 → 1.43.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.
Files changed (115) hide show
  1. package/.agents/skills/style-versioning/SKILL.md +73 -2
  2. package/.github/workflows/ci.yml +52 -32
  3. package/AGENTS.md +23 -2
  4. package/CHANGELOG.md +189 -0
  5. package/README.md +125 -73
  6. package/agents/README.md +17 -4
  7. package/agents/ralph-plan/agent.md +7 -3
  8. package/agents/ralph-plan.agent.md +7 -3
  9. package/bin/agent-cortex.mjs +48 -30
  10. package/bin/installers/pi.mjs +885 -237
  11. package/claude-extras/scripts/statusline-command.sh +0 -0
  12. package/docs/claude-hooks.md +5 -4
  13. package/docs/commit-signing.md +231 -0
  14. package/docs/ideas/ban-content-assertion-tests.md +3 -1
  15. package/docs/ideas/dedicated-review-tests-skill.md +71 -0
  16. package/docs/ideas/enable-signed-commit-enforcement-changesets-bot-commits-must-be-signed.md +10 -1
  17. package/docs/ideas/extension-manifests.md +5 -0
  18. package/docs/ideas/unify-the-ticket-and-task-decomposition-workflows.md +71 -0
  19. package/docs/research/disable-model-invocation.md +103 -0
  20. package/docs/research/skill-design-research.md +2 -2
  21. package/docs/skills/skill-anatomy.md +5 -1
  22. package/docs/technical-direction/harness-config.md +25 -1
  23. package/docs/technical-direction/migration-execution-labels.md +17 -9
  24. package/extensions/agent-modes/discover.test.ts +19 -0
  25. package/extensions/agent-modes/discover.ts +25 -3
  26. package/extensions/session-start/README.md +38 -0
  27. package/extensions/session-start/index.test.ts +122 -0
  28. package/extensions/session-start/index.ts +27 -0
  29. package/extensions/session-start/package.json +19 -0
  30. package/extensions/session-start/tsconfig.json +12 -0
  31. package/extensions/subagent/README.md +1 -1
  32. package/extensions/subagent/agents.test.ts +176 -0
  33. package/extensions/subagent/agents.ts +102 -11
  34. package/extensions/subagent/index.ts +2 -1
  35. package/extensions/subagent/package.json +1 -1
  36. package/lib/cli.mjs +35 -9
  37. package/package.json +10 -6
  38. package/pi/settings.json +1 -7
  39. package/plugin.json +1 -1
  40. package/pnpm-workspace.yaml +6 -0
  41. package/scripts/check-changeset.mjs +42 -0
  42. package/scripts/install-instructions.sh +0 -0
  43. package/scripts/lib/release-gates.mjs +61 -0
  44. package/scripts/lib/verify-worker-tree.mjs +107 -0
  45. package/scripts/resolve-publish-command.mjs +17 -0
  46. package/scripts/sync-plugin-version.sh +0 -0
  47. package/skills/engineering/grill-with-docs/SKILL.md +3 -2
  48. package/skills/engineering/improve-codebase-architecture/REFERENCE.md +5 -0
  49. package/skills/engineering/improve-codebase-architecture/SKILL.md +2 -1
  50. package/skills/planning/create-task/SKILL.md +8 -3
  51. package/skills/planning/create-task/scripts/create-chores.ts +4 -1
  52. package/skills/planning/prd-to-tasks/REFERENCE.md +2 -2
  53. package/skills/planning/prd-to-tasks/SKILL.md +9 -4
  54. package/skills/planning/request-refactor-plan/FORMAT.md +5 -0
  55. package/skills/planning/request-refactor-plan/SKILL.md +3 -2
  56. package/skills/planning/spec-to-tickets/REFERENCE.md +82 -0
  57. package/skills/planning/spec-to-tickets/SKILL.md +143 -0
  58. package/skills/planning/write-a-prd/FORMAT.md +6 -0
  59. package/skills/planning/write-a-prd/SKILL.md +9 -6
  60. package/skills/planning/write-a-ticket/EXAMPLES.md +133 -0
  61. package/skills/planning/write-a-ticket/SKILL.md +77 -59
  62. package/skills/productivity/bd-tool/SKILL.md +27 -2
  63. package/skills/productivity/grill-me/SKILL.md +11 -0
  64. package/skills/review/review-security/scripts/install-gitleaks.sh +0 -0
  65. package/skills/workflow/git-workflow/SKILL.md +35 -1
  66. package/skills/workflow/plan/SKILL.md +20 -8
  67. package/skills/workflow/ralph/REFERENCE.md +20 -2
  68. package/skills/workflow/ralph/SKILL.md +4 -1
  69. package/skills/workflow/run-pipeline-stage/SKILL.md +17 -5
  70. package/skills/workflow/run-pipeline-stage/playbooks/code.md +2 -0
  71. package/skills/workflow/run-pipeline-stage/playbooks/document.md +3 -0
  72. package/skills/workflow/run-pipeline-stage/playbooks/fix.md +2 -0
  73. package/skills/workflow/run-pipeline-stage/prompts/stage-runner.md +11 -0
  74. package/skills/workflow/using-agent-skills/SKILL.md +1 -0
  75. package/test/cli.test.mjs +26 -29
  76. package/test/create-chores.test.mjs +12 -0
  77. package/test/fake-bd.test.mjs +72 -0
  78. package/test/helpers/fake-bd.mjs +26 -6
  79. package/test/helpers/fake-pi.mjs +132 -0
  80. package/test/pi-installer.test.mjs +345 -286
  81. package/test/pi-register.test.mjs +342 -0
  82. package/test/pi-sweep.test.mjs +619 -0
  83. package/test/release-gates.test.mjs +190 -0
  84. package/test/verify-worker-tree.test.mjs +120 -0
  85. package/token-map.README.md +7 -6
  86. package/token-map.json +6 -5
  87. package/extensions/agent-guardrails/node_modules/.bin/pi +0 -21
  88. package/extensions/agent-guardrails/node_modules/.bin/tsc +0 -21
  89. package/extensions/agent-guardrails/node_modules/.bin/tsserver +0 -21
  90. package/extensions/agent-guardrails/node_modules/.bin/tsx +0 -21
  91. package/extensions/agent-modes/node_modules/.bin/pi +0 -21
  92. package/extensions/agent-modes/node_modules/.bin/tsc +0 -21
  93. package/extensions/agent-modes/node_modules/.bin/tsserver +0 -21
  94. package/extensions/agent-modes/node_modules/.bin/tsx +0 -21
  95. package/extensions/session-start.ts +0 -44
  96. package/extensions/skill-stats/node_modules/.bin/pi +0 -21
  97. package/extensions/skill-stats/node_modules/.bin/tsc +0 -21
  98. package/extensions/skill-stats/node_modules/.bin/tsserver +0 -21
  99. package/extensions/skill-stats/node_modules/.bin/tsx +0 -21
  100. package/extensions/subagent/node_modules/.bin/pi +0 -21
  101. package/extensions/subagent/node_modules/.bin/pi-ai +0 -21
  102. package/extensions/subagent/node_modules/.bin/tsc +0 -21
  103. package/extensions/subagent/node_modules/.bin/tsserver +0 -21
  104. package/extensions/subagent/node_modules/.bin/tsx +0 -21
  105. package/lib/pi-packages.mjs +0 -169
  106. package/skills/planning/create-task/scripts/node_modules/.bin/tsc +0 -21
  107. package/skills/planning/create-task/scripts/node_modules/.bin/tsserver +0 -21
  108. package/skills/planning/create-task/scripts/node_modules/.bin/tsx +0 -21
  109. package/skills/productivity/validate-agent-dir/scripts/node_modules/.bin/tsc +0 -21
  110. package/skills/productivity/validate-agent-dir/scripts/node_modules/.bin/tsserver +0 -21
  111. package/skills/productivity/validate-agent-dir/scripts/node_modules/.bin/tsx +0 -21
  112. package/skills/workflow/run-pipeline-stage/scripts/node_modules/.bin/tsc +0 -21
  113. package/skills/workflow/run-pipeline-stage/scripts/node_modules/.bin/tsserver +0 -21
  114. package/skills/workflow/run-pipeline-stage/scripts/node_modules/.bin/tsx +0 -21
  115. package/test/pi-packages.test.mjs +0 -295
@@ -1,295 +0,0 @@
1
- import { describe, it } from "node:test";
2
- import assert from "node:assert/strict";
3
- import { mkdtemp, mkdir, writeFile, rm, chmod } from "node:fs/promises";
4
- import { join } from "node:path";
5
- import { tmpdir } from "node:os";
6
- import {
7
- loadRequiredPackages,
8
- npmSourceName,
9
- planPackageInstalls,
10
- provisionPiPackages,
11
- runPiInstall,
12
- } from "../lib/pi-packages.mjs";
13
-
14
- // ─── Fixtures ────────────────────────────────────────────────────────────────
15
-
16
- async function makePiRoot({ declared = [], installed = [], settingsRaw } = {}) {
17
- const root = await mkdtemp(join(tmpdir(), "pi-packages-"));
18
- if (settingsRaw !== undefined) {
19
- await writeFile(join(root, "settings.json"), settingsRaw);
20
- } else if (declared.length > 0) {
21
- await writeFile(join(root, "settings.json"), JSON.stringify({ packages: declared }));
22
- }
23
- for (const name of installed) {
24
- await mkdir(join(root, "npm", "node_modules", name), { recursive: true });
25
- }
26
- return { root, cleanup: async () => rm(root, { recursive: true, force: true }) };
27
- }
28
-
29
- /** A runner that records every source it is asked to install. */
30
- function recordingRunner({ results = {} } = {}) {
31
- const calls = [];
32
- const runner = async (source) => {
33
- calls.push(source);
34
- return results[source] ?? { ok: true, error: null };
35
- };
36
- return { runner, calls };
37
- }
38
-
39
- /** Run `fn` with PATH set to `pathValue`, restoring the previous PATH afterwards. */
40
- async function withPath(pathValue, fn) {
41
- const original = process.env.PATH;
42
- process.env.PATH = pathValue;
43
- try {
44
- return await fn();
45
- } finally {
46
- process.env.PATH = original;
47
- }
48
- }
49
-
50
- /** Write an executable `pi` stub with the given shell body; returns its dir and cleanup. */
51
- async function makePiStub(body) {
52
- const dir = await mkdtemp(join(tmpdir(), "pi-stub-"));
53
- const file = join(dir, "pi");
54
- await writeFile(file, `#!/bin/sh\n${body}\n`);
55
- await chmod(file, 0o755);
56
- return { dir, cleanup: async () => rm(dir, { recursive: true, force: true }) };
57
- }
58
-
59
- /** A directory with nothing on PATH, so any external command lookup fails. */
60
- async function makeEmptyPathDir() {
61
- const dir = await mkdtemp(join(tmpdir(), "pi-stub-empty-"));
62
- return { dir, cleanup: async () => rm(dir, { recursive: true, force: true }) };
63
- }
64
-
65
- // ─── Manifest ────────────────────────────────────────────────────────────────
66
-
67
- describe("loadRequiredPackages", () => {
68
- it("reads the declared pi packages from the package manifest", async () => {
69
- const root = await mkdtemp(join(tmpdir(), "pi-packages-manifest-"));
70
- try {
71
- await writeFile(
72
- join(root, "package.json"),
73
- JSON.stringify({ name: "x", pi: { extensions: ["./extensions"], packages: ["npm:pi-questions"] } }),
74
- );
75
- assert.deepEqual(await loadRequiredPackages(root), ["npm:pi-questions"]);
76
- } finally {
77
- await rm(root, { recursive: true, force: true });
78
- }
79
- });
80
-
81
- it("returns no packages when the manifest does not declare any", async () => {
82
- const root = await mkdtemp(join(tmpdir(), "pi-packages-manifest-"));
83
- try {
84
- await writeFile(join(root, "package.json"), JSON.stringify({ name: "x", pi: { skills: ["./skills"] } }));
85
- assert.deepEqual(await loadRequiredPackages(root), []);
86
- } finally {
87
- await rm(root, { recursive: true, force: true });
88
- }
89
- });
90
- });
91
-
92
- // ─── Source parsing ──────────────────────────────────────────────────────────
93
-
94
- describe("npmSourceName", () => {
95
- it("extracts the package name from npm sources, including scoped and pinned specs", () => {
96
- assert.equal(npmSourceName("npm:pi-questions"), "pi-questions");
97
- assert.equal(npmSourceName("npm:pi-web-access@0.10.7"), "pi-web-access");
98
- assert.equal(npmSourceName("npm:@scope/pkg@1.2.3"), "@scope/pkg");
99
- });
100
-
101
- it("returns null for non-npm sources it cannot verify locally", () => {
102
- assert.equal(npmSourceName("git:github.com/user/repo"), null);
103
- assert.equal(npmSourceName("./local/path"), null);
104
- });
105
- });
106
-
107
- // ─── Install plan ────────────────────────────────────────────────────────────
108
-
109
- describe("planPackageInstalls", () => {
110
- it("plans nothing when every required package is declared and installed", () => {
111
- assert.deepEqual(
112
- planPackageInstalls(["npm:pi-questions"], {
113
- declaredSources: ["npm:pi-questions"],
114
- installedNames: ["pi-questions"],
115
- }),
116
- [],
117
- );
118
- });
119
-
120
- it("plans a package that is declared but not installed", () => {
121
- assert.deepEqual(
122
- planPackageInstalls(["npm:pi-web-access@0.10.7"], {
123
- declaredSources: ["npm:pi-web-access@0.10.7"],
124
- installedNames: [],
125
- }),
126
- ["npm:pi-web-access@0.10.7"],
127
- );
128
- });
129
-
130
- it("plans a package that is installed but not declared, so pi will load it", () => {
131
- assert.deepEqual(
132
- planPackageInstalls(["npm:pi-questions"], {
133
- declaredSources: [],
134
- installedNames: ["pi-questions"],
135
- }),
136
- ["npm:pi-questions"],
137
- );
138
- });
139
- });
140
-
141
- // ─── Provisioning ────────────────────────────────────────────────────────────
142
-
143
- describe("runPiInstall", () => {
144
- it("degrades to a result when the pi CLI is not on PATH", async () => {
145
- const empty = await makeEmptyPathDir();
146
- try {
147
- const result = await withPath(empty.dir, () => runPiInstall("npm:pi-questions"));
148
- assert.deepEqual(result, { ok: false, error: "pi CLI not found on PATH" });
149
- } finally {
150
- await empty.cleanup();
151
- }
152
- });
153
-
154
- it("maps a successful pi install to ok", async () => {
155
- const stub = await makePiStub("exit 0");
156
- try {
157
- const result = await withPath(stub.dir, () => runPiInstall("npm:pi-questions"));
158
- assert.deepEqual(result, { ok: true, error: null });
159
- } finally {
160
- await stub.cleanup();
161
- }
162
- });
163
-
164
- it("maps a failing pi install to its stderr", async () => {
165
- const stub = await makePiStub('echo "offline: no registry" >&2\nexit 1');
166
- try {
167
- const result = await withPath(stub.dir, () => runPiInstall("npm:pi-questions"));
168
- assert.deepEqual(result, { ok: false, error: "offline: no registry" });
169
- } finally {
170
- await stub.cleanup();
171
- }
172
- });
173
- });
174
-
175
- describe("provisionPiPackages", () => {
176
- it("installs missing packages and skips the ones already present", async () => {
177
- const fx = await makePiRoot({ declared: ["npm:pi-questions"], installed: ["pi-questions"] });
178
- try {
179
- const { runner, calls } = await recordingRunner();
180
-
181
- const result = await provisionPiPackages({
182
- required: ["npm:pi-questions", "npm:pi-web-access@0.10.7"],
183
- piRoot: fx.root,
184
- runInstall: runner,
185
- });
186
-
187
- assert.deepEqual(calls, ["npm:pi-web-access@0.10.7"], "only the missing package is installed");
188
- assert.deepEqual(result.installed, ["npm:pi-web-access@0.10.7"]);
189
- assert.deepEqual(result.failed, []);
190
- } finally {
191
- await fx.cleanup();
192
- }
193
- });
194
-
195
- it("is idempotent — a second run with everything present installs nothing", async () => {
196
- const fx = await makePiRoot({
197
- declared: ["npm:pi-questions", "npm:pi-web-access@0.10.7"],
198
- installed: ["pi-questions", "pi-web-access"],
199
- });
200
- try {
201
- const { runner, calls } = await recordingRunner();
202
- const result = await provisionPiPackages({
203
- required: ["npm:pi-questions", "npm:pi-web-access@0.10.7"],
204
- piRoot: fx.root,
205
- runInstall: runner,
206
- });
207
- assert.deepEqual(calls, []);
208
- assert.deepEqual(result.installed, []);
209
- } finally {
210
- await fx.cleanup();
211
- }
212
- });
213
-
214
- it("reports a failed install and continues with the rest", async () => {
215
- const fx = await makePiRoot();
216
- try {
217
- const warnings = [];
218
- const { runner, calls } = await recordingRunner({
219
- results: { "npm:pi-questions": { ok: false, error: "offline" } },
220
- });
221
-
222
- const result = await provisionPiPackages({
223
- required: ["npm:pi-questions", "npm:pi-web-access@0.10.7"],
224
- piRoot: fx.root,
225
- runInstall: runner,
226
- warn: (msg) => warnings.push(msg),
227
- });
228
-
229
- assert.deepEqual(calls, ["npm:pi-questions", "npm:pi-web-access@0.10.7"], "failure does not abort the rest");
230
- assert.deepEqual(result.installed, ["npm:pi-web-access@0.10.7"]);
231
- assert.deepEqual(result.failed, [{ source: "npm:pi-questions", error: "offline" }]);
232
- assert.ok(warnings.some((w) => w.includes("npm:pi-questions")), "failure is surfaced as a warning");
233
- } finally {
234
- await fx.cleanup();
235
- }
236
- });
237
-
238
- it("uses the pi CLI runner by default and warns when it is missing", async () => {
239
- const fx = await makePiRoot();
240
- const empty = await makeEmptyPathDir();
241
- try {
242
- const warnings = [];
243
- const result = await withPath(empty.dir, () =>
244
- provisionPiPackages({
245
- required: ["npm:pi-questions"],
246
- piRoot: fx.root,
247
- warn: (msg) => warnings.push(msg),
248
- }),
249
- );
250
-
251
- assert.deepEqual(result.failed, [{ source: "npm:pi-questions", error: "pi CLI not found on PATH" }]);
252
- assert.ok(
253
- warnings.some((w) => w.includes("pi CLI not found on PATH")),
254
- "missing CLI is surfaced as a warning, not a thrown error",
255
- );
256
- } finally {
257
- await empty.cleanup();
258
- await fx.cleanup();
259
- }
260
- });
261
-
262
- it("dry-run reports the plan without installing anything", async () => {
263
- const fx = await makePiRoot();
264
- try {
265
- const { runner, calls } = await recordingRunner();
266
- const result = await provisionPiPackages({
267
- required: ["npm:pi-questions"],
268
- piRoot: fx.root,
269
- runInstall: runner,
270
- dryRun: true,
271
- });
272
- assert.deepEqual(calls, []);
273
- assert.deepEqual(result.planned, ["npm:pi-questions"]);
274
- assert.deepEqual(result.installed, []);
275
- } finally {
276
- await fx.cleanup();
277
- }
278
- });
279
-
280
- it("treats an unreadable settings file as no declarations rather than failing the install", async () => {
281
- const fx = await makePiRoot({ settingsRaw: "{ not json" });
282
- try {
283
- const { runner, calls } = await recordingRunner();
284
- const result = await provisionPiPackages({
285
- required: ["npm:pi-questions"],
286
- piRoot: fx.root,
287
- runInstall: runner,
288
- });
289
- assert.deepEqual(calls, ["npm:pi-questions"], "still attempts the install");
290
- assert.deepEqual(result.installed, ["npm:pi-questions"]);
291
- } finally {
292
- await fx.cleanup();
293
- }
294
- });
295
- });