norn-cli 2.2.2 → 2.4.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/.claude/settings.local.json +18 -0
- package/.claude/skills/norn-social-campaign/SKILL.md +70 -0
- package/CHANGELOG.md +22 -1
- package/LICENSE +20 -29
- package/README.md +32 -1
- package/demos/nornenv-region-refactor/README.md +64 -0
- package/demos/nornenv-showcase/README.md +62 -0
- package/demos/nornenv-showcase/norn.config.json +16 -0
- package/demos/nornenv-showcase/showcase.norn +70 -0
- package/demos/nornenv-showcase/showcase.nornapi +26 -0
- package/demos/nornenv-showcase/showcase.nornsql +20 -0
- package/dist/cli.js +564 -54
- package/out/apiResponseIntellisenseCache.js +394 -0
- package/out/assertionRunner.js +567 -0
- package/out/cacheDir.js +136 -0
- package/out/chatParticipant.js +763 -0
- package/out/cli/colors.js +127 -0
- package/out/cli/formatters/assertion.js +102 -0
- package/out/cli/formatters/index.js +23 -0
- package/out/cli/formatters/response.js +106 -0
- package/out/cli/formatters/summary.js +246 -0
- package/out/cli/redaction.js +237 -0
- package/out/cli/reporters/html.js +689 -0
- package/out/cli/reporters/index.js +22 -0
- package/out/cli/reporters/junit.js +226 -0
- package/out/codeLensProvider.js +351 -0
- package/out/compareContentProvider.js +85 -0
- package/out/completionProvider.js +3739 -0
- package/out/contractAssertionSummary.js +225 -0
- package/out/contractDecorationProvider.js +243 -0
- package/out/coverageCalculator.js +879 -0
- package/out/coveragePanel.js +597 -0
- package/out/debug/breakpointResolver.js +84 -0
- package/out/debug/breakpoints.js +52 -0
- package/out/debug/nornDebugAdapter.js +166 -0
- package/out/debug/nornDebugSession.js +613 -0
- package/out/debug/sequenceLocationIndex.js +77 -0
- package/out/debug/types.js +3 -0
- package/out/deepClone.js +21 -0
- package/out/diagnosticProvider.js +2554 -0
- package/out/environmentParser.js +736 -0
- package/out/environmentProvider.js +544 -0
- package/out/environmentTemplates.js +146 -0
- package/out/errors/formatError.js +113 -0
- package/out/errors/nornError.js +29 -0
- package/out/formUrlEncoded.js +89 -0
- package/out/httpClient.js +348 -0
- package/out/httpRuntimeOptions.js +16 -0
- package/out/importErrors.js +31 -0
- package/out/inlayHintResolver.js +70 -0
- package/out/jsonFileReader.js +323 -0
- package/out/mcpClient.js +193 -0
- package/out/mcpConfig.js +184 -0
- package/out/mcpToolIntellisenseCache.js +96 -0
- package/out/mcpToolSchema.js +50 -0
- package/out/nornConfig.js +132 -0
- package/out/nornHoverProvider.js +124 -0
- package/out/nornInlayHintsProvider.js +191 -0
- package/out/nornPrompt.js +755 -0
- package/out/nornSqlParser.js +286 -0
- package/out/nornapiHoverProvider.js +135 -0
- package/out/nornapiInlayHintsProvider.js +94 -0
- package/out/nornapiParser.js +324 -0
- package/out/nornenvCodeActionProvider.js +101 -0
- package/out/nornenvDecorationProvider.js +239 -0
- package/out/nornenvFoldingProvider.js +63 -0
- package/out/nornenvHoverProvider.js +114 -0
- package/out/nornenvInlayHintsProvider.js +99 -0
- package/out/nornenvLanguageModel.js +187 -0
- package/out/nornenvRegionRefactor.js +267 -0
- package/out/nornsqlHoverProvider.js +95 -0
- package/out/nornsqlInlayHintsProvider.js +114 -0
- package/out/parser.js +839 -0
- package/out/pathAccess.js +28 -0
- package/out/postmanImportPanel.js +732 -0
- package/out/postmanImportPlanner.js +1155 -0
- package/out/postmanImportSidebarView.js +532 -0
- package/out/quotedString.js +35 -0
- package/out/requestPreparation.js +179 -0
- package/out/requestValidation.js +146 -0
- package/out/responsePanel.js +7754 -0
- package/out/schemaGenerator.js +562 -0
- package/out/scriptRunner.js +419 -0
- package/out/secrets/cliSecrets.js +415 -0
- package/out/secrets/crypto.js +105 -0
- package/out/secrets/envFileSecrets.js +177 -0
- package/out/secrets/keyStore.js +259 -0
- package/out/sequenceDeclaration.js +15 -0
- package/out/sequenceRunner.js +3590 -0
- package/out/sqlAdapterRunner.js +122 -0
- package/out/sqlBuiltInAdapters.js +604 -0
- package/out/sqlConfig.js +184 -0
- package/out/starterCatalog.js +554 -0
- package/out/stringUtils.js +25 -0
- package/out/swaggerBodyIntellisenseCache.js +114 -0
- package/out/swaggerParser.js +464 -0
- package/out/testProvider.js +767 -0
- package/out/theoryCaseLoader.js +113 -0
- package/out/validationCache.js +211 -0
- package/package.json +38 -11
- package/.kanbn/index.md +0 -31
- package/.kanbn/tasks/book-first-mentor-session.md +0 -13
- package/.kanbn/tasks/decide-what-success-in-a-pilot-looks-like.md +0 -9
- package/.kanbn/tasks/do-5-customer-conversations.md +0 -9
- package/.kanbn/tasks/finalise-the-one-line-pitch.md +0 -11
- package/.kanbn/tasks/interview-script.md +0 -49
- package/.kanbn/tasks/make-a-list-of-10-people-to-speak-to.md +0 -11
- package/.kanbn/tasks/prepare-your-customer-interview-questions.md +0 -11
- package/.kanbn/tasks/recruit-2/342/200/2233-pilot-users.md +0 -9
- package/.kanbn/tasks/refine-your-pitch.md +0 -9
- package/.kanbn/tasks/use-the-shiplight-website-as-a-template-to-improve-norn-website.md +0 -9
- package/.kanbn/tasks/write-down-repeated-wording.md +0 -9
- package/.kanbn/tasks/write-the-one-pager.md +0 -27
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
{
|
|
2
|
+
"permissions": {
|
|
3
|
+
"allow": [
|
|
4
|
+
"Bash(npm run *)",
|
|
5
|
+
"WebSearch",
|
|
6
|
+
"Bash(git checkout *)",
|
|
7
|
+
"Bash(node ./dist/cli.js tests/Regression/nornenv-templates/extends-resolution.norn -s PrintResolvedValues -e prod_uk)",
|
|
8
|
+
"Bash(node ./dist/cli.js tests/Regression/nornenv-templates/extends-resolution.norn -s PrintResolvedValues -e prod_us)",
|
|
9
|
+
"Bash(node ./dist/cli.js tests/Regression/nornenv-templates/extends-resolution.norn -s PrintResolvedValues -e diamond)",
|
|
10
|
+
"Bash(node ./dist/cli.js tests/Regression/nornenv-templates/extends-resolution.norn -s PrintResolvedValues -e base)",
|
|
11
|
+
"Bash(mv .nornenv .nornenv.bak)",
|
|
12
|
+
"Bash(cp cycle.nornenv .nornenv)",
|
|
13
|
+
"Bash(timeout 10 node ../../../dist/cli.js extends-resolution.norn -s PrintResolvedValues -e c)",
|
|
14
|
+
"Bash(time node ../../../dist/cli.js extends-resolution.norn -s PrintResolvedValues -e c)",
|
|
15
|
+
"Bash(time node /Users/petercrest/Worktable/Projects/vsApi/dist/cli.js extends-resolution.norn -s PrintResolvedValues -e c)"
|
|
16
|
+
]
|
|
17
|
+
}
|
|
18
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: norn-social-campaign
|
|
3
|
+
description: Continue Peter's Norn LinkedIn social-media campaign — draft/review/schedule posts, reply to engagement, evaluate Week-N kill-criteria, log community signals. Use whenever the user asks about Norn LinkedIn posts, replies, engagement metrics, the GTM experiment, what to post next, or any social/content work for Norn.
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Norn Social Media Campaign — Cross-Session Continuity
|
|
7
|
+
|
|
8
|
+
You are resuming an ongoing GTM experiment Peter has been running for **Norn** (a commercial VS Code extension + CLI he builds solo while employed full-time, UK-based). Most strategic decisions are **locked** — your job is to execute within them, not re-litigate. The canonical state lives in repo `Docs/`; read those before doing real work.
|
|
9
|
+
|
|
10
|
+
## Read these first (canonical, in this repo)
|
|
11
|
+
|
|
12
|
+
- `Docs/gtm_plan.md` — **the master plan**. Locked positioning, 13-week kill-criteria with anchored dates, action steps, and an append-only **Progress Log** (scroll to the bottom to see exactly where things stand).
|
|
13
|
+
- `Docs/mot_reaction_series.md` — **the LinkedIn posts** (the filename is misnamed — see Anti-patterns; rename pending).
|
|
14
|
+
- `Docs/linkedin_series.md` — LinkedIn delivery rules (tags, first-comment text, image policy, posting cadence).
|
|
15
|
+
- `Docs/market_signals.md` — append-only community pain-signal intel log. Append; don't re-derive.
|
|
16
|
+
- `Docs/postman_rot_essay.md` (long-form v3) and `Docs/mot_series.md` (v1 micro-posts) — backup bank, not active.
|
|
17
|
+
|
|
18
|
+
Memory files `norn-gtm-decision.md` and `norn-messaging-locked.md` auto-load and carry the durable decisions.
|
|
19
|
+
|
|
20
|
+
## What is LOCKED — do not reopen
|
|
21
|
+
|
|
22
|
+
- **Positioning spine (verbatim, never paraphrase):**
|
|
23
|
+
> Norn turns API requests into version-controlled tests your whole team can keep — authored and debugged in VS Code, run on every PR in CI.
|
|
24
|
+
Category = repo-native API regression testing. NOT "REST client", NOT vaguer "workflow automation."
|
|
25
|
+
- **GTM motion:** public commercial launch (PLG + upmarket founder-led semi-sales). 13-week time-boxed experiment. Kill-criteria + anchored dates in `gtm_plan.md`. "CV-asset" is an accepted non-failure outcome.
|
|
26
|
+
- **Sell to:** CTO / founding eng / tech lead at small companies (~≤20–30 people). **QA = evangelist, not buyer.** Eng Manager parked until 50+ people.
|
|
27
|
+
- **Pricing model:** VS Code Extension is **free forever (incl. commercial).** CLI is **free for local use.** **Paid only for CLI Pipeline Use (CI/CD).** No evaluation period. Encoded in `LICENSE` (vsApi + Norn, kept in sync).
|
|
28
|
+
- **Channel: LinkedIn only.** MoT dropped 2026-05-18. One uniform series posted to LinkedIn.
|
|
29
|
+
- **Voice:** dry, specific, recognition-humor, no slang/meme/"touch grass" register, clarity > cleverness, no clever coda after the closing question. ~150–220 words per post.
|
|
30
|
+
- **Canonical ending** (append verbatim, URL-free, to every post):
|
|
31
|
+
> Disclosure so nobody feels tricked: I build Norn — my attempt at the in-the-repo fix. That's the entire pitch; the post stands without it. Still genuinely curious about the question above, though.
|
|
32
|
+
- **Tags (fixed, every post):** `#API #Testing #DeveloperTools`. Add `#MCP` only on the MCP post. 4 max.
|
|
33
|
+
- **First comment** (within ~1 min of posting):
|
|
34
|
+
> The Norn bit I mentioned, if you want to poke at it: https://nornapi.com
|
|
35
|
+
- **Posting cadence:** Tue–Thu ~8:30am UK time, one post/day, ≥4–5 days apart.
|
|
36
|
+
- **Visual rule:** real source screenshot (with identifying bits cropped) if a genuine artifact exists; text-only otherwise. **Never** Norn logo. **Never** AI imagery.
|
|
37
|
+
- **Self-presentation:** "QA / automation engineer who builds Norn." **Never "Founder."** The reason is strategic (credibility + disclosure-not-pitch posture), not legal — Peter's employment contract is permissive, employer has long known.
|
|
38
|
+
|
|
39
|
+
## Anti-patterns — do NOT do
|
|
40
|
+
|
|
41
|
+
- **Don't reopen the positioning spine.** It was rewritten many times before locking; uniformity *is* the strategy.
|
|
42
|
+
- **Don't suggest pitching Peter's employer.** Internal-champion path was closed 2026-05-18 — declined "prefer not to sour the relationship" (structural/relationship objection, not product, not IP). Their "no" is excluded from any market-signal read.
|
|
43
|
+
- **Don't raise the employer IP-alarm.** Contract permissive; employer long aware; Peter refused a restrictive replacement years ago specifically to protect this. Settled.
|
|
44
|
+
- **Don't suggest MoT / Reddit / forums as a posting channel.** Dropped. LinkedIn only.
|
|
45
|
+
- **Don't pitch Norn in post bodies or in comment replies.** The canonical ending + first comment do all the selling. Replies = host of a conversation, not salesperson.
|
|
46
|
+
- **Don't suggest a separate LinkedIn-native content stream.** One uniform series. Per-channel variants caused the consistency problem the whole session was about.
|
|
47
|
+
- **Don't add clever/meta codas after the closing question.** Two prior attempts ("wishful Slack message", "I want to collect these") had to be fixed because they were too clever for the reader. Plain question close, full stop.
|
|
48
|
+
- **Don't suggest building product features speculatively.** Build bets in `market_signals.md` are *candidates* — build only after Week-7+ signals justify. "Don't build on spec."
|
|
49
|
+
- **Don't write more posts on spec before the Week-4 verdict.** If the format doesn't travel, posts 7+ are wasted on a wrong format.
|
|
50
|
+
- **The file `mot_reaction_series.md` is misnamed** (no MoT anymore). Rename to `linkedin_posts.md` is a pending cleanup; cross-refs in `gtm_plan.md` and `linkedin_series.md` will need updating in the same pass.
|
|
51
|
+
|
|
52
|
+
## How to handle common requests
|
|
53
|
+
|
|
54
|
+
- **"Give me the next post" / "what should I post":** check the Progress Log in `gtm_plan.md` to see which posts are scheduled vs sent. Posts live in `mot_reaction_series.md`. Format LinkedIn-ready: strip the internal `## N. Title` label; strip markdown asterisks (LinkedIn shows them literally); append the canonical ending; append the tag line; provide the first-comment text separately. Image: real cropped screenshot if a genuine source exists, otherwise text-only.
|
|
55
|
+
- **"Reply to this comment":** stay in voice; *extend* the discussion, never thank generically; no Norn pitch in the reply (the bio carries it); reply **fast** — early engagement is the single biggest reach lever, far above any other tactic.
|
|
56
|
+
- **"How's the post doing?" / metrics:** calibrate via ratios more than raw numbers. Comment-to-reaction ratio above ~8% = high engagement. A **Send** (LinkedIn DM forward) is the highest-value action — it's the peer-to-peer endorsement the plan was built for. Saves > likes in intent. n=1 is not a trend.
|
|
57
|
+
- **"Week-N review":** open the kill-criteria table in `gtm_plan.md` (dates anchored to 2026-05-21 launch). Evaluate signals honestly against the rule. **The pre-committed exit only works if the review actually happens** — sunk cost will narrate; resist it.
|
|
58
|
+
- **New community pain signal (Reddit/Lobsters/HN):** append verbatim quote + URL + date to `Docs/market_signals.md`, triage into LinkedIn angle + build-bet columns. Don't let mining displace posting.
|
|
59
|
+
|
|
60
|
+
## Working style with Peter
|
|
61
|
+
|
|
62
|
+
- Convert relative dates to absolute when logging (UK timezone).
|
|
63
|
+
- Peter is a non-writer; he trusts drafts. When asked for content, give **clean, copy-pasteable** text. No padding, no "here you go" framing.
|
|
64
|
+
- Peter values **brevity, decisiveness, and honest pushback** over compliance. If something he's about to do is wrong, say so directly with reasoning. Don't be a yes-man — he's caught me on it before.
|
|
65
|
+
- **Consistency is his #1 value.** Keep the Docs as the single source of truth. Any time copy gets revised, sync everywhere it appears.
|
|
66
|
+
- When in doubt about state, **read the bottom of `gtm_plan.md`'s Progress Log** — that's where the truth lives.
|
|
67
|
+
|
|
68
|
+
---
|
|
69
|
+
|
|
70
|
+
This skill is the index. The `Docs/` files are the canon. When in doubt, read them.
|
package/CHANGELOG.md
CHANGED
|
@@ -2,7 +2,28 @@
|
|
|
2
2
|
|
|
3
3
|
All notable changes to the "Norn" extension will be documented in this file.
|
|
4
4
|
|
|
5
|
-
## [
|
|
5
|
+
## [2.4.0] - 2026-05-25
|
|
6
|
+
|
|
7
|
+
### Added
|
|
8
|
+
- **Per-folder and persisted active environment** — the active env is now tracked per `.nornenv` file (keyed by absolute path) and persisted to the workspace memento. In monorepos each folder remembers its own selection, and selections survive VS Code restart. The status bar shows the env for the current editor's nearest `.nornenv`. Stale entries (deleted `.nornenv` files) are pruned on load.
|
|
9
|
+
- **Region-pattern refactor** — when a `.nornenv` contains a flat `[env:STAGE_REGION]` matrix (e.g. `dev_us`, `dev_uk`, `prod_us`, `prod_uk`), the top of the file shows a "Refactor N envs into S+R templates" CodeLens. Clicking it classifies each variable by axis (stage / region / leaf-specific) and lifts shared values into `[template:STAGE]` + `[template:REGION]` blocks, leaving only true leaf-specific overrides in the env sections. Missing values and `connectionString` declarations stay leaf-specific, per-declaration `secret` keywords are preserved, and the same generator is available in the CLI via `--refactor-region-pattern` / `--write`. The VS Code refactor is one `WorkspaceEdit` so a single Cmd+Z reverses it.
|
|
10
|
+
|
|
11
|
+
## [2.3.0] - 2026-05-20
|
|
12
|
+
|
|
13
|
+
### Added
|
|
14
|
+
- **Inlay hints + hover across every Norn file type**:
|
|
15
|
+
- `.norn`: every `{{name}}` / `{{$env.name}}` token resolves under the active env, with three-scope precedence — sequence-local `var` declarations ← file-level `var` declarations ← active env's effective vars. Runtime values (`$1.body.x`, `run X()`, request captures) are intentionally not rendered inline; hover narrates them with source line.
|
|
16
|
+
- `.nornapi`: every `{{...}}` token in headers groups and endpoint definitions resolves under the active env.
|
|
17
|
+
- `.nornsql`: the `connection NAME` line shows the resolved `NAME_connectionString` from `.nornenv` (masked if a `secret connectionString`). Hover narrates the source. Any `{{...}}` in SQL bodies is handled for parity.
|
|
18
|
+
- Resolution and reference parsing live in `src/inlayHintResolver.ts` so every provider behaves identically.
|
|
19
|
+
- **`.nornenv` Templates And Extends (Extension + CLI)**:
|
|
20
|
+
- Added `[template:NAME]` sections and multi-parent template `extends` on `[env:...]` / `[template:...]` headers.
|
|
21
|
+
- Resolved env values as `common <- template1 <- template2 <- self`; templates compose into envs but are not selectable in the status bar or CLI `-e`.
|
|
22
|
+
- Added `.nornenv` Activate/Deactivate and Peek inherited CodeLens actions, folding ranges, smart header decorations, hover resolution chains, inlay hints for `{{...}}`, and inherited-variable completions.
|
|
23
|
+
- Added diagnostics for unknown extends parents, invalid env parents, extends cycles, out-of-scope cross-section references, and typo-like override names.
|
|
24
|
+
|
|
25
|
+
### Fixed
|
|
26
|
+
- Endpoint path arguments now keep bare `.nornenv` names as literal path values unless the reference is explicit (`{{name}}` / `{{$env.name}}`), while declared file/sequence variables still resolve in endpoint calls.
|
|
6
27
|
|
|
7
28
|
## [2.2.0] - 2026-05-09
|
|
8
29
|
|
package/LICENSE
CHANGED
|
@@ -8,13 +8,17 @@ If you do not wish to be bound by the terms of this Agreement, you may not downl
|
|
|
8
8
|
|
|
9
9
|
• DEFINITIONS
|
|
10
10
|
|
|
11
|
-
"
|
|
11
|
+
"Extension" means the Norn extension for Visual Studio Code.
|
|
12
|
+
|
|
13
|
+
"CLI" means the Norn command-line interface.
|
|
12
14
|
|
|
13
|
-
"
|
|
15
|
+
"Pipeline Use" means execution of the CLI within an automated build, test, integration, delivery or deployment pipeline, including but not limited to continuous integration and continuous delivery (CI/CD) systems, whether hosted or self-hosted, and whether or not triggered by a human.
|
|
14
16
|
|
|
15
|
-
"
|
|
17
|
+
"Local Use" means execution of the CLI directly by an individual on a workstation or development machine, outside of any automated pipeline.
|
|
18
|
+
|
|
19
|
+
"Authorized User" means any employee, independent contractor or other temporary worker authorized by Licensee to use the Software while performing duties within the scope of their employment or assignment.
|
|
16
20
|
|
|
17
|
-
"
|
|
21
|
+
"License Key" means a unique key-code that authorizes Pipeline Use of the CLI. Only Licensor and/or its representatives are permitted to produce License Keys for the Software.
|
|
18
22
|
|
|
19
23
|
• OWNERSHIP
|
|
20
24
|
|
|
@@ -26,35 +30,22 @@ Upon your acceptance of this Agreement, Licensor grants you a limited, non-trans
|
|
|
26
30
|
|
|
27
31
|
• INTENDED USERS OF THE SOFTWARE
|
|
28
32
|
|
|
29
|
-
The
|
|
30
|
-
|
|
31
|
-
• FREE USE (PERSONAL USE)
|
|
32
|
-
|
|
33
|
-
You may install and use the Software free of charge for Personal Use, including:
|
|
34
|
-
- Personal projects and experimentation
|
|
35
|
-
- Learning and educational purposes
|
|
36
|
-
- Open-source projects that do not generate revenue
|
|
37
|
-
- Academic research
|
|
38
|
-
|
|
39
|
-
• COMMERCIAL EVALUATION
|
|
33
|
+
The Extension is free to install and use for everyone, including individuals, businesses and organisations, for any purpose including commercial purposes, and never requires a License Key. The CLI is free for Local Use. A License Key is required only for Pipeline Use of the CLI. No License Key is required to use the Extension or to use the CLI for Local Use.
|
|
40
34
|
|
|
41
|
-
|
|
42
|
-
- Limited to one (1) evaluation period per organisation
|
|
43
|
-
- Intended for genuine evaluation purposes only
|
|
44
|
-
- Not to be used for production workloads or client projects
|
|
45
|
-
- Not extendable or renewable without written permission from the Licensor
|
|
35
|
+
• FREE USE
|
|
46
36
|
|
|
47
|
-
|
|
37
|
+
You may install and use the following free of charge, without a License Key:
|
|
38
|
+
- The Extension, for any use, including commercial use within a for-profit company or organisation
|
|
39
|
+
- The CLI for Local Use, including personal projects and experimentation, learning and education, academic research, and open-source projects
|
|
48
40
|
|
|
49
|
-
•
|
|
41
|
+
• LICENSED USE (PIPELINE USE OF THE CLI)
|
|
50
42
|
|
|
51
|
-
A
|
|
52
|
-
-
|
|
53
|
-
- Use
|
|
54
|
-
- Use in CI/CD
|
|
55
|
-
- Use to develop, test, or maintain revenue-generating software or services
|
|
43
|
+
A valid License Key is required for any Pipeline Use of the CLI. For the avoidance of doubt:
|
|
44
|
+
- The Extension never requires a License Key, including when used commercially within a for-profit company or organisation
|
|
45
|
+
- Local Use of the CLI never requires a License Key
|
|
46
|
+
- Only Pipeline Use of the CLI (for example, running the CLI in a CI/CD build, test, or deployment pipeline) requires a License Key
|
|
56
47
|
|
|
57
|
-
Please contact the Licensor for
|
|
48
|
+
Please contact the Licensor for licensing options.
|
|
58
49
|
|
|
59
50
|
• RESTRICTIONS ON USE OF THE SOFTWARE
|
|
60
51
|
|
|
@@ -64,7 +55,7 @@ b) Decompile, disassemble or reverse engineer the Software or attempt to do any
|
|
|
64
55
|
c) Reproduce, copy, distribute, resell or otherwise use the whole or any part of the Software's code for any commercial purpose.
|
|
65
56
|
d) Disable, modify or hide notifications sent by the Software.
|
|
66
57
|
e) Distribute, resell, or share License Keys.
|
|
67
|
-
f) Misrepresent
|
|
58
|
+
f) Misrepresent Pipeline Use of the CLI as Local Use, or otherwise circumvent the License Key requirement for Pipeline Use.
|
|
68
59
|
g) Use older versions of the Software to circumvent licensing requirements.
|
|
69
60
|
|
|
70
61
|
• LIMITED WARRANTY AND DISCLAIMER OF WARRANTY
|
package/README.md
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
# Norn
|
|
2
2
|
|
|
3
|
-
Norn
|
|
3
|
+
Norn turns API requests into version-controlled tests your whole team can keep — authored and debugged in VS Code, run on every PR in CI. Write a request once, turn it into a tested sequence, debug it with breakpoints in the editor, and run the exact same `.norn` files from the CLI in your pipeline.
|
|
4
4
|
|
|
5
5
|
### Simple API Requests
|
|
6
6
|
|
|
@@ -72,6 +72,37 @@ npm install -g norn-cli
|
|
|
72
72
|
norn ./tests/smoke.norn -e dev
|
|
73
73
|
```
|
|
74
74
|
|
|
75
|
+
## `.nornenv` Templates And Extends
|
|
76
|
+
|
|
77
|
+
Use `[template:name]` sections for reusable environment building blocks, then compose selectable `[env:name]` sections with `extends`. Only templates can be extended. Templates are not selectable from the status bar or CLI; only `[env:...]` names can be used with `-e`.
|
|
78
|
+
|
|
79
|
+
```nornenv
|
|
80
|
+
var timeout = 30000
|
|
81
|
+
|
|
82
|
+
[template:prod]
|
|
83
|
+
var baseUrl = https://api.example.com
|
|
84
|
+
secret apiKey = prod-key-789
|
|
85
|
+
|
|
86
|
+
[template:uk]
|
|
87
|
+
var dbHost = db.uk.example.com
|
|
88
|
+
var bucket = data-uk
|
|
89
|
+
|
|
90
|
+
[env:prod_uk extends prod, uk]
|
|
91
|
+
var failoverHost = api-failover.uk.example.com
|
|
92
|
+
```
|
|
93
|
+
|
|
94
|
+
Resolution order is `common <- template1 <- template2 <- self`, so later templates win on collisions and the env section itself wins over everything. The VS Code editor also shows Activate CodeLens actions, inherited-variable peeks, hover resolution chains, and inlay hints for `{{name}}` / `{{$env.name}}` references.
|
|
95
|
+
|
|
96
|
+
## Inlay Hints Across Every File Type
|
|
97
|
+
|
|
98
|
+
Every `{{...}}` reference in any Norn file shows its resolved value as a gray inline hint under the active env, with the same masking-for-secrets rules as `.nornenv`. The three scopes available in `.norn` resolve in precedence order:
|
|
99
|
+
|
|
100
|
+
1. **Sequence-local** `var` declarations inside the current `test sequence ... end sequence` block
|
|
101
|
+
2. **File-level** `var` declarations at the top of the file (above any sequence)
|
|
102
|
+
3. **Active env** effective vars (`common` ← ancestor templates ← self)
|
|
103
|
+
|
|
104
|
+
`{{$env.name}}` always reads from scope 3, skipping local/file vars. Runtime values (`$1.body.id`, request captures, `run X()` returns) render no hint inline; hover narrates them with source line. `.nornapi` and `.nornsql` use env scope only; `.nornsql` additionally shows the resolved connection string after `connection NAME`.
|
|
105
|
+
|
|
75
106
|
## Deterministic MCP Tools
|
|
76
107
|
|
|
77
108
|
Norn can call MCP tools from sequences without leaving the `.norn` runtime. MCP sessions are deterministic and shared across the full sequence run, so nested sequences reuse the same connection for the same resolved server alias.
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
# Region-pattern refactor showcase
|
|
2
|
+
|
|
3
|
+
A flat `[env:STAGE_REGION]` matrix that the Norn extension can refactor into the templates + extends shape in one click.
|
|
4
|
+
|
|
5
|
+
## How to use
|
|
6
|
+
|
|
7
|
+
1. Open [.nornenv](./.nornenv) in VS Code.
|
|
8
|
+
2. A `$(sparkle) Refactor 4 envs into 2+2 templates` CodeLens appears at the top of the file.
|
|
9
|
+
3. Click it. A confirmation dialog summarises what will change:
|
|
10
|
+
- 2 vars (`baseUrl`, `apiKey`) lifted to stage templates (`dev`, `prod`)
|
|
11
|
+
- 2 vars (`dbHost`, `bucket`) lifted to region templates (`us`, `uk`)
|
|
12
|
+
- 1 var (`failoverHost`) kept as leaf-specific on `prod_uk`
|
|
13
|
+
4. Confirm. The flat 4-env matrix is replaced with templates + extending envs:
|
|
14
|
+
|
|
15
|
+
```nornenv
|
|
16
|
+
[template:dev]
|
|
17
|
+
var baseUrl = https://dev.example.com
|
|
18
|
+
var apiKey = dev-key-123
|
|
19
|
+
|
|
20
|
+
[template:prod]
|
|
21
|
+
var baseUrl = https://api.example.com
|
|
22
|
+
secret apiKey = prod-key-789
|
|
23
|
+
|
|
24
|
+
[template:us]
|
|
25
|
+
var dbHost = db.us.example.com
|
|
26
|
+
var bucket = data-us
|
|
27
|
+
|
|
28
|
+
[template:uk]
|
|
29
|
+
var dbHost = db.uk.example.com
|
|
30
|
+
var bucket = data-uk
|
|
31
|
+
|
|
32
|
+
[env:dev_us extends dev, us]
|
|
33
|
+
|
|
34
|
+
[env:dev_uk extends dev, uk]
|
|
35
|
+
|
|
36
|
+
[env:prod_us extends prod, us]
|
|
37
|
+
|
|
38
|
+
[env:prod_uk extends prod, uk]
|
|
39
|
+
var failoverHost = api-failover.uk.example.com
|
|
40
|
+
```
|
|
41
|
+
|
|
42
|
+
5. The `secret` keyword on `apiKey` is preserved when the var is lifted to a template.
|
|
43
|
+
|
|
44
|
+
## CLI
|
|
45
|
+
|
|
46
|
+
The same generator is available from the local CLI:
|
|
47
|
+
|
|
48
|
+
```bash
|
|
49
|
+
node ./dist/cli.js demos/nornenv-region-refactor/.nornenv --refactor-region-pattern
|
|
50
|
+
node ./dist/cli.js demos/nornenv-region-refactor/.nornenv --refactor-region-pattern --write
|
|
51
|
+
```
|
|
52
|
+
|
|
53
|
+
## When the refactor fires
|
|
54
|
+
|
|
55
|
+
The CodeLens appears only when **all** of these are true:
|
|
56
|
+
- At least 2 stages × 2 regions
|
|
57
|
+
- At least 3 populated cells
|
|
58
|
+
- All matrix envs are flat (no existing `extends` clause)
|
|
59
|
+
|
|
60
|
+
It does not touch envs that already use `extends`, envs with names that don't match the `STAGE_REGION` shape, or `connectionString` declarations (those are left in their leaves — refactor manually).
|
|
61
|
+
|
|
62
|
+
## Cmd+Z
|
|
63
|
+
|
|
64
|
+
Everything goes through a single `WorkspaceEdit`, so a single Cmd+Z undoes the whole refactor.
|
|
@@ -0,0 +1,62 @@
|
|
|
1
|
+
# `.nornenv` Feature Showcase
|
|
2
|
+
|
|
3
|
+
A single `.nornenv` that touches every feature we've shipped — templates, multi-parent `extends`, diamond inheritance, secrets, connection-string templates, imports, plus every diagnostic. Open [.nornenv](./.nornenv) in VS Code and the editor experience does most of the talking.
|
|
4
|
+
|
|
5
|
+
## What to try, in order
|
|
6
|
+
|
|
7
|
+
1. **Open the file.** Non-active sections auto-collapse to one line; the smart header chips show `extends X, Y · N vars · K inherited · M overrides` plus any warning pills.
|
|
8
|
+
2. **Click `▶ Activate` on `[env:prod_eu]`.** It's the most feature-dense env. Watch the file change:
|
|
9
|
+
- The `ACTIVE` pill appears on its header
|
|
10
|
+
- A brand-gradient marker shows up in the gutter on its line
|
|
11
|
+
- A teal tick appears on the right-side overview ruler
|
|
12
|
+
- Every `{{...}}` reference in the file gets an inlay hint with the now-resolved value
|
|
13
|
+
- Secrets render as `(secret)` rather than the raw value
|
|
14
|
+
3. **Hover anything** — a variable name on the left side of a `=`, or a `{{ref}}`. The hover shows the resolution chain: where it's defined, whether it was inherited, and the current resolved value.
|
|
15
|
+
4. **Try `▶ Peek inherited`** on a leaf env like `[env:prod_eu]` — a quick-pick lists all 8+ inherited variables with their source templates and resolved values.
|
|
16
|
+
5. **Type `var ` inside `[env:prod_eu]`** — IntelliSense suggests every inherited variable name, so you can pick one to override without retyping.
|
|
17
|
+
6. **Start a new section header `[`** — completion offers both `[env:` and `[template:`. After typing `[env:foo `, completion offers `extends`, then suggests every available template as a parent.
|
|
18
|
+
7. **Scroll to the bottom** — the diagnostics-only block deliberately triggers every linter check:
|
|
19
|
+
- `[env:bad_unknown_parent extends prdo, us]` — `prdo` squiggles as `unknown-extends-parent` with a quick-fix suggesting `prod`
|
|
20
|
+
- `var apiKy = oops-typo` — squiggles as `unknown-override-target` with a suggestion
|
|
21
|
+
- `var dangling = {{kmsKey}}` — squiggles as `unresolved-cross-section-ref`
|
|
22
|
+
- `[env:bad_env_parent extends prod_us]` — `prod_us` squiggles as `extends-env-parent`
|
|
23
|
+
- `[template:loop_a]` / `[template:loop_b]` — both squiggle as `extends-cycle`
|
|
24
|
+
|
|
25
|
+
## What to try at the CLI
|
|
26
|
+
|
|
27
|
+
After `npm run compile`, run [showcase.norn](./showcase.norn) which prints every resolved value.
|
|
28
|
+
|
|
29
|
+
> **Heads-up about `{{…}}` inside `.nornenv` values:** the IDE's inlay hints show the **fully recursively resolved** form (e.g. `apiBase → "https://api.prod.example.com/v2"` under `prod_eu`). The `.norn` runtime substitution is single-level — when you print `{{apiBase}}` from a `.norn` file, you'll see the literal `https://api.{{stageHost}}.example.com/{{apiVersion}}` because `apiBase`'s *value* still contains template tokens. That's standard Norn behavior — switch to the IDE for the deep view, or use leaf vars (stageHost, region, dbHost, …) for clean CLI prints.
|
|
30
|
+
|
|
31
|
+
```bash
|
|
32
|
+
# Most feature-dense env (self-override + diamond touchpoints).
|
|
33
|
+
node ./dist/cli.js demos/nornenv-showcase/showcase.norn -e prod_eu
|
|
34
|
+
|
|
35
|
+
# Right-most-wins demo — prod_strict (rightmost prod-chain template) wins on collisions.
|
|
36
|
+
node ./dist/cli.js demos/nornenv-showcase/showcase.norn -e prod_eu_strict
|
|
37
|
+
|
|
38
|
+
# Diamond inheritance — shared ancestor merged once.
|
|
39
|
+
node ./dist/cli.js demos/nornenv-showcase/showcase.norn -e diamond
|
|
40
|
+
|
|
41
|
+
# Templates are not selectable — this should error and list only env names.
|
|
42
|
+
node ./dist/cli.js demos/nornenv-showcase/showcase.norn -e prod
|
|
43
|
+
```
|
|
44
|
+
|
|
45
|
+
## What each section demonstrates
|
|
46
|
+
|
|
47
|
+
| Section | Feature |
|
|
48
|
+
| --- | --- |
|
|
49
|
+
| `import "./shared/.nornenv"` | Multi-file composition; chained imports merge into common |
|
|
50
|
+
| top-of-file `var ...` | Common variables (shared by every env) |
|
|
51
|
+
| `var apiBase = https://api.{{stageHost}}…` | Common values may reference any name — resolves under the active env |
|
|
52
|
+
| `[template:dev/staging/prod]` | Stage building blocks (not selectable) |
|
|
53
|
+
| `[template:prod_strict extends prod]` | Template extending another template (chained) |
|
|
54
|
+
| `[template:us/eu]` | Region building blocks |
|
|
55
|
+
| `[template:db_main]` with `connectionString` + `secret connectionString` | Connection-string templates, plain and secret |
|
|
56
|
+
| `[env:dev_us extends dev, us, db_main]` | Composing 3 templates into one selectable env |
|
|
57
|
+
| `[env:prod_eu] ... var logLevel = error` | Self-override wins over every parent |
|
|
58
|
+
| `[env:prod_eu_strict extends prod_strict, eu, db_main]` | Right-most parent wins on collisions |
|
|
59
|
+
| `[env:diamond extends dev, prod_strict]` | Diamond: shared ancestor merged once |
|
|
60
|
+
| `[env:bad_unknown_parent ...]` | Unknown parent + typo override + dangling ref diagnostics |
|
|
61
|
+
| `[env:bad_env_parent extends prod_us]` | Env-as-parent diagnostic |
|
|
62
|
+
| `[template:loop_a/loop_b]` | Cycle diagnostic |
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
{
|
|
2
|
+
"version": 1,
|
|
3
|
+
"sql": {
|
|
4
|
+
"connections": {
|
|
5
|
+
"main": {
|
|
6
|
+
"adapter": "showcase-fake-adapter",
|
|
7
|
+
"profile": "main"
|
|
8
|
+
}
|
|
9
|
+
},
|
|
10
|
+
"adapters": {
|
|
11
|
+
"showcase-fake-adapter": {
|
|
12
|
+
"command": ["node", "-e", "process.stderr.write('showcase: SQL adapter not wired; this file is a visual demo only.\\n'); process.exit(1);"]
|
|
13
|
+
}
|
|
14
|
+
}
|
|
15
|
+
}
|
|
16
|
+
}
|
|
@@ -0,0 +1,70 @@
|
|
|
1
|
+
# Showcase .norn — exercises the inlay hints + hover from src/nornInlayHintsProvider
|
|
2
|
+
# and src/nornHoverProvider across all three scopes:
|
|
3
|
+
# 1. Sequence-local `var` declarations inside a `test sequence ... end sequence` block
|
|
4
|
+
# 2. File-level `var` declarations (above any sequence)
|
|
5
|
+
# 3. Active .nornenv environment (common + ancestor templates + self)
|
|
6
|
+
#
|
|
7
|
+
# Open this file with [env:prod_eu] active to watch every {{...}} reference
|
|
8
|
+
# resolve inline; hover any reference for the source + value resolution chain.
|
|
9
|
+
#
|
|
10
|
+
# CLI verification:
|
|
11
|
+
# node ./dist/cli.js demos/nornenv-showcase/showcase.norn -s ShowcaseResolvedValues -e prod_eu
|
|
12
|
+
# node ./dist/cli.js demos/nornenv-showcase/showcase.norn -s ShowcaseResolvedValues -e prod_eu_strict
|
|
13
|
+
# node ./dist/cli.js demos/nornenv-showcase/showcase.norn -s ShowcaseResolvedValues -e diamond
|
|
14
|
+
|
|
15
|
+
# ─── File-level vars (scope 2) ──────────────────────────────────────────────
|
|
16
|
+
# These reference env vars defined in showcase.nornenv ({{region}}, {{apiVersion}}).
|
|
17
|
+
# Inlay hints should resolve them recursively under the active env.
|
|
18
|
+
var siteTag = "showcase-{{region}}"
|
|
19
|
+
var docsHomepage = "{{apiBase}}/help"
|
|
20
|
+
|
|
21
|
+
# ─── Sequence 1: print every resolved env-level value ───────────────────────
|
|
22
|
+
test sequence ShowcaseResolvedValues
|
|
23
|
+
print "apiBase" | "{{apiBase}}"
|
|
24
|
+
print "dataBucket" | "{{dataBucket}}"
|
|
25
|
+
print "docsUrl" | "{{docsUrl}}"
|
|
26
|
+
print "stageHost" | "{{stageHost}}"
|
|
27
|
+
print "region" | "{{region}}"
|
|
28
|
+
print "dbHost" | "{{dbHost}}"
|
|
29
|
+
print "logLevel" | "{{logLevel}}"
|
|
30
|
+
print "retries" | "{{retries}}"
|
|
31
|
+
print "orgName" | "{{orgName}}"
|
|
32
|
+
print "main_connectionString" | "{{main_connectionString}}"
|
|
33
|
+
print "reports_connectionString" | "{{reports_connectionString}}"
|
|
34
|
+
print "apiKey" | "{{apiKey}}"
|
|
35
|
+
end sequence
|
|
36
|
+
|
|
37
|
+
# ─── Sequence 2: demonstrate all three scopes in one place ──────────────────
|
|
38
|
+
test sequence ShowcaseScopeLayers
|
|
39
|
+
# File-level var (scope 2) referenced from inside a sequence
|
|
40
|
+
print "siteTag" | "{{siteTag}}"
|
|
41
|
+
print "docsHomepage" | "{{docsHomepage}}"
|
|
42
|
+
|
|
43
|
+
# Sequence-local var (scope 1) — static value
|
|
44
|
+
var greeting = "Hello from {{stageHost}}"
|
|
45
|
+
print "greeting" | "{{greeting}}"
|
|
46
|
+
|
|
47
|
+
# Sequence-local var (scope 1) — composes env + region
|
|
48
|
+
var fullUserUrl = "{{apiBase}}/{{region}}/users"
|
|
49
|
+
print "fullUserUrl" | "{{fullUserUrl}}"
|
|
50
|
+
|
|
51
|
+
# Sequence-local var (scope 1) — overrides a file-level name within this sequence
|
|
52
|
+
var siteTag = "scoped-override-{{stageHost}}"
|
|
53
|
+
print "siteTag (local override)" | "{{siteTag}}"
|
|
54
|
+
|
|
55
|
+
# Explicit env-only reference — bypasses local/file scope, reads directly from env
|
|
56
|
+
print "env-only region" | "{{$env.region}}"
|
|
57
|
+
end sequence
|
|
58
|
+
|
|
59
|
+
# ─── Sequence 3: runtime vars are intentionally NOT shown by inlay hints ────
|
|
60
|
+
test sequence ShowcaseRuntimeRefs
|
|
61
|
+
# Sequence-local but RUNTIME (response capture) — no inlay hint expected on {{traceId}}.
|
|
62
|
+
# Hover on the reference will narrate "runtime expression" with source line.
|
|
63
|
+
GET https://httpbin.org/uuid
|
|
64
|
+
assert $1.status == 200
|
|
65
|
+
var traceId = $1.body.uuid
|
|
66
|
+
print "traceId" | "{{traceId}}"
|
|
67
|
+
|
|
68
|
+
# Response refs like {{$1.body.uuid}} are also runtime-only — no inlay hint.
|
|
69
|
+
print "uuid" | "{{$1.body.uuid}}"
|
|
70
|
+
end sequence
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
# Showcase .nornapi — every {{...}} on this file resolves under the active env via
|
|
2
|
+
# the inlay hints from src/nornapiInlayHintsProvider.ts. Hover any reference for
|
|
3
|
+
# the resolution chain.
|
|
4
|
+
#
|
|
5
|
+
# Try: activate [env:prod_eu] from showcase.nornenv and watch the URLs/headers
|
|
6
|
+
# below resolve to prod_eu's effective values.
|
|
7
|
+
|
|
8
|
+
headers Standard
|
|
9
|
+
Content-Type: application/json
|
|
10
|
+
Accept: application/json
|
|
11
|
+
end headers
|
|
12
|
+
|
|
13
|
+
headers AuthHeaders
|
|
14
|
+
Authorization: Bearer {{apiKey}}
|
|
15
|
+
X-Region: {{region}}
|
|
16
|
+
X-Stage: {{stageHost}}
|
|
17
|
+
X-Api-Version: {{apiVersion}}
|
|
18
|
+
end headers
|
|
19
|
+
|
|
20
|
+
endpoints
|
|
21
|
+
HealthCheck: GET {{apiBase}}/health
|
|
22
|
+
ListCustomers: GET {{apiBase}}/customers?region={{region}}
|
|
23
|
+
GetCustomer: GET {{apiBase}}/customers/{customerId}
|
|
24
|
+
CreateOrder: POST {{apiBase}}/orders
|
|
25
|
+
Failover: GET {{failoverHost}}/status
|
|
26
|
+
end endpoints
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
# Showcase .nornsql — the `connection main` line below is resolved by
|
|
2
|
+
# src/nornsqlInlayHintsProvider.ts to `main_connectionString` from the
|
|
3
|
+
# nearest .nornenv. Hover the identifier `main` to see where it's defined
|
|
4
|
+
# in [template:db_main] and what it resolves to under the active env.
|
|
5
|
+
#
|
|
6
|
+
# Try: activate [env:prod_eu] and watch the inlay after `main` show the
|
|
7
|
+
# resolved Server=tcp:db.eu.example.com,1433;... connection string.
|
|
8
|
+
|
|
9
|
+
connection main
|
|
10
|
+
|
|
11
|
+
query ListBuyers(region)
|
|
12
|
+
select Id, Company, Email
|
|
13
|
+
from Buyers
|
|
14
|
+
where Region = :region
|
|
15
|
+
end query
|
|
16
|
+
|
|
17
|
+
command RecordAuditEntry(actor, action)
|
|
18
|
+
insert into Audit (Actor, Action, At)
|
|
19
|
+
values (:actor, :action, current_timestamp)
|
|
20
|
+
end command
|