contextos-agents 1.7.0 → 2.0.0-beta.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/.agents/AGENTS.md +16 -50
- package/.agents/adapters/aider/export.js +117 -99
- package/.agents/adapters/claude/export.js +68 -26
- package/.agents/adapters/copilot/export.js +90 -53
- package/.agents/adapters/cursor/export.js +100 -104
- package/.agents/adapters/drift-detector.js +196 -0
- package/.agents/adapters/gemini/export.js +76 -45
- package/.agents/adapters/pure-compiler.js +443 -0
- package/.agents/adapters/zed/export.js +104 -96
- package/.agents/compiled/registry.v2.json +504 -0
- package/.agents/compiled/registry.v2.sha256 +1 -0
- package/.agents/compiler/manifest-compiler.js +963 -0
- package/.agents/compiler/vendor/yaml.LICENSE.txt +13 -0
- package/.agents/compiler/vendor/yaml.SBOM.json +6 -0
- package/.agents/compiler/vendor/yaml.js +139 -0
- package/.agents/core/profiles/init.yaml +25 -0
- package/.agents/core/skills/context-manager/skill.yaml +3 -5
- package/.agents/core/skills/context-os/SKILL.md +3 -6
- package/.agents/core/skills/context-os/skill.yaml +3 -8
- package/.agents/core/skills/engineering-workflow/skill.yaml +1 -7
- package/.agents/core/skills/gemini-precision/skill.yaml +1 -6
- package/.agents/core/skills/gstack-roles/skill.yaml +3 -6
- package/.agents/core/skills/ponytail-mindset/skill.yaml +1 -7
- package/.agents/core/skills/security/skill.yaml +15 -3
- package/.agents/ctx.js +537 -112
- package/.agents/customization-dx.js +282 -0
- package/.agents/doctor.js +855 -66
- package/.agents/filesystem/index.js +71 -0
- package/.agents/filesystem/journaled-transaction.js +451 -0
- package/.agents/filesystem/lockfile-v2.js +275 -0
- package/.agents/filesystem/platform-hardening.js +222 -0
- package/.agents/filesystem/project-lock.js +218 -0
- package/.agents/filesystem/safe-path.js +256 -0
- package/.agents/generated/claude/skills/context-os/SKILL.md +1 -1
- package/.agents/generated/gemini/skills/context-os/SKILL.md +2 -2
- package/.agents/plugins/contextos/plugin.json +1 -1
- package/.agents/plugins.js +278 -64
- package/.agents/profiles.js +486 -51
- package/.agents/resolver/canonical-resolver.js +1348 -0
- package/.agents/resolver.js +50 -534
- package/.agents/rules/rule-catalog.js +525 -0
- package/.agents/schemas/attestation.review.v1.json +111 -0
- package/.agents/schemas/attestation.verification.v1.json +85 -0
- package/.agents/schemas/lockfile.v2.schema.json +134 -0
- package/.agents/schemas/profile.v2.schema.json +114 -0
- package/.agents/schemas/runtime.thread.v1.json +192 -0
- package/.agents/schemas/skill.manifest.v2.json +177 -0
- package/.agents/schemas/verification.spec.v1.json +39 -0
- package/.agents/schemas/workspace.graph.schema.json +106 -0
- package/.agents/skills-index.json +6 -166
- package/.agents/stats.js +9 -9
- package/.agents/transaction-core/event-store.js +288 -0
- package/.agents/transaction-core/idempotency.js +129 -0
- package/.agents/transaction-core/ipc-lock.js +311 -0
- package/.agents/transaction-core/plugin-supply-chain-bundle.js +436 -0
- package/.agents/validate.js +44 -1
- package/.agents/watch.js +354 -102
- package/.agents/workspace/workspace-graph.js +778 -0
- package/README.md +59 -387
- package/benchmarks/v2/analysis/statistics.js +140 -0
- package/benchmarks/v2/analysis/stats.js +69 -0
- package/benchmarks/v2/arms/arm-definitions.js +79 -0
- package/benchmarks/v2/dataset.schema.json +34 -0
- package/benchmarks/v2/evaluators/index.js +25 -0
- package/benchmarks/v2/evaluators/verified-success.js +116 -0
- package/benchmarks/v2/harness/runner.js +88 -0
- package/benchmarks/v2/pilot-tasks.json +392 -0
- package/bin/commands/recover.js +88 -0
- package/bin/commands/update.js +80 -17
- package/bin/commands.js +62 -25
- package/bin/index.js +138 -81
- package/bin/lib/lockfile.js +5 -3
- package/bin/lib/safe-writer.js +34 -3
- package/package.json +87 -72
- package/registry.json +2 -2
- package/registry.v2.schema.json +86 -0
- package/.agents/core/profiles/backend.yaml +0 -47
- package/.agents/core/profiles/enterprise.yaml +0 -46
- package/.agents/core/profiles/frontend.yaml +0 -46
- package/.agents/core/profiles/hackathon.yaml +0 -45
- package/.agents/core/profiles/mvp.yaml +0 -44
- package/.agents/core/profiles/startup.yaml +0 -48
- package/.agents/core/skills/adapters/EXAMPLES.md +0 -19
- package/.agents/core/skills/adapters/SKILL.md +0 -105
- package/.agents/core/skills/adapters/TROUBLESHOOTING.md +0 -7
- package/.agents/core/skills/adapters/VALIDATION.json +0 -12
- package/.agents/core/skills/adapters/skill.yaml +0 -16
- package/.agents/core/skills/architecture-diagrams/SKILL.md +0 -108
- package/.agents/core/skills/architecture-diagrams/VALIDATION.json +0 -12
- package/.agents/core/skills/architecture-diagrams/skill.yaml +0 -12
- package/.agents/core/skills/brutalist-design/SKILL.md +0 -150
- package/.agents/core/skills/brutalist-design/VALIDATION.json +0 -12
- package/.agents/core/skills/brutalist-design/skill.yaml +0 -12
- package/.agents/core/skills/database/EXAMPLES.md +0 -74
- package/.agents/core/skills/database/SKILL.md +0 -101
- package/.agents/core/skills/database/TROUBLESHOOTING.md +0 -18
- package/.agents/core/skills/database/VALIDATION.json +0 -11
- package/.agents/core/skills/database/skill.yaml +0 -31
- package/.agents/core/skills/ddd/EXAMPLES.md +0 -42
- package/.agents/core/skills/ddd/SKILL.md +0 -247
- package/.agents/core/skills/ddd/TROUBLESHOOTING.md +0 -19
- package/.agents/core/skills/ddd/VALIDATION.json +0 -12
- package/.agents/core/skills/ddd/ddd.md +0 -178
- package/.agents/core/skills/ddd/skill.yaml +0 -17
- package/.agents/core/skills/decisions/EXAMPLES.md +0 -35
- package/.agents/core/skills/decisions/SKILL.md +0 -90
- package/.agents/core/skills/decisions/TROUBLESHOOTING.md +0 -13
- package/.agents/core/skills/decisions/VALIDATION.json +0 -12
- package/.agents/core/skills/decisions/skill.yaml +0 -16
- package/.agents/core/skills/docker/EXAMPLES.md +0 -56
- package/.agents/core/skills/docker/SKILL.md +0 -63
- package/.agents/core/skills/docker/TROUBLESHOOTING.md +0 -18
- package/.agents/core/skills/docker/VALIDATION.json +0 -11
- package/.agents/core/skills/docker/skill.yaml +0 -29
- package/.agents/core/skills/fastapi/EXAMPLES.md +0 -36
- package/.agents/core/skills/fastapi/SKILL.md +0 -148
- package/.agents/core/skills/fastapi/TROUBLESHOOTING.md +0 -19
- package/.agents/core/skills/fastapi/VALIDATION.json +0 -12
- package/.agents/core/skills/fastapi/fastapi.md +0 -112
- package/.agents/core/skills/fastapi/skill.yaml +0 -17
- package/.agents/core/skills/generators/EXAMPLES.md +0 -19
- package/.agents/core/skills/generators/SKILL.md +0 -112
- package/.agents/core/skills/generators/TROUBLESHOOTING.md +0 -7
- package/.agents/core/skills/generators/VALIDATION.json +0 -12
- package/.agents/core/skills/generators/skill.yaml +0 -25
- package/.agents/core/skills/generators/templates/API.md +0 -77
- package/.agents/core/skills/generators/templates/ARCHITECTURE.md +0 -70
- package/.agents/core/skills/generators/templates/DATABASE.md +0 -42
- package/.agents/core/skills/generators/templates/DECISION.md +0 -46
- package/.agents/core/skills/generators/templates/PRD.md +0 -67
- package/.agents/core/skills/generators/templates/PROJECT_GRAPH.md +0 -56
- package/.agents/core/skills/generators/templates/ROADMAP.md +0 -51
- package/.agents/core/skills/generators/templates/TASKS.md +0 -43
- package/.agents/core/skills/generators/templates/UI.md +0 -73
- package/.agents/core/skills/graphify/EXAMPLES.md +0 -73
- package/.agents/core/skills/graphify/SKILL.md +0 -130
- package/.agents/core/skills/graphify/VALIDATION.json +0 -12
- package/.agents/core/skills/graphify/skill.yaml +0 -18
- package/.agents/core/skills/impeccable-design/EXAMPLES.md +0 -26
- package/.agents/core/skills/impeccable-design/SKILL.md +0 -201
- package/.agents/core/skills/impeccable-design/TROUBLESHOOTING.md +0 -19
- package/.agents/core/skills/impeccable-design/VALIDATION.json +0 -12
- package/.agents/core/skills/impeccable-design/skill.yaml +0 -20
- package/.agents/core/skills/interview-me/SKILL.md +0 -97
- package/.agents/core/skills/interview-me/VALIDATION.json +0 -12
- package/.agents/core/skills/interview-me/skill.yaml +0 -12
- package/.agents/core/skills/microservices/EXAMPLES.md +0 -38
- package/.agents/core/skills/microservices/SKILL.md +0 -164
- package/.agents/core/skills/microservices/TROUBLESHOOTING.md +0 -19
- package/.agents/core/skills/microservices/VALIDATION.json +0 -12
- package/.agents/core/skills/microservices/microservices.md +0 -119
- package/.agents/core/skills/microservices/skill.yaml +0 -17
- package/.agents/core/skills/minimalist-design/SKILL.md +0 -113
- package/.agents/core/skills/minimalist-design/VALIDATION.json +0 -12
- package/.agents/core/skills/minimalist-design/skill.yaml +0 -12
- package/.agents/core/skills/nestjs/EXAMPLES.md +0 -40
- package/.agents/core/skills/nestjs/SKILL.md +0 -139
- package/.agents/core/skills/nestjs/TROUBLESHOOTING.md +0 -19
- package/.agents/core/skills/nestjs/VALIDATION.json +0 -12
- package/.agents/core/skills/nestjs/nestjs.md +0 -103
- package/.agents/core/skills/nestjs/skill.yaml +0 -17
- package/.agents/core/skills/nextjs/EXAMPLES.md +0 -40
- package/.agents/core/skills/nextjs/SKILL.md +0 -163
- package/.agents/core/skills/nextjs/TROUBLESHOOTING.md +0 -19
- package/.agents/core/skills/nextjs/VALIDATION.json +0 -12
- package/.agents/core/skills/nextjs/nextjs.md +0 -67
- package/.agents/core/skills/nextjs/skill.yaml +0 -17
- package/.agents/core/skills/node/EXAMPLES.md +0 -80
- package/.agents/core/skills/node/SKILL.md +0 -128
- package/.agents/core/skills/node/TROUBLESHOOTING.md +0 -19
- package/.agents/core/skills/node/VALIDATION.json +0 -12
- package/.agents/core/skills/node/node.md +0 -87
- package/.agents/core/skills/node/skill.yaml +0 -17
- package/.agents/core/skills/performance/EXAMPLES.md +0 -30
- package/.agents/core/skills/performance/SKILL.md +0 -75
- package/.agents/core/skills/performance/TROUBLESHOOTING.md +0 -19
- package/.agents/core/skills/performance/VALIDATION.json +0 -12
- package/.agents/core/skills/performance/performance.md +0 -52
- package/.agents/core/skills/performance/skill.yaml +0 -17
- package/.agents/core/skills/react/EXAMPLES.md +0 -79
- package/.agents/core/skills/react/SKILL.md +0 -132
- package/.agents/core/skills/react/TROUBLESHOOTING.md +0 -19
- package/.agents/core/skills/react/VALIDATION.json +0 -12
- package/.agents/core/skills/react/react.md +0 -93
- package/.agents/core/skills/react/skill.yaml +0 -17
- package/.agents/core/skills/react-best-practices/SKILL.md +0 -155
- package/.agents/core/skills/react-best-practices/VALIDATION.json +0 -12
- package/.agents/core/skills/react-best-practices/skill.yaml +0 -14
- package/.agents/core/skills/redesign-audit/SKILL.md +0 -117
- package/.agents/core/skills/redesign-audit/VALIDATION.json +0 -12
- package/.agents/core/skills/redesign-audit/skill.yaml +0 -12
- package/.agents/core/skills/soft-design/SKILL.md +0 -108
- package/.agents/core/skills/soft-design/VALIDATION.json +0 -12
- package/.agents/core/skills/soft-design/skill.yaml +0 -12
- package/.agents/core/skills/state-management/EXAMPLES.md +0 -56
- package/.agents/core/skills/state-management/SKILL.md +0 -48
- package/.agents/core/skills/state-management/TROUBLESHOOTING.md +0 -18
- package/.agents/core/skills/state-management/VALIDATION.json +0 -11
- package/.agents/core/skills/state-management/skill.yaml +0 -28
- package/.agents/core/skills/subagent-orchestrator/SKILL.md +0 -117
- package/.agents/core/skills/subagent-orchestrator/VALIDATION.json +0 -12
- package/.agents/core/skills/subagent-orchestrator/skill.yaml +0 -12
- package/.agents/core/skills/system-design/EXAMPLES.md +0 -75
- package/.agents/core/skills/system-design/SKILL.md +0 -419
- package/.agents/core/skills/system-design/TROUBLESHOOTING.md +0 -19
- package/.agents/core/skills/system-design/VALIDATION.json +0 -12
- package/.agents/core/skills/system-design/skill.yaml +0 -20
- package/.agents/core/skills/system-design/system-design.md +0 -112
- package/.agents/core/skills/testing/EXAMPLES.md +0 -71
- package/.agents/core/skills/testing/SKILL.md +0 -70
- package/.agents/core/skills/testing/TROUBLESHOOTING.md +0 -18
- package/.agents/core/skills/testing/VALIDATION.json +0 -11
- package/.agents/core/skills/testing/skill.yaml +0 -32
- package/.agents/core/skills/typescript/EXAMPLES.md +0 -64
- package/.agents/core/skills/typescript/SKILL.md +0 -112
- package/.agents/core/skills/typescript/TROUBLESHOOTING.md +0 -19
- package/.agents/core/skills/typescript/VALIDATION.json +0 -12
- package/.agents/core/skills/typescript/skill.yaml +0 -17
- package/.agents/core/skills/typescript/typescript.md +0 -71
- package/.agents/core/skills/ui-design/EXAMPLES.md +0 -21
- package/.agents/core/skills/ui-design/SKILL.md +0 -124
- package/.agents/core/skills/ui-design/TROUBLESHOOTING.md +0 -19
- package/.agents/core/skills/ui-design/VALIDATION.json +0 -12
- package/.agents/core/skills/ui-design/skill.yaml +0 -17
- package/.agents/core/skills/ui-design/ui.md +0 -88
- package/.agents/core/skills/ui-ux-pro/EXAMPLES.md +0 -62
- package/.agents/core/skills/ui-ux-pro/SKILL.md +0 -375
- package/.agents/core/skills/ui-ux-pro/TROUBLESHOOTING.md +0 -19
- package/.agents/core/skills/ui-ux-pro/VALIDATION.json +0 -12
- package/.agents/core/skills/ui-ux-pro/skill.yaml +0 -19
- package/.agents/core/skills/ux-design/EXAMPLES.md +0 -36
- package/.agents/core/skills/ux-design/SKILL.md +0 -116
- package/.agents/core/skills/ux-design/TROUBLESHOOTING.md +0 -19
- package/.agents/core/skills/ux-design/VALIDATION.json +0 -12
- package/.agents/core/skills/ux-design/skill.yaml +0 -17
- package/.agents/core/skills/ux-design/ux.md +0 -80
- package/.agents/core/skills/vercel-optimize/SKILL.md +0 -83
- package/.agents/core/skills/vercel-optimize/VALIDATION.json +0 -12
- package/.agents/core/skills/vercel-optimize/scripts/collect-signals.mjs +0 -131
- package/.agents/core/skills/vercel-optimize/scripts/gate-investigations.mjs +0 -142
- package/.agents/core/skills/vercel-optimize/scripts/merge-signals.mjs +0 -143
- package/.agents/core/skills/vercel-optimize/scripts/scan-codebase.mjs +0 -174
- package/.agents/core/skills/vercel-optimize/skill.yaml +0 -18
- package/.agents/core/skills/web-accessibility/EXAMPLES.md +0 -39
- package/.agents/core/skills/web-accessibility/SKILL.md +0 -170
- package/.agents/core/skills/web-accessibility/TROUBLESHOOTING.md +0 -19
- package/.agents/core/skills/web-accessibility/VALIDATION.json +0 -12
- package/.agents/core/skills/web-accessibility/accessibility.md +0 -63
- package/.agents/core/skills/web-accessibility/skill.yaml +0 -17
- package/.agents/generated/claude/skills/adapters/SKILL.md +0 -126
- package/.agents/generated/claude/skills/architecture-diagrams/SKILL.md +0 -101
- package/.agents/generated/claude/skills/brutalist-design/SKILL.md +0 -145
- package/.agents/generated/claude/skills/database/SKILL.md +0 -191
- package/.agents/generated/claude/skills/ddd/SKILL.md +0 -305
- package/.agents/generated/claude/skills/decisions/SKILL.md +0 -134
- package/.agents/generated/claude/skills/docker/SKILL.md +0 -135
- package/.agents/generated/claude/skills/fastapi/SKILL.md +0 -200
- package/.agents/generated/claude/skills/generators/SKILL.md +0 -133
- package/.agents/generated/claude/skills/graphify/SKILL.md +0 -198
- package/.agents/generated/claude/skills/impeccable-design/SKILL.md +0 -241
- package/.agents/generated/claude/skills/interview-me/SKILL.md +0 -90
- package/.agents/generated/claude/skills/microservices/SKILL.md +0 -218
- package/.agents/generated/claude/skills/minimalist-design/SKILL.md +0 -108
- package/.agents/generated/claude/skills/nestjs/SKILL.md +0 -195
- package/.agents/generated/claude/skills/nextjs/SKILL.md +0 -219
- package/.agents/generated/claude/skills/node/SKILL.md +0 -224
- package/.agents/generated/claude/skills/performance/SKILL.md +0 -121
- package/.agents/generated/claude/skills/react/SKILL.md +0 -227
- package/.agents/generated/claude/skills/react-best-practices/SKILL.md +0 -146
- package/.agents/generated/claude/skills/redesign-audit/SKILL.md +0 -112
- package/.agents/generated/claude/skills/soft-design/SKILL.md +0 -103
- package/.agents/generated/claude/skills/state-management/SKILL.md +0 -120
- package/.agents/generated/claude/skills/subagent-orchestrator/SKILL.md +0 -110
- package/.agents/generated/claude/skills/system-design/SKILL.md +0 -507
- package/.agents/generated/claude/skills/testing/SKILL.md +0 -157
- package/.agents/generated/claude/skills/typescript/SKILL.md +0 -192
- package/.agents/generated/claude/skills/ui-design/SKILL.md +0 -161
- package/.agents/generated/claude/skills/ui-ux-pro/SKILL.md +0 -451
- package/.agents/generated/claude/skills/ux-design/SKILL.md +0 -168
- package/.agents/generated/claude/skills/vercel-optimize/SKILL.md +0 -76
- package/.agents/generated/claude/skills/web-accessibility/SKILL.md +0 -225
- package/.agents/generated/gemini/skills/adapters/SKILL.md +0 -135
- package/.agents/generated/gemini/skills/architecture-diagrams/SKILL.md +0 -107
- package/.agents/generated/gemini/skills/brutalist-design/SKILL.md +0 -151
- package/.agents/generated/gemini/skills/database/SKILL.md +0 -200
- package/.agents/generated/gemini/skills/ddd/SKILL.md +0 -314
- package/.agents/generated/gemini/skills/decisions/SKILL.md +0 -143
- package/.agents/generated/gemini/skills/docker/SKILL.md +0 -144
- package/.agents/generated/gemini/skills/fastapi/SKILL.md +0 -209
- package/.agents/generated/gemini/skills/generators/SKILL.md +0 -142
- package/.agents/generated/gemini/skills/graphify/SKILL.md +0 -205
- package/.agents/generated/gemini/skills/impeccable-design/SKILL.md +0 -250
- package/.agents/generated/gemini/skills/interview-me/SKILL.md +0 -96
- package/.agents/generated/gemini/skills/microservices/SKILL.md +0 -227
- package/.agents/generated/gemini/skills/minimalist-design/SKILL.md +0 -114
- package/.agents/generated/gemini/skills/nestjs/SKILL.md +0 -204
- package/.agents/generated/gemini/skills/nextjs/SKILL.md +0 -298
- package/.agents/generated/gemini/skills/node/SKILL.md +0 -323
- package/.agents/generated/gemini/skills/performance/SKILL.md +0 -185
- package/.agents/generated/gemini/skills/react/SKILL.md +0 -332
- package/.agents/generated/gemini/skills/react-best-practices/SKILL.md +0 -152
- package/.agents/generated/gemini/skills/redesign-audit/SKILL.md +0 -118
- package/.agents/generated/gemini/skills/soft-design/SKILL.md +0 -109
- package/.agents/generated/gemini/skills/state-management/SKILL.md +0 -129
- package/.agents/generated/gemini/skills/subagent-orchestrator/SKILL.md +0 -116
- package/.agents/generated/gemini/skills/system-design/SKILL.md +0 -631
- package/.agents/generated/gemini/skills/testing/SKILL.md +0 -166
- package/.agents/generated/gemini/skills/typescript/SKILL.md +0 -275
- package/.agents/generated/gemini/skills/ui-design/SKILL.md +0 -170
- package/.agents/generated/gemini/skills/ui-ux-pro/SKILL.md +0 -460
- package/.agents/generated/gemini/skills/ux-design/SKILL.md +0 -177
- package/.agents/generated/gemini/skills/vercel-optimize/SKILL.md +0 -82
- package/.agents/generated/gemini/skills/web-accessibility/SKILL.md +0 -300
package/.agents/plugins.js
CHANGED
|
@@ -25,6 +25,17 @@ const path = require('path');
|
|
|
25
25
|
const https = require('https');
|
|
26
26
|
const crypto = require('crypto');
|
|
27
27
|
const { execFileSync } = require('child_process');
|
|
28
|
+
const { ProjectMutationLock } = require('./filesystem/project-lock.js');
|
|
29
|
+
const JournaledTransaction = require('./filesystem/journaled-transaction.js');
|
|
30
|
+
const {
|
|
31
|
+
calculateTreeDigest,
|
|
32
|
+
validateArchiveEntry,
|
|
33
|
+
validatePluginPinning,
|
|
34
|
+
ScriptGrantManager,
|
|
35
|
+
AtomicPluginUpdater,
|
|
36
|
+
THREAT_CODES,
|
|
37
|
+
verifyNpmTarballIntegrity,
|
|
38
|
+
} = require('./transaction-core/plugin-supply-chain-bundle.js');
|
|
28
39
|
|
|
29
40
|
// ── Paths ─────────────────────────────────────────────────────────────────────
|
|
30
41
|
const ROOT = process.cwd();
|
|
@@ -51,12 +62,10 @@ const c = {
|
|
|
51
62
|
const PROMPT_INJECTION_PATTERNS = [
|
|
52
63
|
/ignore\s+(all\s+)?previous\s+instructions/i,
|
|
53
64
|
/forget\s+(all\s+)?previous/i,
|
|
54
|
-
/you\s+are\s+now/i,
|
|
55
|
-
/system\s*:\s*/i,
|
|
65
|
+
/you\s+are\s+now\s+(?:an?\s+)?(?:unrestricted|jailbreak|evil|dan|developer\s+mode|bypassed)/i,
|
|
56
66
|
/\[SYSTEM\]/i,
|
|
57
|
-
/
|
|
58
|
-
/https?:\/\/[^\s)]+\/(?:exfil|steal|leak|webhook|collect)/i,
|
|
59
|
-
/\b(?:eval|exec|Function)\s*\(/i,
|
|
67
|
+
/(?:^|[\r\n])\s*system\s*:\s*/i,
|
|
68
|
+
/https?:\/\/[^\s)]+\/(?:exfil|steal|leak|webhook|collect)\b/i,
|
|
60
69
|
];
|
|
61
70
|
|
|
62
71
|
// ── Shell Escapes & Script Injection Scanner ──────────────────────────────────
|
|
@@ -214,9 +223,19 @@ function readLock() {
|
|
|
214
223
|
}
|
|
215
224
|
}
|
|
216
225
|
|
|
217
|
-
function writeLock(lock) {
|
|
218
|
-
|
|
219
|
-
|
|
226
|
+
function writeLock(lock, tx = null) {
|
|
227
|
+
if (tx) {
|
|
228
|
+
const relLockPath = toPosix(path.relative(ROOT, PLUGINS_JSON));
|
|
229
|
+
tx.stageWrite(relLockPath, JSON.stringify(lock, null, 2) + '\n');
|
|
230
|
+
} else {
|
|
231
|
+
fs.mkdirSync(AGENTS_DIR, { recursive: true });
|
|
232
|
+
fs.writeFileSync(PLUGINS_JSON, JSON.stringify(lock, null, 2) + '\n');
|
|
233
|
+
}
|
|
234
|
+
}
|
|
235
|
+
|
|
236
|
+
// POSIX path helper
|
|
237
|
+
function toPosix(p) {
|
|
238
|
+
return p.replace(/\\/g, '/');
|
|
220
239
|
}
|
|
221
240
|
|
|
222
241
|
// ── HTTP fetch helper (no deps) ───────────────────────────────────────────────
|
|
@@ -293,7 +312,17 @@ function parseRef(ref) {
|
|
|
293
312
|
throw new Error('Invalid GitHub plugin reference');
|
|
294
313
|
}
|
|
295
314
|
|
|
296
|
-
|
|
315
|
+
const isPinned = repoRef.includes('@');
|
|
316
|
+
return {
|
|
317
|
+
type: 'github',
|
|
318
|
+
owner,
|
|
319
|
+
repo,
|
|
320
|
+
gitRef,
|
|
321
|
+
commit: isPinned ? gitRef : undefined,
|
|
322
|
+
isPinned,
|
|
323
|
+
subPath,
|
|
324
|
+
raw: ref,
|
|
325
|
+
};
|
|
297
326
|
}
|
|
298
327
|
// npm package
|
|
299
328
|
if (!isValidNpmPackage(ref)) {
|
|
@@ -303,7 +332,7 @@ function parseRef(ref) {
|
|
|
303
332
|
}
|
|
304
333
|
|
|
305
334
|
// ── GitHub installer ──────────────────────────────────────────────────────────
|
|
306
|
-
async function installFromGitHub(descriptor, skillName, dryRun, checksum, forceUnsafe = false) {
|
|
335
|
+
async function installFromGitHub(descriptor, skillName, dryRun, checksum, forceUnsafe = false, tx = null) {
|
|
307
336
|
const { owner, repo, gitRef, isPinned, subPath } = descriptor;
|
|
308
337
|
const skillPath = subPath || '';
|
|
309
338
|
const base = `https://raw.githubusercontent.com/${owner}/${repo}/${gitRef}`;
|
|
@@ -350,6 +379,7 @@ async function installFromGitHub(descriptor, skillName, dryRun, checksum, forceU
|
|
|
350
379
|
}
|
|
351
380
|
|
|
352
381
|
const targetDir = path.join(PLUGINS_DIR, skillName);
|
|
382
|
+
const relTargetDir = path.relative(ROOT, targetDir).replace(/\\/g, '/');
|
|
353
383
|
|
|
354
384
|
if (dryRun) {
|
|
355
385
|
console.log(c.yellow(` [DRY-RUN] Would install to: ${targetDir}`));
|
|
@@ -357,22 +387,47 @@ async function installFromGitHub(descriptor, skillName, dryRun, checksum, forceU
|
|
|
357
387
|
return sha256;
|
|
358
388
|
}
|
|
359
389
|
|
|
360
|
-
|
|
361
|
-
fs.
|
|
390
|
+
// Pre-scan using temp dir to keep `scanPluginDirectory` happy, as it reads from disk
|
|
391
|
+
const temporaryPrefix = fs.mkdtempSync(path.join(os.tmpdir(), 'contextos-github-'));
|
|
392
|
+
try {
|
|
393
|
+
fs.writeFileSync(path.join(temporaryPrefix, 'SKILL.md'), skillMdContent);
|
|
394
|
+
if (yamlContent) fs.writeFileSync(path.join(temporaryPrefix, 'skill.yaml'), yamlContent);
|
|
395
|
+
scanPluginDirectory(temporaryPrefix, { throwOnMatch: !forceUnsafe, forceUnsafe });
|
|
396
|
+
} finally {
|
|
397
|
+
fs.rmSync(temporaryPrefix, { recursive: true, force: true });
|
|
398
|
+
}
|
|
399
|
+
|
|
400
|
+
const manifest = {};
|
|
401
|
+
|
|
402
|
+
const skillMdHash = crypto.createHash('sha256').update(skillMdContent).digest('hex');
|
|
403
|
+
tx.stageWrite(`${relTargetDir}/SKILL.md`, skillMdContent);
|
|
404
|
+
manifest['SKILL.md'] = skillMdHash;
|
|
405
|
+
|
|
362
406
|
if (yamlContent) {
|
|
363
|
-
|
|
407
|
+
const yamlHash = crypto.createHash('sha256').update(yamlContent).digest('hex');
|
|
408
|
+
tx.stageWrite(`${relTargetDir}/skill.yaml`, yamlContent);
|
|
409
|
+
manifest['skill.yaml'] = yamlHash;
|
|
364
410
|
}
|
|
365
411
|
|
|
366
|
-
//
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
|
|
370
|
-
|
|
371
|
-
|
|
412
|
+
// Also try to fetch standard ancillary files if present
|
|
413
|
+
const ancillaryFiles = ['EXAMPLES.md', 'TROUBLESHOOTING.md', 'VALIDATION.json'];
|
|
414
|
+
for (const f of ancillaryFiles) {
|
|
415
|
+
const fUrl = skillPath ? `${base}/${skillPath}/${f}` : `${base}/${f}`;
|
|
416
|
+
try {
|
|
417
|
+
const fContent = await fetchText(fUrl);
|
|
418
|
+
if (fContent && fContent.length > 0) {
|
|
419
|
+
scanForPromptInjection(fContent, { throwOnMatch: !forceUnsafe });
|
|
420
|
+
const fHash = crypto.createHash('sha256').update(fContent).digest('hex');
|
|
421
|
+
tx.stageWrite(`${relTargetDir}/${f}`, fContent);
|
|
422
|
+
manifest[f] = fHash;
|
|
423
|
+
}
|
|
424
|
+
} catch {
|
|
425
|
+
// Ancillary files are optional
|
|
426
|
+
}
|
|
372
427
|
}
|
|
373
428
|
|
|
374
|
-
// Write a source marker
|
|
375
|
-
|
|
429
|
+
// Write a source marker with manifest
|
|
430
|
+
const sourceContent = JSON.stringify({
|
|
376
431
|
type: 'github',
|
|
377
432
|
owner,
|
|
378
433
|
repo,
|
|
@@ -381,7 +436,9 @@ async function installFromGitHub(descriptor, skillName, dryRun, checksum, forceU
|
|
|
381
436
|
ref: descriptor.raw,
|
|
382
437
|
sha256,
|
|
383
438
|
installedAt: new Date().toISOString(),
|
|
384
|
-
|
|
439
|
+
manifest,
|
|
440
|
+
}, null, 2);
|
|
441
|
+
tx.stageWrite(`${relTargetDir}/.source`, sourceContent);
|
|
385
442
|
|
|
386
443
|
console.log(c.green(` ✓ Installed SKILL.md (${skillMdContent.length} bytes, sha256: ${sha256.slice(0, 12)}...)`));
|
|
387
444
|
if (yamlContent) console.log(c.green(` ✓ Installed skill.yaml`));
|
|
@@ -389,12 +446,15 @@ async function installFromGitHub(descriptor, skillName, dryRun, checksum, forceU
|
|
|
389
446
|
}
|
|
390
447
|
|
|
391
448
|
// ── npm installer ─────────────────────────────────────────────────────────────
|
|
392
|
-
function installFromNpm(descriptor, skillName, dryRun, checksum, forceUnsafe = false) {
|
|
449
|
+
function installFromNpm(descriptor, skillName, dryRun, checksum, forceUnsafe = false, tx = null) {
|
|
393
450
|
const pkgName = descriptor.package;
|
|
394
451
|
|
|
452
|
+
const targetDir = path.join(PLUGINS_DIR, skillName);
|
|
453
|
+
const relTargetDir = path.relative(ROOT, targetDir).replace(/\\/g, '/');
|
|
454
|
+
|
|
395
455
|
if (dryRun) {
|
|
396
456
|
console.log(c.yellow(` [DRY-RUN] Would run: npm install ${pkgName}`));
|
|
397
|
-
console.log(c.yellow(` [DRY-RUN] Would copy skill to: ${
|
|
457
|
+
console.log(c.yellow(` [DRY-RUN] Would copy skill to: ${targetDir}`));
|
|
398
458
|
return null;
|
|
399
459
|
}
|
|
400
460
|
|
|
@@ -428,19 +488,39 @@ function installFromNpm(descriptor, skillName, dryRun, checksum, forceUnsafe = f
|
|
|
428
488
|
// Deep security scan across all plugin files (EXAMPLES.md, TROUBLESHOOTING.md, references/, symlinks)
|
|
429
489
|
scanPluginDirectory(skillSrc, { throwOnMatch: !forceUnsafe, forceUnsafe });
|
|
430
490
|
|
|
431
|
-
const
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
491
|
+
const manifest = {};
|
|
492
|
+
|
|
493
|
+
// Helper to walk and stage all files
|
|
494
|
+
const stageRecursive = (dir, relBase) => {
|
|
495
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
496
|
+
if (entry.name === '.git' || entry.name === 'node_modules') continue;
|
|
497
|
+
const fullPath = path.join(dir, entry.name);
|
|
498
|
+
const entryRel = relBase ? `${relBase}/${entry.name}` : entry.name;
|
|
499
|
+
|
|
500
|
+
if (entry.isDirectory()) {
|
|
501
|
+
stageRecursive(fullPath, entryRel);
|
|
502
|
+
} else if (entry.isFile() || entry.isSymbolicLink()) {
|
|
503
|
+
// Read content to stage it
|
|
504
|
+
const content = fs.readFileSync(fullPath);
|
|
505
|
+
const hash = crypto.createHash('sha256').update(content).digest('hex');
|
|
506
|
+
tx.stageWrite(`${relTargetDir}/${entryRel}`, content);
|
|
507
|
+
manifest[entryRel] = hash;
|
|
508
|
+
}
|
|
509
|
+
}
|
|
510
|
+
};
|
|
511
|
+
|
|
512
|
+
stageRecursive(skillSrc, '');
|
|
435
513
|
|
|
436
514
|
// Write source marker
|
|
437
|
-
|
|
515
|
+
const sourceContent = JSON.stringify({
|
|
438
516
|
type: 'npm',
|
|
439
517
|
package: pkgName,
|
|
440
518
|
ref: descriptor.raw,
|
|
441
519
|
sha256,
|
|
442
520
|
installedAt: new Date().toISOString(),
|
|
443
|
-
|
|
521
|
+
manifest,
|
|
522
|
+
}, null, 2);
|
|
523
|
+
tx.stageWrite(`${relTargetDir}/.source`, sourceContent);
|
|
444
524
|
} finally {
|
|
445
525
|
fs.rmSync(temporaryPrefix, { recursive: true, force: true });
|
|
446
526
|
}
|
|
@@ -473,6 +553,8 @@ async function add(ref, options = {}) {
|
|
|
473
553
|
const dryRun = Boolean(options.dryRun || options['dry-run']);
|
|
474
554
|
const checksum = options.checksum || null;
|
|
475
555
|
const forceUnsafe = Boolean(options.forceUnsafe || options['force-unsafe-prompts']);
|
|
556
|
+
const allowFloating = Boolean(options.allowFloating || options['allow-floating']);
|
|
557
|
+
const force = Boolean(options.force);
|
|
476
558
|
|
|
477
559
|
if (!ref) {
|
|
478
560
|
console.error(c.red('Usage: ctx.js skill add <ref> [--checksum <sha256>]'));
|
|
@@ -487,6 +569,27 @@ async function add(ref, options = {}) {
|
|
|
487
569
|
throw new Error(`Invalid plugin name derived from reference: '${skillName}'`);
|
|
488
570
|
}
|
|
489
571
|
|
|
572
|
+
// Supply-chain source pinning check (Wave 6)
|
|
573
|
+
if (!dryRun) {
|
|
574
|
+
const pinning = validatePluginPinning(
|
|
575
|
+
{
|
|
576
|
+
type: descriptor.type,
|
|
577
|
+
commit: descriptor.commit,
|
|
578
|
+
version: descriptor.version,
|
|
579
|
+
integrity: descriptor.integrity,
|
|
580
|
+
},
|
|
581
|
+
{ allowFloating }
|
|
582
|
+
);
|
|
583
|
+
|
|
584
|
+
if (!pinning.valid) {
|
|
585
|
+
console.error(c.red(`\n[ERROR] Supply-chain pinning check failed: ${pinning.error}`));
|
|
586
|
+
if (pinning.code === THREAT_CODES.FLOATING_SOURCE_BLOCKED) {
|
|
587
|
+
console.error(c.yellow(' Pass --allow-floating to override this check with explicit user consent.'));
|
|
588
|
+
}
|
|
589
|
+
process.exit(1);
|
|
590
|
+
}
|
|
591
|
+
}
|
|
592
|
+
|
|
490
593
|
console.log('');
|
|
491
594
|
console.log(c.bold(`Installing skill: ${c.cyan(skillName)}`));
|
|
492
595
|
console.log(c.dim(` Source: ${ref} (${descriptor.type})`));
|
|
@@ -503,45 +606,86 @@ async function add(ref, options = {}) {
|
|
|
503
606
|
// Check if already installed
|
|
504
607
|
const lock = readLock();
|
|
505
608
|
const existing = lock.plugins.find(p => p.name === skillName);
|
|
609
|
+
const targetDir = path.join(PLUGINS_DIR, skillName);
|
|
610
|
+
|
|
506
611
|
if (existing && !dryRun) {
|
|
612
|
+
// Check for local modifications (Wave 6 / Section 20.7)
|
|
613
|
+
if (fs.existsSync(targetDir) && existing.treeDigest && !force) {
|
|
614
|
+
if (AtomicPluginUpdater.isModifiedLocally(targetDir, existing.treeDigest)) {
|
|
615
|
+
const conflictFile = path.join(targetDir, 'CONFLICT_LOCAL_MODIFICATIONS.md');
|
|
616
|
+
fs.writeFileSync(
|
|
617
|
+
conflictFile,
|
|
618
|
+
`# Conflict: Local Modifications Detected\n\nPlugin "${skillName}" contains local uncommitted modifications.\nAutomatic update was blocked to preserve your changes.\n\nTo overwrite local modifications, re-run with --force.\n`,
|
|
619
|
+
'utf8'
|
|
620
|
+
);
|
|
621
|
+
console.error(c.red(`\n[ERROR] Plugin in "${targetDir}" has local modifications.`));
|
|
622
|
+
console.error(c.red(` Update blocked to prevent overwriting user changes.`));
|
|
623
|
+
console.error(c.yellow(` Conflict artifact written to: ${conflictFile}`));
|
|
624
|
+
console.error(c.yellow(` Pass --force to overwrite.`));
|
|
625
|
+
process.exit(1);
|
|
626
|
+
}
|
|
627
|
+
}
|
|
507
628
|
console.log(c.yellow(`\n[WARN] '${skillName}' is already installed (from: ${existing.ref})`));
|
|
508
629
|
console.log(c.yellow(' Re-installing will overwrite it. Continuing...'));
|
|
509
630
|
}
|
|
510
631
|
|
|
511
|
-
|
|
632
|
+
const projectLock = new ProjectMutationLock(ROOT);
|
|
633
|
+
const tx = new JournaledTransaction(ROOT);
|
|
634
|
+
let lockToken = null;
|
|
635
|
+
|
|
512
636
|
try {
|
|
637
|
+
lockToken = projectLock.acquire({ command: 'skill:add' });
|
|
638
|
+
|
|
639
|
+
let installedSha256 = null;
|
|
513
640
|
if (descriptor.type === 'github') {
|
|
514
|
-
installedSha256 = await installFromGitHub(descriptor, skillName, dryRun, checksum, forceUnsafe);
|
|
641
|
+
installedSha256 = await installFromGitHub(descriptor, skillName, dryRun, checksum, forceUnsafe, tx);
|
|
515
642
|
} else {
|
|
516
|
-
installedSha256 = installFromNpm(descriptor, skillName, dryRun, checksum, forceUnsafe);
|
|
643
|
+
installedSha256 = installFromNpm(descriptor, skillName, dryRun, checksum, forceUnsafe, tx);
|
|
644
|
+
}
|
|
645
|
+
|
|
646
|
+
if (!dryRun) {
|
|
647
|
+
// Update lock file
|
|
648
|
+
const idx = lock.plugins.findIndex(p => p.name === skillName);
|
|
649
|
+
const entry = {
|
|
650
|
+
name: skillName,
|
|
651
|
+
ref,
|
|
652
|
+
type: descriptor.type,
|
|
653
|
+
commit: descriptor.commit,
|
|
654
|
+
version: descriptor.version,
|
|
655
|
+
integrity: descriptor.integrity,
|
|
656
|
+
sha256: installedSha256,
|
|
657
|
+
installedAt: new Date().toISOString(),
|
|
658
|
+
};
|
|
659
|
+
if (idx >= 0) lock.plugins[idx] = entry;
|
|
660
|
+
else lock.plugins.push(entry);
|
|
661
|
+
|
|
662
|
+
writeLock(lock, tx);
|
|
663
|
+
tx.commit();
|
|
664
|
+
|
|
665
|
+
// Compute and record full-tree digest into lock
|
|
666
|
+
if (fs.existsSync(targetDir)) {
|
|
667
|
+
const digestResult = calculateTreeDigest(targetDir);
|
|
668
|
+
entry.treeDigest = digestResult.treeDigest;
|
|
669
|
+
writeLock(lock);
|
|
670
|
+
}
|
|
671
|
+
|
|
672
|
+
console.log('');
|
|
673
|
+
console.log(c.green(c.bold('✓ Skill installed successfully!')));
|
|
674
|
+
console.log(c.dim(` Location: .agents/plugins/${skillName}/`));
|
|
675
|
+
console.log('');
|
|
676
|
+
console.log(' Next steps:');
|
|
677
|
+
console.log(` node .agents/ctx.js export all # recompile with new skill`);
|
|
678
|
+
console.log(` node .agents/ctx.js validate # verify everything is consistent`);
|
|
679
|
+
console.log('');
|
|
517
680
|
}
|
|
518
681
|
} catch (err) {
|
|
682
|
+
if (tx && tx.state === 'PLANNED') {
|
|
683
|
+
// We don't need to do anything since it wasn't committed
|
|
684
|
+
}
|
|
519
685
|
console.error(c.red(`\n[ERROR] Failed to install '${skillName}': ${err.message}`));
|
|
520
686
|
process.exit(1);
|
|
521
|
-
}
|
|
522
|
-
|
|
523
|
-
if (!dryRun) {
|
|
524
|
-
// Update lock file
|
|
525
|
-
const idx = lock.plugins.findIndex(p => p.name === skillName);
|
|
526
|
-
const entry = {
|
|
527
|
-
name: skillName,
|
|
528
|
-
ref,
|
|
529
|
-
type: descriptor.type,
|
|
530
|
-
sha256: installedSha256,
|
|
531
|
-
installedAt: new Date().toISOString(),
|
|
532
|
-
};
|
|
533
|
-
if (idx >= 0) lock.plugins[idx] = entry;
|
|
534
|
-
else lock.plugins.push(entry);
|
|
535
|
-
writeLock(lock);
|
|
536
|
-
|
|
537
|
-
console.log('');
|
|
538
|
-
console.log(c.green(c.bold('✓ Skill installed successfully!')));
|
|
539
|
-
console.log(c.dim(` Location: .agents/plugins/${skillName}/`));
|
|
540
|
-
console.log('');
|
|
541
|
-
console.log(' Next steps:');
|
|
542
|
-
console.log(` node .agents/ctx.js export all # recompile with new skill`);
|
|
543
|
-
console.log(` node .agents/ctx.js validate # verify everything is consistent`);
|
|
544
|
-
console.log('');
|
|
687
|
+
} finally {
|
|
688
|
+
if (lockToken) projectLock.release(lockToken);
|
|
545
689
|
}
|
|
546
690
|
}
|
|
547
691
|
|
|
@@ -576,15 +720,85 @@ function remove(skillName) {
|
|
|
576
720
|
process.exit(1);
|
|
577
721
|
}
|
|
578
722
|
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
723
|
+
const projectLock = new ProjectMutationLock(ROOT);
|
|
724
|
+
const tx = new JournaledTransaction(ROOT);
|
|
725
|
+
let lockToken = null;
|
|
726
|
+
|
|
727
|
+
try {
|
|
728
|
+
lockToken = projectLock.acquire({ command: 'skill:remove' });
|
|
582
729
|
|
|
583
|
-
|
|
584
|
-
|
|
730
|
+
if (fs.existsSync(skillDir)) {
|
|
731
|
+
// Find the manifest if it exists
|
|
732
|
+
const sourceFile = path.join(skillDir, '.source');
|
|
733
|
+
let manifest = null;
|
|
734
|
+
if (fs.existsSync(sourceFile)) {
|
|
735
|
+
try {
|
|
736
|
+
const sourceData = JSON.parse(fs.readFileSync(sourceFile, 'utf8'));
|
|
737
|
+
manifest = sourceData.manifest || null;
|
|
738
|
+
} catch {}
|
|
739
|
+
}
|
|
740
|
+
|
|
741
|
+
const stageRecursiveDeletes = (dir, relBase) => {
|
|
742
|
+
let hasPreservedFiles = false;
|
|
743
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
744
|
+
const fullPath = path.join(dir, entry.name);
|
|
745
|
+
const entryRel = relBase ? `${relBase}/${entry.name}` : entry.name;
|
|
746
|
+
|
|
747
|
+
if (entry.isDirectory()) {
|
|
748
|
+
const preserved = stageRecursiveDeletes(fullPath, entryRel);
|
|
749
|
+
if (preserved) hasPreservedFiles = true;
|
|
750
|
+
else tx.stageDeleteDir(toPosix(path.relative(ROOT, fullPath)));
|
|
751
|
+
} else {
|
|
752
|
+
// Check against manifest
|
|
753
|
+
let shouldDelete = false;
|
|
754
|
+
if (manifest && manifest[entryRel]) {
|
|
755
|
+
const currentHash = crypto.createHash('sha256').update(fs.readFileSync(fullPath)).digest('hex');
|
|
756
|
+
if (currentHash === manifest[entryRel]) {
|
|
757
|
+
shouldDelete = true;
|
|
758
|
+
}
|
|
759
|
+
} else if (!manifest) {
|
|
760
|
+
// If we have NO manifest, we fallback to W3.4 "Remove не удаляет modified/unmanaged files"
|
|
761
|
+
// But without a manifest, we don't know what was installed vs modified.
|
|
762
|
+
// We'll safely skip all files unless we can confidently delete them, OR we can just assume
|
|
763
|
+
// if it's the exact SHA256 of SKILL.md, delete it. But it's safer to only delete known things.
|
|
764
|
+
// We'll just delete SKILL.md and skill.yaml if they match the lockfile hash
|
|
765
|
+
if (entry.name === 'SKILL.md' || entry.name === 'skill.yaml' || entry.name === '.source') {
|
|
766
|
+
shouldDelete = true;
|
|
767
|
+
}
|
|
768
|
+
}
|
|
769
|
+
|
|
770
|
+
if (entry.name === '.source') shouldDelete = true;
|
|
771
|
+
|
|
772
|
+
if (shouldDelete) {
|
|
773
|
+
tx.stageDelete(toPosix(path.relative(ROOT, fullPath)));
|
|
774
|
+
} else {
|
|
775
|
+
hasPreservedFiles = true;
|
|
776
|
+
console.log(c.yellow(` [WARN] Preserving modified/unmanaged file: ${entryRel}`));
|
|
777
|
+
}
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
return hasPreservedFiles;
|
|
781
|
+
};
|
|
585
782
|
|
|
586
|
-
|
|
587
|
-
|
|
783
|
+
const preserved = stageRecursiveDeletes(skillDir, '');
|
|
784
|
+
if (!preserved) {
|
|
785
|
+
tx.stageDeleteDir(toPosix(path.relative(ROOT, skillDir)));
|
|
786
|
+
}
|
|
787
|
+
}
|
|
788
|
+
|
|
789
|
+
lock.plugins = lock.plugins.filter(p => p.name !== skillName);
|
|
790
|
+
writeLock(lock, tx);
|
|
791
|
+
|
|
792
|
+
tx.commit();
|
|
793
|
+
|
|
794
|
+
console.log(c.green(`✓ Removed plugin: ${skillName}`));
|
|
795
|
+
console.log(c.dim(' Run: node .agents/ctx.js export all (to recompile)'));
|
|
796
|
+
} catch (err) {
|
|
797
|
+
console.error(c.red(`\n[ERROR] Failed to remove '${skillName}': ${err.message}`));
|
|
798
|
+
process.exit(1);
|
|
799
|
+
} finally {
|
|
800
|
+
if (lockToken) projectLock.release(lockToken);
|
|
801
|
+
}
|
|
588
802
|
}
|
|
589
803
|
|
|
590
804
|
/**
|