@amsterdamdatalabs/enact-extensions 0.1.0 → 0.1.3
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 +96 -21
- package/dist/index.d.ts +5 -3
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +3 -2
- package/dist/index.js.map +1 -1
- package/dist/install.d.ts +171 -1
- package/dist/install.d.ts.map +1 -1
- package/dist/install.js +402 -49
- package/dist/install.js.map +1 -1
- package/dist/internal/codex.d.ts.map +1 -1
- package/dist/internal/codex.js +7 -1
- package/dist/internal/codex.js.map +1 -1
- package/dist/internal/platform.d.ts +8 -0
- package/dist/internal/platform.d.ts.map +1 -1
- package/dist/internal/platform.js +46 -2
- package/dist/internal/platform.js.map +1 -1
- package/dist/provision.d.ts +30 -0
- package/dist/provision.d.ts.map +1 -0
- package/dist/provision.js +202 -0
- package/dist/provision.js.map +1 -0
- package/dist/validate/index.d.ts +44 -0
- package/dist/validate/index.d.ts.map +1 -1
- package/dist/validate/index.js +157 -0
- package/dist/validate/index.js.map +1 -1
- package/extensions/cmux/.agents/plugin.json +37 -0
- package/extensions/cmux/skills/cmux/SKILL.md +82 -0
- package/extensions/cmux/skills/cmux/agents/openai.yaml +4 -0
- package/extensions/cmux/skills/cmux/references/handles-and-identify.md +35 -0
- package/extensions/cmux/skills/cmux/references/panes-surfaces.md +37 -0
- package/extensions/cmux/skills/cmux/references/trigger-flash-and-health.md +23 -0
- package/extensions/cmux/skills/cmux/references/windows-workspaces.md +31 -0
- package/extensions/cmux/skills/cmux-vm-monitor/SKILL.md +122 -0
- package/extensions/cmux/skills/cmux-vm-monitor/agents/openai.yaml +4 -0
- package/extensions/cmux/skills/cmux-vm-monitor/references/cmux-commands.md +66 -0
- package/extensions/cmux/skills/cmux-vm-monitor/scripts/codex_vm_monitor.sh +45 -0
- package/extensions/cmux/skills/cmux-workspace/SKILL.md +93 -0
- package/extensions/dev-state/.agents/plugin.json +35 -0
- package/extensions/dev-state/skills/dev-state-plan-graduation/SKILL.md +194 -0
- package/extensions/dev-state/skills/dev-state-plan-graduation/agents/openai.yaml +4 -0
- package/extensions/dev-state/skills/dev-state-plan-graduation/references/reference.md +130 -0
- package/extensions/devops/.agents/plugin.json +36 -0
- package/extensions/devops/skills/azure-devops-cli/SKILL.md +431 -0
- package/extensions/devops/skills/azure-devops-cli/agents/openai.yaml +4 -0
- package/extensions/devops/skills/ci-pipeline-strategy/SKILL.md +217 -0
- package/extensions/devops/skills/ci-pipeline-strategy/agents/openai.yaml +4 -0
- package/extensions/enact-context/.agents/plugin.json +40 -0
- package/extensions/enact-context/.mcp.json +8 -0
- package/extensions/enact-context/README.md +25 -0
- package/extensions/enact-context/assets/icon.png +0 -0
- package/extensions/enact-context/assets/logo.png +0 -0
- package/extensions/enact-context/hooks/hooks.json +115 -0
- package/extensions/enact-context/skills/enact-context/SKILL.md +149 -0
- package/extensions/enact-context/skills/enact-context/scripts/install.sh +69 -0
- package/extensions/enact-factory/.agents/plugin.json +42 -0
- package/extensions/enact-factory/.mcp.json +8 -0
- package/extensions/enact-factory/assets/icon.png +0 -0
- package/extensions/enact-factory/assets/logo.png +0 -0
- package/extensions/enact-factory/hooks/user-prompt-submit.mjs +67 -0
- package/extensions/enact-factory/skills/testing-strategy/SKILL.md +167 -0
- package/extensions/enact-factory/skills/workitem-triage/SKILL.md +22 -0
- package/extensions/enact-operator/.agents/plugin.json +57 -0
- package/extensions/enact-operator/.app.json +3 -0
- package/extensions/enact-operator/.mcp.json +10 -0
- package/extensions/enact-operator/_taxonomy.md +86 -0
- package/extensions/enact-operator/agents/README.md +5 -0
- package/extensions/enact-operator/agents/architect.toml +25 -0
- package/extensions/enact-operator/agents/code-reviewer.toml +24 -0
- package/extensions/enact-operator/agents/critic.toml +30 -0
- package/extensions/enact-operator/agents/executor.toml +24 -0
- package/extensions/enact-operator/agents/explore.toml +23 -0
- package/extensions/enact-operator/agents/planner.toml +24 -0
- package/extensions/enact-operator/agents/verifier.toml +24 -0
- package/extensions/enact-operator/assets/icon.png +0 -0
- package/extensions/enact-operator/assets/logo.png +0 -0
- package/extensions/enact-operator/commands/doctor.md +39 -0
- package/extensions/enact-operator/commands/setup.md +51 -0
- package/extensions/enact-operator/hooks/hooks.json +146 -0
- package/extensions/enact-operator/skills/_variants.md +44 -0
- package/extensions/enact-operator/skills/ai-slop-cleaner/SKILL.md +50 -0
- package/extensions/enact-operator/skills/analyze/SKILL.md +91 -0
- package/extensions/enact-operator/skills/ask/SKILL.md +47 -0
- package/extensions/enact-operator/skills/autopilot/SKILL.md +170 -0
- package/extensions/enact-operator/skills/autoresearch-goal/SKILL.md +79 -0
- package/extensions/enact-operator/skills/cancel/SKILL.md +99 -0
- package/extensions/enact-operator/skills/configure-notifications/SKILL.md +77 -0
- package/extensions/enact-operator/skills/deep-interview/SKILL.md +80 -0
- package/extensions/enact-operator/skills/doctor/SKILL.md +48 -0
- package/extensions/enact-operator/skills/hud/SKILL.md +49 -0
- package/extensions/enact-operator/skills/hyperplan/SKILL.md +47 -0
- package/extensions/enact-operator/skills/plan/SKILL.md +78 -0
- package/extensions/enact-operator/skills/ralph/SKILL.md +201 -0
- package/extensions/enact-operator/skills/ralph/gemini.md +18 -0
- package/extensions/enact-operator/skills/ralplan/SKILL.md +151 -0
- package/extensions/enact-operator/skills/remove-deadcode/SKILL.md +45 -0
- package/extensions/enact-operator/skills/research/SKILL.md +74 -0
- package/extensions/enact-operator/skills/review/SKILL.md +58 -0
- package/extensions/enact-operator/skills/security-research/SKILL.md +54 -0
- package/extensions/enact-operator/skills/setup/SKILL.md +91 -0
- package/extensions/enact-operator/skills/setup/scripts/install.sh +50 -0
- package/extensions/enact-operator/skills/skill/SKILL.md +82 -0
- package/extensions/enact-operator/skills/tdd/SKILL.md +59 -0
- package/extensions/enact-operator/skills/team/SKILL.md +199 -0
- package/extensions/enact-operator/skills/trace/SKILL.md +41 -0
- package/extensions/enact-operator/skills/ultragoal/SKILL.md +99 -0
- package/extensions/enact-operator/skills/ultraqa/SKILL.md +113 -0
- package/extensions/enact-operator/skills/ultrawork/SKILL.md +145 -0
- package/extensions/enact-operator/skills/ultrawork/planner.md +28 -0
- package/extensions/enact-operator/skills/wiki/SKILL.md +41 -0
- package/extensions/enact-operator/skills/work-with-workitem/SKILL.md +51 -0
- package/extensions/enact-wiki/.agents/plugin.json +42 -0
- package/extensions/enact-wiki/.mcp.json +15 -0
- package/extensions/enact-wiki/README.md +44 -0
- package/extensions/enact-wiki/assets/icon.png +0 -0
- package/extensions/enact-wiki/assets/logo.png +0 -0
- package/extensions/enact-wiki/skills/document-parser/SKILL.md +17 -0
- package/extensions/enact-wiki/skills/document-parser/scripts/parse.sh +60 -0
- package/extensions/enact-wiki/skills/document-parser/skill.json +9 -0
- package/extensions/enact-wiki/skills/enact-wiki/SKILL.md +30 -0
- package/extensions/enact-wiki/skills/enact-wiki/references/ingest.md +62 -0
- package/extensions/enact-wiki/skills/enact-wiki/references/manage.md +34 -0
- package/extensions/enact-wiki/skills/enact-wiki/references/query.md +59 -0
- package/extensions/enact-wiki/skills/search-lab/SKILL.md +57 -0
- package/extensions/enact-wiki/skills/search-lab/scripts/analyze.ts +23 -0
- package/{plugins/net-revenue-management/.codex-plugin → extensions/net-revenue-management/.agents}/plugin.json +10 -6
- package/extensions/plugin-dev/.agents/plugin.json +42 -0
- package/extensions/plugin-dev/.mcp.json +3 -0
- package/extensions/plugin-dev/agents/agent-creator.md +199 -0
- package/extensions/plugin-dev/agents/plugin-validator.md +91 -0
- package/extensions/plugin-dev/agents/skill-reviewer.md +212 -0
- package/extensions/plugin-dev/commands/_archive/create-marketplace.md +427 -0
- package/extensions/plugin-dev/commands/_archive/plugin-dev-guide.md +12 -0
- package/extensions/plugin-dev/commands/create-plugin.md +498 -0
- package/extensions/plugin-dev/commands/start.md +81 -0
- package/extensions/plugin-dev/hooks/hooks.json +3 -0
- package/extensions/plugin-dev/skills/agent-development/SKILL.md +641 -0
- package/extensions/plugin-dev/skills/agent-development/examples/agent-creation-prompt.md +250 -0
- package/extensions/plugin-dev/skills/agent-development/examples/complete-agent-examples.md +461 -0
- package/extensions/plugin-dev/skills/agent-development/references/advanced-agent-fields.md +246 -0
- package/extensions/plugin-dev/skills/agent-development/references/agent-creation-system-prompt.md +216 -0
- package/extensions/plugin-dev/skills/agent-development/references/permission-modes-rules.md +226 -0
- package/extensions/plugin-dev/skills/agent-development/references/system-prompt-design.md +464 -0
- package/extensions/plugin-dev/skills/agent-development/references/triggering-examples.md +474 -0
- package/extensions/plugin-dev/skills/agent-development/scripts/create-agent-skeleton.sh +176 -0
- package/extensions/plugin-dev/skills/agent-development/scripts/test-agent-trigger.sh +227 -0
- package/extensions/plugin-dev/skills/agent-development/scripts/validate-agent.sh +227 -0
- package/extensions/plugin-dev/skills/command-development/SKILL.md +763 -0
- package/extensions/plugin-dev/skills/command-development/examples/plugin-commands.md +612 -0
- package/extensions/plugin-dev/skills/command-development/examples/simple-commands.md +527 -0
- package/extensions/plugin-dev/skills/command-development/references/advanced-workflows.md +762 -0
- package/extensions/plugin-dev/skills/command-development/references/documentation-patterns.md +769 -0
- package/extensions/plugin-dev/skills/command-development/references/frontmatter-reference.md +508 -0
- package/extensions/plugin-dev/skills/command-development/references/interactive-commands.md +966 -0
- package/extensions/plugin-dev/skills/command-development/references/marketplace-considerations.md +943 -0
- package/extensions/plugin-dev/skills/command-development/references/plugin-features-reference.md +637 -0
- package/extensions/plugin-dev/skills/command-development/references/plugin-integration.md +191 -0
- package/extensions/plugin-dev/skills/command-development/references/skill-tool.md +447 -0
- package/extensions/plugin-dev/skills/command-development/references/testing-strategies.md +723 -0
- package/extensions/plugin-dev/skills/command-development/scripts/check-frontmatter.sh +234 -0
- package/extensions/plugin-dev/skills/command-development/scripts/validate-command.sh +160 -0
- package/extensions/plugin-dev/skills/hook-development/SKILL.md +861 -0
- package/extensions/plugin-dev/skills/hook-development/examples/load-context.sh +55 -0
- package/extensions/plugin-dev/skills/hook-development/examples/validate-bash.sh +57 -0
- package/extensions/plugin-dev/skills/hook-development/examples/validate-write.sh +48 -0
- package/extensions/plugin-dev/skills/hook-development/references/advanced.md +871 -0
- package/extensions/plugin-dev/skills/hook-development/references/hook-input-schemas.md +145 -0
- package/extensions/plugin-dev/skills/hook-development/references/migration.md +392 -0
- package/extensions/plugin-dev/skills/hook-development/references/patterns.md +430 -0
- package/extensions/plugin-dev/skills/hook-development/scripts/README.md +181 -0
- package/extensions/plugin-dev/skills/hook-development/scripts/hook-linter.sh +153 -0
- package/extensions/plugin-dev/skills/hook-development/scripts/test-hook.sh +276 -0
- package/extensions/plugin-dev/skills/hook-development/scripts/validate-hook-schema.sh +159 -0
- package/extensions/plugin-dev/skills/mcp-integration/SKILL.md +775 -0
- package/extensions/plugin-dev/skills/mcp-integration/examples/http-server.json +20 -0
- package/extensions/plugin-dev/skills/mcp-integration/examples/sse-server.json +19 -0
- package/extensions/plugin-dev/skills/mcp-integration/examples/stdio-server.json +38 -0
- package/extensions/plugin-dev/skills/mcp-integration/examples/ws-server.json +26 -0
- package/extensions/plugin-dev/skills/mcp-integration/references/authentication.md +601 -0
- package/extensions/plugin-dev/skills/mcp-integration/references/server-discovery.md +190 -0
- package/extensions/plugin-dev/skills/mcp-integration/references/server-types.md +572 -0
- package/extensions/plugin-dev/skills/mcp-integration/references/tool-usage.md +623 -0
- package/extensions/plugin-dev/skills/plugin-dev-guide/SKILL.md +222 -0
- package/extensions/plugin-dev/skills/plugin-structure/SKILL.md +705 -0
- package/extensions/plugin-dev/skills/plugin-structure/examples/advanced-plugin.md +774 -0
- package/extensions/plugin-dev/skills/plugin-structure/examples/minimal-plugin.md +83 -0
- package/extensions/plugin-dev/skills/plugin-structure/examples/standard-plugin.md +611 -0
- package/extensions/plugin-dev/skills/plugin-structure/references/advanced-topics.md +289 -0
- package/extensions/plugin-dev/skills/plugin-structure/references/component-patterns.md +592 -0
- package/extensions/plugin-dev/skills/plugin-structure/references/github-actions.md +233 -0
- package/extensions/plugin-dev/skills/plugin-structure/references/headless-ci-mode.md +193 -0
- package/extensions/plugin-dev/skills/plugin-structure/references/manifest-reference.md +625 -0
- package/extensions/plugin-dev/skills/plugin-structure/references/output-styles.md +116 -0
- package/extensions/plugin-dev/skills/skill-development/SKILL.md +564 -0
- package/extensions/plugin-dev/skills/skill-development/examples/complete-skill.md +465 -0
- package/extensions/plugin-dev/skills/skill-development/examples/frontmatter-templates.md +167 -0
- package/extensions/plugin-dev/skills/skill-development/examples/minimal-skill.md +111 -0
- package/extensions/plugin-dev/skills/skill-development/references/advanced-frontmatter.md +225 -0
- package/extensions/plugin-dev/skills/skill-development/references/commands-vs-skills.md +39 -0
- package/extensions/plugin-dev/skills/skill-development/references/skill-creation-workflow.md +379 -0
- package/extensions/plugin-dev/skills/skill-development/references/skill-creator-original.md +210 -0
- package/package.json +8 -11
- package/scripts/enact-extensions.mjs +823 -21
- package/scripts/hooks/session-start-drift-check.mjs +58 -0
- package/scripts/lib/build-index.mjs +50 -0
- package/scripts/lib/bundle-hash.mjs +137 -0
- package/scripts/lib/hooks.mjs +741 -0
- package/scripts/lib/ledger.mjs +163 -0
- package/scripts/lib/list-bundles.mjs +70 -0
- package/scripts/lib/outdated.mjs +144 -0
- package/scripts/lib/provision-mcp.mjs +16 -0
- package/scripts/lib/resolve-bundle.mjs +121 -0
- package/scripts/lib/run-install.mjs +402 -38
- package/scripts/lib/run-prune.mjs +73 -0
- package/scripts/lib/run-sync.mjs +9 -1
- package/scripts/lib/run-uninstall.mjs +244 -0
- package/scripts/lib/run-update.mjs +152 -0
- package/scripts/lib/run-validate.mjs +21 -18
- package/scripts/lib/serve.mjs +472 -0
- package/scripts/postinstall.mjs +63 -0
- package/scripts/setup-enact-context.sh +2 -2
- package/scripts/version-bump.sh +463 -0
- package/spec/codex.json +1 -11
- package/spec/index.json +59 -0
- package/web/assets/README.md +111 -0
- package/web/assets/logo-full.png +0 -0
- package/web/assets/logo-slim.png +0 -0
- package/web/assets/tokens/base.css +45 -0
- package/web/assets/tokens/colors.css +248 -0
- package/web/assets/tokens/effects.css +24 -0
- package/web/assets/tokens/fonts.css +8 -0
- package/web/assets/tokens/index.css +18 -0
- package/web/assets/tokens/spacing.css +50 -0
- package/web/index.html +1188 -0
- package/.agents/plugins/marketplace.json +0 -20
- package/catalog/enact-context.json +0 -9
- package/catalog/enact-factory.json +0 -7
- package/catalog/enact-operator.json +0 -7
- package/catalog/enact-wiki.json +0 -7
- package/catalog/net-revenue-management.json +0 -8
- package/scripts/rename-supervisor-to-operator.pl +0 -66
- package/scripts/sync-manifests.mjs +0 -23
- package/scripts/validate-catalog.mjs +0 -37
- package/scripts/validate-plugin.mjs +0 -10
- /package/{plugins → extensions}/net-revenue-management/.mcp.json +0 -0
- /package/{plugins → extensions}/net-revenue-management/skills/net-revenue-risks/SKILL.md +0 -0
- /package/{plugins → extensions}/net-revenue-management/skills/net-revenue-scenario/SKILL.md +0 -0
|
@@ -0,0 +1,58 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
/**
|
|
3
|
+
* session-start-drift-check.mjs — Enact Extensions session-start drift hook.
|
|
4
|
+
*
|
|
5
|
+
* Registered as a session-start hook for Claude, Codex, Cursor, and Enact.
|
|
6
|
+
* Checks whether any installed enact-extensions plugins have drifted from
|
|
7
|
+
* their canonical source (i.e. are outdated) and prints a concise advisory
|
|
8
|
+
* if so.
|
|
9
|
+
*
|
|
10
|
+
* Design constraints:
|
|
11
|
+
* - FAIL-SILENT: wrap everything in try/catch; never throw; always exit 0.
|
|
12
|
+
* - FAST: imports computeOutdated directly (no subprocess) for speed.
|
|
13
|
+
* - READ-ONLY: never writes any state.
|
|
14
|
+
* - NO OUTPUT on success (or error): only print when there are outdated entries.
|
|
15
|
+
* - DEPENDENCY-FREE: only node builtins + enact-extensions own modules.
|
|
16
|
+
*/
|
|
17
|
+
|
|
18
|
+
import { dirname, resolve, join } from "node:path";
|
|
19
|
+
import { fileURLToPath } from "node:url";
|
|
20
|
+
|
|
21
|
+
const __dirname = dirname(fileURLToPath(import.meta.url));
|
|
22
|
+
// Navigate from scripts/hooks/ up to the repo root so we can import lib modules.
|
|
23
|
+
const REPO_ROOT = resolve(__dirname, "..", "..");
|
|
24
|
+
|
|
25
|
+
try {
|
|
26
|
+
// Dynamically import so any module-load failure is caught by the outer try/catch.
|
|
27
|
+
const { computeOutdated } = await import(join(REPO_ROOT, "scripts", "lib", "outdated.mjs"));
|
|
28
|
+
|
|
29
|
+
let entries;
|
|
30
|
+
try {
|
|
31
|
+
entries = computeOutdated();
|
|
32
|
+
} catch {
|
|
33
|
+
// computeOutdated threw (ledger missing, I/O error, etc.) — stay silent.
|
|
34
|
+
process.exit(0);
|
|
35
|
+
}
|
|
36
|
+
|
|
37
|
+
// Filter to only outdated entries (not fresh, not orphaned).
|
|
38
|
+
const outdated = (entries ?? []).filter((e) => e && e.status === "outdated");
|
|
39
|
+
|
|
40
|
+
if (outdated.length === 0) {
|
|
41
|
+
// Nothing to report.
|
|
42
|
+
process.exit(0);
|
|
43
|
+
}
|
|
44
|
+
|
|
45
|
+
// Build a concise list of (plugin, surface) pairs.
|
|
46
|
+
const pairs = outdated
|
|
47
|
+
.map((e) => `${e.name}/${e.platform}`)
|
|
48
|
+
.join(", ");
|
|
49
|
+
|
|
50
|
+
// Single advisory line to stdout.
|
|
51
|
+
process.stdout.write(
|
|
52
|
+
`[enact-extensions] ${outdated.length} plugin surface${outdated.length === 1 ? "" : "s"} outdated: ${pairs}. Run: enact-extensions update --all\n`,
|
|
53
|
+
);
|
|
54
|
+
} catch {
|
|
55
|
+
// Any top-level error (import failure, parse error, etc.) — silent exit 0.
|
|
56
|
+
}
|
|
57
|
+
|
|
58
|
+
process.exit(0);
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import { relative } from "node:path";
|
|
2
|
+
import { listBundles } from "./list-bundles.mjs";
|
|
3
|
+
|
|
4
|
+
/**
|
|
5
|
+
* Build a discovery index of all plugin bundles.
|
|
6
|
+
*
|
|
7
|
+
* The index is a generated artifact — it is NEVER committed. The schema
|
|
8
|
+
* contract lives in spec/index.json.
|
|
9
|
+
*
|
|
10
|
+
* @param {string[]} roots - Absolute paths to scan for plugin bundles
|
|
11
|
+
* (passed directly to listBundles).
|
|
12
|
+
* @param {object} [opts]
|
|
13
|
+
* @param {string|null} [opts.now] - ISO timestamp to stamp on generatedAt.
|
|
14
|
+
* Pass a fixed value for deterministic tests.
|
|
15
|
+
* Defaults to null when omitted — this lib is
|
|
16
|
+
* pure and never calls new Date(). The CLI
|
|
17
|
+
* boundary computes the live timestamp and
|
|
18
|
+
* passes it in as `now`.
|
|
19
|
+
* @param {string} [opts.packageRoot] - Absolute package root used to compute
|
|
20
|
+
* repo-relative paths. Defaults to the
|
|
21
|
+
* directory two levels above this file.
|
|
22
|
+
* @returns {{ generatedAt: string|null, count: number, plugins: object[] }}
|
|
23
|
+
*/
|
|
24
|
+
export function buildIndex(roots, opts = {}) {
|
|
25
|
+
const { now = null, packageRoot } = opts;
|
|
26
|
+
|
|
27
|
+
// Resolve package root: two levels up from this file (scripts/lib/ → repo root)
|
|
28
|
+
const pkgRoot =
|
|
29
|
+
packageRoot ??
|
|
30
|
+
new URL("../../", import.meta.url).pathname.replace(/\/$/, "");
|
|
31
|
+
|
|
32
|
+
// Source bundles via the canonical list-bundles helper (deduplicated, resilient).
|
|
33
|
+
const entries = listBundles(roots);
|
|
34
|
+
|
|
35
|
+
const plugins = entries.map((entry) => ({
|
|
36
|
+
name: entry.name,
|
|
37
|
+
version: entry.version,
|
|
38
|
+
category: entry.category,
|
|
39
|
+
description: entry.description,
|
|
40
|
+
targets: entry.targets,
|
|
41
|
+
// Make path repo-relative so the artifact is portable.
|
|
42
|
+
path: relative(pkgRoot, entry.path),
|
|
43
|
+
}));
|
|
44
|
+
|
|
45
|
+
return {
|
|
46
|
+
generatedAt: now,
|
|
47
|
+
count: plugins.length,
|
|
48
|
+
plugins,
|
|
49
|
+
};
|
|
50
|
+
}
|
|
@@ -0,0 +1,137 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* bundle-hash.mjs — deterministic content hash for a plugin bundle.
|
|
3
|
+
*
|
|
4
|
+
* bundleHash(pluginRoot) → sha256 hex string
|
|
5
|
+
*
|
|
6
|
+
* The hash covers the CANONICAL bundle content only:
|
|
7
|
+
* - .agents/plugin.json (the manifest itself)
|
|
8
|
+
* - Component dirs/files referenced in the manifest:
|
|
9
|
+
* skills, mcpServers, apps, commands, hooks, agents, _agents, rules
|
|
10
|
+
* - .mcp.json (if present at pluginRoot root)
|
|
11
|
+
*
|
|
12
|
+
* EXCLUDED (generated / derived surfaces, never present in canonical source):
|
|
13
|
+
* - .claude-plugin/
|
|
14
|
+
* - .codex-plugin/
|
|
15
|
+
* - .cursor-plugin/
|
|
16
|
+
*
|
|
17
|
+
* Algorithm:
|
|
18
|
+
* 1. Collect the set of paths to include (manifest + referenced component paths).
|
|
19
|
+
* 2. Walk each path recursively; collect all (relativePath, bytes) pairs.
|
|
20
|
+
* 3. Sort by relative path (order-independence).
|
|
21
|
+
* 4. Feed path + bytes for each file into a single sha256 digest.
|
|
22
|
+
* 5. Return the hex digest.
|
|
23
|
+
*
|
|
24
|
+
* Pure, no writes, synchronous.
|
|
25
|
+
*/
|
|
26
|
+
|
|
27
|
+
import { createHash } from "node:crypto";
|
|
28
|
+
import { existsSync, readdirSync, readFileSync, statSync } from "node:fs";
|
|
29
|
+
import { join, relative } from "node:path";
|
|
30
|
+
|
|
31
|
+
// ---------------------------------------------------------------------------
|
|
32
|
+
// Canonical component field names (mirrors pathFieldsFromManifest in install.ts)
|
|
33
|
+
// ---------------------------------------------------------------------------
|
|
34
|
+
const COMPONENT_FIELDS = [
|
|
35
|
+
"skills",
|
|
36
|
+
"mcpServers",
|
|
37
|
+
"apps",
|
|
38
|
+
"commands",
|
|
39
|
+
"hooks",
|
|
40
|
+
"agents",
|
|
41
|
+
"_agents",
|
|
42
|
+
"rules",
|
|
43
|
+
];
|
|
44
|
+
|
|
45
|
+
// Generated platform dirs — always excluded from the canonical hash.
|
|
46
|
+
const EXCLUDED_DIRS = new Set([".claude-plugin", ".codex-plugin", ".cursor-plugin"]);
|
|
47
|
+
|
|
48
|
+
/**
|
|
49
|
+
* Recursively collect all file entries under `root`.
|
|
50
|
+
* Returns an array of { rel: string, abs: string } sorted by rel.
|
|
51
|
+
* Silently skips non-file, non-directory entries.
|
|
52
|
+
*
|
|
53
|
+
* @param {string} abs - absolute path to walk
|
|
54
|
+
* @param {string} base - the pluginRoot (for computing relative paths)
|
|
55
|
+
* @param {string[]} acc - accumulator
|
|
56
|
+
*/
|
|
57
|
+
function walkFiles(abs, base, acc) {
|
|
58
|
+
if (!existsSync(abs)) return;
|
|
59
|
+
const stat = statSync(abs);
|
|
60
|
+
if (stat.isFile()) {
|
|
61
|
+
acc.push(relative(base, abs));
|
|
62
|
+
return;
|
|
63
|
+
}
|
|
64
|
+
if (!stat.isDirectory()) return;
|
|
65
|
+
const entries = readdirSync(abs).sort(); // sort for determinism
|
|
66
|
+
for (const name of entries) {
|
|
67
|
+
walkFiles(join(abs, name), base, acc);
|
|
68
|
+
}
|
|
69
|
+
}
|
|
70
|
+
|
|
71
|
+
/**
|
|
72
|
+
* Collect the canonical set of relative paths to include in the hash.
|
|
73
|
+
*
|
|
74
|
+
* @param {string} pluginRoot
|
|
75
|
+
* @param {object} manifest - parsed .agents/plugin.json
|
|
76
|
+
* @returns {string[]} sorted relative paths (relative to pluginRoot)
|
|
77
|
+
*/
|
|
78
|
+
function canonicalPaths(pluginRoot, manifest) {
|
|
79
|
+
// Always include the manifest itself.
|
|
80
|
+
const collected = [];
|
|
81
|
+
|
|
82
|
+
// 1. Always walk .agents/plugin.json (the manifest).
|
|
83
|
+
walkFiles(join(pluginRoot, ".agents", "plugin.json"), pluginRoot, collected);
|
|
84
|
+
|
|
85
|
+
// 2. Walk each component path that exists.
|
|
86
|
+
for (const field of COMPONENT_FIELDS) {
|
|
87
|
+
const raw = manifest[field];
|
|
88
|
+
if (typeof raw !== "string" || !raw.trim()) continue;
|
|
89
|
+
// Normalise: strip leading ./ and trailing /
|
|
90
|
+
const cleaned = raw.replace(/^\.\//, "").replace(/\/+$/, "");
|
|
91
|
+
if (!cleaned || cleaned.startsWith("../")) continue;
|
|
92
|
+
// Refuse to hash generated platform dirs even if the manifest references them.
|
|
93
|
+
const topSegment = cleaned.split("/")[0];
|
|
94
|
+
if (EXCLUDED_DIRS.has(topSegment)) continue;
|
|
95
|
+
walkFiles(join(pluginRoot, cleaned), pluginRoot, collected);
|
|
96
|
+
}
|
|
97
|
+
|
|
98
|
+
// 3. .mcp.json at pluginRoot root (included if present, regardless of manifest field)
|
|
99
|
+
walkFiles(join(pluginRoot, ".mcp.json"), pluginRoot, collected);
|
|
100
|
+
|
|
101
|
+
// Sort for order-independence, then deduplicate.
|
|
102
|
+
const unique = [...new Set(collected)].sort();
|
|
103
|
+
return unique;
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
/**
|
|
107
|
+
* Compute a deterministic sha256 hex hash of the canonical plugin bundle.
|
|
108
|
+
*
|
|
109
|
+
* @param {string} pluginRoot - absolute path to the bundle root
|
|
110
|
+
* @returns {string} sha256 hex digest (64 lowercase hex chars)
|
|
111
|
+
* @throws {Error} if the manifest cannot be read (ENOENT, parse error, etc.)
|
|
112
|
+
*/
|
|
113
|
+
export function bundleHash(pluginRoot) {
|
|
114
|
+
// Read and parse the manifest first — this is the anchor; if it's missing
|
|
115
|
+
// we cannot know which component paths to include, so we throw.
|
|
116
|
+
const manifestPath = join(pluginRoot, ".agents", "plugin.json");
|
|
117
|
+
if (!existsSync(manifestPath)) {
|
|
118
|
+
throw new Error(`Cannot compute bundle hash: manifest not found at ${manifestPath}`);
|
|
119
|
+
}
|
|
120
|
+
const manifest = JSON.parse(readFileSync(manifestPath, "utf8"));
|
|
121
|
+
|
|
122
|
+
// Collect the sorted list of relative paths.
|
|
123
|
+
const paths = canonicalPaths(pluginRoot, manifest);
|
|
124
|
+
|
|
125
|
+
// Hash all paths and their contents in sorted order.
|
|
126
|
+
const hash = createHash("sha256");
|
|
127
|
+
for (const rel of paths) {
|
|
128
|
+
const abs = join(pluginRoot, rel);
|
|
129
|
+
// Feed the relative path as a NUL-terminated string to make path changes
|
|
130
|
+
// visible even when content is identical.
|
|
131
|
+
hash.update(rel + "\0", "utf8");
|
|
132
|
+
// Feed the file bytes.
|
|
133
|
+
hash.update(readFileSync(abs));
|
|
134
|
+
}
|
|
135
|
+
|
|
136
|
+
return hash.digest("hex");
|
|
137
|
+
}
|