@hybridlabor-api/aos 4.12.1 → 4.13.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/.agents/vendor-manifest.json +6 -0
- package/.claude/agents/reviewer.md +1 -1
- package/.claude/agents/techlead.md +1 -1
- package/.opencode/agents/architect.md +1 -1
- package/.opencode/agents/reviewer.md +1 -1
- package/.opencode/agents/techlead.md +1 -1
- package/README.de.md +10 -9
- package/README.md +10 -9
- package/README.pt.md +10 -9
- package/THIRD_PARTY_NOTICES.md +94 -0
- package/bin/aos-store.mjs +48 -45
- package/installer.js +22 -20
- package/lib/scenario-store-index.json +1 -0
- package/lib/store-shared.mjs +81 -4
- package/lib/store-ui/index.html +14 -5
- package/lib/store-ui/server.mjs +44 -21
- package/package.json +2 -2
- package/scripts/build-plugin-manifest.mjs +33 -10
- package/scripts/build-scenario-store-index.mjs +154 -0
- package/skills/bdbrainstorm/SKILL.md +1 -0
- package/skills/global_config/agent-pipeline/SKILL.md +4 -0
- package/skills/global_config/aos-store/SKILL.md +3 -3
- package/skills/global_config/design-control-loop/SKILL.md +184 -0
- package/skills/global_config/design-control-loop/references/agent-iteration.ts +174 -0
- package/skills/global_config/design-control-loop/references/agent-runner-templates.md +157 -0
- package/skills/global_config/design-control-loop/references/control-loop-taxonomy.md +75 -0
- package/skills/global_config/design-control-loop/references/example-control-loop.md +57 -0
- package/skills/global_config/design-control-loop/references/example-skill.md +171 -0
- package/skills/global_config/design-control-loop/references/memory-template.md +7 -0
- package/skills/global_config/design-control-loop/references/prompt-template.md +58 -0
- package/skills/global_config/design-control-loop/references/response-template.md +103 -0
- package/skills/global_config/design-control-loop/references/skill-template.md +57 -0
- package/skills/global_config/design-control-loop/references/workflow-template.yml +273 -0
package/installer.js
CHANGED
|
@@ -3354,27 +3354,27 @@ function loadPipelineConfig(projectDir = currentDir) {
|
|
|
3354
3354
|
function resolveAgentConfig(agentSlug, harness, pipelineConfig = null) {
|
|
3355
3355
|
const normSlug = agentSlug.toLowerCase().replace(/-/g, '_');
|
|
3356
3356
|
const roleCfg = pipelineConfig ? (pipelineConfig[normSlug] || pipelineConfig[agentSlug]) : null;
|
|
3357
|
-
|
|
3358
|
-
|
|
3359
|
-
|
|
3360
|
-
|
|
3361
|
-
|
|
3362
|
-
|
|
3363
|
-
|
|
3364
|
-
|
|
3365
|
-
}
|
|
3366
|
-
|
|
3367
|
-
|
|
3368
|
-
|
|
3369
|
-
|
|
3370
|
-
|
|
3371
|
-
|
|
3372
|
-
|
|
3373
|
-
}
|
|
3357
|
+
// A role's model/harness describes where AO runs that role; only valid for that harness.
|
|
3358
|
+
const ownHarness = !!roleCfg && (!roleCfg.harness || roleCfg.harness === harness);
|
|
3359
|
+
if (roleCfg && ownHarness && roleCfg.model) {
|
|
3360
|
+
return {
|
|
3361
|
+
model: roleCfg.model,
|
|
3362
|
+
tier: roleCfg.tier || 'custom',
|
|
3363
|
+
enabled: roleCfg.enabled !== false,
|
|
3364
|
+
harness
|
|
3365
|
+
};
|
|
3366
|
+
}
|
|
3367
|
+
if (roleCfg && roleCfg.tier && CANONICAL_TIERS[roleCfg.tier] && CANONICAL_TIERS[roleCfg.tier][harness]) {
|
|
3368
|
+
return {
|
|
3369
|
+
model: CANONICAL_TIERS[roleCfg.tier][harness],
|
|
3370
|
+
tier: roleCfg.tier,
|
|
3371
|
+
enabled: roleCfg.enabled !== false,
|
|
3372
|
+
harness
|
|
3373
|
+
};
|
|
3374
3374
|
}
|
|
3375
3375
|
const defaultTier = (normSlug === 'architect' || normSlug === 'reviewer') ? 'reasoning_max' : 'standard_fast';
|
|
3376
3376
|
const fallbackModel = (CANONICAL_TIERS[defaultTier] && CANONICAL_TIERS[defaultTier][harness]) || 'inherit';
|
|
3377
|
-
return { model: fallbackModel, tier: defaultTier, enabled:
|
|
3377
|
+
return { model: fallbackModel, tier: defaultTier, enabled: !(roleCfg && roleCfg.model && roleCfg.enabled === false), harness };
|
|
3378
3378
|
}
|
|
3379
3379
|
|
|
3380
3380
|
// Generates .claude/agents/<name>.md — Claude Code's native subagent format.
|
|
@@ -3385,7 +3385,8 @@ function compileClaudeAgents(agents, targetDir, pipelineConfig = null) {
|
|
|
3385
3385
|
for (const a of agents) {
|
|
3386
3386
|
const slug = a.name.toLowerCase().replace(/_/g, '-');
|
|
3387
3387
|
const resolved = resolveAgentConfig(slug, 'claude', pipelineConfig);
|
|
3388
|
-
|
|
3388
|
+
let model = (resolved && resolved.model) ? resolved.model.toLowerCase() : (a.model ? a.model.toLowerCase() : 'inherit');
|
|
3389
|
+
if (!/^(opus|sonnet|haiku|inherit|claude-.+)$/.test(model)) model = CANONICAL_TIERS[resolved.tier in CANONICAL_TIERS ? resolved.tier : 'standard_fast'].claude;
|
|
3389
3390
|
const body = [
|
|
3390
3391
|
a.role,
|
|
3391
3392
|
a.skills.length ? `**Primary skills:** ${a.skills.join(', ')}` : null,
|
|
@@ -3412,7 +3413,8 @@ function compileOpenCodeAgents(agents, targetDir, pipelineConfig = null) {
|
|
|
3412
3413
|
for (const a of agents) {
|
|
3413
3414
|
const slug = a.name.toLowerCase().replace(/_/g, '-');
|
|
3414
3415
|
const resolved = resolveAgentConfig(slug, 'opencode', pipelineConfig);
|
|
3415
|
-
|
|
3416
|
+
let model = resolved && resolved.model ? resolved.model : null;
|
|
3417
|
+
if (model && !model.includes('/')) model = CANONICAL_TIERS[resolved.tier in CANONICAL_TIERS ? resolved.tier : 'standard_fast'].opencode;
|
|
3416
3418
|
const body = [
|
|
3417
3419
|
a.role,
|
|
3418
3420
|
a.skills.length ? `**Primary skills:** ${a.skills.join(', ')}` : null,
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":"1.1.0","generated_at":"2026-09-28T16:20:46+02:00","pinned_commit":"5786accd3bb6d79808330230c698898862e8a1d4","source":{"id":"scenario","label":"Scenario","upstream":"https://github.com/scenario-labs/skills","raw_base":"https://raw.githubusercontent.com/scenario-labs/skills","license":"MIT","copyright":"Copyright (c) 2026 Scenario","third_party":true},"harness_support":["claude","antigravity","codex","cursor","roo"],"skills":{"scenario-blender-animation":{"description":"Use when animating characters or objects in Blender through Python, a bouncing ball, walk or run cy…","category":"media-eventtech","tier":"free","origin":"scenario","requires_auth":false,"sha256":"aff7450263b6435bd3d654147d971f38ed8effb37ea6aac86e21a3e574d4fa49","upstream_path":"skills/dcc/blender/scenario-blender-animation/SKILL.md","requires":["scenario-blender-expert"],"software":["Blender"],"hasScripts":true,"scriptCount":1,"execBridge":false,"execBridgeFiles":[],"files":[{"path":"SKILL.md","sha256":"aff7450263b6435bd3d654147d971f38ed8effb37ea6aac86e21a3e574d4fa49","size":20288,"exec":false},{"path":"references/critique.md","sha256":"cb00a869d0847033d0d5dcc31ced3c4b21169f2c40158e8907ff22384d9c71da","size":29916,"exec":false},{"path":"references/expert-notes.md","sha256":"811e83faf618f9edfcc273d1c21d903c76c787dd73e2092c9c0d31cb3fd06454","size":27069,"exec":false},{"path":"references/procedures.md","sha256":"514cf2ce6f40ecb1184cc57ee63c21deb76193111986d2238e4e909e3fa9155c","size":41355,"exec":false},{"path":"references/sources.md","sha256":"1b45bbf9c056ce1bfd266a3bdfd55677803898758d47f4bafe39bdb34043f662","size":9058,"exec":false},{"path":"scripts/bx_anim.py","sha256":"75db8650041f02d881bb5895130571c8ea7e437d2c20fa77154d961ab8c5f005","size":103257,"exec":false}]},"scenario-blender-expert":{"description":"Use when doing any 3D work in Blender through Python or an MCP bridge, headless or in a live sessio…","category":"media-eventtech","tier":"free","origin":"scenario","requires_auth":false,"sha256":"66af9735948dd16ed619c48fdd66b03124a4b521e70543df0f90f77fe6f55376","upstream_path":"skills/dcc/blender/scenario-blender-expert/SKILL.md","software":["Blender"],"hasScripts":true,"scriptCount":3,"execBridge":false,"execBridgeFiles":[],"files":[{"path":"SKILL.md","sha256":"66af9735948dd16ed619c48fdd66b03124a4b521e70543df0f90f77fe6f55376","size":12817,"exec":false},{"path":"references/blender-5.2-deltas.md","sha256":"a3edcef99a5d44c3853901417b9682b17bdda3185bc74f3d1ccada6c7c5f6677","size":118596,"exec":false},{"path":"references/bpy-reliability.md","sha256":"b43625d8ae078dd983fb8b4ddc3d99fa3b71d793142ee1956d6b306b24957566","size":24633,"exec":false},{"path":"scripts/bx_audit.py","sha256":"0ff01ffdc6f9413c42be15016c84fbf8f0696434e1b30cc5ad952813d748a0f8","size":9810,"exec":false},{"path":"scripts/bx_gui.py","sha256":"d5c020f27d2714f7f773da30cfa190017be453a621bb45f1eccececa3a33d60c","size":8951,"exec":false},{"path":"scripts/bx_review.py","sha256":"3862dc1452960f01219206bbc0f24d487810d0f4cda6ab41b97108e522e53986","size":14914,"exec":false}]},"scenario-blender-geometry-nodes":{"description":"Use when building or debugging Geometry Nodes, headless or live: procedural modeling, scattering ob…","category":"media-eventtech","tier":"free","origin":"scenario","requires_auth":false,"sha256":"c7465134d8506ad0975063974d5c462ea3638aadf9f316d74dc81c4b7a522923","upstream_path":"skills/dcc/blender/scenario-blender-geometry-nodes/SKILL.md","requires":["scenario-blender-expert"],"software":[],"hasScripts":true,"scriptCount":1,"execBridge":false,"execBridgeFiles":[],"files":[{"path":"SKILL.md","sha256":"c7465134d8506ad0975063974d5c462ea3638aadf9f316d74dc81c4b7a522923","size":16371,"exec":false},{"path":"references/critique.md","sha256":"88331d11fad74946a8989cdfd1d79703f65fe8efd8565c9be152bdbb85cb9e8b","size":11373,"exec":false},{"path":"references/expert-notes.md","sha256":"49fa43b73f7a423a078e2405bd962545a3f6a2a10fa3e57965914b2eb9320c11","size":18172,"exec":false},{"path":"references/procedures.md","sha256":"8f0b2dc24dcbd01296351cee4177cdd7ce11fa7077402293541c9040f85cb58d","size":55863,"exec":false},{"path":"references/sources.md","sha256":"fe060140ec154d9f0c49e0efbe996a9ebf10c1eb0de0467614cf9aa2116df374","size":7510,"exec":false},{"path":"scripts/bx_gn.py","sha256":"b325317f54e1e944f33f1af91e141c20bd5ebe7d3a3c487738fa70fd725639e0","size":57043,"exec":false}]},"scenario-blender-hard-surface":{"description":"Use when modeling hard-surface objects in Blender (sci-fi panels, props, weapons, vehicles, robots,…","category":"media-eventtech","tier":"free","origin":"scenario","requires_auth":false,"sha256":"f14733f37d3f0ee2654fcac4f9f0bb3c1bc3112854a38848f71736eb155a525d","upstream_path":"skills/dcc/blender/scenario-blender-hard-surface/SKILL.md","requires":["scenario-blender-expert"],"software":["Blender"],"hasScripts":true,"scriptCount":1,"execBridge":false,"execBridgeFiles":[],"files":[{"path":"SKILL.md","sha256":"f14733f37d3f0ee2654fcac4f9f0bb3c1bc3112854a38848f71736eb155a525d","size":18295,"exec":false},{"path":"references/critique.md","sha256":"32fae7dc8e3759556aa4571b868d5fcb783217ce9270c9802aa8b380ca24ee4d","size":14411,"exec":false},{"path":"references/expert-notes.md","sha256":"b9682d071a0fcafa03afa99ae9aecf3831176681d5e74eb7d10c27369386a87b","size":17875,"exec":false},{"path":"references/procedures.md","sha256":"6dbe1b7567a6ff1f21ff5debf4c9235cd7fc4ccea51f736a1b74448bcccca70c","size":25309,"exec":false},{"path":"references/sources.md","sha256":"71d90f1effa9477abdfe4bd77bea4d6b0fb8c21ae2ec449168d9b7d972ba77eb","size":7412,"exec":false},{"path":"scripts/bx_hardsurface.py","sha256":"a7eb60b356c16609573ea8bb0005cd1278e908dcd7593eb7ff1f749ceb7b9999","size":69529,"exec":false}]},"scenario-blender-lighting-rendering":{"description":"Use when lighting, rendering or compositing in Blender: light a character, product or hero shot, in…","category":"media-eventtech","tier":"free","origin":"scenario","requires_auth":false,"sha256":"93a3bea574312104922feba0884afa05332a2a7e12720995b9fabb948e0d297e","upstream_path":"skills/dcc/blender/scenario-blender-lighting-rendering/SKILL.md","requires":["scenario-blender-expert"],"software":["Blender"],"hasScripts":true,"scriptCount":1,"execBridge":false,"execBridgeFiles":[],"files":[{"path":"SKILL.md","sha256":"93a3bea574312104922feba0884afa05332a2a7e12720995b9fabb948e0d297e","size":20126,"exec":false},{"path":"references/critique.md","sha256":"04c4b949a62019d4cfe70cbe536dc96b2411fdd0c82980b750004e0f04ce38db","size":8035,"exec":false},{"path":"references/expert-notes.md","sha256":"fcf07efdf876fa500f96e25ce8477c56bd70c3fe13451ee85b26146c75d70f38","size":19917,"exec":false},{"path":"references/procedures.md","sha256":"774ce5f5c1577d3a74845b73bd716348cb587d0f0d7ea447a5dd64e706ff84a0","size":30203,"exec":false},{"path":"references/sources.md","sha256":"8beafcf59b2822a81ce09f255ef81cc333d12a464f0a58e6f6ac5e37c3679999","size":15667,"exec":false},{"path":"scripts/bx_light.py","sha256":"6f6624765f2afdfebc0efc4b77313fee3cacef9e7d983bcb3a95c88c8fa2f8f2","size":102909,"exec":false}]},"scenario-blender-retopology":{"description":"Use when turning a dense sculpt, scan or AI-generated mesh into clean topology in Blender, for anim…","category":"media-eventtech","tier":"free","origin":"scenario","requires_auth":false,"sha256":"b6f31d60d7cd7d4cd055d0e7ba160eaa58b9d165739055eb3a1c1e381c08036e","upstream_path":"skills/dcc/blender/scenario-blender-retopology/SKILL.md","requires":["scenario-blender-expert"],"software":["Blender"],"hasScripts":true,"scriptCount":1,"execBridge":false,"execBridgeFiles":[],"files":[{"path":"SKILL.md","sha256":"b6f31d60d7cd7d4cd055d0e7ba160eaa58b9d165739055eb3a1c1e381c08036e","size":22026,"exec":false},{"path":"references/critique.md","sha256":"f23b9afc01bc0489d834978277323e1612f576983be98c388ba54e0c0e5ba7d7","size":15592,"exec":false},{"path":"references/expert-notes.md","sha256":"b1faff4c7fdce09eadbe438f4c8d52bceb05930729dd54ad5e6cae9f8406dd58","size":36275,"exec":false},{"path":"references/procedures.md","sha256":"d55d861c34134a6d1681d67577d3c81f4d5be904fdd3c87108e4a6b940790ae5","size":31490,"exec":false},{"path":"references/sources.md","sha256":"d25df1db2d06c8e378349bf188ba19d229ea7f912b46097854afce669d234017","size":17379,"exec":false},{"path":"scripts/bx_retopo.py","sha256":"871005569e63d4d947e5d5a6cd6344f6bee4113302ec5498270b028ad53922dd","size":128751,"exec":false}]},"scenario-blender-texturing-shading":{"description":"Use when texturing, shading or look-developing in Blender: building a PBR material from a texture s…","category":"media-eventtech","tier":"free","origin":"scenario","requires_auth":false,"sha256":"df7f11cc812e5b2dd61bd5770de88017fdb67898951e2957bbdc78717f40c45c","upstream_path":"skills/dcc/blender/scenario-blender-texturing-shading/SKILL.md","requires":["scenario-blender-expert"],"software":["Blender"],"hasScripts":true,"scriptCount":1,"execBridge":false,"execBridgeFiles":[],"files":[{"path":"SKILL.md","sha256":"df7f11cc812e5b2dd61bd5770de88017fdb67898951e2957bbdc78717f40c45c","size":15695,"exec":false},{"path":"references/critique.md","sha256":"8365bb221a2ad681120beb2346ec6ee194a0affca441d98243f35e66540a8d50","size":5828,"exec":false},{"path":"references/expert-notes.md","sha256":"0472e6a6faa26770e603f97a25bd1c34007b9c0220c98967973d937d7a4dbb20","size":28024,"exec":false},{"path":"references/procedures.md","sha256":"703f71d73daab57183ee472b6069e3368b6f79ce72e0a273f8a67ed29a5a61f4","size":31419,"exec":false},{"path":"references/sources.md","sha256":"093bd302b898e3bc3fc438cf0ed0be59cbc6057108c03091ea828d25f31e8503","size":11474,"exec":false},{"path":"scripts/bx_materials.py","sha256":"15877d81bea8d2c95e1393b7c6ce8c96182fdb1a8d26dfa6bfbaf2d88886e72b","size":87244,"exec":false}]},"scenario-blender-uv-baking":{"description":"Use when UV unwrapping, placing seams, straightening or packing UVs, setting texel density, laying …","category":"media-eventtech","tier":"free","origin":"scenario","requires_auth":false,"sha256":"4dba740b856bb7cda4b158c53f1972221d08059ef89bfaaca15a5ac985db9b90","upstream_path":"skills/dcc/blender/scenario-blender-uv-baking/SKILL.md","requires":["scenario-blender-expert"],"software":["Blender"],"hasScripts":true,"scriptCount":1,"execBridge":false,"execBridgeFiles":[],"files":[{"path":"SKILL.md","sha256":"4dba740b856bb7cda4b158c53f1972221d08059ef89bfaaca15a5ac985db9b90","size":17085,"exec":false},{"path":"references/critique.md","sha256":"e9a0bde9c4b2b416cd3d73ceb4dee21f584175fdd7b855a3fa3e04ac434c7a7b","size":17474,"exec":false},{"path":"references/expert-notes.md","sha256":"04fba3c9f09eb7643a5d27329c6eed250da06bb55df9b2374e760a8e0689e52c","size":23242,"exec":false},{"path":"references/procedures.md","sha256":"c8c2f81b18fb66360c2a6ac71c918a2494318b775648e0af2d725d5636df4a94","size":17979,"exec":false},{"path":"references/sources.md","sha256":"fb8a8a3b4d69ab7119e7db3f2f60756bedbe275912e8acbd5e9339cbfef9bb95","size":12550,"exec":false},{"path":"scripts/bx_uvbake.py","sha256":"f07fd3b6c02fdeff9dfaa77e164f24843ece1113e23ba073e61b68002d5c0762","size":107567,"exec":false}]},"scenario-unity-expert":{"description":"Use when an agent drives Unity 6.3 (6000.3) on a Mac for any task: batch mode and -executeMethod jo…","category":"media-eventtech","tier":"free","origin":"scenario","requires_auth":false,"sha256":"61a31dd57792d42514912d864f23aa4ac7511b2c288d78e491987f6747142357","upstream_path":"skills/game-engines/unity/scenario-unity-expert/SKILL.md","software":["Unity 6.3"],"hasScripts":true,"scriptCount":12,"execBridge":true,"execBridgeFiles":[{"path":"scripts/AgentKit/AgentBridge.cs","reason":"invokes a method named in a request + file inbox polled for requests"},{"path":"scripts/ut_live.py","reason":"calls exec()/eval() + file inbox polled for requests"}],"files":[{"path":"SKILL.md","sha256":"61a31dd57792d42514912d864f23aa4ac7511b2c288d78e491987f6747142357","size":20832,"exec":false},{"path":"references/gui-paths.md","sha256":"8571540332e3095ff1855b641ac847dc9a4bf14f64011883f77d1421c6c5f041","size":5161,"exec":false},{"path":"references/live-channels.md","sha256":"37c9bf7a84ee3f81cb003977de6ae7b819bddbc341babf842558ac4a33f10d81","size":10861,"exec":false},{"path":"references/procedures.md","sha256":"d0e79adbed05d073ca9d25f088155f677735210ebe99f27d10670007afed42ad","size":7975,"exec":false},{"path":"references/routing-handoffs.md","sha256":"99fc636babe797bd83f580d11d58cfd7db551528eb946251d09cd97067eb12b8","size":19866,"exec":false},{"path":"references/sources.md","sha256":"49d0bf4a5d0470f6c2d5d5f436cab43789b1f17e0b7b361bed277c397bc218cd","size":28778,"exec":false},{"path":"references/toolkit-map.md","sha256":"db1f8b6d2e1dd685d44398266c8f956d36b862cef867bb8b8cf7e3895a5ab7e3","size":38967,"exec":false},{"path":"references/unity-6.3-traps.md","sha256":"f2c308fdfde091b022077958cd93dac186441cb8fd5dc2ae049697533b4191f3","size":51439,"exec":false},{"path":"references/writing-jobs.md","sha256":"a0f58f7ba6ef31c460c437484305f88b57ee6621a5f5851ecfbc636cc54d8a7e","size":9767,"exec":false},{"path":"scripts/AgentKit/AgentAudit.cs","sha256":"ef3462273115de3e5dfe0728a1eb884a01bfca1368846f563ba3e82acc25c1a4","size":26345,"exec":false},{"path":"scripts/AgentKit/AgentBridge.cs","sha256":"1cd83d4ed4b03d4e4440eab88ca4ca777e6057478d93db2b98fb35f3cd5a0b10","size":12418,"exec":false},{"path":"scripts/AgentKit/AgentBuild.cs","sha256":"9d97386d404e30ba3b286e202e95645b39bcc7b449b791298ce181e9ec7dfa66","size":12631,"exec":false},{"path":"scripts/AgentKit/AgentCapture.cs","sha256":"ebbf7f867607a9f563760161fba53ab0336e91858bc741fb01ffdb183861390a","size":22677,"exec":false},{"path":"scripts/AgentKit/AgentJob.cs","sha256":"a7e56ca70de1a3714509f128d112ea2afaf7817ddfea5c8fd65e9cfd25498328","size":16347,"exec":false},{"path":"scripts/AgentKit/AgentJson.cs","sha256":"9ef0f999966536846a358d647126d863d38140dd5dcf1f2ab51719dc0f4ea6c0","size":12599,"exec":false},{"path":"scripts/AgentKit/AgentProfile.cs","sha256":"61047d48198e42ebd9b9d43d1fa51feab16475232b3ca02837d86850997d3d43","size":13210,"exec":false},{"path":"scripts/ut_env.py","sha256":"0945a5e3d32f0610f73a50a5c186b18cb63301df736ac25be0c8da27f83bc1ec","size":16048,"exec":false},{"path":"scripts/ut_live.py","sha256":"ad4b62c2f4f2551e5edd84a6ac70cb96b5a0956629d1c29034b20b2d92a177c7","size":21945,"exec":false},{"path":"scripts/ut_review.py","sha256":"b698fda1327c7073e1f82593f3f4050278ebd072631342f3a0bc709e0845bb44","size":24732,"exec":false},{"path":"scripts/ut_run.py","sha256":"64e0c0050faaf784c78e5bb3f575b1177d2d55ecc8c30e6dd2f14ae02b92a279","size":26972,"exec":false},{"path":"scripts/ut_stat.py","sha256":"367879ffa58641f67e7e44f190f01bac4b2864128f3ab567df028ac38f18ec9e","size":11680,"exec":false}]},"scenario-unity-performance":{"description":"Use when a Unity 6.3 game is slow or stutters: low fps, frame spikes, hitches when entering areas o…","category":"engineering-method","tier":"free","origin":"scenario","requires_auth":false,"sha256":"c12a5c903f396a72a15e56226d8a0dab553fef6caa13d9c801c54e8125c22333","upstream_path":"skills/game-engines/unity/scenario-unity-performance/SKILL.md","requires":["scenario-unity-expert"],"software":["Unity 6.3"],"hasScripts":true,"scriptCount":11,"execBridge":false,"execBridgeFiles":[],"files":[{"path":"SKILL.md","sha256":"c12a5c903f396a72a15e56226d8a0dab553fef6caa13d9c801c54e8125c22333","size":19744,"exec":false},{"path":"references/critique.md","sha256":"2731a46adbeec0f9c3b4a77c4b9c3f48ea8b942a1c1541f83f6f0fe620b5aa2d","size":8642,"exec":false},{"path":"references/expert-notes.md","sha256":"9980ee29a301309ab626a67fedefe84948ca03bebb033326f9623b7db8918169","size":25410,"exec":false},{"path":"references/gui-paths.md","sha256":"da2d3546fec852aafec6cb353d021c14ed24ea0bd8a21a3545f0f9563caa84da","size":24245,"exec":false},{"path":"references/procedures.md","sha256":"d28316c0c66d52e921c8e0b6a9c2cd5c9e892763be5b35e10a13999c2a6f258e","size":44495,"exec":false},{"path":"references/sources.md","sha256":"ce76807bc6ca64274be03f998726197261f1946604918a7e3b3be08a9c3f3c4c","size":24539,"exec":false},{"path":"scripts/AgentKit/Performance/PerfAudit.cs","sha256":"1f04553de72dbcfcee20ae496d5e80f256b4376dc7a849558c4586b6101e165b","size":17453,"exec":false},{"path":"scripts/AgentKit/Performance/PerfBuild.cs","sha256":"a89fa1b4532123a5816f97394ecd35ce12a5e45072764dc1abebdcf267f50d0e","size":11692,"exec":false},{"path":"scripts/AgentKit/Performance/PerfCapture.cs","sha256":"0a1788e09d50c2fe1d97fe749bf884b0e887f5ecc7514b86823e1c508d51c743","size":12297,"exec":false},{"path":"scripts/AgentKit/Performance/PerfFrameDebug.cs","sha256":"19e69f94b6aced6358a15edd8c8d78ec992677b25372b55b4fa09383469fd879","size":16446,"exec":false},{"path":"scripts/AgentKit/Performance/PerfLod.cs","sha256":"cc9bf20740a9d5bbaaa7410c75a0003660f0d556737012a067bb02e8dcf4bd70","size":5062,"exec":false},{"path":"scripts/AgentKit/Performance/PerfRendering.cs","sha256":"af7ba69beeb6d74d17de949a81e13ab2112d6d45a47156c3653f4ecae15c1b1b","size":33683,"exec":false},{"path":"scripts/AgentKit/Performance/PerfShaders.cs","sha256":"6aa5cae1262e930c9a4fa07e18555f9b95dcce3391c8da33f82ae266f5cef9cd","size":13473,"exec":false},{"path":"scripts/Runtime/Performance/AgentKit.Performance.Runtime.asmdef","sha256":"eb71145c132486c46bfecc868a63b51c196a4437043c422d61e01de40e30d184","size":382,"exec":false},{"path":"scripts/Runtime/Performance/AllocScope.cs","sha256":"f469ee9f659dbda3d387817854999d141b1fd56889b8a3209f0f4fc63159da8e","size":2206,"exec":false},{"path":"scripts/Runtime/Performance/PerfProbe.cs","sha256":"2a42c3dc9a416d8655bb9f43335ff81535133d25ae04f206ad3ff24a4680c80f","size":28166,"exec":false},{"path":"scripts/ut_perf.py","sha256":"46cb7a5b9922546a6510eef9de4779017989681b1715f3fa3328d1502dd53fb7","size":44913,"exec":false}]},"scenario-unity-pipeline-automation":{"description":"Use when automating a Unity 6.3 content pipeline or build: importing an art drop (FBX, PNG) with As…","category":"engineering-method","tier":"free","origin":"scenario","requires_auth":false,"sha256":"438d60621e5c93a35d0f6085af22e9c1377ed154b24486c134d79cc9d584948c","upstream_path":"skills/game-engines/unity/scenario-unity-pipeline-automation/SKILL.md","requires":["scenario-unity-expert"],"software":["Unity 6.3"],"hasScripts":true,"scriptCount":16,"execBridge":false,"execBridgeFiles":[],"files":[{"path":"SKILL.md","sha256":"438d60621e5c93a35d0f6085af22e9c1377ed154b24486c134d79cc9d584948c","size":19929,"exec":false},{"path":"references/critique.md","sha256":"4f35497615c24efa9c9265557f5794c5c343a20c99fd64e903c588bfa581e684","size":17680,"exec":false},{"path":"references/expert-notes.md","sha256":"134238c2280662d3e71153ea12c6e127713677f9a3b06441ce79250044168bbd","size":24228,"exec":false},{"path":"references/gui-paths.md","sha256":"441f6f46698e99cef420db6de67cf2cbf040d62e149528ad29174392b66c5038","size":15507,"exec":false},{"path":"references/procedures.md","sha256":"04c16e0d2b28fb1b619537f3f491a403d38c6304ea4b7b8befe7ab38575f2431","size":50486,"exec":false},{"path":"references/sources.md","sha256":"9db649871d50cec70bc7909ab0a4fd68bf902745cb128173c3994aa8b8c5a988","size":17352,"exec":false},{"path":"scripts/AgentKit/Pipeline/AddressablesJobs.cs","sha256":"862a2fc4c651be751cbfbf46a0e51b14eff7b7530f8691c72a8f0aedc2cf80dd","size":24414,"exec":false},{"path":"scripts/AgentKit/Pipeline/ArtDropJobs.cs","sha256":"38f5d8d349aa8362b453ae08e179dbaf6778fa2692ddf505601bea56fcd88f2b","size":37459,"exec":false},{"path":"scripts/AgentKit/Pipeline/EditorEditJobs.cs","sha256":"505a5816a64a92fb00536db5bfec238085fb1a95df0c960667260386c9627269","size":16776,"exec":false},{"path":"scripts/AgentKit/Pipeline/PipelineBuild.cs","sha256":"6774278798c91440489cce698138013cb1bf1a821e8b80a02c408656c1702729","size":17557,"exec":false},{"path":"scripts/AgentKit/Pipeline/PipelineChecks.cs","sha256":"558cb4716bd61abb73f6a8ef1ca0ebdb9f15df10be9c669b3f4102d7b1e76f05","size":13428,"exec":false},{"path":"scripts/AgentKit/Pipeline/PipelineRules.cs","sha256":"bec6dd9704f7668e9fed9cec3cc975bdfaebacbec4298b7c8a38056c36a263f4","size":7302,"exec":false},{"path":"scripts/AgentKit/Pipeline/PropImportPostprocessor.cs","sha256":"3cd1dee4c68e92e68e41757b932fa4c4e77f38f316f8d72fb9acfb275e06262e","size":6656,"exec":false},{"path":"scripts/AgentKit/Pipeline/Tests/PipelineContentTests.cs","sha256":"570276dda02f9ea24e887b5e6019ef9634cde5319974bfb2ce9a26e451be7227","size":7083,"exec":false},{"path":"scripts/AgentKit/PipelineCli/AgentKit.PipelineCli.asmdef","sha256":"73e86ed42f8560e39944febced4bc45c4b6087dc452495fe94d017724e7069e2","size":612,"exec":false},{"path":"scripts/AgentKit/PipelineCli/PipelineCliCommands.cs","sha256":"a0143e932002e3f6b54ef9b4bc334415c39823ae794751fc7db2d7dd622203f4","size":4296,"exec":false},{"path":"scripts/Runtime/AgentAddressablesSmoke.cs","sha256":"9dd0d8cb0b95ec65bed284d026eb1abc71ea2e2d62bdaa029f96b6198013ed6d","size":4174,"exec":false},{"path":"scripts/templates/PipelineAsmdef/Editor/Game.Pipeline.Editor.asmdef","sha256":"cf802502971da70b9a6b9c6f18d0d32728d3f5ff9c6c2b948ccdf38ddb918ed3","size":389,"exec":false},{"path":"scripts/templates/PipelineAsmdef/Editor/TextureRuleAudit.cs","sha256":"7c4256ca74aa2be2a1e453c40653807b895b00b7eade2ae601897e3fb596c75b","size":2327,"exec":false},{"path":"scripts/templates/PipelineAsmdef/Tests/Game.Pipeline.Tests.asmdef","sha256":"5289a53406fef4ee53d882bbaa825cc52a063514c1eb8b3e759ef2dc637eab03","size":568,"exec":false},{"path":"scripts/templates/PipelineAsmdef/Tests/TextureRuleTests.cs","sha256":"9ab47e781c293bd22a74ac44ca95b55164b6a1b4f20eb9e446237a15aa8a0e0a","size":1280,"exec":false},{"path":"scripts/ut_pipeline.py","sha256":"8b93ba575f6859d7dc05ba0c664eb8a210ccee22eec123835a59b853d6e5a05d","size":56155,"exec":false}]},"scenario-unity-shaders":{"description":"Use when a Unity 6.3 URP task involves shaders: hand-written HLSL, Shader Graph water, toon, dissol…","category":"media-eventtech","tier":"free","origin":"scenario","requires_auth":false,"sha256":"bf0cf46c1e6bb2d0ffe3852fc363a2ad3d1ded020cf4b7b41ffd7cae7e653de3","upstream_path":"skills/game-engines/unity/scenario-unity-shaders/SKILL.md","requires":["scenario-unity-expert"],"software":["Unity 6.3"],"hasScripts":true,"scriptCount":21,"execBridge":false,"execBridgeFiles":[],"files":[{"path":"SKILL.md","sha256":"bf0cf46c1e6bb2d0ffe3852fc363a2ad3d1ded020cf4b7b41ffd7cae7e653de3","size":20513,"exec":false},{"path":"references/critique.md","sha256":"e8934e753805665a4bb8fbdea78db41268040eeb7695aba5ca790227137fd438","size":12242,"exec":false},{"path":"references/expert-notes.md","sha256":"23ba5da22cdd325b46c91df8b34c3b8a7b14fa28a0374ffb6beb888dea924856","size":25730,"exec":false},{"path":"references/gui-paths.md","sha256":"e00f3a24db197575541a9ae5287c5ac4350487fc517460d19e9c1316cd4ad315","size":18163,"exec":false},{"path":"references/procedures.md","sha256":"e4d6c4b92c3841d0a270533cec5c525bf258ddae8ac0fe8997e356da3630b1fa","size":44695,"exec":false},{"path":"references/sources.md","sha256":"6f498801b0b43200f1d6357f9077001c9fb78267ae0317086a903d27bc6d41f0","size":22805,"exec":false},{"path":"scripts/AgentKit/Shaders/ComputeJobs.cs","sha256":"e22096eb5b25adea4e7b685b4a671189c0a77ed7ecde3b0aa181a05269b2e333","size":6984,"exec":false},{"path":"scripts/AgentKit/Shaders/GpuCostJobs.cs","sha256":"48a53c13e2cabde1c7a13b66cde69baf67c2beeab15204a642cc72dc5edf5d41","size":9740,"exec":false},{"path":"scripts/AgentKit/Shaders/PsoJobs.cs","sha256":"e9e5a28f8f7df32005fbfb8943f328de127c764f004d06ef6fcc575f617056ab","size":9830,"exec":false},{"path":"scripts/AgentKit/Shaders/RendererFeatureJobs.cs","sha256":"db119383b251fced87b28ecf2d832578a576eb0beb8a54b23f5cb371f8385a3c","size":10833,"exec":false},{"path":"scripts/AgentKit/Shaders/ShaderGraphJobs.cs","sha256":"ce896c4f3d082f4f44221af6dfbd1ef0602f128e92a66af0bd626c0aa72808f3","size":9291,"exec":false},{"path":"scripts/AgentKit/Shaders/ShaderJobs.cs","sha256":"844d0757ddbe40212840ff7169d9a2a6a98d3e9ebcfbaad92acea85bf5b4ce98","size":27032,"exec":false},{"path":"scripts/AgentKit/Shaders/ShaderLab.cs","sha256":"87dccaefc8a312f3d0debdcacdcca2510fb415a4c70af987255bf67b6c67fb10","size":25080,"exec":false},{"path":"scripts/AgentKit/Shaders/VariantJobs.cs","sha256":"1b83dfa175aeeb8a12647d5a52221b3222f5b87a7d4fdcab1163bfc0e7b68ad4","size":24544,"exec":false},{"path":"scripts/Runtime/AgentFullscreenFeature.cs","sha256":"a838d52edd32af2fc3cb281d5ea89c957b453f9d7ad13d20213411e31c6f1e87","size":6243,"exec":false},{"path":"scripts/Runtime/AgentPsoProbe.cs","sha256":"d6da1632573854e9327e3a5b2b7d757a514f14e85ed5f7817038df1f73049f36","size":12803,"exec":false},{"path":"scripts/Shaders/AgentCompute.compute","sha256":"e63376793bdbfbd062e828e5c7e9e62b31fc2e3be62697df356a09466b548c80","size":1874,"exec":false},{"path":"scripts/Shaders/AgentCustomLighting.hlsl","sha256":"14092128d768901fadefc3e39d6c077a68c0438faae09a368ddee4fd77dfeb19","size":6105,"exec":false},{"path":"scripts/Shaders/AgentDissolve.shader","sha256":"c26c41c19b486df876c35670c95d7dc8a5417124b0df0b5ded34ab3373455e84","size":9467,"exec":false},{"path":"scripts/Shaders/AgentEdgeOutline.shader","sha256":"eb06e6c478344ed4a75acd2dbaee0f24e821fe6ad52241ad40b9958d4604d08e","size":4025,"exec":false},{"path":"scripts/Shaders/AgentGrayscale.shader","sha256":"3f986574b9af4b8013e0c7d361e410b8da00f327715e9dccbfc00c63fc28404b","size":1493,"exec":false},{"path":"scripts/Shaders/AgentLit.shader","sha256":"519555c889f33d8b53843aa0d3ab1396566d1428275f5f8464c2be45827dfe34","size":9152,"exec":false},{"path":"scripts/Shaders/AgentNoise.hlsl","sha256":"9d70aac4e3aacbf828fc6aaabd64bfa351446e87572ff3e5d618cfe038e4ce43","size":3208,"exec":false},{"path":"scripts/Shaders/AgentPasses.hlsl","sha256":"80b0ce1f1da27983f514228ad6639b5f52591e4bee9083491b2aa1bb551d37d8","size":5452,"exec":false},{"path":"scripts/Shaders/AgentToon.shader","sha256":"8f49cc1da741f457b6da3e0ac9ec564b4d89149d90cee0bff4df3007c05baa15","size":9828,"exec":false},{"path":"scripts/Shaders/AgentWater.shader","sha256":"b865a7bb72a28d1767d88b00e1c85e63676df0778c478b09d3d2e27a348e608a","size":9437,"exec":false},{"path":"scripts/ut_shaders.py","sha256":"71fcd7c4311b784d0fbc70f0d3f4a62f853455715f9dbe0d7952c7d4ec17f2cd","size":56132,"exec":false}]},"scenario-unity-ui":{"description":"Use when building or fixing game UI in Unity 6.3: main menu, settings screen (resolution, quality, …","category":"design-ui-ux","tier":"free","origin":"scenario","requires_auth":false,"sha256":"9cf61b9ca815b3ed1886d5bcec98ebfc22571f948803c5fc06bf9f584333f755","upstream_path":"skills/game-engines/unity/scenario-unity-ui/SKILL.md","requires":["scenario-unity-expert"],"software":["Unity 6.3"],"hasScripts":true,"scriptCount":32,"execBridge":false,"execBridgeFiles":[],"files":[{"path":"SKILL.md","sha256":"9cf61b9ca815b3ed1886d5bcec98ebfc22571f948803c5fc06bf9f584333f755","size":17307,"exec":false},{"path":"references/critique.md","sha256":"1467315c43abf62aad6d2174df54d93e9c4bdb232bf1834296c8f3c3766bb78a","size":8630,"exec":false},{"path":"references/expert-notes.md","sha256":"e0c128bf8645ee5fe221664cd5c781dabfb14ea6248f43d77d0733d378e7af8b","size":23781,"exec":false},{"path":"references/gui-paths.md","sha256":"66807ad5265940a31547daf5a8537cbc62141501065decd7b465e6dd4dbc1026","size":5200,"exec":false},{"path":"references/procedures.md","sha256":"29d4faa6e8f2ad331d9ce4aef85303e8b8d94f56f36df0d8274a2a4fdc0b438e","size":42170,"exec":false},{"path":"references/sources.md","sha256":"1c776696c9d54cf2b4b377ed8e61d2e92f9da8d4bc4a265ac4759ef71c7a28cb","size":16748,"exec":false},{"path":"scripts/AgentKit/UI/UIAudit.cs","sha256":"50714d1cacced7ed3b9744cfee771589ebc693727b275b8d55a0c98ed3795d45","size":39487,"exec":false},{"path":"scripts/AgentKit/UI/UIBuild.cs","sha256":"ac023db602fd898f174a5d2192aba29a629f825c0d5d48f9fbaeb1b2e21ab335","size":29856,"exec":false},{"path":"scripts/AgentKit/UI/UICapture.cs","sha256":"0c1ce99993d28f71c90f68897b7c6ca3ba8fadc85d20b399c48db2c7f2dfb964","size":33102,"exec":false},{"path":"scripts/AgentKit/UI/UIPerf.cs","sha256":"8985971fd81578a6fd3f9919de02108da269965dd6cd96065cbdff64a84368d4","size":26392,"exec":false},{"path":"scripts/AgentKit/UI/UISetup.cs","sha256":"07f23ef2a7e16eb5a1ab1833ed2972c7cdbc69e120309ae637f925e1f87cb2dc","size":5897,"exec":false},{"path":"scripts/AgentKit/UI/UIToolkitBuild.cs","sha256":"75049ce3ec93d2657d98046708afc5bf630fe2ac07f712ca6b584f5f1206d07d","size":20382,"exec":false},{"path":"scripts/Runtime/UI/AgentUI.Runtime.asmdef","sha256":"3c9fb95fe5977b71ae42137d01ba7d24cbfe674b2a0d5c5641b1da5038ccf4e3","size":444,"exec":false},{"path":"scripts/Runtime/UI/CanvasDeviceScale.cs","sha256":"43958d24558a260e2aff19a68a4d6dae2a4ee477dbda7ba050b8a1213fb0fa73","size":2069,"exec":false},{"path":"scripts/Runtime/UI/ClampedWidth.cs","sha256":"54f78309df4637a53c76250542a93189cdf0f9bfa06a15e24449a8857fe740ae","size":1994,"exec":false},{"path":"scripts/Runtime/UI/HudBar.cs","sha256":"14488466f574030b05a3eb35eeaedf9ae66b52d3d77878cbf877e802b5322abf","size":2906,"exec":false},{"path":"scripts/Runtime/UI/HudModel.cs","sha256":"4f44c529b07811e3486ec24816ed24203db203eb75442f76a5cc84cdc79f807b","size":3623,"exec":false},{"path":"scripts/Runtime/UI/HudView.cs","sha256":"712e93b3b1f6490007c4672dd31eb0bb44843af7e53bec9b8af55fac3ae9bbae","size":1481,"exec":false},{"path":"scripts/Runtime/UI/MenuRouter.cs","sha256":"3da348c7952fbf9c9e6f078a1eff44571b7e6dfe19697930b979ecd00ff3fdaa","size":4163,"exec":false},{"path":"scripts/Runtime/UI/MenuScreen.cs","sha256":"7b26db2aa577b13f19fd9a69c4d7112756e14c83d097258d65d84a56f3b6324d","size":4843,"exec":false},{"path":"scripts/Runtime/UI/PanelChangeLog.cs","sha256":"18ff907c0d203f42a47910a288337196d547176934600274fafbc49e123010fd","size":3676,"exec":false},{"path":"scripts/Runtime/UI/RebindRow.cs","sha256":"5650a5dcf31f703125916cf1af73b893ef9533286f91a0cd7e896c458b27ce5a","size":3454,"exec":false},{"path":"scripts/Runtime/UI/RebuildProbe.cs","sha256":"52c42816a5cf95d0b0cdb195ebc003db1dc8a75397e9a77b862bf51c4718283f","size":1212,"exec":false},{"path":"scripts/Runtime/UI/ScrollToSelection.cs","sha256":"d9401696c2b0cc5ee1659fef865801f358e0e226715b42a83ae25a9ad7944fbc","size":2264,"exec":false},{"path":"scripts/Runtime/UI/SelectableFeedback.cs","sha256":"ecf8bbab358a0a867208fb92e1e4a790c4cb993b992192d151f52f1ef0d80bad","size":3642,"exec":false},{"path":"scripts/Runtime/UI/SettingsScreen.cs","sha256":"7b386b9e7de1d4425fd4fdaaf9703d1a1499fbb1023baaee05456b23a7fa62e1","size":6628,"exec":false},{"path":"scripts/Runtime/UI/SettingsService.cs","sha256":"d19662fc7ed48b89b22af678db1c64c2ea3558331a5a3d44aad5fb550c7ef246","size":4291,"exec":false},{"path":"scripts/Runtime/UI/UILoader.cs","sha256":"ae3b8087cbe41f65d9c6aab54a2fbb41caa24fd7f8f4b504996945e6e8065f76","size":2504,"exec":false},{"path":"scripts/Runtime/UI/UiCounterSampler.cs","sha256":"34cebfc40d47925f8d378322b978bb84d54a61fc555699bafd77c1fbe649e824","size":4149,"exec":false},{"path":"scripts/Runtime/UI/UiPerfDriver.cs","sha256":"6ce266e1ca0f9e33fcbd4a45fadd0a29f996fe00ceca23cc4ef16591fe7d8288","size":927,"exec":false},{"path":"scripts/Runtime/UI/UiTheme.cs","sha256":"27a513e460d683f6c51f8cd16445aa53d4f7d3b11221d069d0717a13e98f265e","size":2572,"exec":false},{"path":"scripts/Runtime/UI/UitkHideDriver.cs","sha256":"ffe011cbf1b2d148a14b6ebe829269750de922594e52529fc63eae648829ff3b","size":6414,"exec":false},{"path":"scripts/Runtime/UI/UitkTextureGrid.cs","sha256":"8ae73058d4a3e59138d58849e9d2803559079ce0ef4cfb5c95396e980111e2ec","size":3052,"exec":false},{"path":"scripts/Runtime/UI/UitkVertexGrid.cs","sha256":"d33f5fe3c25e51f0e02f858981113fc67c5c63f4ca87f6f490a4f0dc43e8c3bf","size":2121,"exec":false},{"path":"scripts/templates/uitk/AgentRuntimeTheme.tss","sha256":"682e2b1c6cc1d6e332c15f56c840f7d8282cb1e5bc627eb6664580352a752fda","size":38,"exec":false},{"path":"scripts/templates/uitk/Hud.uss","sha256":"774b424ea9f9624b07970ef7c40f70fdec7835290e0d8bebdabb325db8e8d5cb","size":2445,"exec":false},{"path":"scripts/templates/uitk/Hud.uxml","sha256":"d379afb21468f1c516c4c4fe349f96b6d8d46d0e03406e1ac717a460d69b36f3","size":2643,"exec":false},{"path":"scripts/ut_ui.py","sha256":"0b2aaa743a160d4c8c31cb4e16513f9e4503de6a3129fdd4eaa4b13338ec5c46","size":24204,"exec":false}]}},"subagents":{}}
|
package/lib/store-shared.mjs
CHANGED
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { createHash } from 'node:crypto';
|
|
2
|
-
import { chmodSync, existsSync, lstatSync, mkdirSync, readdirSync, statSync, writeFileSync } from 'node:fs';
|
|
2
|
+
import { chmodSync, existsSync, lstatSync, mkdirSync, readdirSync, readFileSync, statSync, writeFileSync } from 'node:fs';
|
|
3
3
|
import { homedir } from 'node:os';
|
|
4
4
|
import { basename, dirname, join, resolve, sep } from 'node:path';
|
|
5
5
|
|
|
@@ -66,10 +66,10 @@ function assertNoSymlink(path) {
|
|
|
66
66
|
catch (e) { if (e.code !== 'ENOENT') throw e; }
|
|
67
67
|
}
|
|
68
68
|
|
|
69
|
-
// Checks every destination
|
|
70
|
-
export function
|
|
69
|
+
// Checks every destination; throws on an unsafe path and touches nothing.
|
|
70
|
+
export function planSkillFiles(skillMd, files) {
|
|
71
71
|
const dir = resolve(dirname(skillMd));
|
|
72
|
-
|
|
72
|
+
return files.map((f) => {
|
|
73
73
|
safeRel(f.path);
|
|
74
74
|
const dest = resolve(dir, ...f.path.split('/'));
|
|
75
75
|
if (!dest.startsWith(dir + sep)) throw new Error(`Path escapes skill dir: ${f.path}`);
|
|
@@ -77,6 +77,9 @@ export function writeSkillFiles(skillMd, files) {
|
|
|
77
77
|
assertNoSymlink(dir);
|
|
78
78
|
return { ...f, dest };
|
|
79
79
|
});
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
export function writePlan(plan) {
|
|
80
83
|
for (const f of plan) {
|
|
81
84
|
mkdirSync(dirname(f.dest), { recursive: true });
|
|
82
85
|
writeFileSync(f.dest, f.data);
|
|
@@ -85,6 +88,80 @@ export function writeSkillFiles(skillMd, files) {
|
|
|
85
88
|
return plan.map((f) => f.dest);
|
|
86
89
|
}
|
|
87
90
|
|
|
91
|
+
export const writeSkillFiles = (skillMd, files) => writePlan(planSkillFiles(skillMd, files));
|
|
92
|
+
|
|
93
|
+
const RAW_BASE_RE = /^https:\/\/raw\.githubusercontent\.com\/[\w.-]+\/[\w.-]+$/;
|
|
94
|
+
const ECC_SOURCE = {
|
|
95
|
+
id: 'ecc', label: 'ECC', raw_base: 'https://raw.githubusercontent.com/affaan-m/ECC',
|
|
96
|
+
license: 'MIT', copyright: 'Copyright (c) 2026 Affaan Mustafa', third_party: true,
|
|
97
|
+
};
|
|
98
|
+
|
|
99
|
+
// Test overrides: AOS_STORE_INDEX / AOS_STORE_RAW_BASE (ECC), AOS_STORE_INDEX_SCENARIO / AOS_STORE_RAW_BASE_SCENARIO (Scenario).
|
|
100
|
+
export function loadSources(root, env = process.env) {
|
|
101
|
+
const specs = [
|
|
102
|
+
{ file: env.AOS_STORE_INDEX || join(root, 'lib', 'ecc-store-index.json'), base: env.AOS_STORE_RAW_BASE, fallback: ECC_SOURCE },
|
|
103
|
+
{ file: env.AOS_STORE_INDEX_SCENARIO || join(root, 'lib', 'scenario-store-index.json'), base: env.AOS_STORE_RAW_BASE_SCENARIO },
|
|
104
|
+
];
|
|
105
|
+
return specs.map(({ file, base, fallback }) => {
|
|
106
|
+
const index = JSON.parse(readFileSync(file, 'utf8'));
|
|
107
|
+
if (!index.pinned_commit || !index.skills || !index.subagents) throw new Error(`Invalid AOS store index: ${file}`);
|
|
108
|
+
const meta = { ...fallback, ...index.source };
|
|
109
|
+
if (!meta.id || !meta.label) throw new Error(`Store index has no source descriptor: ${file}`);
|
|
110
|
+
if (!base && !RAW_BASE_RE.test(meta.raw_base || '')) throw new Error(`Untrusted raw_base in ${file}: ${meta.raw_base}`);
|
|
111
|
+
return { ...meta, raw_base: (base || meta.raw_base).replace(/\/+$/, ''), pinned_commit: index.pinned_commit, index };
|
|
112
|
+
});
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function findItems(sources, name) {
|
|
116
|
+
const found = [];
|
|
117
|
+
for (const src of sources) {
|
|
118
|
+
for (const type of ['skills', 'subagents']) {
|
|
119
|
+
if (src.index[type]?.[name]) found.push({ name, item: src.index[type][name], type, src });
|
|
120
|
+
}
|
|
121
|
+
}
|
|
122
|
+
return found;
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
export function findItem(sources, name) {
|
|
126
|
+
const found = findItems(sources, name);
|
|
127
|
+
if (found.length > 1) {
|
|
128
|
+
throw new Error(`Name collision: '${name}' exists in ${found.map((f) => f.src.label).join(' and ')}; refusing to pick one or overwrite`);
|
|
129
|
+
}
|
|
130
|
+
return found[0] || null;
|
|
131
|
+
}
|
|
132
|
+
|
|
133
|
+
// The item plus the skills it requires (same source), dependencies first.
|
|
134
|
+
export function installPlan(sources, found) {
|
|
135
|
+
const plan = [];
|
|
136
|
+
const visit = (entry, chain) => {
|
|
137
|
+
if (chain.includes(entry.name)) throw new Error(`Circular requires: ${[...chain, entry.name].join(' -> ')}`);
|
|
138
|
+
for (const dep of entry.item.requires || []) {
|
|
139
|
+
const hit = findItem(sources, dep);
|
|
140
|
+
if (!hit || hit.src !== entry.src || hit.type !== 'skills') throw new Error(`${entry.name} requires '${dep}', which is not available in ${entry.src.label}`);
|
|
141
|
+
visit(hit, [...chain, entry.name]);
|
|
142
|
+
}
|
|
143
|
+
if (!plan.some((p) => p.name === entry.name)) plan.push(entry);
|
|
144
|
+
};
|
|
145
|
+
visit(found, []);
|
|
146
|
+
return plan;
|
|
147
|
+
}
|
|
148
|
+
|
|
149
|
+
export function planSummary(plan) {
|
|
150
|
+
const all = plan.flatMap((p) => (p.item.files || []).map((f) => ({ ...f, skill: p.name })));
|
|
151
|
+
const bridge = plan.flatMap((p) => (p.item.execBridgeFiles || []).map((f) => ({ skill: p.name, ...f })));
|
|
152
|
+
return {
|
|
153
|
+
skills: plan.map((p) => p.name),
|
|
154
|
+
requires: plan.slice(0, -1).map((p) => p.name),
|
|
155
|
+
fileCount: all.length || plan.length,
|
|
156
|
+
totalSize: all.reduce((n, f) => n + f.size, 0),
|
|
157
|
+
scriptCount: plan.reduce((n, p) => n + (p.item.scriptCount || 0), 0),
|
|
158
|
+
hasScripts: plan.some((p) => p.item.hasScripts),
|
|
159
|
+
execBridge: plan.some((p) => p.item.execBridge),
|
|
160
|
+
execBridgeFiles: bridge,
|
|
161
|
+
software: [...new Set(plan.flatMap((p) => p.item.software || []))],
|
|
162
|
+
};
|
|
163
|
+
}
|
|
164
|
+
|
|
88
165
|
export function localSkills(root) {
|
|
89
166
|
const found = new Map();
|
|
90
167
|
const visit = (dir) => {
|
package/lib/store-ui/index.html
CHANGED
|
@@ -56,6 +56,8 @@ dialog h2{font-family:var(--serif);font-weight:500;margin:0 0 .6rem}
|
|
|
56
56
|
dialog pre{margin:.6rem 0;padding:.7rem;border-radius:.6rem;background:var(--ink);color:var(--white);font-size:.7rem;overflow-x:auto;white-space:pre-wrap;word-break:break-all}
|
|
57
57
|
dialog .acts{display:flex;gap:.5rem;justify-content:flex-end;margin-top:1rem}
|
|
58
58
|
.err{color:oklch(0.5 0.2 25);font-size:.75rem}
|
|
59
|
+
.badge.warn{border-color:oklch(0.5 0.2 25);color:oklch(0.5 0.2 25)}
|
|
60
|
+
.warnbox{padding:.6rem .8rem;border:2px solid oklch(0.5 0.2 25);border-radius:.6rem;color:oklch(0.5 0.2 25);font-size:.78rem;font-weight:700}
|
|
59
61
|
</style></head><body>
|
|
60
62
|
<div class="container"><main id="app"></main></div>
|
|
61
63
|
<dialog id="dlg"></dialog>
|
|
@@ -70,7 +72,7 @@ const visible=()=>{const q=S.q.toLowerCase();return base().filter(i=>(S.sub==='i
|
|
|
70
72
|
const uniq=f=>[...new Set(S.data.items.map(f))].sort();
|
|
71
73
|
const count=(f,v)=>base().filter(i=>f(i)===v).length;
|
|
72
74
|
const chip=(a,v,label,n)=>`<button class="chip" aria-pressed="${S[a]===v}" data-a="${a}" data-v="${esc(v)}">${esc(label)}<b>${n}</b></button>`;
|
|
73
|
-
function strip(){const all=S.data.items;
|
|
75
|
+
function strip(){const all=S.data.items;return `<div class="strip"><div><strong>${all.length}</strong><small>total</small></div>${uniq(i=>i.source).map(s=>`<div><strong>${all.filter(i=>i.source===s).length}</strong><small>${esc(s)}</small></div>`).join('')}</div>`}
|
|
74
76
|
function tabs(){const n=base(),ic=n.filter(i=>i.installed).length,k=x=>S.data.items.filter(i=>i.kind===x).length;return `<div class="tabs">${chip('tab','skill','Skills',k('skill'))}${chip('tab','agent','Agents',k('agent'))}<span style="width:1rem"></span>${chip('sub','installed','Installed',ic)}${chip('sub','discover','Discover',n.length-ic)}</div>`}
|
|
75
77
|
const scopeToggle=()=>`<div class="scope"><span class="kicker" style="margin:0">Scope</span>${chip('scope','global','Global','')}${chip('scope','project','Project','')}</div>`;
|
|
76
78
|
function act(i){
|
|
@@ -81,7 +83,7 @@ function act(i){
|
|
|
81
83
|
}
|
|
82
84
|
function row(i){
|
|
83
85
|
const k=key(i),open=S.expanded.has(k);
|
|
84
|
-
const badge=i.fileCount>1?`<span class="badge">${i.fileCount} files</span>`:'';
|
|
86
|
+
const badge=(i.fileCount>1?`<span class="badge">${i.fileCount} files</span>`:'')+(i.execBridge?'<span class="badge warn">exec bridge</span>':'')+(i.requires.length?`<span class="badge">+${i.requires.length} required</span>`:'');
|
|
85
87
|
let h=`<div class="rowwrap"><div class="row"><span class="dot ${i.installed?'g':''}"></span><span class="n" data-a="exp" data-v="${esc(k)}" style="cursor:pointer" title="Show description">${esc(i.name)}${badge}</span><span class="d" style="color:var(--muted)">${esc(i.description)}</span><span class="c cat">${esc(i.category)}</span><span class="s src">${esc(i.source)}</span><span style="text-align:right">${act(i)}</span></div>`;
|
|
86
88
|
if(open){const d=i.core?i.description:S.detail[k];h+=`<div class="detail">${d===undefined?'Loading...':esc(d)}</div>`}
|
|
87
89
|
return h+'</div>';
|
|
@@ -109,9 +111,16 @@ async function preview(k){
|
|
|
109
111
|
try{
|
|
110
112
|
const d=await post('/api/preview',i);
|
|
111
113
|
const ok=d.ok&&d.targets.length;
|
|
112
|
-
const
|
|
113
|
-
const
|
|
114
|
-
|
|
114
|
+
const m=d.meta||{};
|
|
115
|
+
const fc=m.fileCount||i.fileCount,tc=fc>0?Math.round(d.targets.length/fc):1;const size=m.totalSize>0?` = ${fc} file(s) \u00d7 ${tc} target(s), ${(m.totalSize/1024).toFixed(1)} KB each`:(i.totalSize!=null?` = ${i.fileCount} file(s) \u00d7 ${tc} target(s), ${(i.totalSize/1024).toFixed(1)} KB each`:'');
|
|
116
|
+
const warn=(i.hasHooks?'<p class="err">Includes hooks \u2014 copied only, NOT registered in your harness settings; the skill may need manual wiring.</p>':'')
|
|
117
|
+
+(m.execBridge?`<p class="warnbox">Warning: contains a script that executes code received over a local socket or file channel without authentication \u2014 install only if you use this bridge.<br><span style="font-weight:400">${esc((m.execBridgeFiles||[]).map(f=>f.skill+'/'+f.path).join(', '))}</span></p>`:(m.hasScripts?`<p class="cmdnote">Contains ${m.scriptCount} script file(s) that run on your machine when the skill is used. Review them before use.</p>`:''))
|
|
118
|
+
+(m.software&&m.software.length?`<p class="cmdnote">Needs third-party software that is not included: ${esc(m.software.join(', '))}.</p>`:'')
|
|
119
|
+
+(m.requires&&m.requires.length?`<p class="cmdnote">Also installs required skill(s): ${esc(m.requires.join(', '))}.</p>`:'');
|
|
120
|
+
const srcLabel=m.source||i.source,pin=(m.pinned_commit||S.data.pinned_commit).slice(0,10);
|
|
121
|
+
const lic=m.license?` \u2014 ${esc(m.license)}${m.copyright?', '+esc(m.copyright):''}`:'';
|
|
122
|
+
const nfiles=m.fileCount||i.fileCount;
|
|
123
|
+
dlg.innerHTML=`<h2>Add ${esc(i.name)}</h2><p class="kicker">${scopeName()} scope \u2014 will write ${d.targets.length} file(s)${size}</p><p class="cmdnote">Source: ${esc(srcLabel)}${lic}${m.thirdParty?' (third-party content)':''}</p>${warn}<pre style="max-height:16rem;overflow:auto">${esc(ok?d.targets.join('\n'):(d.stdout+d.stderr).trim())}</pre><p class="cmdnote">Downloads ${nfiles>1?nfiles+' files':'the file'} from ${esc(srcLabel)} at ${esc(pin)}, each verified by SHA-256.</p><div id="res"></div><div class="acts"><button class="button secondary" data-a="close">Cancel</button>${ok?`<button class="button" data-a="confirm" data-v="${esc(k)}">Install to ${scopeName()}</button>`:''}</div>`;
|
|
115
124
|
dlg.showModal();
|
|
116
125
|
}catch(e){alert('Preview failed: '+e.message)}
|
|
117
126
|
finally{S.busy=null;render()}
|
package/lib/store-ui/server.mjs
CHANGED
|
@@ -4,7 +4,7 @@ import { readFileSync } from 'node:fs';
|
|
|
4
4
|
import { dirname, join, resolve } from 'node:path';
|
|
5
5
|
import { randomBytes, timingSafeEqual } from 'node:crypto';
|
|
6
6
|
import { fileURLToPath } from 'node:url';
|
|
7
|
-
import { isInstalled, localAgents, localSkills } from '../store-shared.mjs';
|
|
7
|
+
import { findItem, installPlan, isInstalled, loadSources, localAgents, localSkills, planSummary } from '../store-shared.mjs';
|
|
8
8
|
|
|
9
9
|
const ROOT = resolve(dirname(fileURLToPath(import.meta.url)), '..', '..');
|
|
10
10
|
const CLI = join(ROOT, 'bin', 'aos-store.mjs');
|
|
@@ -18,7 +18,7 @@ const frontDescription = (file) => {
|
|
|
18
18
|
};
|
|
19
19
|
|
|
20
20
|
function catalog(scope, cwd) {
|
|
21
|
-
const
|
|
21
|
+
const sources = loadSources(ROOT);
|
|
22
22
|
const project = scope === 'project';
|
|
23
23
|
const items = [];
|
|
24
24
|
const core = { skill: localSkills(ROOT), agent: localAgents(ROOT) };
|
|
@@ -27,35 +27,57 @@ function catalog(scope, cwd) {
|
|
|
27
27
|
items.push({ name, kind, description: frontDescription(file), category: 'core', source: 'AOS Core', installed: true, core: true });
|
|
28
28
|
}
|
|
29
29
|
}
|
|
30
|
-
for (const
|
|
31
|
-
for (const [
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
30
|
+
for (const src of sources) {
|
|
31
|
+
for (const [kind, key, type] of [['skill', 'skills', 'skills'], ['agent', 'subagents', 'agents']]) {
|
|
32
|
+
for (const [name, it] of Object.entries(src.index[key] || {})) {
|
|
33
|
+
if (core[kind].has(name)) continue;
|
|
34
|
+
const installed = isInstalled(type, name, it, { project, cwd });
|
|
35
|
+
const files = kind === 'skill' && it.files?.length > 1 ? it.files : null;
|
|
36
|
+
let plan = [];
|
|
37
|
+
let problem = '';
|
|
38
|
+
if (kind === 'skill') {
|
|
39
|
+
try { plan = installPlan(sources, { name, item: it, type, src }); } catch (e) { problem = e.message; }
|
|
40
|
+
}
|
|
41
|
+
const sum = plan.length ? planSummary(plan) : {};
|
|
42
|
+
items.push({
|
|
43
|
+
name, kind, description: it.description || '', category: it.category || '', source: src.label, installed, upstreamPath: it.upstream_path,
|
|
44
|
+
fileCount: files ? files.length : 1,
|
|
45
|
+
totalSize: files ? files.reduce((n, f) => n + f.size, 0) : null,
|
|
46
|
+
hasHooks: !!files?.some((f) => f.path.split('/').includes('hooks')),
|
|
47
|
+
thirdParty: !!src.third_party, license: src.license, requiresAuth: !!it.requires_auth,
|
|
48
|
+
requires: it.requires || [], hasScripts: !!sum.hasScripts, execBridge: !!sum.execBridge, software: sum.software || [], problem,
|
|
49
|
+
});
|
|
50
|
+
}
|
|
41
51
|
}
|
|
42
52
|
}
|
|
43
|
-
return {
|
|
53
|
+
return {
|
|
54
|
+
scope, cwd, pinned_commit: sources[0].pinned_commit, items,
|
|
55
|
+
sources: sources.map((s) => ({ label: s.label, pinned_commit: s.pinned_commit, license: s.license, copyright: s.copyright, upstream: s.upstream })),
|
|
56
|
+
};
|
|
44
57
|
}
|
|
45
58
|
|
|
46
59
|
const details = new Map();
|
|
47
|
-
async function fetchDetail(
|
|
48
|
-
|
|
49
|
-
|
|
60
|
+
async function fetchDetail(item, src) {
|
|
61
|
+
const cacheKey = `${src.label}:${item.name}`;
|
|
62
|
+
if (details.has(cacheKey)) return details.get(cacheKey);
|
|
63
|
+
const url = `${src.raw_base}/${src.pinned_commit}/${item.upstreamPath}`;
|
|
50
64
|
const res = await fetch(url, { headers: { 'user-agent': 'aos-store' }, signal: AbortSignal.timeout(10000) });
|
|
51
65
|
if (!res.ok) throw new Error(`upstream ${res.status}`);
|
|
52
66
|
const fm = (await res.text()).match(/^---\n([\s\S]*?)\n---/);
|
|
53
67
|
const d = fm?.[1].match(/^description:\s*(?:>-?|\|-?)?\s*([\s\S]*?)(?=\n[A-Za-z_-]+:|(?![\s\S]))/m);
|
|
54
68
|
const text = (d?.[1] || '').replace(/\s*\n\s*/g, ' ').trim().replace(/^["']|["']$/g, '');
|
|
55
|
-
details.set(
|
|
69
|
+
details.set(cacheKey, text);
|
|
56
70
|
return text;
|
|
57
71
|
}
|
|
58
72
|
|
|
73
|
+
function previewMeta(name, kind) {
|
|
74
|
+
const sources = loadSources(ROOT);
|
|
75
|
+
const found = findItem(sources, name);
|
|
76
|
+
const plan = kind === 'skill' ? installPlan(sources, found) : [found];
|
|
77
|
+
const { src } = found;
|
|
78
|
+
return { source: src.label, license: src.license, copyright: src.copyright, pinned_commit: src.pinned_commit, thirdParty: !!src.third_party, ...planSummary(plan) };
|
|
79
|
+
}
|
|
80
|
+
|
|
59
81
|
const runCli = (args, cwd, timeout) => new Promise((done) => {
|
|
60
82
|
execFile(process.execPath, [CLI, ...args], { cwd, timeout, maxBuffer: 1 << 20 }, (error, stdout, stderr) => {
|
|
61
83
|
done({ ok: !error, stdout, stderr: stderr || (error && error.message) || '' });
|
|
@@ -96,9 +118,10 @@ export function createStoreServer({ cwd = process.cwd() } = {}) {
|
|
|
96
118
|
const name = url.searchParams.get('name') || '';
|
|
97
119
|
if (!NAME_RE.test(name)) return send(res, 400, { error: 'invalid name' });
|
|
98
120
|
const data = catalog('global', cwd);
|
|
99
|
-
const item = data.items.find((i) => i.name === name && i.
|
|
121
|
+
const item = data.items.find((i) => i.name === name && !i.core && i.kind === url.searchParams.get('kind'));
|
|
100
122
|
if (!item) return send(res, 404, { error: 'not found' });
|
|
101
|
-
|
|
123
|
+
const src = loadSources(ROOT).find((x) => x.label === item.source);
|
|
124
|
+
try { return send(res, 200, { description: await fetchDetail(item, src) }); }
|
|
102
125
|
catch (e) { return send(res, 502, { error: e.message }); }
|
|
103
126
|
}
|
|
104
127
|
if (p === '/' || p === '/index.html') {
|
|
@@ -122,7 +145,7 @@ export function createStoreServer({ cwd = process.cwd() } = {}) {
|
|
|
122
145
|
if (p === '/api/preview') {
|
|
123
146
|
const r = await runCli(['install', name, '--dry-run', ...flags], cwd, 10000);
|
|
124
147
|
const targets = r.stdout.split('\n').filter((l) => l.startsWith('[dry-run] write ')).map((l) => l.slice(16));
|
|
125
|
-
return send(res, 200, { ...r, scope, targets });
|
|
148
|
+
return send(res, 200, { ...r, scope, targets, meta: (() => { try { return previewMeta(name, kind); } catch { return null; } })() });
|
|
126
149
|
}
|
|
127
150
|
const r = await runCli(['install', name, '--net', ...flags], cwd, 30000);
|
|
128
151
|
const installed = catalog(scope, cwd).items.find((i) => i.name === name && i.kind === kind).installed;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@hybridlabor-api/aos",
|
|
3
|
-
"version": "4.
|
|
3
|
+
"version": "4.13.0",
|
|
4
4
|
"description": "AOS — A Curated AI AGENT OS. Optimized agent skills and add-ons like memB, OpenWiki, Heimdall Token Saver, and Godmode architectures.",
|
|
5
5
|
"main": "installer.js",
|
|
6
6
|
"engines": {
|
|
@@ -27,7 +27,7 @@
|
|
|
27
27
|
"plugin:build": "node scripts/build-plugin-manifest.mjs",
|
|
28
28
|
"plugin:check": "node scripts/build-plugin-manifest.mjs --check",
|
|
29
29
|
"doctor": "node bin/aos-doctor.mjs",
|
|
30
|
-
"test": "node scripts/validate-skills.mjs --selftest && node scripts/validate-skills.mjs && node scripts/build-plugin-manifest.mjs --check && node --test tests/opencode-graph-gate.test.js && node --test tests/cross-harness-hooks.test.js && node tests/aos-store.test.mjs && node --test tests/aos-store-ui.test.mjs && node tests/aos-doctor.test.mjs && node tests/build-plugin-manifest.test.mjs"
|
|
30
|
+
"test": "node scripts/validate-skills.mjs --selftest && node scripts/validate-skills.mjs && node scripts/build-plugin-manifest.mjs --check && node --test tests/opencode-graph-gate.test.js && node --test tests/cross-harness-hooks.test.js && node tests/aos-store.test.mjs && node --test tests/aos-store-ui.test.mjs && node tests/aos-store-scenario.test.mjs && node tests/aos-doctor.test.mjs && node tests/build-plugin-manifest.test.mjs && node --test tests/agent-models.test.js"
|
|
31
31
|
},
|
|
32
32
|
"publishConfig": {
|
|
33
33
|
"access": "public"
|
|
@@ -1,6 +1,8 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
2
|
|
|
3
|
-
// Generates .claude-plugin/plugin.json
|
|
3
|
+
// Generates .claude-plugin/plugin.json, the plugin-root agents/ directory and the
|
|
4
|
+
// subfolder plugin plugins/bdb-aos/ (same manifest data + skills/agents symlinks
|
|
5
|
+
// into the repo root, so the marketplace install cache stays small).
|
|
4
6
|
//
|
|
5
7
|
// Claude Code resolves plugin components two different ways, and only one of
|
|
6
8
|
// them is obvious:
|
|
@@ -21,7 +23,7 @@
|
|
|
21
23
|
//
|
|
22
24
|
// Usage: node scripts/build-plugin-manifest.mjs [--check]
|
|
23
25
|
|
|
24
|
-
import { existsSync, mkdirSync, readFileSync, readdirSync, rmSync, writeFileSync } from 'node:fs';
|
|
26
|
+
import { existsSync, lstatSync, mkdirSync, readFileSync, readdirSync, readlinkSync, rmSync, symlinkSync, writeFileSync } from 'node:fs';
|
|
25
27
|
import { dirname, join, relative, resolve } from 'node:path';
|
|
26
28
|
import { fileURLToPath } from 'node:url';
|
|
27
29
|
|
|
@@ -94,9 +96,20 @@ const manifest = {
|
|
|
94
96
|
skills,
|
|
95
97
|
};
|
|
96
98
|
|
|
97
|
-
const target = join(ROOT, '.claude-plugin', 'plugin.json');
|
|
98
99
|
const serialized = `${JSON.stringify(manifest, null, 2)}\n`;
|
|
99
|
-
const
|
|
100
|
+
const SUBDIR = join(ROOT, 'plugins', 'bdb-aos');
|
|
101
|
+
// Both manifests come from the same data; the subfolder one resolves the same
|
|
102
|
+
// ./skills/... paths through its symlinks.
|
|
103
|
+
const targets = [
|
|
104
|
+
join(ROOT, '.claude-plugin', 'plugin.json'),
|
|
105
|
+
join(SUBDIR, '.claude-plugin', 'plugin.json'),
|
|
106
|
+
];
|
|
107
|
+
const stale = targets.filter((t) => !existsSync(t) || readFileSync(t, 'utf8') !== serialized);
|
|
108
|
+
const links = { skills: '../../skills', agents: '../../agents' };
|
|
109
|
+
const badLinks = Object.entries(links).filter(([name, to]) => {
|
|
110
|
+
const path = join(SUBDIR, name);
|
|
111
|
+
return !existsSync(path) || !lstatSync(path).isSymbolicLink() || readlinkSync(path) !== to;
|
|
112
|
+
});
|
|
100
113
|
|
|
101
114
|
// `claude plugin tag` refuses to cut a release unless plugin.json and the
|
|
102
115
|
// enclosing marketplace entry agree on the version, so the marketplace copy of
|
|
@@ -110,8 +123,12 @@ const marketSerialized = `${JSON.stringify(market, null, 2)}\n`;
|
|
|
110
123
|
const marketCurrent = readFileSync(marketPath, 'utf8');
|
|
111
124
|
|
|
112
125
|
if (CHECK) {
|
|
113
|
-
if (
|
|
114
|
-
console.error(
|
|
126
|
+
if (stale.length > 0) {
|
|
127
|
+
console.error(`plugin.json is out of date (${stale.map((t) => relative(ROOT, t)).join(', ')}) — run: node scripts/build-plugin-manifest.mjs`);
|
|
128
|
+
process.exit(1);
|
|
129
|
+
}
|
|
130
|
+
if (badLinks.length > 0) {
|
|
131
|
+
console.error(`plugins/bdb-aos symlinks missing or wrong (${badLinks.map(([n]) => n).join(', ')}) — run: node scripts/build-plugin-manifest.mjs`);
|
|
115
132
|
process.exit(1);
|
|
116
133
|
}
|
|
117
134
|
if (marketCurrent !== marketSerialized) {
|
|
@@ -122,10 +139,16 @@ if (CHECK) {
|
|
|
122
139
|
console.error(`agents/ is out of date (${drift.join(', ')}) — run: node scripts/build-plugin-manifest.mjs`);
|
|
123
140
|
process.exit(1);
|
|
124
141
|
}
|
|
125
|
-
console.log(`plugin
|
|
142
|
+
console.log(`plugin manifests up to date: ${skills.length} skills, ${agentNames.length} agents`);
|
|
126
143
|
} else {
|
|
127
|
-
|
|
128
|
-
|
|
144
|
+
for (const t of targets) {
|
|
145
|
+
mkdirSync(dirname(t), { recursive: true });
|
|
146
|
+
writeFileSync(t, serialized);
|
|
147
|
+
}
|
|
148
|
+
for (const [name, to] of badLinks) {
|
|
149
|
+
rmSync(join(SUBDIR, name), { force: true });
|
|
150
|
+
symlinkSync(to, join(SUBDIR, name));
|
|
151
|
+
}
|
|
129
152
|
writeFileSync(marketPath, marketSerialized);
|
|
130
|
-
console.log(`Wrote
|
|
153
|
+
console.log(`Wrote 2 plugin.json files with ${skills.length} skills and ${agentNames.length} agents`);
|
|
131
154
|
}
|