create-rigline-plugin 1.0.0-alpha.0 → 1.0.0-alpha.10

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
package/README.md CHANGED
@@ -5,6 +5,10 @@ Claude Code VS Code extension.
5
5
 
6
6
  npm create rigline-plugin my-plugins
7
7
 
8
+ A plugin runs inside a modification of Anthropic's extension, so the
9
+ [plugin policy](https://github.com/Rigline/Rigline/blob/main/docs/plugin-policy.md) applies to it —
10
+ whether or not you ever publish it. One page, and the scaffolded README points at it too.
11
+
8
12
  ## What you get
9
13
 
10
14
  A pnpm workspace with `plugins/*` and one plugin in it, rather than a single-plugin repository. The
@@ -29,6 +33,11 @@ Then:
29
33
 
30
34
  and *Developer: Reload Webviews*.
31
35
 
36
+ The workspace declares `@rigline/core` — the engine, which carries the `rigline-engine` command its
37
+ `build` and `codegen` scripts run — and never `rigline`, which is the layer a *user* installs to
38
+ fetch that engine. `pnpm rigline <verb>` here is a script forwarding to the engine in your own
39
+ `node_modules`, so the loop above needs nothing installed globally.
40
+
32
41
  `generated.ts` ships as a placeholder so a fresh scaffold typechecks before `codegen` has ever run.
33
42
  Once you run `codegen` it holds the identifiers *your* extension version actually has; commit it,
34
43
  and the diff when you run against a newer extension is how you find out what moved.
@@ -42,4 +51,7 @@ is the one ordering dependency in the whole arrangement.
42
51
 
43
52
  [Authoring guide](https://github.com/Rigline/Rigline/blob/main/docs/authoring.md)
44
53
 
54
+ [Changelog](https://github.com/Rigline/Rigline/blob/main/CHANGELOG.md) — every package in this
55
+ workspace shares it, and one version number.
56
+
45
57
  MIT.
package/dist/index.js CHANGED
@@ -1,37 +1,21 @@
1
1
  #!/usr/bin/env node
2
- /**
3
- * `create-rigline-plugin`: scaffolds a workspace holding one plugin (decisions.md, D50).
4
- *
5
- * A pnpm workspace with `plugins/*` rather than a single-plugin repository, because the multi-plugin
6
- * shape is a superset: it scaffolds correctly for one plugin, and a second plugin is then a
7
- * directory copy rather than a restructure.
8
- *
9
- * The template is real files under `template/`, copied and substituted, rather than strings in this
10
- * module. It stays readable and reviewable that way, and the example plugin's own source is a file
11
- * an editor can check rather than a string literal with its backticks escaped. Two things that
12
- * takes care of, both of which have caught people out before: `.gitignore` is shipped as
13
- * `gitignore`, because npm renames a `.gitignore` inside a published tarball and the scaffolded
14
- * repository would arrive without one; and `generated.ts` is shipped as a placeholder, so the
15
- * scaffold typechecks before `rigline codegen` has ever run, which is the promise D40 makes and the
16
- * one moment it is easiest to break.
17
- */
18
2
  import { existsSync, mkdirSync, readdirSync, readFileSync, writeFileSync } from "node:fs";
19
3
  import { basename, dirname, join, relative, resolve } from "node:path";
20
4
  import { fileURLToPath } from "node:url";
21
- /** The manifest's own rule for a name, which is also npm's for an unscoped package. */
22
5
  const NAME_PATTERN = /^[a-z0-9][a-z0-9._-]{0,213}$/;
23
6
  export class ScaffoldError extends Error {
24
7
  }
25
- /** The template shipped with this package. */
26
8
  export function defaultTemplateDir() {
27
9
  return resolve(dirname(fileURLToPath(import.meta.url)), "..", "template");
28
10
  }
29
- /**
30
- * Writes the template into `target`, substituted.
31
- *
32
- * It refuses a directory that already has anything in it. A scaffold is not a merge, and a
33
- * half-overwritten workspace is worse than either a new one or the one that was there.
34
- */
11
+ export function riglineRange() {
12
+ const path = resolve(dirname(fileURLToPath(import.meta.url)), "..", "package.json");
13
+ const { version } = JSON.parse(readFileSync(path, "utf8"));
14
+ if (typeof version !== "string" || version.length === 0) {
15
+ throw new ScaffoldError(`this package's own version is missing from ${path}`);
16
+ }
17
+ return `^${version}`;
18
+ }
35
19
  export function scaffold(options) {
36
20
  const dir = resolve(options.target);
37
21
  const name = options.name ?? basename(dir);
@@ -46,15 +30,16 @@ export function scaffold(options) {
46
30
  if (!existsSync(templateDir)) {
47
31
  throw new ScaffoldError(`the template is missing from this package: ${templateDir}`);
48
32
  }
33
+ const range = options.riglineRange ?? riglineRange();
49
34
  const substitutions = {
50
35
  NAME: name,
51
36
  DESCRIPTION: options.description ?? `A Rigline plugin called ${name}.`,
37
+ RIGLINE_RANGE: range,
38
+ RIGLINE_VERSION: range.replace(/^\^/, ""),
52
39
  };
53
40
  const files = [];
54
41
  for (const source of walk(templateDir)) {
55
42
  const relativePath = substitute(relative(templateDir, source), substitutions);
56
- // npm renames a `.gitignore` inside a published tarball, so the template ships it undotted and
57
- // it is put back here. Without this the scaffolded repository arrives with none at all.
58
43
  const written = relativePath === "gitignore" ? ".gitignore" : relativePath;
59
44
  const target = join(dir, written);
60
45
  mkdirSync(dirname(target), { recursive: true });
@@ -64,7 +49,6 @@ export function scaffold(options) {
64
49
  files.sort();
65
50
  return { dir, name, files };
66
51
  }
67
- /** Every file under `root`, recursively, in a stable order. */
68
52
  function walk(root) {
69
53
  const found = [];
70
54
  for (const entry of readdirSync(root, { withFileTypes: true }).sort((a, b) => a.name.localeCompare(b.name))) {
@@ -76,7 +60,6 @@ function walk(root) {
76
60
  }
77
61
  return found;
78
62
  }
79
- /** `__NAME__` and `__DESCRIPTION__`, in a path or in a file's contents. */
80
63
  function substitute(text, substitutions) {
81
64
  let out = text;
82
65
  for (const [key, value] of Object.entries(substitutions)) {
@@ -84,10 +67,7 @@ function substitute(text, substitutions) {
84
67
  }
85
68
  return out;
86
69
  }
87
- /** Everything this scaffold wants said afterwards, in the order it wants doing. */
88
70
  export function nextSteps(result) {
89
- // The relative path, unless it is the worse of the two: a target several directories up produces
90
- // a run of `..` nobody wants to read, let alone type.
91
71
  const from = relative(process.cwd(), result.dir);
92
72
  const here = from === "" ? "." : from.startsWith("..") ? result.dir : from;
93
73
  return [
@@ -103,12 +83,12 @@ export function nextSteps(result) {
103
83
  "Then reload the webview: Developer: Reload Webviews.",
104
84
  "",
105
85
  `${join(here, "README.md")} has the rest, including the four rules worth reading first.`,
86
+ "",
87
+ "Read the plugin policy once — what Rigline promises Anthropic, and the part your plugin has",
88
+ "to hold up. It applies whether or not you ever publish this:",
89
+ " https://github.com/Rigline/Rigline/blob/main/docs/plugin-policy.md",
106
90
  ].join("\n");
107
91
  }
108
- /**
109
- * The command. One positional, the directory; `--name` where it should differ from the directory's
110
- * own, and `--description` for the sentence that lands in three files.
111
- */
112
92
  export function main(argv) {
113
93
  const positionals = [];
114
94
  let name;
@@ -146,14 +126,12 @@ export function main(argv) {
146
126
  throw error;
147
127
  }
148
128
  }
149
- const USAGE = `create-rigline-plugin
150
-
151
- pnpm create rigline-plugin <directory> [--name NAME] [--description TEXT]
152
-
153
- Scaffolds a pnpm workspace holding one Rigline plugin. The directory's own name is the plugin's
129
+ const USAGE = `create-rigline-plugin
130
+
131
+ pnpm create rigline-plugin <directory> [--name NAME] [--description TEXT]
132
+
133
+ Scaffolds a pnpm workspace holding one Rigline plugin. The directory's own name is the plugin's
154
134
  unless --name says otherwise; a second plugin later is a copy of the first.`;
155
- // Only when run as the command, so that a test may import `scaffold` without scaffolding anything.
156
- // Compared as resolved paths rather than by suffix, which a directory named after the bin defeats.
157
135
  if (process.argv[1] !== undefined && fileURLToPath(import.meta.url) === resolve(process.argv[1])) {
158
136
  process.exitCode = main(process.argv.slice(2));
159
137
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-rigline-plugin",
3
- "version": "1.0.0-alpha.0",
3
+ "version": "1.0.0-alpha.10",
4
4
  "description": "Scaffold a workspace for Claude Code VS Code extension plugins",
5
5
  "keywords": [
6
6
  "rigline",
@@ -20,18 +20,22 @@
20
20
  "author": "Lionell Pack",
21
21
  "type": "module",
22
22
  "license": "MIT",
23
+ "engines": {
24
+ "node": ">=22.12.0"
25
+ },
23
26
  "files": [
24
27
  "dist",
28
+ "!dist/**/*.map",
25
29
  "template"
26
30
  ],
27
31
  "bin": {
28
32
  "create-rigline-plugin": "./dist/index.js"
29
33
  },
30
34
  "devDependencies": {
31
- "@rigline/plugin-api": "1.0.0-alpha.0"
35
+ "@rigline/plugin-api": "1.0.0-alpha.10"
32
36
  },
33
37
  "scripts": {
34
- "build": "tsc -p tsconfig.build.json",
38
+ "build": "node ../../scripts/clean-dist.mjs && tsc -p tsconfig.build.json",
35
39
  "typecheck": "tsc -p tsconfig.json"
36
40
  }
37
41
  }
@@ -0,0 +1,62 @@
1
+ # Your plugins, checked on every push and every pull request. The release workflow runs the same
2
+ # steps again before it stages anything, so this is the copy that tells you early — and the copy a
3
+ # contributor's pull request gets, which is the whole reason it is separate.
4
+ #
5
+ # There is no lint step because this workspace ships no linter. Add one here if you add one.
6
+ name: CI
7
+
8
+ on:
9
+ push:
10
+ # GitHub takes no expression here, so your default branch cannot be filled in for you. These
11
+ # are the two common names; edit if yours is neither.
12
+ branches: [main, master]
13
+ pull_request:
14
+
15
+ permissions:
16
+ contents: read
17
+
18
+ # A push supersedes the run before it on the same ref, and a pull request supersedes its own last
19
+ # push. Two runs of one ref prove the same thing, and the newer one is what is being asked about.
20
+ concurrency:
21
+ group: ci-${{ github.ref }}
22
+ cancel-in-progress: true
23
+
24
+ jobs:
25
+ check:
26
+ name: Node ${{ matrix.node }}
27
+ runs-on: ubuntu-latest
28
+ strategy:
29
+ # Every rung reports. A failure on the floor and a failure on the newest runtime are
30
+ # different bugs, and cancelling the rest hides which one this is.
31
+ fail-fast: false
32
+ matrix:
33
+ # The first is the floor this workspace's package.json declares in `engines`, pinned
34
+ # exactly so that the number claimed is a number something ran; the others float to the
35
+ # latest of their major, which says the major is supported rather than that a patch was
36
+ # tested. Cutting this to one rung is a reasonable thing to do — then drop the `engines`
37
+ # claim to match, because a floor nothing runs on is a guess.
38
+ node: ["22.12.0", "24", "26"]
39
+ steps:
40
+ - uses: actions/checkout@v5
41
+
42
+ # Pinned exactly rather than to the major: this action's `v6` tag still resolves to the last
43
+ # release before pnpm v12 support, and `v4` runs on a runner runtime GitHub has deprecated.
44
+ - uses: pnpm/action-setup@v6.1.0
45
+
46
+ # After pnpm, never before: `cache: pnpm` asks pnpm where its store is.
47
+ - uses: actions/setup-node@v5
48
+ with:
49
+ node-version: ${{ matrix.node }}
50
+ cache: pnpm
51
+
52
+ # Needs `pnpm-lock.yaml` committed, which is why nothing ignores it. Installing what the
53
+ # lockfile says is the point: a run that resolved its own dependencies would be testing
54
+ # something nobody has.
55
+ - run: pnpm install --frozen-lockfile
56
+
57
+ - run: pnpm typecheck
58
+
59
+ # Before the tests, because a test that imports a built entry should import this build.
60
+ - run: pnpm build
61
+
62
+ - run: pnpm test
@@ -0,0 +1,130 @@
1
+ # Publish your plugins to npm, without an npm token ever being stored here.
2
+ #
3
+ # GitHub authenticates to npm over OIDC, so the secret this workflow would otherwise need does not
4
+ # exist. What it does is *stage*: a staged version sits in a queue that nobody can install until you
5
+ # approve it from your own machine with 2FA. Approving says you meant to ship it.
6
+ #
7
+ # pnpm stage approve
8
+ #
9
+ # Before this works, once per package, on npmjs.com:
10
+ #
11
+ # 1. Publish the first version by hand. A package that does not exist yet has nothing for a
12
+ # trusted publisher to attach to: `pnpm publish -r --otp <code>` (a one-time password, not a
13
+ # token — there is then nothing to store or revoke).
14
+ # 2. Add a trusted publisher under the package's settings, naming this repository and this file
15
+ # by path. Renaming this file breaks the exchange until the entry is edited to match.
16
+ # Set its permission to stage-only.
17
+ #
18
+ # `-r` stages every package in the workspace whose version is not already on the registry, in
19
+ # dependency order, so bumping one plugin releases one plugin.
20
+ name: Release
21
+
22
+ on:
23
+ workflow_dispatch:
24
+ inputs:
25
+ dist_tag:
26
+ description: The tag these versions go to. A prerelease belongs on `next`, not `latest`.
27
+ type: choice
28
+ options: [latest, next]
29
+ default: latest
30
+ dry_run:
31
+ description: Build, test and pack, but stage nothing
32
+ type: boolean
33
+ default: false
34
+
35
+ permissions:
36
+ contents: read
37
+
38
+ concurrency:
39
+ group: release
40
+ cancel-in-progress: false
41
+
42
+ jobs:
43
+ stage:
44
+ name: Stage to npm
45
+ runs-on: ubuntu-latest
46
+ permissions:
47
+ contents: read
48
+ # What lets the runner ask GitHub for the token npm exchanges for a publishing one. Without
49
+ # it there is nothing to send, and pnpm falls back to looking for a credential that is not
50
+ # here — reporting that as a warning, not an error, so read the log rather than the tick.
51
+ id-token: write
52
+ steps:
53
+ - name: Refuse anything but the default branch
54
+ if: github.ref_name != github.event.repository.default_branch
55
+ run: |
56
+ echo "::error::Releases go from ${{ github.event.repository.default_branch }}."
57
+ exit 1
58
+
59
+ - uses: actions/checkout@v5
60
+
61
+ # npm binds a provenance attestation to the package's `repository` field, so a package
62
+ # without one cannot be staged with `--provenance` at all. Asked here, before the build, so
63
+ # that the answer is a package name rather than an error about attestations two minutes in.
64
+ # A dry run is checked too: a rehearsal that skips this rehearses a different release.
65
+ - name: Refuse a publishable package with no repository
66
+ run: |
67
+ node -e '
68
+ const fs = require("fs");
69
+ const dirs = fs.existsSync("plugins") ? fs.readdirSync("plugins") : [];
70
+ const missing = [];
71
+ for (const dir of dirs) {
72
+ const path = `plugins/${dir}/package.json`;
73
+ if (!fs.existsSync(path)) continue;
74
+ const manifest = JSON.parse(fs.readFileSync(path, "utf8"));
75
+ if (!manifest.private && !manifest.repository) missing.push(manifest.name || dir);
76
+ }
77
+ if (missing.length === 0) process.exit(0);
78
+ console.log(`::error::No "repository" field in ${missing.join(", ")}. npm binds a provenance attestation to it, so --provenance cannot stage a package without one.`);
79
+ process.exit(1);
80
+ '
81
+
82
+ # Pinned exactly rather than to the major: this action's `v6` tag still resolves to the last
83
+ # release before pnpm v12 support, and `v4` runs on a runner runtime GitHub has deprecated.
84
+ - uses: pnpm/action-setup@v6.1.0
85
+ - uses: actions/setup-node@v5
86
+ with:
87
+ node-version: 26
88
+ cache: pnpm
89
+
90
+ - run: pnpm install --frozen-lockfile
91
+ - run: pnpm typecheck
92
+ - run: pnpm build
93
+ - run: pnpm test
94
+
95
+ # `generated.ts` is committed, so this needs no installed extension. `rigline codegen` is
96
+ # something you run locally against your own editor and commit the result of.
97
+ - name: Stage
98
+ if: ${{ !inputs.dry_run }}
99
+ run: pnpm stage publish -r --tag ${{ inputs.dist_tag }} --provenance --report-summary --no-git-checks
100
+
101
+ - name: Pack only
102
+ if: ${{ inputs.dry_run }}
103
+ run: pnpm stage publish -r --tag ${{ inputs.dist_tag }} --dry-run --report-summary --no-git-checks
104
+
105
+ # Nothing notifies you that a stage is waiting, and pnpm's publish output carries no stage id
106
+ # to quote (the registry has one; `npm stage list` shows it). So the run summary names what
107
+ # went up and the one command that finishes the job.
108
+ - name: Summarise
109
+ if: always()
110
+ run: |
111
+ if [ ! -f pnpm-publish-summary.json ]; then
112
+ echo "## Nothing was staged" >> "$GITHUB_STEP_SUMMARY"
113
+ echo "" >> "$GITHUB_STEP_SUMMARY"
114
+ echo "Either the run stopped before staging, or every version is already on the registry." >> "$GITHUB_STEP_SUMMARY"
115
+ exit 0
116
+ fi
117
+ node -e '
118
+ const s = JSON.parse(require("fs").readFileSync("pnpm-publish-summary.json", "utf8"));
119
+ const out = [];
120
+ const staged = s.publishedPackages ?? [];
121
+ if (staged.length === 0) {
122
+ out.push("## Nothing was staged", "", "Every version is already on the registry. Bump one to release it.");
123
+ } else {
124
+ out.push("## Staged, and awaiting approval", "", "| package | version |", "| --- | --- |");
125
+ for (const p of staged) out.push(`| \`${p.name}\` | \`${p.version}\` |`);
126
+ out.push("", "**Nobody can install these yet.** On a machine with your npm 2FA:", "", "```", "pnpm stage approve", "```", "",
127
+ "It lists what is queued and takes the batch under one one-time password. A version you would rather not ship needs no action — do not approve it, and it expires.");
128
+ }
129
+ require("fs").appendFileSync(process.env.GITHUB_STEP_SUMMARY, out.join("\n") + "\n");
130
+ '
@@ -1,67 +1,120 @@
1
- # __NAME__
2
-
3
- Plugins for the Claude Code VS Code extension, built with [Rigline](https://github.com/Rigline/Rigline).
4
-
5
- A plugin is one browser ES module and a `rigline.json` manifest. This workspace holds one to start
6
- with; adding a second is a directory copy.
7
-
8
- ## First run
9
-
10
- pnpm install
11
- pnpm codegen # harvest the installed extension, and commit the result
12
- pnpm build
13
- pnpm rigline add plugins/__NAME__
14
-
15
- Then reload the webview: **Developer: Reload Webviews** in the command palette. The badge appears
16
- in the composer footer.
17
-
18
- `pnpm codegen` writes `generated.ts` at this workspace's root: the identifiers the installed
19
- extension actually has, as types every plugin here compiles against. Commit it. It is replaced when
20
- you run against a newer extension, and the diff is how you find out what moved.
21
-
22
- ## The loop while you work
23
-
24
- pnpm rigline dev plugins/__NAME__
25
-
26
- Rebuilds and re-injects on every save. Reload webviews to see each change.
27
-
28
- ## What a plugin declares
29
-
30
- Everything in `uses` is a dependency on the installed extension still having something. An update
31
- that retires one refuses this plugin by name, at install, rather than leaving it subtly broken —
32
- which is the whole reason to declare rather than to reach.
33
-
34
- pnpm rigline check # what this extension version would refuse, and why
35
- pnpm rigline list # every plugin installed, and what each says it can do
36
-
37
- Put a dependency you can do without under `uses.optional`: it is checked the same way and costs the
38
- plugin that one decoration rather than the whole plugin.
39
-
40
- ## Testing
41
-
42
- `pnpm test` runs the pure half — the functions that do not touch the DOM. Whether a decoration
43
- lands in the right place, survives a re-render, or costs a row a line of height is a question only
44
- the app can answer: build, add, reload, look.
45
-
46
- ## Publishing
47
-
48
- A plugin is published as an ordinary npm package carrying `rigline.json` and its built entry, and
49
- installed with `rigline add <name>`. Nothing about publishing is special: `rigline build` bundles
50
- everything the entry imports, so a published plugin has no runtime dependency to install, and
51
- `@rigline/plugin-api` stays a *devDependency*.
52
-
53
- pnpm --filter rigline-plugin-__NAME__ publish
54
-
55
- ## Rules that will cost you if you break them
56
-
57
- - **Never name a class from the bundle by hand.** They are minifier output and change every build.
58
- Use `ctx.anchor("footerSpacer")` for curated names, and `ctx.cls(module, local)` — declared in the
59
- manifest — for anything not curated yet.
60
- - **Never scope a stylesheet rule to an anchor's bare class.** One class is applied wherever that
61
- look is wanted, so a rule written against it lands on every control wearing it. Scope to something
62
- you placed.
63
- - **Ask what a container does about its children before decorating it.** The composer footer
64
- measures its own element children and re-measures on any foreign change inside it; footer
65
- decorations go beside `footerSpacer`, with `ctx.mountBefore`.
66
- - **Do not poll for an element.** `ctx.watch(name, …)` hands it over when it appears and again when
67
- the app replaces it.
1
+ # __NAME__
2
+
3
+ Plugins for the Claude Code VS Code extension, built with [Rigline](https://github.com/Rigline/Rigline).
4
+
5
+ A plugin is one browser ES module and a `rigline.json` manifest. This workspace holds one to start
6
+ with; adding a second is a directory copy.
7
+
8
+ ## First run
9
+
10
+ pnpm install
11
+ pnpm codegen # harvest the installed extension, and commit the result
12
+ pnpm build
13
+ pnpm rigline add plugins/__NAME__
14
+
15
+ Then reload the webview: **Developer: Reload Webviews** in the command palette. The badge appears
16
+ in the composer footer.
17
+
18
+ `pnpm codegen` writes `generated.ts` at this workspace's root: the identifiers the installed
19
+ extension actually has, as types every plugin here compiles against. Commit it. It is replaced when
20
+ you run against a newer extension, and the diff is how you find out what moved.
21
+
22
+ ## The loop while you work
23
+
24
+ pnpm rigline dev plugins/__NAME__
25
+
26
+ Rebuilds and re-injects on every save. Reload webviews to see each change.
27
+
28
+ ## What a plugin declares
29
+
30
+ Everything in `uses` is a dependency on the installed extension still having something. An update
31
+ that retires one refuses this plugin by name, at install, rather than leaving it subtly broken —
32
+ which is the whole reason to declare rather than to reach.
33
+
34
+ pnpm rigline check # what this extension version would refuse, and why
35
+ pnpm rigline list # every plugin installed, and what each says it can do
36
+
37
+ Put a dependency you can do without under `uses.optional`: it is checked the same way and costs the
38
+ plugin that one decoration rather than the whole plugin.
39
+
40
+ ## The plugin policy
41
+
42
+ **This applies whether or not you ever publish.** A plugin you wrote for yourself and will never
43
+ share still runs inside a modification of Anthropic's extension, and Anthropic's terms still apply
44
+ to what it does on your machine. Read it once, at
45
+ [docs/plugin-policy.md](https://github.com/Rigline/Rigline/blob/main/docs/plugin-policy.md); it
46
+ takes a minute.
47
+
48
+ Rigline modifies Anthropic's extension and publishes a compliance position saying what it does and
49
+ does not do. Your plugin runs inside that modification, so the position has to hold for it too.
50
+
51
+ Most of it is not left to you — the webview has no network egress, no filesystem, and no way into
52
+ the extension host, so the usual ways to do harm are absent rather than forbidden. What the policy
53
+ asks is the part the architecture cannot cover: do not deceive the person using it, do not reach for
54
+ credentials, do not carry conversation content off the machine by a path the closed network does not
55
+ cover, and keep any host patch to switching on a capability the extension already has.
56
+
57
+ ## Testing
58
+
59
+ `pnpm test` runs the pure half — the functions that do not touch the DOM. Whether a decoration
60
+ lands in the right place, survives a re-render, or costs a row a line of height is a question only
61
+ the app can answer: build, add, reload, look.
62
+
63
+ `.github/workflows/ci.yml` runs typecheck, build and test on every push and every pull request,
64
+ over three Node versions — the same set the release workflow runs, so nothing reaches a release
65
+ that a pull request would not already have failed on. Commit `pnpm-lock.yaml`: CI installs what it
66
+ says rather than resolving its own.
67
+
68
+ ## Publishing
69
+
70
+ A plugin is published as an ordinary npm package carrying `rigline.json` and its built entry, and
71
+ installed with `rigline add <name>`. Nothing about publishing is special: `rigline-engine build`
72
+ bundles everything the entry imports, so a published plugin has no runtime dependency to install,
73
+ and both `@rigline/core` and `@rigline/plugin-api` stay *devDependencies*.
74
+
75
+ `.github/workflows/release.yml` does it from CI, with no npm token stored anywhere: GitHub
76
+ authenticates to npm over OIDC, and what the workflow does is *stage* — a version nobody can
77
+ install until you approve it from your own machine with 2FA.
78
+
79
+ pnpm stage approve
80
+
81
+ **One field to fill in before the first publish: `repository`.** npm binds a provenance attestation
82
+ to it, and this workflow stages with provenance, so a package without one cannot be staged at all.
83
+ Nothing can scaffold it for you — a guessed URL would be a wrong one in the registry rather than a
84
+ missing one — so the workflow refuses by name, before it builds anything, until it is there:
85
+
86
+ "repository": {
87
+ "type": "git",
88
+ "url": "git+https://github.com/you/your-repo.git",
89
+ "directory": "plugins/__NAME__"
90
+ }
91
+
92
+ `homepage` and `bugs` are worth the same minute; npm shows them on the package page. A `LICENSE`
93
+ file is not scaffolded either, because the copyright line is yours to write — the manifest says
94
+ MIT, and npm ships a licence file whatever `files` says, so adding one is the whole job. The
95
+ `rigline-plugin` keyword is already there: it is how somebody finds a plugin on npm.
96
+
97
+ Two things to set up once per package, the first time. Publish version one by hand, because a
98
+ package that does not exist yet has nothing for a trusted publisher to attach to — `pnpm publish -r
99
+ --otp <code>`, supplying a one-time password rather than creating a token, so there is nothing to
100
+ store or to revoke afterwards. Then add a trusted publisher in the package's settings on npmjs.com,
101
+ naming this repository and `release.yml` by path, with its permission set to stage-only. The
102
+ workflow's own header repeats both, where you will be when you need them.
103
+
104
+ Adding a second plugin later means one more of each: npm's exchange is per package, so a trusted
105
+ publisher is too. That is friction on a second plugin, never on a second release — `-r` stages only
106
+ what you bumped.
107
+
108
+ ## Rules that will cost you if you break them
109
+
110
+ - **Never name a class from the bundle by hand.** They are minifier output and change every build.
111
+ Use `ctx.anchor("footerSpacer")` for curated names, and `ctx.cls(module, local)` — declared in the
112
+ manifest — for anything not curated yet.
113
+ - **Never scope a stylesheet rule to an anchor's bare class.** One class is applied wherever that
114
+ look is wanted, so a rule written against it lands on every control wearing it. Scope to something
115
+ you placed.
116
+ - **Ask what a container does about its children before decorating it.** The composer footer
117
+ measures its own element children and re-measures on any foreign change inside it; footer
118
+ decorations go beside `footerSpacer`, with `ctx.mountBefore`.
119
+ - **Do not poll for an element.** `ctx.watch(name, …)` hands it over when it appears and again when
120
+ the app replaces it.
@@ -1,3 +1,4 @@
1
- node_modules/
2
- dist/
3
- *.log
1
+ node_modules/
2
+ dist/
3
+ *.log
4
+ pnpm-publish-summary.json
@@ -1,19 +1,21 @@
1
- {
2
- "name": "__NAME__-plugins",
3
- "private": true,
4
- "type": "module",
5
- "packageManager": "pnpm@12.3.4",
6
- "engines": { "node": ">=26" },
7
- "scripts": {
8
- "codegen": "rigline codegen",
9
- "build": "pnpm -r build",
10
- "typecheck": "pnpm -r typecheck",
11
- "test": "vitest run"
12
- },
13
- "devDependencies": {
14
- "@rigline/plugin-api": "^1.0.0",
15
- "rigline": "^1.0.0",
16
- "typescript": "^7.0.2",
17
- "vitest": "^5.0.0"
18
- }
19
- }
1
+ {
2
+ "name": "__NAME__-plugins",
3
+ "private": true,
4
+ "type": "module",
5
+ "packageManager": "pnpm@12.3.4",
6
+ "engines": { "node": ">=22.12.0" },
7
+ "scripts": {
8
+ "rigline": "rigline-engine",
9
+ "codegen": "rigline-engine codegen",
10
+ "build": "pnpm -r build",
11
+ "typecheck": "pnpm -r typecheck",
12
+ "test": "vitest run"
13
+ },
14
+ "devDependencies": {
15
+ "@rigline/core": "__RIGLINE_RANGE__",
16
+ "@rigline/plugin-api": "__RIGLINE_RANGE__",
17
+ "rolldown": "^1.2.8",
18
+ "typescript": "^7.0.2",
19
+ "vitest": "^5.0.0"
20
+ }
21
+ }
@@ -1,19 +1,19 @@
1
- # __NAME__
2
-
3
- __DESCRIPTION__
4
-
5
- ## Depends on
6
-
7
- - `uses.anchors: ["footerSpacer"]` — the flexible gap dividing the composer footer's left cluster
8
- from its right, and the anchor every footer decoration uses. The footer measures the widths of its
9
- own element children to pick a fit stage; the spacer renders in every stage, so a decoration
10
- beside it contributes a constant width and the measurement settles.
11
- - `uses.mount` — `ctx.watch` and `ctx.mountBefore`, which place the badge and keep it placed across
12
- a re-render.
13
- - `uses.style` — one stylesheet, scoped to the class this plugin puts on its own element.
14
- - `uses.tools` — `ctx.onToolUse`, every completed tool call the assistant makes.
15
-
16
- ## Notes
17
-
18
- `badgeText` is exported and tested because it is the half a plain test run can hold. Everything
19
- else is a question about the app, and only the app can answer it.
1
+ # __NAME__
2
+
3
+ __DESCRIPTION__
4
+
5
+ ## Depends on
6
+
7
+ - `uses.anchors: ["footerSpacer"]` — the flexible gap dividing the composer footer's left cluster
8
+ from its right, and the anchor every footer decoration uses. The footer measures the widths of its
9
+ own element children to pick a fit stage; the spacer renders in every stage, so a decoration
10
+ beside it contributes a constant width and the measurement settles.
11
+ - `uses.mount` — `ctx.watch` and `ctx.mountBefore`, which place the badge and keep it placed across
12
+ a re-render.
13
+ - `uses.style` — one stylesheet, scoped to the class this plugin puts on its own element.
14
+ - `uses.tools` — `ctx.onToolUse`, every completed tool call the assistant makes.
15
+
16
+ ## Notes
17
+
18
+ `badgeText` is exported and tested because it is the half a plain test run can hold. Everything
19
+ else is a question about the app, and only the app can answer it.
@@ -1,16 +1,18 @@
1
- {
2
- "name": "rigline-plugin-__NAME__",
3
- "version": "0.1.0",
4
- "description": "__DESCRIPTION__",
5
- "type": "module",
6
- "license": "MIT",
7
- "files": ["dist", "rigline.json"],
8
- "scripts": {
9
- "build": "rigline build",
10
- "typecheck": "tsc -p tsconfig.json"
11
- },
12
- "devDependencies": {
13
- "@rigline/plugin-api": "^1.0.0",
14
- "rigline": "^1.0.0"
15
- }
16
- }
1
+ {
2
+ "name": "rigline-plugin-__NAME__",
3
+ "version": "0.1.0",
4
+ "description": "__DESCRIPTION__",
5
+ "keywords": ["rigline-plugin", "rigline", "claude-code", "vscode"],
6
+ "type": "module",
7
+ "license": "MIT",
8
+ "publishConfig": { "access": "public" },
9
+ "files": ["dist", "rigline.json"],
10
+ "scripts": {
11
+ "build": "rigline-engine build",
12
+ "typecheck": "tsc -p tsconfig.json"
13
+ },
14
+ "devDependencies": {
15
+ "@rigline/core": "__RIGLINE_RANGE__",
16
+ "@rigline/plugin-api": "__RIGLINE_RANGE__"
17
+ }
18
+ }
@@ -1,14 +1,14 @@
1
- {
2
- "$schema": "../../node_modules/@rigline/plugin-api/schema/manifest.json",
3
- "api": 1,
4
- "name": "__NAME__",
5
- "description": "__DESCRIPTION__",
6
- "entry": "dist/index.js",
7
- "surfaces": ["editor", "sidebar"],
8
- "uses": {
9
- "anchors": ["footerSpacer"],
10
- "mount": true,
11
- "style": true,
12
- "tools": true
13
- }
14
- }
1
+ {
2
+ "$schema": "../../node_modules/@rigline/plugin-api/schema/manifest.json",
3
+ "api": 1,
4
+ "name": "__NAME__",
5
+ "description": "__DESCRIPTION__",
6
+ "entry": "dist/index.js",
7
+ "surfaces": ["editor", "sidebar"],
8
+ "uses": {
9
+ "anchors": ["footerSpacer"],
10
+ "mount": true,
11
+ "style": true,
12
+ "tools": true
13
+ }
14
+ }
@@ -1,21 +1,21 @@
1
- /**
2
- * The pure half of the plugin, under plain `vitest`.
3
- *
4
- * Verification splits three ways, and knowing which tier a question belongs to is most of writing
5
- * a test that is worth having. A pure function is this tier. Whether a decoration lands in the
6
- * right place, survives a re-render, or costs the row a line of height is a question about the app,
7
- * and only the app can answer it: build, `rigline add`, reload the webview, look.
8
- */
9
- import { describe, expect, it } from "vitest";
10
- import { badgeText } from "./index.ts";
11
-
12
- describe("badgeText", () => {
13
- it("says something before anything has happened", () => {
14
- expect(badgeText(0)).toBe("no tools yet");
15
- });
16
-
17
- it("does not make a reader read (s)", () => {
18
- expect(badgeText(1)).toBe("1 tool call");
19
- expect(badgeText(2)).toBe("2 tool calls");
20
- });
21
- });
1
+ /**
2
+ * The pure half of the plugin, under plain `vitest`.
3
+ *
4
+ * Verification splits three ways, and knowing which tier a question belongs to is most of writing
5
+ * a test that is worth having. A pure function is this tier. Whether a decoration lands in the
6
+ * right place, survives a re-render, or costs the row a line of height is a question about the app,
7
+ * and only the app can answer it: `pnpm build`, `pnpm rigline add`, reload the webview, look.
8
+ */
9
+ import { describe, expect, it } from "vitest";
10
+ import { badgeText } from "./index.ts";
11
+
12
+ describe("badgeText", () => {
13
+ it("says something before anything has happened", () => {
14
+ expect(badgeText(0)).toBe("no tools yet");
15
+ });
16
+
17
+ it("does not make a reader read (s)", () => {
18
+ expect(badgeText(1)).toBe("1 tool call");
19
+ expect(badgeText(2)).toBe("2 tool calls");
20
+ });
21
+ });
@@ -1,64 +1,82 @@
1
- /**
2
- * __DESCRIPTION__
3
- *
4
- * A worked example of the loop every plugin is: declare what you depend on in `rigline.json`, wait
5
- * to be handed the element you decorate, and put something beside it. Replace the body; keep the
6
- * shape.
7
- */
8
- import { definePlugin, type PluginContext, type Teardown } from "@rigline/plugin-api";
9
-
10
- /**
11
- * What the badge reads, for a given number of tool calls.
12
- *
13
- * Pure, and exported, because this is the half a plain `vitest` run can hold: anything that touches
14
- * the DOM wants the app itself, and anything that does not should not need it. See
15
- * `src/index.test.ts`.
16
- */
17
- export function badgeText(calls: number): string {
18
- if (calls === 0) return "no tools yet";
19
- return `${calls} tool ${calls === 1 ? "call" : "calls"}`;
20
- }
21
-
22
- export default definePlugin({
23
- setup(ctx: PluginContext): Teardown {
24
- let calls = 0;
25
- const badge = document.createElement("span");
26
- badge.className = "example-badge";
27
- badge.textContent = badgeText(calls);
28
-
29
- // Scoped to a class this plugin put on its own element. Never scope a rule to an anchor's bare
30
- // class: one class is applied wherever that look is wanted, so a rule written against it lands
31
- // on every control wearing it. See the anchors guide.
32
- const stopStyle = ctx.style(`
33
- .example-badge {
34
- font-size: 11px;
35
- opacity: 0.7;
36
- padding: 0 6px;
37
- white-space: nowrap;
38
- }
39
- `);
40
-
41
- // Every completed tool call the assistant makes. `uses.tools` is what makes this fire; without
42
- // the declaration it throws and disables the plugin, which is the point of declaring.
43
- const stopTools = ctx.onToolUse(() => {
44
- calls += 1;
45
- badge.textContent = badgeText(calls);
46
- });
47
-
48
- // `watch` hands over the element for an anchor whenever one is in the document, and again if
49
- // the app replaces it. No plugin polls for an element.
50
- //
51
- // `footerSpacer` and `mountBefore` together, rather than any other footer anchor: the composer
52
- // footer measures the widths of its own element children to pick a fit stage, and resets that
53
- // measurement on any foreign change inside it. A decoration whose membership of the footer
54
- // changes with the stage fights the ladder that moved it. The spacer renders in every stage, so
55
- // a decoration beside it contributes a constant width and the ladder settles.
56
- const stopWatch = ctx.watch("footerSpacer", (spacer) => ctx.mountBefore(spacer, () => badge));
57
-
58
- return () => {
59
- stopWatch();
60
- stopTools();
61
- stopStyle();
62
- };
63
- },
64
- });
1
+ /**
2
+ * __DESCRIPTION__
3
+ *
4
+ * A worked example of the loop every plugin is: declare what you depend on in `rigline.json`, wait
5
+ * to be handed the element you decorate, and put something beside it. Replace the body; keep the
6
+ * shape.
7
+ */
8
+ import { definePlugin, type PluginContext, type Teardown } from "@rigline/plugin-api";
9
+
10
+ /**
11
+ * What the badge reads, for a given number of tool calls.
12
+ *
13
+ * Pure, and exported, because this is the half a plain `vitest` run can hold: anything that touches
14
+ * the DOM wants the app itself, and anything that does not should not need it. See
15
+ * `src/index.test.ts`.
16
+ */
17
+ export function badgeText(calls: number): string {
18
+ if (calls === 0) return "no tools yet";
19
+ return `${calls} tool ${calls === 1 ? "call" : "calls"}`;
20
+ }
21
+
22
+ export default definePlugin({
23
+ setup(ctx: PluginContext): Teardown {
24
+ let calls = 0;
25
+ const badge = document.createElement("span");
26
+ badge.className = "example-badge";
27
+ badge.textContent = badgeText(calls);
28
+
29
+ // Scoped to a class this plugin put on its own element. Never scope a rule to an anchor's bare
30
+ // class: one class is applied wherever that look is wanted, so a rule written against it lands
31
+ // on every control wearing it. See the anchors guide.
32
+ const stopStyle = ctx.style(`
33
+ .example-badge {
34
+ font-size: 11px;
35
+ opacity: 0.7;
36
+ padding: 0 6px;
37
+ white-space: nowrap;
38
+ }
39
+ `);
40
+
41
+ // Every completed tool call the assistant makes. `uses.tools` is what makes this fire; without
42
+ // the declaration it throws and disables the plugin, which is the point of declaring.
43
+ const stopTools = ctx.onToolUse(() => {
44
+ calls += 1;
45
+ badge.textContent = badgeText(calls);
46
+ });
47
+
48
+ // `watch` hands over the element for an anchor whenever one is in the document, and again if
49
+ // the app replaces it. No plugin polls for an element.
50
+ //
51
+ // `footerSpacer` and `mountBefore` together, rather than any other footer anchor: the composer
52
+ // footer measures the widths of its own element children to pick a fit stage, and resets that
53
+ // measurement on any foreign change inside it. A decoration whose membership of the footer
54
+ // changes with the stage fights the ladder that moved it. The spacer renders in every stage, so
55
+ // a decoration beside it contributes a constant width and the ladder settles.
56
+ const stopWatch = ctx.watch("footerSpacer", (spacer) => ctx.mountBefore(spacer, () => badge));
57
+
58
+ // One line in Rigline's diagnostics panel, under this plugin's name. It declares nothing: the
59
+ // host calls it, hands it nothing, and gets a verdict back.
60
+ //
61
+ // Worth the four lines from the first day, because the failure a plugin has is normally silent.
62
+ // An extension update can leave this one loaded, declared, styled and drawing nothing, and
63
+ // every other line in that panel will say it is fine. Ask the question only your own state can
64
+ // answer — here, whether the badge is actually in the document — and say `n/a` with a reason
65
+ // when there is nothing to report yet.
66
+ //
67
+ // The host runs this about once a second for the life of the window, so read state you already
68
+ // keep. Do not walk the DOM or recompute an answer here; do that work where it already happens.
69
+ const stopCheck = ctx.check("badge is mounted", () =>
70
+ badge.isConnected
71
+ ? { verdict: "pass", detail: badgeText(calls) }
72
+ : { verdict: "fail", detail: "the badge is not in the document" },
73
+ );
74
+
75
+ return () => {
76
+ stopCheck();
77
+ stopWatch();
78
+ stopTools();
79
+ stopStyle();
80
+ };
81
+ },
82
+ });
@@ -1,5 +1,5 @@
1
- {
2
- "extends": "../../tsconfig.plugin.json",
3
- "include": ["src/**/*.ts"],
4
- "exclude": ["src/**/*.test.ts"]
5
- }
1
+ {
2
+ "extends": "../../tsconfig.plugin.json",
3
+ "include": ["src/**/*.ts"],
4
+ "exclude": ["src/**/*.test.ts"]
5
+ }
@@ -1,21 +1,31 @@
1
- packages:
2
- - plugins/*
3
-
4
- # Supply-chain settings, written down rather than inherited.
5
- #
6
- # Three of these are pnpm's own defaults today. They are stated anyway, because a default is not a
7
- # position: a fresh clone on a different pnpm, or a default that moves, would quietly change what
8
- # this repository is willing to install without anyone deciding to.
9
- #
10
- # minimumReleaseAge is the rule rigline applies to plugins, applied here to your own dependencies:
11
- # a day is where a compromised publish is usually caught, and a day of latency costs nothing.
12
- minimumReleaseAge: 1440
13
-
14
- # Only a direct dependency may come from a git repository or a tarball URL. A transitive dependency
15
- # that resolves outside the registry is the shape of a supply-chain problem rather than of an
16
- # ordinary package.
17
- blockExoticSubdeps: true
18
-
19
- # No dependency may run an install script. Empty because nothing here needs one; the day something
20
- # does, a person decides about it by name, here.
21
- allowBuilds: {}
1
+ packages:
2
+ - plugins/*
3
+
4
+ # Supply-chain settings, written down rather than inherited.
5
+ #
6
+ # Two of these restate a pnpm default. They are stated anyway, because a default is not a position:
7
+ # a fresh clone on a different pnpm, or a default that moves, would quietly change what this
8
+ # repository is willing to install without anyone deciding to.
9
+ #
10
+ # minimumReleaseAge is the third and is not a restatement. pnpm applies the same cutoff by default
11
+ # but merely records anything younger; writing it down is what makes it refuse. That is the rule
12
+ # rigline applies to plugins, applied here to your own dependencies: a day is where a compromised
13
+ # publish is usually caught.
14
+ minimumReleaseAge: 1440
15
+
16
+ # The exception, and the reason for it: pnpm resolves to the newest version in range that is old
17
+ # enough, and these two ranges have no older version in them to fall back on. Scaffolding you ran
18
+ # minutes ago is this same release, so waiting a day for the rest of it protects nothing. Drop these
19
+ # once the versions are a day old; a later Rigline release is gated like anything else.
20
+ minimumReleaseAgeExclude:
21
+ - "@rigline/core@__RIGLINE_VERSION__"
22
+ - "@rigline/plugin-api@__RIGLINE_VERSION__"
23
+
24
+ # Only a direct dependency may come from a git repository or a tarball URL. A transitive dependency
25
+ # that resolves outside the registry is the shape of a supply-chain problem rather than of an
26
+ # ordinary package.
27
+ blockExoticSubdeps: true
28
+
29
+ # No dependency may run an install script. Empty because nothing here needs one; the day something
30
+ # does, a person decides about it by name, here.
31
+ allowBuilds: {}
@@ -1,19 +1,19 @@
1
- {
2
- "compilerOptions": {
3
- "target": "esnext",
4
- "module": "nodenext",
5
- "moduleResolution": "nodenext",
6
- "moduleDetection": "force",
7
- "strict": true,
8
- "noUncheckedIndexedAccess": true,
9
- "noImplicitOverride": true,
10
- "noUnusedLocals": true,
11
- "noUnusedParameters": true,
12
- "noFallthroughCasesInSwitch": true,
13
- "isolatedModules": true,
14
- "verbatimModuleSyntax": true,
15
- "erasableSyntaxOnly": true,
16
- "skipLibCheck": true,
17
- "forceConsistentCasingInFileNames": true
18
- }
19
- }
1
+ {
2
+ "compilerOptions": {
3
+ "target": "esnext",
4
+ "module": "nodenext",
5
+ "moduleResolution": "nodenext",
6
+ "moduleDetection": "force",
7
+ "strict": true,
8
+ "noUncheckedIndexedAccess": true,
9
+ "noImplicitOverride": true,
10
+ "noUnusedLocals": true,
11
+ "noUnusedParameters": true,
12
+ "noFallthroughCasesInSwitch": true,
13
+ "isolatedModules": true,
14
+ "verbatimModuleSyntax": true,
15
+ "erasableSyntaxOnly": true,
16
+ "skipLibCheck": true,
17
+ "forceConsistentCasingInFileNames": true
18
+ }
19
+ }
@@ -1,11 +1,11 @@
1
- {
2
- "//": "The base every plugin here extends. `files` names the committed harvest so that its module augmentation is in each plugin's own program: augmentation is per-program, so a plugin whose tsconfig does not pull generated.ts in compiles with every extension identifier widened to `string`. Relative paths in an extended config resolve against the config that declared them, so this one entry serves every plugin however deep it sits. A plugin's own tsconfig overrides `include` and leaves `files` alone. That augmentation resolves `@rigline/plugin-api` from this directory rather than from the plugin's, which is why the workspace root depends on it too.",
3
- "extends": "./tsconfig.base.json",
4
- "compilerOptions": {
5
- "lib": ["esnext", "dom"],
6
- "types": [],
7
- "noEmit": true,
8
- "allowImportingTsExtensions": true
9
- },
10
- "files": ["generated.ts"]
11
- }
1
+ {
2
+ "//": "The base every plugin here extends. `files` names the committed harvest so that its module augmentation is in each plugin's own program: augmentation is per-program, so a plugin whose tsconfig does not pull generated.ts in compiles with every extension identifier widened to `string`. Relative paths in an extended config resolve against the config that declared them, so this one entry serves every plugin however deep it sits. A plugin's own tsconfig overrides `include` and leaves `files` alone. That augmentation resolves `@rigline/plugin-api` from this directory rather than from the plugin's, which is why the workspace root depends on it too.",
3
+ "extends": "./tsconfig.base.json",
4
+ "compilerOptions": {
5
+ "lib": ["esnext", "dom"],
6
+ "types": [],
7
+ "noEmit": true,
8
+ "allowImportingTsExtensions": true
9
+ },
10
+ "files": ["generated.ts"]
11
+ }
package/dist/index.js.map DELETED
@@ -1 +0,0 @@
1
- {"version":3,"file":"index.js","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":";AACA;;;;;;;;;;;;;;;GAeG;AACH,OAAO,EAAE,UAAU,EAAE,SAAS,EAAE,WAAW,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,SAAS,CAAC;AAC1F,OAAO,EAAE,QAAQ,EAAE,OAAO,EAAE,IAAI,EAAE,QAAQ,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACvE,OAAO,EAAE,aAAa,EAAE,MAAM,UAAU,CAAC;AAEzC,uFAAuF;AACvF,MAAM,YAAY,GAAG,8BAA8B,CAAC;AAwBpD,MAAM,OAAO,aAAc,SAAQ,KAAK;CAAG;AAE3C,8CAA8C;AAC9C,MAAM,UAAU,kBAAkB;IAChC,OAAO,OAAO,CAAC,OAAO,CAAC,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,CAAC,EAAE,IAAI,EAAE,UAAU,CAAC,CAAC;AAC5E,CAAC;AAED;;;;;GAKG;AACH,MAAM,UAAU,QAAQ,CAAC,OAAwB;IAC/C,MAAM,GAAG,GAAG,OAAO,CAAC,OAAO,CAAC,MAAM,CAAC,CAAC;IACpC,MAAM,IAAI,GAAG,OAAO,CAAC,IAAI,IAAI,QAAQ,CAAC,GAAG,CAAC,CAAC;IAC3C,IAAI,CAAC,YAAY,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,aAAa,CACrB,IAAI,IAAI,oFAAoF;YAC1F,sDAAsD,CACzD,CAAC;IACJ,CAAC;IACD,IAAI,UAAU,CAAC,GAAG,CAAC,IAAI,WAAW,CAAC,GAAG,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACnD,MAAM,IAAI,aAAa,CAAC,GAAG,GAAG,eAAe,CAAC,CAAC;IACjD,CAAC;IAED,MAAM,WAAW,GAAG,OAAO,CAAC,WAAW,IAAI,kBAAkB,EAAE,CAAC;IAChE,IAAI,CAAC,UAAU,CAAC,WAAW,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,aAAa,CAAC,8CAA8C,WAAW,EAAE,CAAC,CAAC;IACvF,CAAC;IAED,MAAM,aAAa,GAAkB;QACnC,IAAI,EAAE,IAAI;QACV,WAAW,EAAE,OAAO,CAAC,WAAW,IAAI,2BAA2B,IAAI,GAAG;KACvE,CAAC;IAEF,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,MAAM,IAAI,IAAI,CAAC,WAAW,CAAC,EAAE,CAAC;QACvC,MAAM,YAAY,GAAG,UAAU,CAAC,QAAQ,CAAC,WAAW,EAAE,MAAM,CAAC,EAAE,aAAa,CAAC,CAAC;QAC9E,+FAA+F;QAC/F,wFAAwF;QACxF,MAAM,OAAO,GAAG,YAAY,KAAK,WAAW,CAAC,CAAC,CAAC,YAAY,CAAC,CAAC,CAAC,YAAY,CAAC;QAC3E,MAAM,MAAM,GAAG,IAAI,CAAC,GAAG,EAAE,OAAO,CAAC,CAAC;QAClC,SAAS,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,CAAC,CAAC;QAChD,aAAa,CAAC,MAAM,EAAE,UAAU,CAAC,YAAY,CAAC,MAAM,EAAE,MAAM,CAAC,EAAE,aAAa,CAAC,CAAC,CAAC;QAC/E,KAAK,CAAC,IAAI,CAAC,OAAO,CAAC,KAAK,CAAC,IAAI,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC;IAC5C,CAAC;IAED,KAAK,CAAC,IAAI,EAAE,CAAC;IACb,OAAO,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC;AAC9B,CAAC;AAED,+DAA+D;AAC/D,SAAS,IAAI,CAAC,IAAY;IACxB,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,KAAK,MAAM,KAAK,IAAI,WAAW,CAAC,IAAI,EAAE,EAAE,aAAa,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAC3E,CAAC,CAAC,IAAI,CAAC,aAAa,CAAC,CAAC,CAAC,IAAI,CAAC,CAC7B,EAAE,CAAC;QACF,MAAM,IAAI,GAAG,IAAI,CAAC,IAAI,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;QACpC,IAAI,KAAK,CAAC,WAAW,EAAE;YAAE,KAAK,CAAC,IAAI,CAAC,GAAG,IAAI,CAAC,IAAI,CAAC,CAAC,CAAC;;YAC9C,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACxB,CAAC;IACD,OAAO,KAAK,CAAC;AACf,CAAC;AAED,2EAA2E;AAC3E,SAAS,UAAU,CAAC,IAAY,EAAE,aAA4B;IAC5D,IAAI,GAAG,GAAG,IAAI,CAAC;IACf,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,aAAa,CAAC,EAAE,CAAC;QACzD,GAAG,GAAG,GAAG,CAAC,KAAK,CAAC,KAAK,GAAG,IAAI,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC;IAC5C,CAAC;IACD,OAAO,GAAG,CAAC;AACb,CAAC;AAED,mFAAmF;AACnF,MAAM,UAAU,SAAS,CAAC,MAAsB;IAC9C,iGAAiG;IACjG,sDAAsD;IACtD,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,GAAG,EAAE,EAAE,MAAM,CAAC,GAAG,CAAC,CAAC;IACjD,MAAM,IAAI,GAAG,IAAI,KAAK,EAAE,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,UAAU,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC;IAC3E,OAAO;QACL,WAAW,MAAM,CAAC,KAAK,CAAC,MAAM,aAAa,MAAM,CAAC,GAAG,EAAE;QACvD,EAAE;QACF,OAAO;QACP,QAAQ,IAAI,EAAE;QACd,gBAAgB;QAChB,8EAA8E;QAC9E,cAAc;QACd,8BAA8B,MAAM,CAAC,IAAI,EAAE;QAC3C,EAAE;QACF,sDAAsD;QACtD,EAAE;QACF,GAAG,IAAI,CAAC,IAAI,EAAE,WAAW,CAAC,8DAA8D;KACzF,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;AACf,CAAC;AAED;;;GAGG;AACH,MAAM,UAAU,IAAI,CAAC,IAAuB;IAC1C,MAAM,WAAW,GAAa,EAAE,CAAC;IACjC,IAAI,IAAwB,CAAC;IAC7B,IAAI,WAA+B,CAAC;IAEpC,KAAK,IAAI,EAAE,GAAG,CAAC,EAAE,EAAE,GAAG,IAAI,CAAC,MAAM,EAAE,EAAE,EAAE,EAAE,CAAC;QACxC,MAAM,QAAQ,GAAG,IAAI,CAAC,EAAE,CAAW,CAAC;QACpC,IAAI,QAAQ,KAAK,QAAQ;YAAE,IAAI,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;aACxC,IAAI,QAAQ,KAAK,eAAe;YAAE,WAAW,GAAG,IAAI,CAAC,EAAE,EAAE,CAAC,CAAC;aAC3D,IAAI,QAAQ,KAAK,IAAI,IAAI,QAAQ,KAAK,QAAQ,EAAE,CAAC;YACpD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC;YACnB,OAAO,CAAC,CAAC;QACX,CAAC;aAAM,IAAI,QAAQ,CAAC,UAAU,CAAC,GAAG,CAAC,EAAE,CAAC;YACpC,OAAO,CAAC,KAAK,CAAC,0CAA0C,QAAQ,QAAQ,KAAK,EAAE,CAAC,CAAC;YACjF,OAAO,CAAC,CAAC;QACX,CAAC;;YAAM,WAAW,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;IACpC,CAAC;IAED,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;QAC7B,OAAO,CAAC,KAAK,CAAC,oDAAoD,KAAK,EAAE,CAAC,CAAC;QAC3E,OAAO,CAAC,CAAC;IACX,CAAC;IAED,IAAI,CAAC;QACH,OAAO,CAAC,GAAG,CAAC,SAAS,CAAC,QAAQ,CAAC,EAAE,MAAM,EAAE,WAAW,CAAC,CAAC,CAAW,EAAE,IAAI,EAAE,WAAW,EAAE,CAAC,CAAC,CAAC,CAAC;QAC1F,OAAO,CAAC,CAAC;IACX,CAAC;IAAC,OAAO,KAAK,EAAE,CAAC;QACf,IAAI,KAAK,YAAY,aAAa,EAAE,CAAC;YACnC,OAAO,CAAC,KAAK,CAAC,0BAA0B,KAAK,CAAC,OAAO,EAAE,CAAC,CAAC;YACzD,OAAO,CAAC,CAAC;QACX,CAAC;QACD,MAAM,KAAK,CAAC;IACd,CAAC;AACH,CAAC;AAED,MAAM,KAAK,GAAG;;;;;4EAK8D,CAAC;AAE7E,mGAAmG;AACnG,mGAAmG;AACnG,IAAI,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,KAAK,SAAS,IAAI,aAAa,CAAC,OAAO,IAAI,CAAC,GAAG,CAAC,KAAK,OAAO,CAAC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC;IACjG,OAAO,CAAC,QAAQ,GAAG,IAAI,CAAC,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC;AACjD,CAAC"}