contextos-agents 1.7.0 → 2.0.0-beta.2
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 +1 -1
- 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 +80 -101
- 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 +574 -111
- package/.agents/customization-dx.js +282 -0
- package/.agents/doctor.js +719 -64
- 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 +259 -60
- package/.agents/profiles.js +486 -51
- package/.agents/resolver.js +50 -534
- 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/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 +85 -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();
|
|
@@ -214,9 +225,19 @@ function readLock() {
|
|
|
214
225
|
}
|
|
215
226
|
}
|
|
216
227
|
|
|
217
|
-
function writeLock(lock) {
|
|
218
|
-
|
|
219
|
-
|
|
228
|
+
function writeLock(lock, tx = null) {
|
|
229
|
+
if (tx) {
|
|
230
|
+
const relLockPath = toPosix(path.relative(ROOT, PLUGINS_JSON));
|
|
231
|
+
tx.stageWrite(relLockPath, JSON.stringify(lock, null, 2) + '\n');
|
|
232
|
+
} else {
|
|
233
|
+
fs.mkdirSync(AGENTS_DIR, { recursive: true });
|
|
234
|
+
fs.writeFileSync(PLUGINS_JSON, JSON.stringify(lock, null, 2) + '\n');
|
|
235
|
+
}
|
|
236
|
+
}
|
|
237
|
+
|
|
238
|
+
// POSIX path helper
|
|
239
|
+
function toPosix(p) {
|
|
240
|
+
return p.replace(/\\/g, '/');
|
|
220
241
|
}
|
|
221
242
|
|
|
222
243
|
// ── HTTP fetch helper (no deps) ───────────────────────────────────────────────
|
|
@@ -293,7 +314,17 @@ function parseRef(ref) {
|
|
|
293
314
|
throw new Error('Invalid GitHub plugin reference');
|
|
294
315
|
}
|
|
295
316
|
|
|
296
|
-
|
|
317
|
+
const isPinned = repoRef.includes('@');
|
|
318
|
+
return {
|
|
319
|
+
type: 'github',
|
|
320
|
+
owner,
|
|
321
|
+
repo,
|
|
322
|
+
gitRef,
|
|
323
|
+
commit: isPinned ? gitRef : undefined,
|
|
324
|
+
isPinned,
|
|
325
|
+
subPath,
|
|
326
|
+
raw: ref,
|
|
327
|
+
};
|
|
297
328
|
}
|
|
298
329
|
// npm package
|
|
299
330
|
if (!isValidNpmPackage(ref)) {
|
|
@@ -303,7 +334,7 @@ function parseRef(ref) {
|
|
|
303
334
|
}
|
|
304
335
|
|
|
305
336
|
// ── GitHub installer ──────────────────────────────────────────────────────────
|
|
306
|
-
async function installFromGitHub(descriptor, skillName, dryRun, checksum, forceUnsafe = false) {
|
|
337
|
+
async function installFromGitHub(descriptor, skillName, dryRun, checksum, forceUnsafe = false, tx = null) {
|
|
307
338
|
const { owner, repo, gitRef, isPinned, subPath } = descriptor;
|
|
308
339
|
const skillPath = subPath || '';
|
|
309
340
|
const base = `https://raw.githubusercontent.com/${owner}/${repo}/${gitRef}`;
|
|
@@ -350,6 +381,7 @@ async function installFromGitHub(descriptor, skillName, dryRun, checksum, forceU
|
|
|
350
381
|
}
|
|
351
382
|
|
|
352
383
|
const targetDir = path.join(PLUGINS_DIR, skillName);
|
|
384
|
+
const relTargetDir = path.relative(ROOT, targetDir).replace(/\\/g, '/');
|
|
353
385
|
|
|
354
386
|
if (dryRun) {
|
|
355
387
|
console.log(c.yellow(` [DRY-RUN] Would install to: ${targetDir}`));
|
|
@@ -357,22 +389,30 @@ async function installFromGitHub(descriptor, skillName, dryRun, checksum, forceU
|
|
|
357
389
|
return sha256;
|
|
358
390
|
}
|
|
359
391
|
|
|
360
|
-
|
|
361
|
-
fs.
|
|
362
|
-
|
|
363
|
-
fs.writeFileSync(path.join(
|
|
392
|
+
// Pre-scan using temp dir to keep `scanPluginDirectory` happy, as it reads from disk
|
|
393
|
+
const temporaryPrefix = fs.mkdtempSync(path.join(os.tmpdir(), 'contextos-github-'));
|
|
394
|
+
try {
|
|
395
|
+
fs.writeFileSync(path.join(temporaryPrefix, 'SKILL.md'), skillMdContent);
|
|
396
|
+
if (yamlContent) fs.writeFileSync(path.join(temporaryPrefix, 'skill.yaml'), yamlContent);
|
|
397
|
+
scanPluginDirectory(temporaryPrefix, { throwOnMatch: !forceUnsafe, forceUnsafe });
|
|
398
|
+
} finally {
|
|
399
|
+
fs.rmSync(temporaryPrefix, { recursive: true, force: true });
|
|
364
400
|
}
|
|
365
401
|
|
|
366
|
-
|
|
367
|
-
|
|
368
|
-
|
|
369
|
-
}
|
|
370
|
-
|
|
371
|
-
|
|
402
|
+
const manifest = {};
|
|
403
|
+
|
|
404
|
+
const skillMdHash = crypto.createHash('sha256').update(skillMdContent).digest('hex');
|
|
405
|
+
tx.stageWrite(`${relTargetDir}/SKILL.md`, skillMdContent);
|
|
406
|
+
manifest['SKILL.md'] = skillMdHash;
|
|
407
|
+
|
|
408
|
+
if (yamlContent) {
|
|
409
|
+
const yamlHash = crypto.createHash('sha256').update(yamlContent).digest('hex');
|
|
410
|
+
tx.stageWrite(`${relTargetDir}/skill.yaml`, yamlContent);
|
|
411
|
+
manifest['skill.yaml'] = yamlHash;
|
|
372
412
|
}
|
|
373
413
|
|
|
374
|
-
// Write a source marker
|
|
375
|
-
|
|
414
|
+
// Write a source marker with manifest
|
|
415
|
+
const sourceContent = JSON.stringify({
|
|
376
416
|
type: 'github',
|
|
377
417
|
owner,
|
|
378
418
|
repo,
|
|
@@ -381,7 +421,9 @@ async function installFromGitHub(descriptor, skillName, dryRun, checksum, forceU
|
|
|
381
421
|
ref: descriptor.raw,
|
|
382
422
|
sha256,
|
|
383
423
|
installedAt: new Date().toISOString(),
|
|
384
|
-
|
|
424
|
+
manifest,
|
|
425
|
+
}, null, 2);
|
|
426
|
+
tx.stageWrite(`${relTargetDir}/.source`, sourceContent);
|
|
385
427
|
|
|
386
428
|
console.log(c.green(` ✓ Installed SKILL.md (${skillMdContent.length} bytes, sha256: ${sha256.slice(0, 12)}...)`));
|
|
387
429
|
if (yamlContent) console.log(c.green(` ✓ Installed skill.yaml`));
|
|
@@ -389,12 +431,15 @@ async function installFromGitHub(descriptor, skillName, dryRun, checksum, forceU
|
|
|
389
431
|
}
|
|
390
432
|
|
|
391
433
|
// ── npm installer ─────────────────────────────────────────────────────────────
|
|
392
|
-
function installFromNpm(descriptor, skillName, dryRun, checksum, forceUnsafe = false) {
|
|
434
|
+
function installFromNpm(descriptor, skillName, dryRun, checksum, forceUnsafe = false, tx = null) {
|
|
393
435
|
const pkgName = descriptor.package;
|
|
394
436
|
|
|
437
|
+
const targetDir = path.join(PLUGINS_DIR, skillName);
|
|
438
|
+
const relTargetDir = path.relative(ROOT, targetDir).replace(/\\/g, '/');
|
|
439
|
+
|
|
395
440
|
if (dryRun) {
|
|
396
441
|
console.log(c.yellow(` [DRY-RUN] Would run: npm install ${pkgName}`));
|
|
397
|
-
console.log(c.yellow(` [DRY-RUN] Would copy skill to: ${
|
|
442
|
+
console.log(c.yellow(` [DRY-RUN] Would copy skill to: ${targetDir}`));
|
|
398
443
|
return null;
|
|
399
444
|
}
|
|
400
445
|
|
|
@@ -428,19 +473,39 @@ function installFromNpm(descriptor, skillName, dryRun, checksum, forceUnsafe = f
|
|
|
428
473
|
// Deep security scan across all plugin files (EXAMPLES.md, TROUBLESHOOTING.md, references/, symlinks)
|
|
429
474
|
scanPluginDirectory(skillSrc, { throwOnMatch: !forceUnsafe, forceUnsafe });
|
|
430
475
|
|
|
431
|
-
const
|
|
432
|
-
|
|
433
|
-
|
|
434
|
-
|
|
476
|
+
const manifest = {};
|
|
477
|
+
|
|
478
|
+
// Helper to walk and stage all files
|
|
479
|
+
const stageRecursive = (dir, relBase) => {
|
|
480
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
481
|
+
if (entry.name === '.git' || entry.name === 'node_modules') continue;
|
|
482
|
+
const fullPath = path.join(dir, entry.name);
|
|
483
|
+
const entryRel = relBase ? `${relBase}/${entry.name}` : entry.name;
|
|
484
|
+
|
|
485
|
+
if (entry.isDirectory()) {
|
|
486
|
+
stageRecursive(fullPath, entryRel);
|
|
487
|
+
} else if (entry.isFile() || entry.isSymbolicLink()) {
|
|
488
|
+
// Read content to stage it
|
|
489
|
+
const content = fs.readFileSync(fullPath);
|
|
490
|
+
const hash = crypto.createHash('sha256').update(content).digest('hex');
|
|
491
|
+
tx.stageWrite(`${relTargetDir}/${entryRel}`, content);
|
|
492
|
+
manifest[entryRel] = hash;
|
|
493
|
+
}
|
|
494
|
+
}
|
|
495
|
+
};
|
|
496
|
+
|
|
497
|
+
stageRecursive(skillSrc, '');
|
|
435
498
|
|
|
436
499
|
// Write source marker
|
|
437
|
-
|
|
500
|
+
const sourceContent = JSON.stringify({
|
|
438
501
|
type: 'npm',
|
|
439
502
|
package: pkgName,
|
|
440
503
|
ref: descriptor.raw,
|
|
441
504
|
sha256,
|
|
442
505
|
installedAt: new Date().toISOString(),
|
|
443
|
-
|
|
506
|
+
manifest,
|
|
507
|
+
}, null, 2);
|
|
508
|
+
tx.stageWrite(`${relTargetDir}/.source`, sourceContent);
|
|
444
509
|
} finally {
|
|
445
510
|
fs.rmSync(temporaryPrefix, { recursive: true, force: true });
|
|
446
511
|
}
|
|
@@ -473,6 +538,8 @@ async function add(ref, options = {}) {
|
|
|
473
538
|
const dryRun = Boolean(options.dryRun || options['dry-run']);
|
|
474
539
|
const checksum = options.checksum || null;
|
|
475
540
|
const forceUnsafe = Boolean(options.forceUnsafe || options['force-unsafe-prompts']);
|
|
541
|
+
const allowFloating = Boolean(options.allowFloating || options['allow-floating']);
|
|
542
|
+
const force = Boolean(options.force);
|
|
476
543
|
|
|
477
544
|
if (!ref) {
|
|
478
545
|
console.error(c.red('Usage: ctx.js skill add <ref> [--checksum <sha256>]'));
|
|
@@ -487,6 +554,27 @@ async function add(ref, options = {}) {
|
|
|
487
554
|
throw new Error(`Invalid plugin name derived from reference: '${skillName}'`);
|
|
488
555
|
}
|
|
489
556
|
|
|
557
|
+
// Supply-chain source pinning check (Wave 6)
|
|
558
|
+
if (!dryRun) {
|
|
559
|
+
const pinning = validatePluginPinning(
|
|
560
|
+
{
|
|
561
|
+
type: descriptor.type,
|
|
562
|
+
commit: descriptor.commit,
|
|
563
|
+
version: descriptor.version,
|
|
564
|
+
integrity: descriptor.integrity,
|
|
565
|
+
},
|
|
566
|
+
{ allowFloating }
|
|
567
|
+
);
|
|
568
|
+
|
|
569
|
+
if (!pinning.valid) {
|
|
570
|
+
console.error(c.red(`\n[ERROR] Supply-chain pinning check failed: ${pinning.error}`));
|
|
571
|
+
if (pinning.code === THREAT_CODES.FLOATING_SOURCE_BLOCKED) {
|
|
572
|
+
console.error(c.yellow(' Pass --allow-floating to override this check with explicit user consent.'));
|
|
573
|
+
}
|
|
574
|
+
process.exit(1);
|
|
575
|
+
}
|
|
576
|
+
}
|
|
577
|
+
|
|
490
578
|
console.log('');
|
|
491
579
|
console.log(c.bold(`Installing skill: ${c.cyan(skillName)}`));
|
|
492
580
|
console.log(c.dim(` Source: ${ref} (${descriptor.type})`));
|
|
@@ -503,45 +591,86 @@ async function add(ref, options = {}) {
|
|
|
503
591
|
// Check if already installed
|
|
504
592
|
const lock = readLock();
|
|
505
593
|
const existing = lock.plugins.find(p => p.name === skillName);
|
|
594
|
+
const targetDir = path.join(PLUGINS_DIR, skillName);
|
|
595
|
+
|
|
506
596
|
if (existing && !dryRun) {
|
|
597
|
+
// Check for local modifications (Wave 6 / Section 20.7)
|
|
598
|
+
if (fs.existsSync(targetDir) && existing.treeDigest && !force) {
|
|
599
|
+
if (AtomicPluginUpdater.isModifiedLocally(targetDir, existing.treeDigest)) {
|
|
600
|
+
const conflictFile = path.join(targetDir, 'CONFLICT_LOCAL_MODIFICATIONS.md');
|
|
601
|
+
fs.writeFileSync(
|
|
602
|
+
conflictFile,
|
|
603
|
+
`# 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`,
|
|
604
|
+
'utf8'
|
|
605
|
+
);
|
|
606
|
+
console.error(c.red(`\n[ERROR] Plugin in "${targetDir}" has local modifications.`));
|
|
607
|
+
console.error(c.red(` Update blocked to prevent overwriting user changes.`));
|
|
608
|
+
console.error(c.yellow(` Conflict artifact written to: ${conflictFile}`));
|
|
609
|
+
console.error(c.yellow(` Pass --force to overwrite.`));
|
|
610
|
+
process.exit(1);
|
|
611
|
+
}
|
|
612
|
+
}
|
|
507
613
|
console.log(c.yellow(`\n[WARN] '${skillName}' is already installed (from: ${existing.ref})`));
|
|
508
614
|
console.log(c.yellow(' Re-installing will overwrite it. Continuing...'));
|
|
509
615
|
}
|
|
510
616
|
|
|
511
|
-
|
|
617
|
+
const projectLock = new ProjectMutationLock(ROOT);
|
|
618
|
+
const tx = new JournaledTransaction(ROOT);
|
|
619
|
+
let lockToken = null;
|
|
620
|
+
|
|
512
621
|
try {
|
|
622
|
+
lockToken = projectLock.acquire({ command: 'skill:add' });
|
|
623
|
+
|
|
624
|
+
let installedSha256 = null;
|
|
513
625
|
if (descriptor.type === 'github') {
|
|
514
|
-
installedSha256 = await installFromGitHub(descriptor, skillName, dryRun, checksum, forceUnsafe);
|
|
626
|
+
installedSha256 = await installFromGitHub(descriptor, skillName, dryRun, checksum, forceUnsafe, tx);
|
|
515
627
|
} else {
|
|
516
|
-
installedSha256 = installFromNpm(descriptor, skillName, dryRun, checksum, forceUnsafe);
|
|
628
|
+
installedSha256 = installFromNpm(descriptor, skillName, dryRun, checksum, forceUnsafe, tx);
|
|
629
|
+
}
|
|
630
|
+
|
|
631
|
+
if (!dryRun) {
|
|
632
|
+
// Update lock file
|
|
633
|
+
const idx = lock.plugins.findIndex(p => p.name === skillName);
|
|
634
|
+
const entry = {
|
|
635
|
+
name: skillName,
|
|
636
|
+
ref,
|
|
637
|
+
type: descriptor.type,
|
|
638
|
+
commit: descriptor.commit,
|
|
639
|
+
version: descriptor.version,
|
|
640
|
+
integrity: descriptor.integrity,
|
|
641
|
+
sha256: installedSha256,
|
|
642
|
+
installedAt: new Date().toISOString(),
|
|
643
|
+
};
|
|
644
|
+
if (idx >= 0) lock.plugins[idx] = entry;
|
|
645
|
+
else lock.plugins.push(entry);
|
|
646
|
+
|
|
647
|
+
writeLock(lock, tx);
|
|
648
|
+
tx.commit();
|
|
649
|
+
|
|
650
|
+
// Compute and record full-tree digest into lock
|
|
651
|
+
if (fs.existsSync(targetDir)) {
|
|
652
|
+
const digestResult = calculateTreeDigest(targetDir);
|
|
653
|
+
entry.treeDigest = digestResult.treeDigest;
|
|
654
|
+
writeLock(lock);
|
|
655
|
+
}
|
|
656
|
+
|
|
657
|
+
console.log('');
|
|
658
|
+
console.log(c.green(c.bold('✓ Skill installed successfully!')));
|
|
659
|
+
console.log(c.dim(` Location: .agents/plugins/${skillName}/`));
|
|
660
|
+
console.log('');
|
|
661
|
+
console.log(' Next steps:');
|
|
662
|
+
console.log(` node .agents/ctx.js export all # recompile with new skill`);
|
|
663
|
+
console.log(` node .agents/ctx.js validate # verify everything is consistent`);
|
|
664
|
+
console.log('');
|
|
517
665
|
}
|
|
518
666
|
} catch (err) {
|
|
667
|
+
if (tx && tx.state === 'PLANNED') {
|
|
668
|
+
// We don't need to do anything since it wasn't committed
|
|
669
|
+
}
|
|
519
670
|
console.error(c.red(`\n[ERROR] Failed to install '${skillName}': ${err.message}`));
|
|
520
671
|
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('');
|
|
672
|
+
} finally {
|
|
673
|
+
if (lockToken) projectLock.release(lockToken);
|
|
545
674
|
}
|
|
546
675
|
}
|
|
547
676
|
|
|
@@ -576,15 +705,85 @@ function remove(skillName) {
|
|
|
576
705
|
process.exit(1);
|
|
577
706
|
}
|
|
578
707
|
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
708
|
+
const projectLock = new ProjectMutationLock(ROOT);
|
|
709
|
+
const tx = new JournaledTransaction(ROOT);
|
|
710
|
+
let lockToken = null;
|
|
711
|
+
|
|
712
|
+
try {
|
|
713
|
+
lockToken = projectLock.acquire({ command: 'skill:remove' });
|
|
714
|
+
|
|
715
|
+
if (fs.existsSync(skillDir)) {
|
|
716
|
+
// Find the manifest if it exists
|
|
717
|
+
const sourceFile = path.join(skillDir, '.source');
|
|
718
|
+
let manifest = null;
|
|
719
|
+
if (fs.existsSync(sourceFile)) {
|
|
720
|
+
try {
|
|
721
|
+
const sourceData = JSON.parse(fs.readFileSync(sourceFile, 'utf8'));
|
|
722
|
+
manifest = sourceData.manifest || null;
|
|
723
|
+
} catch {}
|
|
724
|
+
}
|
|
725
|
+
|
|
726
|
+
const stageRecursiveDeletes = (dir, relBase) => {
|
|
727
|
+
let hasPreservedFiles = false;
|
|
728
|
+
for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
|
|
729
|
+
const fullPath = path.join(dir, entry.name);
|
|
730
|
+
const entryRel = relBase ? `${relBase}/${entry.name}` : entry.name;
|
|
731
|
+
|
|
732
|
+
if (entry.isDirectory()) {
|
|
733
|
+
const preserved = stageRecursiveDeletes(fullPath, entryRel);
|
|
734
|
+
if (preserved) hasPreservedFiles = true;
|
|
735
|
+
else tx.stageDeleteDir(toPosix(path.relative(ROOT, fullPath)));
|
|
736
|
+
} else {
|
|
737
|
+
// Check against manifest
|
|
738
|
+
let shouldDelete = false;
|
|
739
|
+
if (manifest && manifest[entryRel]) {
|
|
740
|
+
const currentHash = crypto.createHash('sha256').update(fs.readFileSync(fullPath)).digest('hex');
|
|
741
|
+
if (currentHash === manifest[entryRel]) {
|
|
742
|
+
shouldDelete = true;
|
|
743
|
+
}
|
|
744
|
+
} else if (!manifest) {
|
|
745
|
+
// If we have NO manifest, we fallback to W3.4 "Remove не удаляет modified/unmanaged files"
|
|
746
|
+
// But without a manifest, we don't know what was installed vs modified.
|
|
747
|
+
// We'll safely skip all files unless we can confidently delete them, OR we can just assume
|
|
748
|
+
// if it's the exact SHA256 of SKILL.md, delete it. But it's safer to only delete known things.
|
|
749
|
+
// We'll just delete SKILL.md and skill.yaml if they match the lockfile hash
|
|
750
|
+
if (entry.name === 'SKILL.md' || entry.name === 'skill.yaml' || entry.name === '.source') {
|
|
751
|
+
shouldDelete = true;
|
|
752
|
+
}
|
|
753
|
+
}
|
|
754
|
+
|
|
755
|
+
if (entry.name === '.source') shouldDelete = true;
|
|
756
|
+
|
|
757
|
+
if (shouldDelete) {
|
|
758
|
+
tx.stageDelete(toPosix(path.relative(ROOT, fullPath)));
|
|
759
|
+
} else {
|
|
760
|
+
hasPreservedFiles = true;
|
|
761
|
+
console.log(c.yellow(` [WARN] Preserving modified/unmanaged file: ${entryRel}`));
|
|
762
|
+
}
|
|
763
|
+
}
|
|
764
|
+
}
|
|
765
|
+
return hasPreservedFiles;
|
|
766
|
+
};
|
|
767
|
+
|
|
768
|
+
const preserved = stageRecursiveDeletes(skillDir, '');
|
|
769
|
+
if (!preserved) {
|
|
770
|
+
tx.stageDeleteDir(toPosix(path.relative(ROOT, skillDir)));
|
|
771
|
+
}
|
|
772
|
+
}
|
|
582
773
|
|
|
583
|
-
|
|
584
|
-
|
|
774
|
+
lock.plugins = lock.plugins.filter(p => p.name !== skillName);
|
|
775
|
+
writeLock(lock, tx);
|
|
776
|
+
|
|
777
|
+
tx.commit();
|
|
585
778
|
|
|
586
|
-
|
|
587
|
-
|
|
779
|
+
console.log(c.green(`✓ Removed plugin: ${skillName}`));
|
|
780
|
+
console.log(c.dim(' Run: node .agents/ctx.js export all (to recompile)'));
|
|
781
|
+
} catch (err) {
|
|
782
|
+
console.error(c.red(`\n[ERROR] Failed to remove '${skillName}': ${err.message}`));
|
|
783
|
+
process.exit(1);
|
|
784
|
+
} finally {
|
|
785
|
+
if (lockToken) projectLock.release(lockToken);
|
|
786
|
+
}
|
|
588
787
|
}
|
|
589
788
|
|
|
590
789
|
/**
|