@jaybeeuu/agent-cortex 1.42.0 → 2.0.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/.agents/skills/style-versioning/SKILL.md +78 -8
- package/.github/workflows/ci.yml +51 -38
- package/AGENTS.md +32 -17
- package/CHANGELOG.md +182 -0
- package/README.md +167 -126
- package/agents/README.md +26 -27
- package/agents/ralph/agent.md +7 -10
- package/agents/ralph/claude/polling.md +1 -1
- package/bin/agent-cortex.mjs +46 -44
- package/bin/installers/claude.mjs +2 -2
- package/bin/installers/pi.mjs +885 -237
- package/docs/claude-hooks.md +5 -4
- package/docs/commit-signing.md +231 -0
- package/docs/ideas/enable-signed-commit-enforcement-changesets-bot-commits-must-be-signed.md +10 -1
- package/docs/ideas/extension-manifests.md +5 -0
- package/docs/research/disable-model-invocation.md +82 -0
- package/docs/research/skill-design-research.md +2 -2
- package/docs/skills/skill-anatomy.md +5 -2
- package/docs/technical-direction/harness-config.md +30 -14
- package/docs/technical-direction/migration-execution-labels.md +17 -9
- package/docs/user-preferences.md +2 -2
- package/extensions/agent-modes/README.md +3 -3
- package/extensions/agent-modes/discover.test.ts +19 -0
- package/extensions/agent-modes/discover.ts +31 -9
- package/extensions/session-start/README.md +38 -0
- package/extensions/session-start/index.test.ts +122 -0
- package/extensions/session-start/index.ts +27 -0
- package/extensions/session-start/package.json +19 -0
- package/extensions/session-start/tsconfig.json +12 -0
- package/extensions/skill-stats/pnpm-lock.yaml +329 -0
- package/extensions/subagent/README.md +3 -3
- package/extensions/subagent/agents.test.ts +176 -0
- package/extensions/subagent/agents.ts +101 -11
- package/extensions/subagent/index.ts +2 -1
- package/extensions/subagent/package.json +1 -1
- package/lib/cli.mjs +40 -16
- package/package.json +8 -9
- package/pi/settings.json +1 -7
- package/pnpm-workspace.yaml +6 -0
- package/scripts/check-changeset.mjs +42 -0
- package/scripts/lib/compose-agent.mjs +10 -10
- package/scripts/lib/release-gates.mjs +61 -0
- package/scripts/lib/verify-worker-tree.mjs +107 -0
- package/scripts/resolve-publish-command.mjs +17 -0
- package/skills/planning/create-task/scripts/pnpm-lock.yaml +342 -0
- package/skills/productivity/validate-agent-dir/scripts/pnpm-lock.yaml +329 -0
- package/skills/workflow/git-workflow/SKILL.md +35 -1
- package/skills/workflow/ralph/REFERENCE.md +20 -4
- package/skills/workflow/ralph/SKILL.md +9 -6
- package/skills/workflow/run-pipeline-stage/SKILL.md +11 -4
- package/skills/workflow/run-pipeline-stage/playbooks/code.md +2 -0
- package/skills/workflow/run-pipeline-stage/playbooks/document.md +3 -0
- package/skills/workflow/run-pipeline-stage/playbooks/fix.md +2 -0
- package/skills/workflow/run-pipeline-stage/prompts/stage-runner.md +11 -0
- package/skills/workflow/run-pipeline-stage/scripts/pnpm-lock.yaml +342 -0
- package/test/cli.test.mjs +37 -39
- package/test/helpers/fake-pi.mjs +132 -0
- package/test/pi-installer.test.mjs +345 -286
- package/test/pi-register.test.mjs +342 -0
- package/test/pi-sweep.test.mjs +619 -0
- package/test/release-gates.test.mjs +190 -0
- package/test/verify-worker-tree.test.mjs +120 -0
- package/token-map.README.md +16 -18
- package/token-map.json +29 -33
- package/agents/plan/copilot/frontmatter.json +0 -6
- package/agents/plan.agent.md +0 -59
- package/agents/ralph/copilot/frontmatter.json +0 -6
- package/agents/ralph/copilot/polling.md +0 -62
- package/agents/ralph-plan/copilot/frontmatter.json +0 -6
- package/agents/ralph-plan.agent.md +0 -126
- package/agents/ralph.agent.md +0 -331
- package/agents/strategy/copilot/frontmatter.json +0 -6
- package/agents/strategy.agent.md +0 -112
- package/bin/installers/copilot.mjs +0 -124
- package/extensions/session-start.ts +0 -44
- package/hooks.json +0 -10
- package/lib/pi-packages.mjs +0 -169
- package/plugin.json +0 -35
- package/scripts/build-copilot-agents.mjs +0 -30
- package/scripts/install-instructions.sh +0 -82
- package/scripts/sync-plugin-version.sh +0 -17
- package/test/copilot-installer.test.mjs +0 -308
- package/test/pi-packages.test.mjs +0 -295
|
@@ -1,124 +0,0 @@
|
|
|
1
|
-
// Install-time generator for the Copilot CLI flat agent files (agents/*.agent.md).
|
|
2
|
-
// This is the single code path for producing those files from the canonical
|
|
3
|
-
// composable sources — both entry points below call installCopilot(), so
|
|
4
|
-
// install-time and build-time output can never diverge:
|
|
5
|
-
//
|
|
6
|
-
// - bin/agent-cortex.mjs `agent-cortex install copilot` (install-time;
|
|
7
|
-
// `--output <dir>` overrides the target,
|
|
8
|
-
// `--dry-run` plans without writing)
|
|
9
|
-
// - scripts/build-copilot-agents.mjs `pnpm build:copilot` (dev/CI: regenerates
|
|
10
|
-
// the committed agents/*.agent.md files in place)
|
|
11
|
-
//
|
|
12
|
-
// Output lands in <root>/agents/ (the default `output`) because that is the
|
|
13
|
-
// directory the Copilot plugin actually loads: plugin.json declares
|
|
14
|
-
// "agents": "agents/", which scans for *.agent.md files. The generated flat
|
|
15
|
-
// files therefore share the agents/ directory with the canonical composable
|
|
16
|
-
// dirs they are composed from (agents/<name>/) — only flat *.agent.md files are
|
|
17
|
-
// written, nothing is deleted, so a generated file can never clobber a
|
|
18
|
-
// composable source. `--output` exists for the same preview/test contract as the
|
|
19
|
-
// claude and pi installers: point it at a scratch dir and inspect the output.
|
|
20
|
-
//
|
|
21
|
-
// agents/<name>.agent.md composed from agents/<name>/agent.md +
|
|
22
|
-
// agents/<name>/copilot/frontmatter.json +
|
|
23
|
-
// agents/<name>/copilot/<section>.md ({{SECTION:...}}),
|
|
24
|
-
// with {{TOOL:...}}/{{PATH:...}} substituted against
|
|
25
|
-
// the copilot column of token-map.json.
|
|
26
|
-
//
|
|
27
|
-
// The flat files stay committed and CI drift-checks them (build:copilot +
|
|
28
|
-
// git diff --exit-code -- 'agents/*.agent.md'), so a fresh clone (or a direct
|
|
29
|
-
// path plugin install) ships the plugin read-ready.
|
|
30
|
-
//
|
|
31
|
-
// Zero dependencies so it runs on the CI Node and local Node alike.
|
|
32
|
-
|
|
33
|
-
import { writeFile, mkdir, readdir } from "node:fs/promises";
|
|
34
|
-
import { join, dirname } from "node:path";
|
|
35
|
-
import { fileURLToPath } from "node:url";
|
|
36
|
-
import { composeAgent } from "../../scripts/lib/compose-agent.mjs";
|
|
37
|
-
import { isDirectory, isFile } from "../../scripts/lib/fs.mjs";
|
|
38
|
-
|
|
39
|
-
const MODULE_DIR = dirname(fileURLToPath(import.meta.url));
|
|
40
|
-
const DEFAULT_ROOT = join(MODULE_DIR, "..", "..");
|
|
41
|
-
|
|
42
|
-
function byName(a, b) {
|
|
43
|
-
return a.localeCompare(b);
|
|
44
|
-
}
|
|
45
|
-
|
|
46
|
-
/**
|
|
47
|
-
* Serialise the flat-file YAML frontmatter. Field order and names mirror the
|
|
48
|
-
* pre-migration flat sources (description, name, tools, argument-hint) so
|
|
49
|
-
* Copilot CLI sees the same agent metadata. The GENERATED comment references
|
|
50
|
-
* scripts/build-copilot-agents.mjs — the committed entry point — so the
|
|
51
|
-
* generated bytes are identical whichever of the two entry points ran.
|
|
52
|
-
*/
|
|
53
|
-
function frontmatterYaml(name, fm) {
|
|
54
|
-
const lines = [
|
|
55
|
-
"---",
|
|
56
|
-
`# GENERATED from agents/${name}/ by scripts/build-copilot-agents.mjs — DO NOT EDIT.`,
|
|
57
|
-
`description: ${JSON.stringify(fm.description)}`,
|
|
58
|
-
`name: ${JSON.stringify(fm.name)}`,
|
|
59
|
-
`tools: [${fm.tools.map((t) => JSON.stringify(t)).join(", ")}]`,
|
|
60
|
-
];
|
|
61
|
-
if (fm.argumentHint) lines.push(`argument-hint: ${JSON.stringify(fm.argumentHint)}`);
|
|
62
|
-
lines.push("---");
|
|
63
|
-
return lines.join("\n");
|
|
64
|
-
}
|
|
65
|
-
|
|
66
|
-
/** Compose agents from agents/<name>/; every composable dir must ship a copilot harness. */
|
|
67
|
-
async function buildAgents(root) {
|
|
68
|
-
const files = [];
|
|
69
|
-
const entries = (await readdir(join(root, "agents"), { withFileTypes: true })).sort((a, b) =>
|
|
70
|
-
byName(a.name, b.name),
|
|
71
|
-
);
|
|
72
|
-
|
|
73
|
-
for (const entry of entries) {
|
|
74
|
-
if (!entry.isDirectory()) continue; // skip generated *.agent.md flat files and README
|
|
75
|
-
const dir = join(root, "agents", entry.name);
|
|
76
|
-
if (!(await isFile(join(dir, "agent.md")))) continue; // not a composable agent dir
|
|
77
|
-
if (!(await isDirectory(join(dir, "copilot"))) || !(await isFile(join(dir, "copilot", "frontmatter.json")))) {
|
|
78
|
-
throw new Error(`agent "${entry.name}": composable directory without copilot/frontmatter.json — define the copilot harness or exclude the agent`);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const fm = await composeAgent(root, entry.name, "copilot");
|
|
82
|
-
files.push({
|
|
83
|
-
name: entry.name,
|
|
84
|
-
file: `${entry.name}.agent.md`,
|
|
85
|
-
content: `${frontmatterYaml(entry.name, fm)}\n\n${fm.body}\n`,
|
|
86
|
-
});
|
|
87
|
-
}
|
|
88
|
-
return files;
|
|
89
|
-
}
|
|
90
|
-
|
|
91
|
-
/**
|
|
92
|
-
* Generate the Copilot CLI flat agent files.
|
|
93
|
-
*
|
|
94
|
-
* @param {object} options
|
|
95
|
-
* @param {string} [options.root] Package root (contains agents/, token-map.json, …).
|
|
96
|
-
* Defaults to the repo containing this module.
|
|
97
|
-
* @param {string} [options.output] Directory to write the flat *.agent.md files into
|
|
98
|
-
* (default: <root>/agents — the dir plugin.json's
|
|
99
|
-
* "agents": "agents/" scans for the plugin).
|
|
100
|
-
* @param {boolean} [options.dryRun] Plan and report without writing anything.
|
|
101
|
-
* @returns {{ output: string, agents: string[], dryRun: boolean }}
|
|
102
|
-
*/
|
|
103
|
-
export async function installCopilot({ root = DEFAULT_ROOT, output, dryRun = false } = {}) {
|
|
104
|
-
const out = output ?? join(root, "agents");
|
|
105
|
-
const files = await buildAgents(root);
|
|
106
|
-
const summary = {
|
|
107
|
-
output: out,
|
|
108
|
-
agents: files.map((f) => f.name),
|
|
109
|
-
dryRun,
|
|
110
|
-
};
|
|
111
|
-
|
|
112
|
-
if (dryRun) {
|
|
113
|
-
console.log(`DRY-RUN — would generate into ${out}, no files written:`);
|
|
114
|
-
console.log(` agents: ${summary.agents.join(", ")}`);
|
|
115
|
-
return summary;
|
|
116
|
-
}
|
|
117
|
-
|
|
118
|
-
await mkdir(out, { recursive: true });
|
|
119
|
-
for (const { file, content } of files) {
|
|
120
|
-
await writeFile(join(out, file), content);
|
|
121
|
-
}
|
|
122
|
-
console.log(`Generated ${files.length} Copilot agent file(s): ${summary.agents.join(", ")}`);
|
|
123
|
-
return summary;
|
|
124
|
-
}
|
|
@@ -1,44 +0,0 @@
|
|
|
1
|
-
import type { ExtensionAPI } from "@earendil-works/pi-coding-agent";
|
|
2
|
-
import { loadSessionContext } from "./lib/context-loader.js";
|
|
3
|
-
|
|
4
|
-
/**
|
|
5
|
-
* Session-start extension.
|
|
6
|
-
*
|
|
7
|
-
* Injects baseline context at the start of every PI session:
|
|
8
|
-
* 1. Skill availability hints (so the agent knows they exist)
|
|
9
|
-
* 2. Project context files (AGENTS.md, user-preferences.md)
|
|
10
|
-
*
|
|
11
|
-
* Context files are read dynamically from the project root (cwd).
|
|
12
|
-
*/
|
|
13
|
-
export default function (pi: ExtensionAPI) {
|
|
14
|
-
pi.on("before_agent_start", async (_event, ctx) => {
|
|
15
|
-
const skillHints = [
|
|
16
|
-
"Available skills — invoke when relevant (not pre-loaded to save context):",
|
|
17
|
-
"",
|
|
18
|
-
"• /skill:using-agent-skills — meta-skill that routes to the right skill",
|
|
19
|
-
" and enforces core agent behaviors. Check this first if unsure.",
|
|
20
|
-
"",
|
|
21
|
-
"• /skill:bd-tool — project context & task tracking with beads.",
|
|
22
|
-
" Run `bd ready` to see available work.",
|
|
23
|
-
"",
|
|
24
|
-
"• /skill:git-workflow — git discipline: feature branches,",
|
|
25
|
-
" worktrees for solo AFK work, PR workflow, and when to ask.",
|
|
26
|
-
"",
|
|
27
|
-
"Read the SKILL.md for full instructions when needed.",
|
|
28
|
-
].join("\n");
|
|
29
|
-
|
|
30
|
-
const contextFiles = loadSessionContext(ctx.cwd);
|
|
31
|
-
|
|
32
|
-
const content = contextFiles
|
|
33
|
-
? `${skillHints}\n\n---\n\n${contextFiles}`
|
|
34
|
-
: skillHints;
|
|
35
|
-
|
|
36
|
-
return {
|
|
37
|
-
message: {
|
|
38
|
-
customType: "session-start",
|
|
39
|
-
content,
|
|
40
|
-
display: false,
|
|
41
|
-
},
|
|
42
|
-
};
|
|
43
|
-
});
|
|
44
|
-
}
|
package/hooks.json
DELETED
package/lib/pi-packages.mjs
DELETED
|
@@ -1,169 +0,0 @@
|
|
|
1
|
-
// Pi third-party package provisioning.
|
|
2
|
-
//
|
|
3
|
-
// agent-cortex's pi harness needs tools that live in third-party pi packages:
|
|
4
|
-
// ask_questions comes from pi-questions, fetch_content from pi-web-access (see
|
|
5
|
-
// token-map.json notes and docs/ideas/extension-manifests.md). Those packages
|
|
6
|
-
// are declared in the package manifest — package.json → pi.packages — and this
|
|
7
|
-
// module makes them real: `agent-cortex install pi` reads the declaration and
|
|
8
|
-
// installs any package the pi user scope is missing.
|
|
9
|
-
//
|
|
10
|
-
// Provisioning goes through the pi CLI (`pi install <source>`), which both
|
|
11
|
-
// installs the package under ~/.pi/agent/npm and declares it in
|
|
12
|
-
// ~/.pi/agent/settings.json — the same store pi loads packages from. It is
|
|
13
|
-
// opt-in (installPi option `provisionPackages`) and idempotent: a package that
|
|
14
|
-
// is already declared and installed is skipped. A failed install warns and the
|
|
15
|
-
// rest continue, so an offline machine never breaks the agent install.
|
|
16
|
-
|
|
17
|
-
import { readFile, readdir } from "node:fs/promises";
|
|
18
|
-
import { join } from "node:path";
|
|
19
|
-
import { spawn } from "node:child_process";
|
|
20
|
-
|
|
21
|
-
const DEFAULT_WARN = (msg) => console.warn(`[pi-packages] ${msg}`);
|
|
22
|
-
|
|
23
|
-
/**
|
|
24
|
-
* Read the pi package sources agent-cortex declares it needs.
|
|
25
|
-
*
|
|
26
|
-
* @param {string} root Package root containing package.json
|
|
27
|
-
* @returns {Promise<string[]>} Declared sources, e.g. ["npm:pi-questions"]
|
|
28
|
-
*/
|
|
29
|
-
export async function loadRequiredPackages(root) {
|
|
30
|
-
const manifest = JSON.parse(await readFile(join(root, "package.json"), "utf-8"));
|
|
31
|
-
const packages = manifest?.pi?.packages;
|
|
32
|
-
return Array.isArray(packages) ? packages.filter((entry) => typeof entry === "string") : [];
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
/**
|
|
36
|
-
* Extract the npm package name from a pi source string.
|
|
37
|
-
*
|
|
38
|
-
* @param {string} source e.g. "npm:pi-web-access@0.10.7", "npm:@scope/pkg"
|
|
39
|
-
* @returns {string | null} The name, or null for sources we cannot inspect locally
|
|
40
|
-
*/
|
|
41
|
-
export function npmSourceName(source) {
|
|
42
|
-
if (typeof source !== "string" || !source.startsWith("npm:")) return null;
|
|
43
|
-
const spec = source.slice("npm:".length);
|
|
44
|
-
const at = spec.lastIndexOf("@");
|
|
45
|
-
return at > 0 ? spec.slice(0, at) : spec;
|
|
46
|
-
}
|
|
47
|
-
|
|
48
|
-
/**
|
|
49
|
-
* Decide which required packages still need installing.
|
|
50
|
-
*
|
|
51
|
-
* A package is satisfied only when it is both declared in settings (so pi loads
|
|
52
|
-
* it) and present in the npm store (so it is installed) — otherwise it needs a
|
|
53
|
-
* `pi install` to reconcile.
|
|
54
|
-
*
|
|
55
|
-
* @param {string[]} required
|
|
56
|
-
* @param {{ declaredSources: string[], installedNames: string[] }} state
|
|
57
|
-
* @returns {string[]} The sources still to install
|
|
58
|
-
*/
|
|
59
|
-
export function planPackageInstalls(required, { declaredSources, installedNames }) {
|
|
60
|
-
const declared = new Set(declaredSources.map(npmSourceName).filter(Boolean));
|
|
61
|
-
const installed = new Set(installedNames);
|
|
62
|
-
return required.filter((source) => {
|
|
63
|
-
const name = npmSourceName(source);
|
|
64
|
-
return name === null || !declared.has(name) || !installed.has(name);
|
|
65
|
-
});
|
|
66
|
-
}
|
|
67
|
-
|
|
68
|
-
/**
|
|
69
|
-
* Install every required package the pi user scope is missing.
|
|
70
|
-
*
|
|
71
|
-
* @param {object} options
|
|
72
|
-
* @param {string[]} options.required Declared pi sources (see loadRequiredPackages)
|
|
73
|
-
* @param {string} options.piRoot Pi user scope dir (default ~/.pi/agent)
|
|
74
|
-
* @param {boolean} [options.dryRun] Report the plan without installing
|
|
75
|
-
* @param {(source: string) => Promise<{ok: boolean, error: string | null}>} [options.runInstall]
|
|
76
|
-
* @param {(msg: string) => void} [options.warn]
|
|
77
|
-
* @returns {Promise<{planned: string[], installed: string[], failed: {source: string, error: string}[]}>}
|
|
78
|
-
*/
|
|
79
|
-
export async function provisionPiPackages({
|
|
80
|
-
required,
|
|
81
|
-
piRoot,
|
|
82
|
-
dryRun = false,
|
|
83
|
-
runInstall = runPiInstall,
|
|
84
|
-
warn = DEFAULT_WARN,
|
|
85
|
-
}) {
|
|
86
|
-
const declaredSources = await readDeclaredSources(join(piRoot, "settings.json"));
|
|
87
|
-
const installedNames = await readInstalledNames(join(piRoot, "npm", "node_modules"));
|
|
88
|
-
const planned = planPackageInstalls(required, { declaredSources, installedNames });
|
|
89
|
-
|
|
90
|
-
if (dryRun) return { planned, installed: [], failed: [] };
|
|
91
|
-
|
|
92
|
-
const installed = [];
|
|
93
|
-
const failed = [];
|
|
94
|
-
for (const source of planned) {
|
|
95
|
-
const result = await runInstall(source);
|
|
96
|
-
if (result.ok) {
|
|
97
|
-
installed.push(source);
|
|
98
|
-
} else {
|
|
99
|
-
failed.push({ source, error: result.error });
|
|
100
|
-
warn(`could not install pi package ${source}: ${result.error}`);
|
|
101
|
-
}
|
|
102
|
-
}
|
|
103
|
-
return { planned, installed, failed };
|
|
104
|
-
}
|
|
105
|
-
|
|
106
|
-
/** Install one pi package source through the pi CLI. */
|
|
107
|
-
export function runPiInstall(source) {
|
|
108
|
-
return new Promise((resolve) => {
|
|
109
|
-
const child = spawn("pi", ["install", source], { stdio: ["ignore", "pipe", "pipe"] });
|
|
110
|
-
let stderr = "";
|
|
111
|
-
child.stdout.resume(); // drain; only failures are interesting
|
|
112
|
-
child.stderr.on("data", (chunk) => {
|
|
113
|
-
stderr += chunk;
|
|
114
|
-
});
|
|
115
|
-
child.on("error", (err) => {
|
|
116
|
-
resolve({
|
|
117
|
-
ok: false,
|
|
118
|
-
error: err.code === "ENOENT" ? "pi CLI not found on PATH" : err.message,
|
|
119
|
-
});
|
|
120
|
-
});
|
|
121
|
-
child.on("close", (code) => {
|
|
122
|
-
resolve({
|
|
123
|
-
ok: code === 0,
|
|
124
|
-
error: code === 0 ? null : stderr.trim() || `pi install exited with code ${code}`,
|
|
125
|
-
});
|
|
126
|
-
});
|
|
127
|
-
});
|
|
128
|
-
}
|
|
129
|
-
|
|
130
|
-
// ─── Pi user-scope inspection ────────────────────────────────────────────────
|
|
131
|
-
|
|
132
|
-
/** Read the package sources declared in a pi settings.json (missing or unreadable → none). */
|
|
133
|
-
async function readDeclaredSources(settingsPath) {
|
|
134
|
-
let settings;
|
|
135
|
-
try {
|
|
136
|
-
settings = JSON.parse(await readFile(settingsPath, "utf-8"));
|
|
137
|
-
} catch {
|
|
138
|
-
// Nothing declared yet, or a file pi itself owns and repairs. Provisioning is
|
|
139
|
-
// a non-essential step — it must never fail the agent install.
|
|
140
|
-
return [];
|
|
141
|
-
}
|
|
142
|
-
const packages = Array.isArray(settings?.packages) ? settings.packages : [];
|
|
143
|
-
return packages
|
|
144
|
-
.map((entry) => (typeof entry === "string" ? entry : entry?.source))
|
|
145
|
-
.filter((source) => typeof source === "string");
|
|
146
|
-
}
|
|
147
|
-
|
|
148
|
-
/** List installed package names in the pi npm store (missing dir → none). */
|
|
149
|
-
async function readInstalledNames(nodeModulesDir) {
|
|
150
|
-
let entries;
|
|
151
|
-
try {
|
|
152
|
-
entries = await readdir(nodeModulesDir, { withFileTypes: true });
|
|
153
|
-
} catch (err) {
|
|
154
|
-
if (err.code === "ENOENT") return [];
|
|
155
|
-
throw err;
|
|
156
|
-
}
|
|
157
|
-
const names = [];
|
|
158
|
-
for (const entry of entries) {
|
|
159
|
-
if (!entry.isDirectory()) continue;
|
|
160
|
-
if (!entry.name.startsWith("@")) {
|
|
161
|
-
names.push(entry.name);
|
|
162
|
-
continue;
|
|
163
|
-
}
|
|
164
|
-
for (const scoped of await readdir(join(nodeModulesDir, entry.name), { withFileTypes: true })) {
|
|
165
|
-
if (scoped.isDirectory()) names.push(`${entry.name}/${scoped.name}`);
|
|
166
|
-
}
|
|
167
|
-
}
|
|
168
|
-
return names;
|
|
169
|
-
}
|
package/plugin.json
DELETED
|
@@ -1,35 +0,0 @@
|
|
|
1
|
-
{
|
|
2
|
-
"name": "agent-cortex",
|
|
3
|
-
"description": "Personal Copilot CLI plugin with custom agents and skills",
|
|
4
|
-
"version": "1.42.0",
|
|
5
|
-
"author": {
|
|
6
|
-
"name": "jaybeeuu"
|
|
7
|
-
},
|
|
8
|
-
"license": "MIT",
|
|
9
|
-
"repository": "https://github.com/jaybeeuu/agent-cortex",
|
|
10
|
-
"bin": "bin/agent-cortex.mjs",
|
|
11
|
-
"agents": "agents/",
|
|
12
|
-
"skills": "skills/",
|
|
13
|
-
"mcpServers": {
|
|
14
|
-
"context7": {
|
|
15
|
-
"type": "stdio",
|
|
16
|
-
"command": "npx",
|
|
17
|
-
"args": [
|
|
18
|
-
"-y",
|
|
19
|
-
"@upstash/context7-mcp@latest"
|
|
20
|
-
]
|
|
21
|
-
},
|
|
22
|
-
"github": {
|
|
23
|
-
"type": "stdio",
|
|
24
|
-
"command": "pnpm",
|
|
25
|
-
"args": [
|
|
26
|
-
"dlx",
|
|
27
|
-
"@modelcontextprotocol/server-github"
|
|
28
|
-
],
|
|
29
|
-
"tools": [
|
|
30
|
-
"*"
|
|
31
|
-
]
|
|
32
|
-
}
|
|
33
|
-
},
|
|
34
|
-
"hooks": "hooks.json"
|
|
35
|
-
}
|
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
// Regenerates the committed Copilot CLI flat agent files (agents/*.agent.md)
|
|
2
|
-
// from the canonical composable agent sources (agents/<name>/).
|
|
3
|
-
//
|
|
4
|
-
// This script is a thin wrapper over the shared install-time generator
|
|
5
|
-
// (bin/installers/copilot.mjs) — `agent-cortex install copilot` runs exactly the
|
|
6
|
-
// same code path, so install-time and build-time output can never diverge. CI
|
|
7
|
-
// runs this and checks `git diff --exit-code -- 'agents/*.agent.md'` to
|
|
8
|
-
// guarantee the committed flat files are never stale: a fresh clone (or a
|
|
9
|
-
// direct path plugin install) ships the Copilot plugin read-ready.
|
|
10
|
-
//
|
|
11
|
-
// agents/<name>.agent.md composed from agents/<name>/agent.md +
|
|
12
|
-
// agents/<name>/copilot/frontmatter.json +
|
|
13
|
-
// agents/<name>/copilot/<section>.md ({{SECTION:...}}),
|
|
14
|
-
// with {{TOOL:...}}/{{PATH:...}} substituted against
|
|
15
|
-
// the copilot column of token-map.json.
|
|
16
|
-
//
|
|
17
|
-
// The flat files live in the same agents/ directory the Copilot plugin scans
|
|
18
|
-
// (plugin.json "agents": "agents/"), next to the composable dirs they come
|
|
19
|
-
// from — the generator only writes *.agent.md files and never deletes.
|
|
20
|
-
//
|
|
21
|
-
// Run: pnpm build:copilot (node scripts/build-copilot-agents.mjs)
|
|
22
|
-
// Zero dependencies so it runs on the CI Node (20) and local Node alike.
|
|
23
|
-
|
|
24
|
-
import { join, dirname } from "node:path";
|
|
25
|
-
import { fileURLToPath } from "node:url";
|
|
26
|
-
import { installCopilot } from "../bin/installers/copilot.mjs";
|
|
27
|
-
|
|
28
|
-
const ROOT = join(dirname(fileURLToPath(import.meta.url)), "..");
|
|
29
|
-
|
|
30
|
-
await installCopilot({ root: ROOT, output: join(ROOT, "agents") });
|
|
@@ -1,82 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# Installs ~/.copilot/copilot-instructions.md with proactive skill directives.
|
|
3
|
-
# Run after cloning this plugin: pnpm install (or bash scripts/install-instructions.sh)
|
|
4
|
-
# Safe to re-run — replaces the agent-cortex section only.
|
|
5
|
-
|
|
6
|
-
set -euo pipefail
|
|
7
|
-
|
|
8
|
-
INSTRUCTIONS_FILE="$HOME/.copilot/copilot-instructions.md"
|
|
9
|
-
MARKER_START="<!-- agent-cortex:start -->"
|
|
10
|
-
MARKER_END="<!-- agent-cortex:end -->"
|
|
11
|
-
|
|
12
|
-
BLOCK="$MARKER_START
|
|
13
|
-
<!-- This block is managed by agent-cortex. Manual edits inside will be overwritten. -->
|
|
14
|
-
|
|
15
|
-
## Proactive skill use (agent-cortex plugin)
|
|
16
|
-
|
|
17
|
-
You have a set of custom skills available. Apply them automatically whenever they are relevant — the user should not have to invoke them by name.
|
|
18
|
-
|
|
19
|
-
### Code & tests
|
|
20
|
-
|
|
21
|
-
- Apply **style-code** whenever writing, editing, or reviewing code. It defines naming, module boundaries, and architectural conventions.
|
|
22
|
-
- Apply **style-tests** whenever writing, editing, or reviewing tests. It defines assertion strategy, mock discipline, and what to test.
|
|
23
|
-
- Apply **style-comms** whenever writing external-facing communication: tickets, RFCs, PRDs, proposals, or reports.
|
|
24
|
-
- Apply **style-documentation** whenever deciding what to document or reviewing existing docs.
|
|
25
|
-
- Use **tdd** (red-green-refactor loop) whenever building a new feature or fixing a bug where correctness matters.
|
|
26
|
-
- Run **review-security** before committing any changes that touch secrets, auth, or credentials.
|
|
27
|
-
|
|
28
|
-
### Planning & design
|
|
29
|
-
|
|
30
|
-
- Use **write-a-prd** when the user wants to plan a new feature or product requirement.
|
|
31
|
-
- Use **prd-to-tasks** after a PRD is approved to break it into phased epics and task beads.
|
|
32
|
-
- Use **create-task** when creating a new trackable task bead.
|
|
33
|
-
- Use **record-idea** when the user shares an early-stage idea that is not yet ready to implement.
|
|
34
|
-
- Use **request-refactor-plan** when the user wants to plan a refactor with safe incremental commits.
|
|
35
|
-
- Use **write-a-ticket** when writing a ticket for an external issue tracker (e.g. Jira).
|
|
36
|
-
- Use **design-an-interface** when the user wants to explore multiple API or module designs.
|
|
37
|
-
- Use **technical-direction** when evaluating architecture or technology choices with tradeoff analysis.
|
|
38
|
-
- Use **grill-me** or **grill-with-docs** when the user wants to stress-test a plan or design.
|
|
39
|
-
- Use **improve-codebase-architecture** when the user wants to find architectural improvement opportunities.
|
|
40
|
-
|
|
41
|
-
### Task execution
|
|
42
|
-
|
|
43
|
-
- Use **bd-tool** whenever the user mentions beads, bd, tasks, or asks what work is available.
|
|
44
|
-
- Use **ralph** to run all pending beads end-to-end with review gates.
|
|
45
|
-
- Use **run-pipeline-stage** to work through individual pipeline stages inline.
|
|
46
|
-
- Use **hitl-collab** when a task requires human review, manual steps, or a PR handoff.
|
|
47
|
-
- Use **classify-bead** when a bead is missing its implementation-type label.
|
|
48
|
-
|
|
49
|
-
### Repo & plugin maintenance
|
|
50
|
-
|
|
51
|
-
- Use **maintain-agent-docs** when reviewing or updating AGENTS.md or agent-consumed docs.
|
|
52
|
-
- Use **refactor-skill** when restructuring or reviewing an existing skill.
|
|
53
|
-
- Use **write-a-skill** when creating a new skill.
|
|
54
|
-
- Use **init-beads** when setting up the bd task-tracker in a new project.
|
|
55
|
-
|
|
56
|
-
$MARKER_END"
|
|
57
|
-
|
|
58
|
-
mkdir -p "$(dirname "$INSTRUCTIONS_FILE")"
|
|
59
|
-
|
|
60
|
-
if [ ! -f "$INSTRUCTIONS_FILE" ]; then
|
|
61
|
-
printf '%s\n' "$BLOCK" > "$INSTRUCTIONS_FILE"
|
|
62
|
-
echo "✓ Created $INSTRUCTIONS_FILE"
|
|
63
|
-
elif grep -qF "$MARKER_START" "$INSTRUCTIONS_FILE"; then
|
|
64
|
-
# Write replacement block to a temp file so awk can read it with getline
|
|
65
|
-
BLOCK_FILE=$(mktemp)
|
|
66
|
-
printf '%s\n' "$BLOCK" > "$BLOCK_FILE"
|
|
67
|
-
awk -v start="$MARKER_START" -v end="$MARKER_END" -v blockfile="$BLOCK_FILE" '
|
|
68
|
-
$0 == start {
|
|
69
|
-
while ((getline line < blockfile) > 0) print line
|
|
70
|
-
close(blockfile)
|
|
71
|
-
skip=1; next
|
|
72
|
-
}
|
|
73
|
-
$0 == end { skip=0; next }
|
|
74
|
-
!skip { print }
|
|
75
|
-
' "$INSTRUCTIONS_FILE" > "${INSTRUCTIONS_FILE}.tmp"
|
|
76
|
-
mv "${INSTRUCTIONS_FILE}.tmp" "$INSTRUCTIONS_FILE"
|
|
77
|
-
rm -f "$BLOCK_FILE"
|
|
78
|
-
echo "✓ Updated agent-cortex section in $INSTRUCTIONS_FILE"
|
|
79
|
-
else
|
|
80
|
-
printf '\n%s\n' "$BLOCK" >> "$INSTRUCTIONS_FILE"
|
|
81
|
-
echo "✓ Appended agent-cortex section to $INSTRUCTIONS_FILE"
|
|
82
|
-
fi
|
|
@@ -1,17 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bash
|
|
2
|
-
# Sync plugin.json version with package.json
|
|
3
|
-
# Called by changesets after versioning to keep them in lockstep
|
|
4
|
-
|
|
5
|
-
set -euo pipefail
|
|
6
|
-
|
|
7
|
-
VERSION=$(node -p "require('./package.json').version")
|
|
8
|
-
|
|
9
|
-
# Update plugin.json version field
|
|
10
|
-
node -e "
|
|
11
|
-
const fs = require('fs');
|
|
12
|
-
const plugin = JSON.parse(fs.readFileSync('plugin.json', 'utf8'));
|
|
13
|
-
plugin.version = '$VERSION';
|
|
14
|
-
fs.writeFileSync('plugin.json', JSON.stringify(plugin, null, 2) + '\n');
|
|
15
|
-
"
|
|
16
|
-
|
|
17
|
-
echo "✓ Synced plugin.json to version $VERSION"
|