rnxsim 0.1.313 → 0.1.314
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/LICENSE +11 -10
- package/README.md +5 -0
- package/cli/app-config.ts +65 -0
- package/cli/app-fonts.ts +408 -0
- package/cli/app-project.ts +231 -0
- package/cli/app-splash.ts +185 -0
- package/cli/app-state-reset.ts +24 -0
- package/cli/auth.ts +155 -0
- package/cli/bin.ts +594 -0
- package/cli/bridge-diagnostics.ts +226 -0
- package/cli/bridge-flow-runner.ts +2830 -0
- package/cli/browser-evals.ts +96 -0
- package/cli/commands/agent-wrapper.ts +986 -0
- package/cli/commands/agent.ts +423 -0
- package/cli/commands/app-fonts.ts +98 -0
- package/cli/commands/assert.ts +541 -0
- package/cli/commands/auth.ts +59 -0
- package/cli/commands/camera.ts +266 -0
- package/cli/commands/cleanup.ts +169 -0
- package/cli/commands/compat.ts +87 -0
- package/cli/commands/config.ts +32 -0
- package/cli/commands/control.ts +2142 -0
- package/cli/commands/cpu-profile.ts +269 -0
- package/cli/commands/daemon-mac-app.ts +169 -0
- package/cli/commands/daemon.ts +874 -0
- package/cli/commands/debug.ts +719 -0
- package/cli/commands/desktop.ts +39 -0
- package/cli/commands/detect.ts +197 -0
- package/cli/commands/detox.ts +385 -0
- package/cli/commands/device.ts +133 -0
- package/cli/commands/diagnose.ts +589 -0
- package/cli/commands/electron.ts +95 -0
- package/cli/commands/film.ts +379 -0
- package/cli/commands/flow.ts +1124 -0
- package/cli/commands/inspect/actions.ts +622 -0
- package/cli/commands/inspect/core.ts +2405 -0
- package/cli/commands/inspect/count.ts +17 -0
- package/cli/commands/inspect/describe.ts +192 -0
- package/cli/commands/inspect/env.ts +23 -0
- package/cli/commands/inspect/find.ts +171 -0
- package/cli/commands/inspect/get-layout.ts +39 -0
- package/cli/commands/inspect/keyboard.ts +52 -0
- package/cli/commands/inspect/list.ts +58 -0
- package/cli/commands/inspect/memory.ts +215 -0
- package/cli/commands/inspect/redaction.ts +39 -0
- package/cli/commands/inspect/resolve-target.ts +82 -0
- package/cli/commands/inspect/screens.ts +78 -0
- package/cli/commands/inspect/settle.ts +22 -0
- package/cli/commands/inspect/settling.ts +158 -0
- package/cli/commands/inspect/shared.ts +353 -0
- package/cli/commands/inspect/sleep.ts +14 -0
- package/cli/commands/inspect/tree.ts +32 -0
- package/cli/commands/inspect/url.ts +17 -0
- package/cli/commands/inspect/wait-event.ts +210 -0
- package/cli/commands/inspect/wait-idle.ts +24 -0
- package/cli/commands/inspect/wait-ready.ts +74 -0
- package/cli/commands/inspect/wait-selector.ts +54 -0
- package/cli/commands/inspect/wait.ts +31 -0
- package/cli/commands/inspect.ts +4519 -0
- package/cli/commands/install-desktop.ts +351 -0
- package/cli/commands/login.ts +331 -0
- package/cli/commands/logout.ts +31 -0
- package/cli/commands/maestro-generate.ts +361 -0
- package/cli/commands/maestro.ts +453 -0
- package/cli/commands/mode.ts +57 -0
- package/cli/commands/no-bridge-hint.ts +80 -0
- package/cli/commands/perf.ts +66 -0
- package/cli/commands/permissions.ts +203 -0
- package/cli/commands/profile.ts +108 -0
- package/cli/commands/react.ts +353 -0
- package/cli/commands/record.ts +1434 -0
- package/cli/commands/report-issue.ts +305 -0
- package/cli/commands/reset.ts +85 -0
- package/cli/commands/runtime.ts +351 -0
- package/cli/commands/screenshot-command.ts +106 -0
- package/cli/commands/screenshot-layers.ts +143 -0
- package/cli/commands/screenshot-mode.ts +37 -0
- package/cli/commands/screenshot.ts +488 -0
- package/cli/commands/screenshots-capture.ts +607 -0
- package/cli/commands/screenshots.ts +127 -0
- package/cli/commands/serve.ts +168 -0
- package/cli/commands/setup.ts +545 -0
- package/cli/commands/shell-boolean-mode.ts +81 -0
- package/cli/commands/skills.ts +467 -0
- package/cli/commands/slides.ts +361 -0
- package/cli/commands/state.ts +87 -0
- package/cli/commands/storage.ts +58 -0
- package/cli/commands/telemetry.ts +54 -0
- package/cli/commands/three-mode.ts +763 -0
- package/cli/commands/timeline.ts +122 -0
- package/cli/commands/upgrade.ts +208 -0
- package/cli/commands/upload.ts +1225 -0
- package/cli/commands/version.ts +54 -0
- package/cli/commands/what-happened.ts +327 -0
- package/cli/current-sim.ts +204 -0
- package/cli/desktop-companion.ts +300 -0
- package/cli/drivers/electron.ts +70 -0
- package/cli/drivers/index.ts +20 -0
- package/cli/drivers/playwright-provisioning.ts +180 -0
- package/cli/drivers/playwright.ts +698 -0
- package/cli/drivers/registry.ts +65 -0
- package/cli/drivers/types.ts +102 -0
- package/cli/flow-file.ts +142 -0
- package/cli/flow-live-status.ts +120 -0
- package/cli/flow-session.ts +187 -0
- package/cli/help.ts +80 -0
- package/cli/hidden-runtime-alias.ts +19 -0
- package/cli/hints.ts +216 -0
- package/cli/inspect-notice-state.ts +114 -0
- package/cli/maestro-js.ts +334 -0
- package/cli/open-url.ts +8 -0
- package/cli/parent-pid.ts +204 -0
- package/cli/parse-args.ts +211 -0
- package/cli/prompt.ts +51 -0
- package/cli/recording-access.ts +107 -0
- package/cli/registry.ts +1 -0
- package/cli/resolve-assets.ts +63 -0
- package/cli/run-registry.ts +226 -0
- package/cli/runtime-notes.ts +66 -0
- package/cli/runtime-summary.ts +25 -0
- package/cli/setup-repository.ts +187 -0
- package/cli/telemetry.ts +187 -0
- package/cli/ws-bridge.ts +798 -0
- package/dist-cli/bin.js +5 -5
- package/dist-cli/chunks/{agent-XZ2KTPCU.js → agent-7YBDCYMA.js} +2 -2
- package/dist-cli/chunks/{agent-wrapper-JJYYW2WH.js → agent-wrapper-2GHFBHCR.js} +2 -2
- package/dist-cli/chunks/{app-fonts-IXRNQG6B.js → app-fonts-RSNVPQSU.js} +2 -2
- package/dist-cli/chunks/{assert-54T5SK5F.js → assert-XCMX3XJX.js} +2 -2
- package/dist-cli/chunks/{auth-FI5UDI45.js → auth-B442HRAX.js} +2 -2
- package/dist-cli/chunks/{beta-JV6UKADW.js → beta-XJ55JK3M.js} +2 -2
- package/dist-cli/chunks/camera-UGYSSLIK.js +33 -0
- package/dist-cli/chunks/{chunk-3NV2NCNX.js → chunk-277AEQZX.js} +2 -2
- package/dist-cli/chunks/{chunk-2YR5BGA5.js → chunk-2JNSK774.js} +2 -2
- package/dist-cli/chunks/{chunk-RSZWCKNT.js → chunk-32WOTSTR.js} +3 -3
- package/dist-cli/chunks/{chunk-WEXDAC74.js → chunk-3S753SNQ.js} +2 -2
- package/dist-cli/chunks/{chunk-IJO63TDP.js → chunk-46ZOLOYA.js} +2 -2
- package/dist-cli/chunks/{chunk-WUSWBCWA.js → chunk-5L7ELDQL.js} +8 -9
- package/dist-cli/chunks/{chunk-WF3T4SVI.js → chunk-7OOPFSQS.js} +2 -2
- package/dist-cli/chunks/{chunk-TZFFR3SD.js → chunk-7SV3RPRW.js} +2 -2
- package/dist-cli/chunks/{chunk-WWZIXIRD.js → chunk-7ZC35MOU.js} +1 -1
- package/dist-cli/chunks/chunk-AMG5E6CC.js +9 -0
- package/dist-cli/chunks/{chunk-WINYQ44O.js → chunk-APWNH3A4.js} +1 -1
- package/dist-cli/chunks/chunk-B57XUKY3.js +4 -0
- package/dist-cli/chunks/{chunk-YDGQTMQL.js → chunk-C2NL26TD.js} +1 -1
- package/dist-cli/chunks/{chunk-NMF2ZMZQ.js → chunk-D2FNUWAB.js} +4 -4
- package/dist-cli/chunks/{chunk-YIFT42WN.js → chunk-E5T4XSJ3.js} +2 -2
- package/dist-cli/chunks/{chunk-46EUUFJ5.js → chunk-EAC34EQS.js} +1 -1
- package/dist-cli/chunks/{chunk-OVFJFXUD.js → chunk-EG32ML36.js} +2 -2
- package/dist-cli/chunks/{chunk-5YJCOWCH.js → chunk-FXUAC6D5.js} +1 -1
- package/dist-cli/chunks/chunk-GQSL4USA.js +6 -0
- package/dist-cli/chunks/{chunk-VFCMSYZK.js → chunk-HAXW27SS.js} +2 -2
- package/dist-cli/chunks/{chunk-2D2UPBBR.js → chunk-IZAHPAN6.js} +1 -1
- package/dist-cli/chunks/{chunk-7GN3LVWB.js → chunk-J62KM5TB.js} +2 -2
- package/dist-cli/chunks/{chunk-BTWORNNG.js → chunk-JEMCD5E4.js} +1 -1
- package/dist-cli/chunks/{chunk-DCEMHR2Y.js → chunk-JZS3Q37N.js} +2 -2
- package/dist-cli/chunks/{chunk-D4FFVGI5.js → chunk-KR4JON7D.js} +1 -1
- package/dist-cli/chunks/chunk-KWCYKQIQ.js +4 -0
- package/dist-cli/chunks/{chunk-VNQEB4L7.js → chunk-MCWPL644.js} +2 -2
- package/dist-cli/chunks/chunk-MJYK3N2I.js +4 -0
- package/dist-cli/chunks/{chunk-5TEF3ET3.js → chunk-O6TRIZNS.js} +2 -2
- package/dist-cli/chunks/{chunk-QKDWYITG.js → chunk-P7XL2E73.js} +3 -3
- package/dist-cli/chunks/{chunk-BBULZ7CG.js → chunk-PFQTUKQ4.js} +62 -87
- package/dist-cli/chunks/{chunk-GGRX24GF.js → chunk-PG5RZCTN.js} +2 -2
- package/dist-cli/chunks/{chunk-W6K4EFPH.js → chunk-QGRI2Z4M.js} +2 -2
- package/dist-cli/chunks/{chunk-ZMJD5GEC.js → chunk-QLXXE7GE.js} +1 -1
- package/dist-cli/chunks/{chunk-VZXWHRUZ.js → chunk-QOJJJWJE.js} +89 -133
- package/dist-cli/chunks/{chunk-OZSSI4WN.js → chunk-RWZY5427.js} +2 -2
- package/dist-cli/chunks/{chunk-UC6U3MML.js → chunk-RZKU2K3J.js} +2 -2
- package/dist-cli/chunks/{chunk-IJ5CAZZC.js → chunk-SBV4IK4H.js} +1 -1
- package/dist-cli/chunks/{chunk-DZS6WPUI.js → chunk-SGMVFFMK.js} +1 -1
- package/dist-cli/chunks/{chunk-OHAZNXLK.js → chunk-TAX4UT2N.js} +1 -1
- package/dist-cli/chunks/{chunk-5DHC6KHQ.js → chunk-TUOFAWXT.js} +1 -1
- package/dist-cli/chunks/{chunk-GASE6UBA.js → chunk-UHZLOHGP.js} +1 -1
- package/dist-cli/chunks/{chunk-F5ZRSS3C.js → chunk-VC7V76U3.js} +1 -1
- package/dist-cli/chunks/{chunk-RTN5C5RL.js → chunk-VQVMLW4U.js} +1 -1
- package/dist-cli/chunks/{chunk-WMIIKMGK.js → chunk-VUKKYPZN.js} +2 -2
- package/dist-cli/chunks/{chunk-5TPRP5QT.js → chunk-WGGRJDRE.js} +1 -1
- package/dist-cli/chunks/chunk-X6H76EKP.js +15 -0
- package/dist-cli/chunks/chunk-XLZ5FNRT.js +27 -0
- package/dist-cli/chunks/{chunk-HI5TFJWN.js → chunk-XULEACM4.js} +2 -2
- package/dist-cli/chunks/{chunk-MJRLLB4R.js → chunk-YFSDM7AX.js} +4 -4
- package/dist-cli/chunks/chunk-YWI3UEVX.js +5 -0
- package/dist-cli/chunks/{chunk-XEVZYVIW.js → chunk-ZBSJO4NB.js} +10 -9
- package/dist-cli/chunks/{cleanup-P27PA6JI.js → cleanup-EYLGCA6Z.js} +2 -2
- package/dist-cli/chunks/cli-version-LL2UGIHE.js +4 -0
- package/dist-cli/chunks/{compat-ZD65FED3.js → compat-TLJYHB4E.js} +2 -2
- package/dist-cli/chunks/{config-XMJRNM2A.js → config-4JWUOEXK.js} +2 -2
- package/dist-cli/chunks/{control-KMIQT3QP.js → control-HPAOYF4N.js} +2 -2
- package/dist-cli/chunks/daemon-OYLASXLE.js +4 -0
- package/dist-cli/chunks/{debug-PT4HOP7N.js → debug-4BKXF6KI.js} +5 -5
- package/dist-cli/chunks/{desktop-S3FG72AK.js → desktop-ZQ6ZD2S6.js} +3 -3
- package/dist-cli/chunks/{detox-B3D4IFCN.js → detox-WNPASSS3.js} +2 -2
- package/dist-cli/chunks/{device-XBNDSB2R.js → device-BXLXVG3V.js} +2 -2
- package/dist-cli/chunks/{diagnose-HMQXJE5N.js → diagnose-3QX7W5RW.js} +2 -2
- package/dist-cli/chunks/{disk-cleanup-BLCZ5BSZ.js → disk-cleanup-KSWKI7WB.js} +2 -2
- package/dist-cli/chunks/drivers-EPIEFF7P.js +4 -0
- package/dist-cli/chunks/{film-BJGTBYZB.js → film-GDMR33VO.js} +3 -3
- package/dist-cli/chunks/flow-NKMPBYCJ.js +4 -0
- package/dist-cli/chunks/help-OGCBHOKA.js +4 -0
- package/dist-cli/chunks/{hidden-runtime-alias-ANOYADHM.js → hidden-runtime-alias-S2GTDX3T.js} +2 -2
- package/dist-cli/chunks/home-paths-QRCDLTTV.js +4 -0
- package/dist-cli/chunks/inspect-FUYMOZPY.js +4 -0
- package/dist-cli/chunks/install-desktop-FR6YKW7Y.js +4 -0
- package/dist-cli/chunks/{login-FJ737MWG.js → login-IJAPUZHI.js} +4 -4
- package/dist-cli/chunks/{logout-ZCNMMHMY.js → logout-QMXDFU2X.js} +2 -2
- package/dist-cli/chunks/{maestro-SZTNKLDF.js → maestro-ZXU3YCVX.js} +3 -3
- package/dist-cli/chunks/{maestro-generate-DCFAIZ4H.js → maestro-generate-PYB5QY7K.js} +3 -3
- package/dist-cli/chunks/{mode-GRMQCRXR.js → mode-WGUCL5FZ.js} +2 -2
- package/dist-cli/chunks/{optional-demo-registry-W36EWFFB.js → optional-demo-registry-WH2O6H36.js} +2 -2
- package/dist-cli/chunks/{perf-QYBAAUZG.js → perf-TOD3UFAH.js} +2 -2
- package/dist-cli/chunks/{permissions-3QCQ6VF4.js → permissions-I5BRJGTB.js} +2 -2
- package/dist-cli/chunks/{record-QPPC2S4E.js → record-ZYL2FYSK.js} +3 -3
- package/dist-cli/chunks/{report-issue-7NMFP4HK.js → report-issue-TAI6DYZO.js} +2 -2
- package/dist-cli/chunks/reset-7YGYKQPQ.js +4 -0
- package/dist-cli/chunks/runtime-B4JO6QRI.js +4 -0
- package/dist-cli/chunks/{screenshot-command-67AECJFB.js → screenshot-command-7ANLODZY.js} +7 -7
- package/dist-cli/chunks/{screenshot-layers-ASWBYPJL.js → screenshot-layers-A7FYXSVU.js} +3 -3
- package/dist-cli/chunks/{screenshots-capture-PXA3HFQK.js → screenshots-capture-WT2ZY6CB.js} +2 -2
- package/dist-cli/chunks/serve-TG5WKA4V.js +44 -0
- package/dist-cli/chunks/{setup-7DWPMRSB.js → setup-PCWLD22V.js} +2 -2
- package/dist-cli/chunks/{skills-S3Y22TUA.js → skills-27ZHWCQS.js} +2 -2
- package/dist-cli/chunks/state-ZQVY46ZO.js +14 -0
- package/dist-cli/chunks/{storage-XUIMJWAJ.js → storage-OYC57C4X.js} +6 -6
- package/dist-cli/chunks/store-32HSPZHI.js +4 -0
- package/dist-cli/chunks/telemetry-PBJR7XHR.js +4 -0
- package/dist-cli/chunks/{timeline-TMPLQPSP.js → timeline-RAJJFQT6.js} +2 -2
- package/dist-cli/chunks/{upgrade-7HDSIM7K.js → upgrade-OEFNZRIP.js} +2 -2
- package/dist-cli/chunks/upload-LQJITLKK.js +4 -0
- package/dist-cli/chunks/version-NIXTY6PL.js +6 -0
- package/dist-cli/chunks/{web-DG3WBYD3.js → web-XBUTBVGR.js} +2 -2
- package/dist-cli/chunks/{what-happened-XFVUTZR7.js → what-happened-YNHRFUDX.js} +3 -3
- package/dist-lib/agent-daemon-client.cjs +1 -1
- package/dist-lib/agent-events.cjs +1 -1
- package/dist-lib/agent-identity.cjs +1 -1
- package/dist-lib/agent-sessions.cjs +1 -1
- package/dist-lib/attached-projects.cjs +1 -1
- package/dist-lib/auth/shared-session.cjs +1 -1
- package/dist-lib/backend-origin.cjs +1 -1
- package/dist-lib/beta.cjs +1 -1
- package/dist-lib/beta.mjs +1 -1
- package/dist-lib/bridge-constants.cjs +1 -1
- package/dist-lib/bridge-contract.cjs +20 -0
- package/dist-lib/cli-constants.cjs +1 -1
- package/dist-lib/config.cjs +1 -1
- package/dist-lib/detox/index.cjs +1 -1
- package/dist-lib/dev-bundle-resolution.cjs +1 -1
- package/dist-lib/home-paths.cjs +67 -28
- package/dist-lib/host/bridge-host.cjs +140 -12
- package/dist-lib/host/fetch-proxy-handler.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.cjs +1 -1
- package/dist-lib/host/fetch-proxy-overrides.mjs +1 -1
- package/dist-lib/host/websocket-proxy.cjs +1 -1
- package/dist-lib/index.cjs +2815 -40
- package/dist-lib/jump-to-source-babel.cjs +1 -1
- package/dist-lib/menu.cjs +1 -1
- package/dist-lib/menu.mjs +1 -1
- package/dist-lib/metro.cjs +1 -1
- package/dist-lib/profiles.cjs +1 -1
- package/dist-lib/public-brand.cjs +1 -1
- package/dist-lib/render-mode.cjs +1 -1
- package/dist-lib/scripts/dev-server-scanner.cjs +1 -1
- package/dist-lib/sdk.cjs +2549 -2061
- package/dist-lib/sdk.mjs +2543 -2061
- package/dist-lib/skills.cjs +480 -280
- package/dist-lib/vite.cjs +1 -1
- package/package.json +8 -2
- package/src/bridge-constants.ts +3 -4
- package/src/bridge-contract.ts +251 -0
- package/src/connect.ts +83 -0
- package/src/disk-cleanup.ts +30 -0
- package/src/home-paths.ts +81 -38
- package/src/host/bridge-host.ts +134 -6
- package/src/index.ts +27 -1
- package/src/sdk.ts +8 -0
- package/src/sim-client.ts +660 -0
- package/dist-cli/chunks/camera-VL73YIKP.js +0 -22
- package/dist-cli/chunks/chunk-4NPPOV2N.js +0 -5
- package/dist-cli/chunks/chunk-FSUYIVJ6.js +0 -9
- package/dist-cli/chunks/chunk-G2WW6L2C.js +0 -23
- package/dist-cli/chunks/chunk-KTHV3RUS.js +0 -26
- package/dist-cli/chunks/chunk-LF2ZVT7O.js +0 -6
- package/dist-cli/chunks/chunk-NFK7T35W.js +0 -4
- package/dist-cli/chunks/chunk-TIVZIMMW.js +0 -4
- package/dist-cli/chunks/cli-version-WWLPBDQ7.js +0 -4
- package/dist-cli/chunks/daemon-G2ME7NLB.js +0 -4
- package/dist-cli/chunks/drivers-LDECZGP2.js +0 -4
- package/dist-cli/chunks/flow-UEQNVTU7.js +0 -4
- package/dist-cli/chunks/help-T5FYSVGB.js +0 -4
- package/dist-cli/chunks/home-paths-GT3LFNOR.js +0 -4
- package/dist-cli/chunks/inspect-ZA6XF5LD.js +0 -4
- package/dist-cli/chunks/install-desktop-TIMUDHPL.js +0 -4
- package/dist-cli/chunks/runtime-XOAXMSTU.js +0 -4
- package/dist-cli/chunks/serve-BI2NBAXG.js +0 -44
- package/dist-cli/chunks/store-JTHEJLAZ.js +0 -4
- package/dist-cli/chunks/telemetry-ZYJGD2DB.js +0 -4
- package/dist-cli/chunks/upload-GMSZPWM6.js +0 -4
- package/dist-cli/chunks/version-HOCHZ37L.js +0 -6
|
@@ -0,0 +1,467 @@
|
|
|
1
|
+
// sootsim skill - install and inspect agent skill files
|
|
2
|
+
//
|
|
3
|
+
// usage:
|
|
4
|
+
// sootsim skill install install all skills to supported agents
|
|
5
|
+
// sootsim skill install codex debug install specific skills to Codex only
|
|
6
|
+
// sootsim skill show [name] list skills or print one skill
|
|
7
|
+
|
|
8
|
+
import * as fs from 'fs'
|
|
9
|
+
import * as os from 'os'
|
|
10
|
+
import * as path from 'path'
|
|
11
|
+
import { fileURLToPath } from 'url'
|
|
12
|
+
import { rnxPublicBrand } from '../../src/public-brand'
|
|
13
|
+
|
|
14
|
+
function getSkillsDir(): string {
|
|
15
|
+
try {
|
|
16
|
+
const pkgPath = fileURLToPath(
|
|
17
|
+
import.meta.resolve(`${rnxPublicBrand.packageName}/package.json`),
|
|
18
|
+
)
|
|
19
|
+
return path.join(path.dirname(pkgPath), 'skills')
|
|
20
|
+
} catch {
|
|
21
|
+
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
22
|
+
return path.resolve(__dirname, '../../skills')
|
|
23
|
+
}
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
const SKILLS_DIR = getSkillsDir()
|
|
27
|
+
const AGENT_TARGET_IDS = new Set(['all', 'codex', 'claude'])
|
|
28
|
+
|
|
29
|
+
interface SkillInfo {
|
|
30
|
+
name: string
|
|
31
|
+
description: string
|
|
32
|
+
}
|
|
33
|
+
|
|
34
|
+
interface InstallTarget {
|
|
35
|
+
label: string
|
|
36
|
+
dir: string
|
|
37
|
+
}
|
|
38
|
+
|
|
39
|
+
function printSkillHelp() {
|
|
40
|
+
console.log(`rnxsim skill
|
|
41
|
+
|
|
42
|
+
install and inspect bundled rnx agent skills.
|
|
43
|
+
|
|
44
|
+
usage:
|
|
45
|
+
rnxsim skill install [all|codex|claude] [skill-name...]
|
|
46
|
+
rnxsim skill install --target <dir> [skill-name...]
|
|
47
|
+
rnxsim skill show [skill-name]
|
|
48
|
+
|
|
49
|
+
commands:
|
|
50
|
+
install install skills; no target means all supported local agents
|
|
51
|
+
show list bundled skills, or print one skill markdown
|
|
52
|
+
|
|
53
|
+
targets:
|
|
54
|
+
all Codex and Claude Code (default)
|
|
55
|
+
codex $CODEX_HOME/skills, or ~/.codex/skills
|
|
56
|
+
claude $CLAUDE_CONFIG_DIR/skills, or ~/.claude/skills
|
|
57
|
+
`)
|
|
58
|
+
}
|
|
59
|
+
|
|
60
|
+
function printInstallHelp() {
|
|
61
|
+
console.log(`rnxsim skill install
|
|
62
|
+
|
|
63
|
+
install bundled rnx skills in the agent skill layout: <skill>/SKILL.md.
|
|
64
|
+
each skill directory is symlinked back to its source, so edits stay live
|
|
65
|
+
without a re-install. an existing install from an older CLI is upgraded in
|
|
66
|
+
place; an unrelated skill directory is left alone unless --force is passed.
|
|
67
|
+
|
|
68
|
+
usage:
|
|
69
|
+
rnxsim skill install [all|codex|claude] [skill-name...]
|
|
70
|
+
rnxsim skill install --target <dir> [skill-name...]
|
|
71
|
+
|
|
72
|
+
options:
|
|
73
|
+
--force, -f replace a conflicting existing skill with the symlink
|
|
74
|
+
|
|
75
|
+
examples:
|
|
76
|
+
rnxsim skill install
|
|
77
|
+
rnxsim skill install codex
|
|
78
|
+
rnxsim skill install codex rnx-debug
|
|
79
|
+
rnxsim skill install --force rnx-debug
|
|
80
|
+
`)
|
|
81
|
+
}
|
|
82
|
+
|
|
83
|
+
function targetFromHome(envName: string, fallbackDir: string): string {
|
|
84
|
+
const home = process.env[envName] || path.join(os.homedir(), fallbackDir)
|
|
85
|
+
return path.join(home, 'skills')
|
|
86
|
+
}
|
|
87
|
+
|
|
88
|
+
function defaultAgentTargets(): InstallTarget[] {
|
|
89
|
+
return [
|
|
90
|
+
{ label: 'codex', dir: targetFromHome('CODEX_HOME', '.codex') },
|
|
91
|
+
{ label: 'claude', dir: targetFromHome('CLAUDE_CONFIG_DIR', '.claude') },
|
|
92
|
+
]
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
function agentTarget(target: string): InstallTarget[] {
|
|
96
|
+
if (target === 'all') return defaultAgentTargets()
|
|
97
|
+
if (target === 'codex') {
|
|
98
|
+
return [{ label: 'codex', dir: targetFromHome('CODEX_HOME', '.codex') }]
|
|
99
|
+
}
|
|
100
|
+
if (target === 'claude') {
|
|
101
|
+
return [{ label: 'claude', dir: targetFromHome('CLAUDE_CONFIG_DIR', '.claude') }]
|
|
102
|
+
}
|
|
103
|
+
console.error(` unknown skill install target: ${target}`)
|
|
104
|
+
console.error(' expected all, codex, or claude')
|
|
105
|
+
process.exit(1)
|
|
106
|
+
}
|
|
107
|
+
|
|
108
|
+
function parseSkillFrontmatter(
|
|
109
|
+
content: string,
|
|
110
|
+
): { name: string; description: string } | null {
|
|
111
|
+
const match = content.match(/^---\n([\s\S]*?)\n---/)
|
|
112
|
+
if (!match) return null
|
|
113
|
+
const frontmatter = match[1]
|
|
114
|
+
const name = readFrontmatterField(frontmatter, 'name')
|
|
115
|
+
if (!name) return null
|
|
116
|
+
return {
|
|
117
|
+
name,
|
|
118
|
+
description: readFrontmatterField(frontmatter, 'description') || '',
|
|
119
|
+
}
|
|
120
|
+
}
|
|
121
|
+
|
|
122
|
+
function readFrontmatterField(frontmatter: string, field: string): string | null {
|
|
123
|
+
const lines = frontmatter.split('\n')
|
|
124
|
+
const prefix = `${field}:`
|
|
125
|
+
for (let index = 0; index < lines.length; index++) {
|
|
126
|
+
const line = lines[index]
|
|
127
|
+
if (!line.startsWith(prefix)) continue
|
|
128
|
+
|
|
129
|
+
const rawValue = line.slice(prefix.length).trim()
|
|
130
|
+
if (rawValue === '>-' || rawValue === '>' || rawValue === '|-' || rawValue === '|') {
|
|
131
|
+
const blockLines: string[] = []
|
|
132
|
+
for (let blockIndex = index + 1; blockIndex < lines.length; blockIndex++) {
|
|
133
|
+
const blockLine = lines[blockIndex]
|
|
134
|
+
if (/^[A-Za-z0-9_-]+:\s*/.test(blockLine)) break
|
|
135
|
+
if (blockLine.trim() === '') {
|
|
136
|
+
blockLines.push('')
|
|
137
|
+
continue
|
|
138
|
+
}
|
|
139
|
+
if (!/^\s+/.test(blockLine)) break
|
|
140
|
+
blockLines.push(blockLine.trim())
|
|
141
|
+
}
|
|
142
|
+
return blockLines.join(rawValue.startsWith('|') ? '\n' : ' ').trim()
|
|
143
|
+
}
|
|
144
|
+
|
|
145
|
+
if (
|
|
146
|
+
(rawValue.startsWith('"') && rawValue.endsWith('"')) ||
|
|
147
|
+
(rawValue.startsWith("'") && rawValue.endsWith("'"))
|
|
148
|
+
) {
|
|
149
|
+
return rawValue.slice(1, -1)
|
|
150
|
+
}
|
|
151
|
+
return rawValue
|
|
152
|
+
}
|
|
153
|
+
return null
|
|
154
|
+
}
|
|
155
|
+
|
|
156
|
+
// bundled skills live in the standard agent layout: skills/<name>/SKILL.md.
|
|
157
|
+
// the directory name is the skill name; frontmatter is the display metadata.
|
|
158
|
+
function listSkills(): SkillInfo[] {
|
|
159
|
+
if (!fs.existsSync(SKILLS_DIR)) return []
|
|
160
|
+
const skills: SkillInfo[] = []
|
|
161
|
+
for (const entry of fs.readdirSync(SKILLS_DIR)) {
|
|
162
|
+
const skillMd = path.join(SKILLS_DIR, entry, 'SKILL.md')
|
|
163
|
+
if (!fs.existsSync(skillMd)) continue
|
|
164
|
+
const meta = parseSkillFrontmatter(fs.readFileSync(skillMd, 'utf8'))
|
|
165
|
+
if (meta) {
|
|
166
|
+
skills.push({ name: entry, description: meta.description })
|
|
167
|
+
}
|
|
168
|
+
}
|
|
169
|
+
return skills.sort((a, b) => a.name.localeCompare(b.name))
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
function matchSkills(skills: SkillInfo[], filters: string[]): SkillInfo[] {
|
|
173
|
+
if (filters.length === 0) return skills
|
|
174
|
+
const matched = skills.filter((skill) =>
|
|
175
|
+
filters.some((filter) => {
|
|
176
|
+
const needle = filter.replace(/^sootsim-/, '').replace(/^rnx-/, '')
|
|
177
|
+
return (
|
|
178
|
+
skill.name.includes(filter) || skill.name.replace(/^rnx-/, '').includes(needle)
|
|
179
|
+
)
|
|
180
|
+
}),
|
|
181
|
+
)
|
|
182
|
+
if (matched.length === 0) {
|
|
183
|
+
console.error(` no skills matched: ${filters.join(', ')}`)
|
|
184
|
+
console.error(' available: ' + skills.map((skill) => skill.name).join(', '))
|
|
185
|
+
process.exit(1)
|
|
186
|
+
}
|
|
187
|
+
return matched
|
|
188
|
+
}
|
|
189
|
+
|
|
190
|
+
// install is a SYMLINK of the whole skill DIRECTORY from the agent store back
|
|
191
|
+
// to the source, not a copy, so editing the source skill is live everywhere
|
|
192
|
+
// without re-installing. the directory (not the SKILL.md file) is linked
|
|
193
|
+
// because Codex's skill discovery follows directory symlinks but silently
|
|
194
|
+
// skips a SKILL.md that is itself a file symlink. conflict-safe: skip if
|
|
195
|
+
// already linked to source, upgrade an install from an older CLI (or anything
|
|
196
|
+
// under --force), otherwise refuse so we never clobber a skill the user owns.
|
|
197
|
+
type LinkResult = 'up-to-date' | 'linked' | 'replaced' | 'conflict'
|
|
198
|
+
|
|
199
|
+
function lstatOrNull(p: string): fs.Stats | null {
|
|
200
|
+
try {
|
|
201
|
+
return fs.lstatSync(p)
|
|
202
|
+
} catch {
|
|
203
|
+
return null
|
|
204
|
+
}
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
function symlinkPointsTo(dest: string, src: string): boolean {
|
|
208
|
+
const stat = lstatOrNull(dest)
|
|
209
|
+
if (!stat || !stat.isSymbolicLink()) return false
|
|
210
|
+
try {
|
|
211
|
+
return fs.realpathSync(dest) === fs.realpathSync(src)
|
|
212
|
+
} catch {
|
|
213
|
+
return false
|
|
214
|
+
}
|
|
215
|
+
}
|
|
216
|
+
|
|
217
|
+
// a store entry left by an older CLI is safe to upgrade: either a real dir
|
|
218
|
+
// whose only content is a SKILL.md symlink into a sootsim skills source (the
|
|
219
|
+
// pre-dir-layout install — possibly broken after the source moved), or a dir
|
|
220
|
+
// holding a byte-identical copy of the skill. only our installer creates
|
|
221
|
+
// those shapes, so replacing them can't lose user work.
|
|
222
|
+
function isOwnLegacyInstall(stat: fs.Stats, dest: string, srcDir: string): boolean {
|
|
223
|
+
if (stat.isSymbolicLink() || !stat.isDirectory()) return false
|
|
224
|
+
let entries: string[]
|
|
225
|
+
try {
|
|
226
|
+
entries = fs.readdirSync(dest)
|
|
227
|
+
} catch {
|
|
228
|
+
return false
|
|
229
|
+
}
|
|
230
|
+
if (entries.length !== 1 || entries[0] !== 'SKILL.md') return false
|
|
231
|
+
const skillMd = path.join(dest, 'SKILL.md')
|
|
232
|
+
const mdStat = lstatOrNull(skillMd)
|
|
233
|
+
if (!mdStat) return false
|
|
234
|
+
if (mdStat.isSymbolicLink()) {
|
|
235
|
+
try {
|
|
236
|
+
return fs.readlinkSync(skillMd).includes(`${path.sep}skills${path.sep}`)
|
|
237
|
+
} catch {
|
|
238
|
+
return false
|
|
239
|
+
}
|
|
240
|
+
}
|
|
241
|
+
if (!mdStat.isFile()) return false
|
|
242
|
+
try {
|
|
243
|
+
return fs.readFileSync(skillMd).equals(fs.readFileSync(path.join(srcDir, 'SKILL.md')))
|
|
244
|
+
} catch {
|
|
245
|
+
return false
|
|
246
|
+
}
|
|
247
|
+
}
|
|
248
|
+
|
|
249
|
+
function linkSkill(skill: SkillInfo, targetDir: string, force: boolean): LinkResult {
|
|
250
|
+
const src = path.join(SKILLS_DIR, skill.name)
|
|
251
|
+
const dest = path.join(targetDir, skill.name)
|
|
252
|
+
fs.mkdirSync(targetDir, { recursive: true })
|
|
253
|
+
|
|
254
|
+
const existing = lstatOrNull(dest)
|
|
255
|
+
if (!existing) {
|
|
256
|
+
fs.symlinkSync(src, dest)
|
|
257
|
+
return 'linked'
|
|
258
|
+
}
|
|
259
|
+
if (symlinkPointsTo(dest, src)) {
|
|
260
|
+
return 'up-to-date'
|
|
261
|
+
}
|
|
262
|
+
if (force || isOwnLegacyInstall(existing, dest, src)) {
|
|
263
|
+
fs.rmSync(dest, { recursive: true, force: true })
|
|
264
|
+
fs.symlinkSync(src, dest)
|
|
265
|
+
return 'replaced'
|
|
266
|
+
}
|
|
267
|
+
return 'conflict'
|
|
268
|
+
}
|
|
269
|
+
|
|
270
|
+
// quiet, conflict-safe (re)install of all bundled skills into the agent stores
|
|
271
|
+
// that already exist on this machine. wired into the CLI build so building or
|
|
272
|
+
// updating the CLI re-establishes the symlinks idempotently — never forces, so
|
|
273
|
+
// it can't clobber a skill the user customized, and never creates a store for
|
|
274
|
+
// an agent that isn't set up here. silent on success.
|
|
275
|
+
export function refreshInstalledSkills() {
|
|
276
|
+
const skills = listSkills()
|
|
277
|
+
if (skills.length === 0) return
|
|
278
|
+
for (const target of defaultAgentTargets()) {
|
|
279
|
+
const skillsDir = path.resolve(target.dir)
|
|
280
|
+
// only touch agents already present (~/.claude, ~/.codex) — don't seed a
|
|
281
|
+
// store on a CI runner or a machine that doesn't use that agent.
|
|
282
|
+
if (!fs.existsSync(path.dirname(skillsDir))) continue
|
|
283
|
+
try {
|
|
284
|
+
fs.mkdirSync(skillsDir, { recursive: true })
|
|
285
|
+
} catch {
|
|
286
|
+
continue
|
|
287
|
+
}
|
|
288
|
+
try {
|
|
289
|
+
removeLegacyBundledSkills(skillsDir)
|
|
290
|
+
} catch {}
|
|
291
|
+
for (const skill of skills) {
|
|
292
|
+
try {
|
|
293
|
+
linkSkill(skill, skillsDir, false)
|
|
294
|
+
} catch {
|
|
295
|
+
// best-effort: a single bad store must not fail the build
|
|
296
|
+
}
|
|
297
|
+
}
|
|
298
|
+
}
|
|
299
|
+
}
|
|
300
|
+
|
|
301
|
+
const LEGACY_BUNDLED_SKILL_DIRS = [
|
|
302
|
+
'sootsim-setup',
|
|
303
|
+
'sootsim-debug',
|
|
304
|
+
'sootsim-perf',
|
|
305
|
+
'sootsim-test',
|
|
306
|
+
'sootsim-visual',
|
|
307
|
+
]
|
|
308
|
+
|
|
309
|
+
function removeLegacyBundledSkills(targetDir: string) {
|
|
310
|
+
for (const name of LEGACY_BUNDLED_SKILL_DIRS) {
|
|
311
|
+
const dest = path.join(targetDir, name)
|
|
312
|
+
const stat = lstatOrNull(dest)
|
|
313
|
+
if (!stat) continue
|
|
314
|
+
if (
|
|
315
|
+
stat.isSymbolicLink() ||
|
|
316
|
+
isOwnLegacyInstall(stat, dest, path.join(SKILLS_DIR, name))
|
|
317
|
+
) {
|
|
318
|
+
fs.rmSync(dest, { recursive: true, force: true })
|
|
319
|
+
}
|
|
320
|
+
}
|
|
321
|
+
}
|
|
322
|
+
|
|
323
|
+
function printSkillList(skills: SkillInfo[]) {
|
|
324
|
+
if (skills.length === 0) {
|
|
325
|
+
console.log(' no skills found')
|
|
326
|
+
return
|
|
327
|
+
}
|
|
328
|
+
console.log('\n available skills:\n')
|
|
329
|
+
for (const skill of skills) {
|
|
330
|
+
console.log(` ${skill.name}`)
|
|
331
|
+
console.log(` ${skill.description}\n`)
|
|
332
|
+
}
|
|
333
|
+
console.log(' usage: rnxsim skill install [all|codex|claude] [skill-name...]')
|
|
334
|
+
console.log(' usage: rnxsim skill show [skill-name]\n')
|
|
335
|
+
}
|
|
336
|
+
|
|
337
|
+
function parseInstallArgs(args: string[]): {
|
|
338
|
+
targets: InstallTarget[]
|
|
339
|
+
filters: string[]
|
|
340
|
+
force: boolean
|
|
341
|
+
} {
|
|
342
|
+
let targets: InstallTarget[] | null = null
|
|
343
|
+
let force = false
|
|
344
|
+
const filters: string[] = []
|
|
345
|
+
|
|
346
|
+
for (let index = 0; index < args.length; index++) {
|
|
347
|
+
const arg = args[index]
|
|
348
|
+
if (arg === '--help' || arg === '-h') {
|
|
349
|
+
printInstallHelp()
|
|
350
|
+
process.exit(0)
|
|
351
|
+
}
|
|
352
|
+
if (arg === '--force' || arg === '-f') {
|
|
353
|
+
force = true
|
|
354
|
+
continue
|
|
355
|
+
}
|
|
356
|
+
if (arg === '--target') {
|
|
357
|
+
const dir = args[index + 1]
|
|
358
|
+
if (!dir || dir.startsWith('-')) {
|
|
359
|
+
console.error(' --target requires a directory')
|
|
360
|
+
process.exit(1)
|
|
361
|
+
}
|
|
362
|
+
if (targets) {
|
|
363
|
+
console.error(' pass only one install target')
|
|
364
|
+
process.exit(1)
|
|
365
|
+
}
|
|
366
|
+
targets = [{ label: 'target', dir }]
|
|
367
|
+
index++
|
|
368
|
+
continue
|
|
369
|
+
}
|
|
370
|
+
if (arg.startsWith('-')) {
|
|
371
|
+
console.error(` unknown option: ${arg}`)
|
|
372
|
+
printInstallHelp()
|
|
373
|
+
process.exit(1)
|
|
374
|
+
}
|
|
375
|
+
if (!targets && AGENT_TARGET_IDS.has(arg)) {
|
|
376
|
+
targets = agentTarget(arg)
|
|
377
|
+
continue
|
|
378
|
+
}
|
|
379
|
+
filters.push(arg)
|
|
380
|
+
}
|
|
381
|
+
|
|
382
|
+
return { targets: targets ?? defaultAgentTargets(), filters, force }
|
|
383
|
+
}
|
|
384
|
+
|
|
385
|
+
async function runInstall(args: string[]) {
|
|
386
|
+
const skills = listSkills()
|
|
387
|
+
if (skills.length === 0) {
|
|
388
|
+
console.error(' no skills found in rnxsim package')
|
|
389
|
+
process.exit(1)
|
|
390
|
+
}
|
|
391
|
+
|
|
392
|
+
const parsed = parseInstallArgs(args)
|
|
393
|
+
const toInstall = matchSkills(skills, parsed.filters)
|
|
394
|
+
const resolvedTargets = parsed.targets.map((target) => ({
|
|
395
|
+
...target,
|
|
396
|
+
dir: path.resolve(target.dir),
|
|
397
|
+
}))
|
|
398
|
+
for (const target of resolvedTargets) {
|
|
399
|
+
fs.mkdirSync(target.dir, { recursive: true })
|
|
400
|
+
if (!fs.statSync(target.dir).isDirectory()) {
|
|
401
|
+
console.error(` target is not a directory: ${target.dir}`)
|
|
402
|
+
process.exit(1)
|
|
403
|
+
}
|
|
404
|
+
removeLegacyBundledSkills(target.dir)
|
|
405
|
+
}
|
|
406
|
+
|
|
407
|
+
console.log(
|
|
408
|
+
`\n installing ${toInstall.length} skill(s) to ${resolvedTargets.length} target(s)\n`,
|
|
409
|
+
)
|
|
410
|
+
let conflicts = 0
|
|
411
|
+
for (const target of resolvedTargets) {
|
|
412
|
+
console.log(` target ${target.label}: ${target.dir}`)
|
|
413
|
+
for (const skill of toInstall) {
|
|
414
|
+
const dest = path.join(target.dir, skill.name)
|
|
415
|
+
const result = linkSkill(skill, target.dir, parsed.force)
|
|
416
|
+
if (result === 'linked') console.log(` linked ${skill.name} -> ${dest}`)
|
|
417
|
+
else if (result === 'replaced') console.log(` relinked ${skill.name} -> ${dest}`)
|
|
418
|
+
else if (result === 'up-to-date') console.log(` up to date ${skill.name}`)
|
|
419
|
+
else {
|
|
420
|
+
conflicts++
|
|
421
|
+
console.log(
|
|
422
|
+
` conflict ${skill.name}: ${dest} exists and is not this skill — pass --force to replace`,
|
|
423
|
+
)
|
|
424
|
+
}
|
|
425
|
+
}
|
|
426
|
+
console.log('')
|
|
427
|
+
}
|
|
428
|
+
if (conflicts > 0) {
|
|
429
|
+
console.error(
|
|
430
|
+
` ${conflicts} conflict(s); rerun with --force only if replacing them is intended.\n`,
|
|
431
|
+
)
|
|
432
|
+
process.exit(1)
|
|
433
|
+
}
|
|
434
|
+
console.log(' done. restart the agent session to load newly installed skills.\n')
|
|
435
|
+
}
|
|
436
|
+
|
|
437
|
+
function runShow(args: string[]) {
|
|
438
|
+
const skills = listSkills()
|
|
439
|
+
const name = args.find((arg) => !arg.startsWith('-'))
|
|
440
|
+
if (!name) {
|
|
441
|
+
printSkillList(skills)
|
|
442
|
+
return
|
|
443
|
+
}
|
|
444
|
+
const [skill] = matchSkills(skills, [name])
|
|
445
|
+
const content = fs.readFileSync(path.join(SKILLS_DIR, skill.name, 'SKILL.md'), 'utf8')
|
|
446
|
+
console.log(content)
|
|
447
|
+
}
|
|
448
|
+
|
|
449
|
+
export async function runSkill(args: string[]) {
|
|
450
|
+
const [command, ...rest] = args
|
|
451
|
+
if (!command || command === '--help' || command === '-h') {
|
|
452
|
+
printSkillHelp()
|
|
453
|
+
return
|
|
454
|
+
}
|
|
455
|
+
if (command === 'install') {
|
|
456
|
+
await runInstall(rest)
|
|
457
|
+
return
|
|
458
|
+
}
|
|
459
|
+
if (command === 'show' || command === 'list') {
|
|
460
|
+
runShow(rest)
|
|
461
|
+
return
|
|
462
|
+
}
|
|
463
|
+
|
|
464
|
+
console.error(` unknown skill command: ${command}`)
|
|
465
|
+
printSkillHelp()
|
|
466
|
+
process.exit(1)
|
|
467
|
+
}
|