norn-cli 3.3.0 → 4.0.1

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.
Files changed (58) hide show
  1. package/dist/cli.js +1396 -276
  2. package/dist/knowledgeIndexWorker.js +71 -35
  3. package/package.json +3 -3
  4. package/schemas/norn.config.schema.json +13 -0
  5. package/CLAUDE.md +0 -69
  6. package/NOW.md +0 -223
  7. package/demos/agent-workbench/README.md +0 -156
  8. package/demos/agent-workbench/agents.nornagent +0 -87
  9. package/demos/agent-workbench/contracts/domain-answer.schema.json +0 -28
  10. package/demos/agent-workbench/contracts/domain-question.schema.json +0 -34
  11. package/demos/agent-workbench/contracts/router-verdict.schema.json +0 -43
  12. package/demos/agent-workbench/contracts/ticket.schema.json +0 -29
  13. package/demos/agent-workbench/contracts/verdict.schema.json +0 -48
  14. package/demos/agent-workbench/fake-openai-server.js +0 -128
  15. package/demos/agent-workbench/fixtures/aligned-ticket.json +0 -10
  16. package/demos/agent-workbench/fixtures/cross-domain-ticket.json +0 -10
  17. package/demos/agent-workbench/fixtures/invalid-output-ticket.json +0 -8
  18. package/demos/agent-workbench/norn.config.json +0 -15
  19. package/demos/agent-workbench/prompts/ticket-router.md +0 -11
  20. package/demos/agent-workbench/workbench.norn +0 -32
  21. package/demos/knowledge-editor/README.md +0 -74
  22. package/demos/knowledge-editor/agents.nornagent +0 -16
  23. package/demos/knowledge-editor/api.nornapi +0 -10
  24. package/demos/knowledge-editor/handbook/ops/flow.svg +0 -1
  25. package/demos/knowledge-editor/handbook/ops/retired.md +0 -9
  26. package/demos/knowledge-editor/handbook/ops/runbook.md +0 -14
  27. package/demos/knowledge-editor/handbook/payments/charges.md +0 -25
  28. package/demos/knowledge-editor/handbook/payments/pricing-tiers.draft.md +0 -7
  29. package/demos/knowledge-editor/handbook/payments/refunds/policy.md +0 -12
  30. package/demos/knowledge-editor/support.norn +0 -10
  31. package/demos/mcp-ticket-testing/README.md +0 -114
  32. package/demos/mcp-ticket-testing/agents.nornagent +0 -77
  33. package/demos/mcp-ticket-testing/contracts/test-run.schema.json +0 -31
  34. package/demos/mcp-ticket-testing/expectations/proj-142.md +0 -12
  35. package/demos/mcp-ticket-testing/fixtures/proj-142.json +0 -13
  36. package/demos/mcp-ticket-testing/prompts/backend-tester.md +0 -12
  37. package/demos/mcp-ticket-testing/prompts/frontend-tester.md +0 -14
  38. package/demos/mcp-ticket-testing/prompts/reporter.md +0 -10
  39. package/demos/mcp-ticket-testing/servers/browser-server.js +0 -133
  40. package/demos/mcp-ticket-testing/servers/house-server.js +0 -125
  41. package/demos/mcp-ticket-testing/tickets.norn +0 -32
  42. package/demos/nornenv-region-refactor/README.md +0 -64
  43. package/demos/nornenv-showcase/README.md +0 -62
  44. package/demos/nornenv-showcase/norn.config.json +0 -16
  45. package/demos/nornenv-showcase/showcase.norn +0 -70
  46. package/demos/nornenv-showcase/showcase.nornapi +0 -26
  47. package/demos/nornenv-showcase/showcase.nornsql +0 -20
  48. package/demos/tests-showcase/01-single-requests.norn +0 -31
  49. package/demos/tests-showcase/02-sequences.norn +0 -54
  50. package/demos/tests-showcase/03-sidecars.norn +0 -42
  51. package/demos/tests-showcase/04-api-plus-sql.norn +0 -27
  52. package/demos/tests-showcase/db/testDb.nornsql +0 -12
  53. package/demos/tests-showcase/demo-api.nornapi +0 -17
  54. package/demos/tests-showcase/norn.config.json +0 -16
  55. package/playground/ai.norn +0 -15
  56. package/playground/ai_orchastration.nornagent +0 -34
  57. package/playground/knowedge_base/ACDC/testing_notes_new_clients.md +0 -11
  58. package/playground/knowedge_base/nexus_system_prompt.md +0 -1
@@ -1,125 +0,0 @@
1
- #!/usr/bin/env node
2
-
3
- /**
4
- * "House" — the custom MCP server a team writes for its own product.
5
- *
6
- * Deterministic on purpose: the demo is about declaring a server and granting it, not about
7
- * what any particular tool does. Everything here is in-memory and reset per process.
8
- */
9
-
10
- const { Server } = require('@modelcontextprotocol/sdk/server/index.js');
11
- const { StdioServerTransport } = require('@modelcontextprotocol/sdk/server/stdio.js');
12
- const { ListToolsRequestSchema, CallToolRequestSchema } = require('@modelcontextprotocol/sdk/types.js');
13
-
14
- const state = {
15
- tenant: 'acme',
16
- auditLog: [],
17
- orders: [
18
- { id: 'A-1001', tenant: 'acme', total: 42.5, status: 'placed' },
19
- { id: 'A-1002', tenant: 'acme', total: 18.0, status: 'shipped' }
20
- ]
21
- };
22
-
23
- const TOOLS = [
24
- {
25
- name: 'getFixtureUser',
26
- description: 'Return the seeded test user for the current tenant.',
27
- inputSchema: { type: 'object', additionalProperties: false, properties: {} }
28
- },
29
- {
30
- name: 'resetTenant',
31
- description: 'Reset the tenant to its seeded state before a test run.',
32
- inputSchema: { type: 'object', additionalProperties: false, properties: {} }
33
- },
34
- {
35
- name: 'callEndpoint',
36
- description: 'Call a backend endpoint and return its status and body.',
37
- inputSchema: {
38
- type: 'object',
39
- additionalProperties: false,
40
- properties: {
41
- method: { type: 'string', description: 'HTTP method, e.g. GET or POST.' },
42
- path: { type: 'string', description: 'Endpoint path, e.g. /orders/A-1001.' }
43
- },
44
- required: ['method', 'path']
45
- }
46
- },
47
- {
48
- name: 'readAuditLog',
49
- description: 'Return the audit entries written during this run, oldest first.',
50
- inputSchema: { type: 'object', additionalProperties: false, properties: {} }
51
- },
52
- {
53
- name: 'queryDb',
54
- description: 'Read rows from a seeded table by name.',
55
- inputSchema: {
56
- type: 'object',
57
- additionalProperties: false,
58
- properties: { table: { type: 'string', description: 'Table to read, e.g. orders.' } },
59
- required: ['table']
60
- }
61
- }
62
- ];
63
-
64
- function structured(value) {
65
- return { content: [{ type: 'text', text: JSON.stringify(value) }], structuredContent: value };
66
- }
67
-
68
- function callEndpoint(args) {
69
- const path = String(args.path || '');
70
- const method = String(args.method || 'GET').toUpperCase();
71
- state.auditLog.push({ at: state.auditLog.length + 1, method, path });
72
-
73
- const orderMatch = path.match(/^\/orders\/([A-Za-z0-9-]+)$/);
74
- if (orderMatch) {
75
- const order = state.orders.find(item => item.id === orderMatch[1]);
76
- return order
77
- ? { status: 200, body: order }
78
- : { status: 404, body: { error: 'order not found' } };
79
- }
80
- if (path === '/orders') {
81
- return { status: 200, body: { orders: state.orders } };
82
- }
83
- return { status: 404, body: { error: 'no such endpoint' } };
84
- }
85
-
86
- async function main() {
87
- const server = new Server(
88
- { name: 'norn-demo-house', version: '1.0.0' },
89
- { capabilities: { tools: {} } }
90
- );
91
-
92
- server.setRequestHandler(ListToolsRequestSchema, async () => ({ tools: TOOLS }));
93
-
94
- server.setRequestHandler(CallToolRequestSchema, async request => {
95
- const args = request.params.arguments || {};
96
- switch (request.params.name) {
97
- case 'getFixtureUser':
98
- return structured({ id: 'u-1', email: 'tester@example.com', tenant: state.tenant });
99
- case 'resetTenant':
100
- state.auditLog = [];
101
- return structured({ tenant: state.tenant, reset: true });
102
- case 'callEndpoint':
103
- return structured(callEndpoint(args));
104
- case 'readAuditLog':
105
- return structured({ entries: state.auditLog });
106
- case 'queryDb':
107
- return structured({
108
- table: args.table,
109
- rows: args.table === 'orders' ? state.orders : []
110
- });
111
- default:
112
- return {
113
- isError: true,
114
- content: [{ type: 'text', text: `Unknown tool: ${request.params.name}` }]
115
- };
116
- }
117
- });
118
-
119
- await server.connect(new StdioServerTransport());
120
- }
121
-
122
- main().catch(error => {
123
- console.error(error instanceof Error ? error.message : String(error));
124
- process.exit(1);
125
- });
@@ -1,32 +0,0 @@
1
- import "./agents.nornagent"
2
-
3
- # Prove both servers are reachable without spending anything on a model.
4
- # These steps resolve the same aliases the agents use, so a failure here points at the server
5
- # rather than at an agent — this is the loop to develop a server against.
6
- test sequence ServersUp
7
- var browserTools = run mcp list Browser
8
- assert browserTools.length > 0
9
-
10
- var houseTools = run mcp list House
11
- assert houseTools.length > 0
12
-
13
- var user = run mcp call House getFixtureUser()
14
- assert user.structuredContent.email == "tester@example.com"
15
- end sequence
16
-
17
- # The application this whole slice was designed against: a ticket arrives, two agents test it
18
- # from different sides with different tools, a third writes it up, and a judge rules on whether
19
- # the expected test cases were actually covered.
20
- test sequence TicketPROJ142
21
- var ticket = run readJson "./fixtures/proj-142.json"
22
-
23
- var frontend = run FrontendTester ticket
24
- var backend = run BackendTester ticket
25
- # An agent's input is a variable or a string — there is no object-literal form — so the two
26
- # runs are interpolated into one prompt.
27
- var report = run Reporter "Frontend run:\n{{frontend.body}}\n\nBackend run:\n{{backend.body}}"
28
-
29
- print "QA report" | "{{report.text}}"
30
-
31
- judge report with Reviewer expects file expectations/proj-142.md
32
- end sequence
@@ -1,64 +0,0 @@
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.
@@ -1,62 +0,0 @@
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 |
@@ -1,16 +0,0 @@
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
- }
@@ -1,70 +0,0 @@
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
@@ -1,26 +0,0 @@
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
@@ -1,20 +0,0 @@
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
@@ -1,31 +0,0 @@
1
-
2
- GET https://httpbin.org/uuid
3
-
4
- GET https://httpbin.org/anything/catalog?region=uk&segment=enterprise
5
-
6
-
7
-
8
-
9
-
10
- POST https://httpbin.org/post
11
- Content-Type: application/json
12
- Accept: application/json
13
- X-Demo-Stage: exploratory-json
14
- {
15
- "customerId": "C-1001",
16
- "workspace": "Northwind",
17
- "plan": "Enterprise"
18
- }
19
-
20
-
21
- POST https://httpbin.org/post
22
- Content-Type: application/json
23
- Accept: application/json
24
- X-Demo-Stage: exploratory-quote
25
- X-Demo-Audience: exploratory-testers
26
- {
27
- "customerId": "C-1001",
28
- "step": "quote-preview",
29
- "seats": 250,
30
- "currency": "GBP"
31
- }
@@ -1,54 +0,0 @@
1
-
2
-
3
- @demo
4
- test sequence SimpleRequestChain
5
- print "Simple requests" | "Bare URLs become a repeatable flow with assertions."
6
-
7
- GET https://httpbin.org/uuid
8
- assert $1.status == 200
9
- var traceId = $1.body.uuid
10
-
11
- GET https://httpbin.org/anything/catalog?region=uk&segment=enterprise&trace={{traceId}}
12
- assert $2.status == 200
13
- assert $2.body.args.region == "uk"
14
- assert $2.body.args.segment == "enterprise"
15
- assert $2.body.url contains "{{traceId}}"
16
-
17
- print "Trace id" | "{{traceId}}"
18
- end sequence
19
-
20
- @demo
21
- test sequence RichRequestChain
22
- print "Headers and payloads" | "The same idea works when the requests carry real data."
23
-
24
- var draft = POST https://httpbin.org/post
25
- Content-Type: application/json
26
- Accept: application/json
27
- X-Demo-Stage: sequence-draft
28
- {
29
- "customerId": "C-1001",
30
- "workspace": "Northwind",
31
- "plan": "Enterprise"
32
- }
33
-
34
- assert draft.status == 200
35
- assert draft.body.json.customerId == "C-1001"
36
- var customerId = draft.body.json.customerId
37
-
38
- var quote = POST https://httpbin.org/post
39
- Content-Type: application/json
40
- Accept: application/json
41
- X-Demo-Stage: sequence-quote
42
- {
43
- "customerId": "{{customerId}}",
44
- "step": "quote-preview",
45
- "seats": 250,
46
- "currency": "GBP"
47
- }
48
-
49
- assert quote.status == 200
50
- assert quote.body.json.customerId == "C-1001"
51
- assert quote.body.json.step == "quote-preview"
52
-
53
- print "Chained value" | "customerId={{customerId}}"
54
- end sequence
@@ -1,42 +0,0 @@
1
- import "./demo-api.nornapi"
2
-
3
- @demo
4
- test sequence CleanerExplorationFlow
5
- print "Cleaner requests" | "Shared setup moved into .nornapi and .nornenv."
6
-
7
- var trace = GET GetTraceId
8
- assert trace.status == 200
9
-
10
- var catalog = GET BrowseCustomer({{demoCustomerId}}) DemoHeaders
11
- assert catalog.status == 200
12
- assert catalog.body.args.region == "uk"
13
- assert catalog.body.url contains "/customers/C-1001"
14
-
15
- print "Why this helps" | "The request lines stay focused on intent, not plumbing."
16
- end sequence
17
-
18
- @demo
19
- test sequence CleanerPayloadFlow
20
- var draft = POST SaveDraft Json DemoHeaders
21
- {
22
- "customerId": "{{demoCustomerId}}",
23
- "workspace": "{{workspaceName}}",
24
- "owner": "{{ownerName}}"
25
- }
26
-
27
- assert draft.status == 200
28
- assert draft.body.json.workspace == "Northwind-Workspace"
29
-
30
- var quote = POST QuotePreview Json DemoHeaders
31
- {
32
- "customerId": "{{demoCustomerId}}",
33
- "traceId": "{{tracePrefix}}-001",
34
- "step": "quote-preview",
35
- "seats": 250
36
- }
37
-
38
- assert quote.status == 200
39
- assert quote.body.json.step == "quote-preview"
40
-
41
- print "Cleaner file" | "Base URL, reusable headers, and shared names are all sidecars now."
42
- end sequence
@@ -1,27 +0,0 @@
1
- import "./demo-api.nornapi"
2
- import "./db//testDb.nornsql"
3
-
4
- @demo
5
- test sequence ApiPlusSqlDemo
6
- print "API plus SQL" | "Show the service call and the data-side check in one workflow."
7
-
8
- var quote = POST QuotePreview Json DemoHeaders
9
- {
10
- "customerId": "{{demoCustomerId}}",
11
- "step": "quote-preview",
12
- "seats": 250,
13
- "currency": "GBP"
14
- }
15
-
16
- assert quote.status == 200
17
- assert quote.body.json.customerId == "C-1001"
18
-
19
- var buyers = run sql ListBuyerAccounts("Enterprise")
20
- assert buyers[0].Segment == "Enterprise"
21
- assert buyers[0].Company == "Northwind Retail"
22
-
23
- var audit = run sql RecordDemoRun("northwind@example.com", "buyer-showcase")
24
- assert audit.affectedRows == 1
25
-
26
- print "SQL sidecar" | "HTTP stays in .norn, SQL stays in .nornsql, config stays in sidecars."
27
- end sequence
@@ -1,12 +0,0 @@
1
- connection buyerDemoDb
2
-
3
- query ListBuyerAccounts(segment)
4
- select Id, Company, Email, Segment
5
- from Buyers
6
- where Segment = :segment
7
- end query
8
-
9
- command RecordDemoRun(email, scenario)
10
- insert into DemoAudit (Email, Scenario)
11
- values (:email, :scenario)
12
- end command
@@ -1,17 +0,0 @@
1
- headers Json
2
- Content-Type: application/json
3
- Accept: application/json
4
- end headers
5
-
6
- headers DemoHeaders
7
- X-Demo-Stage: {{demoStage}}
8
- X-Demo-Audience: {{audience}}
9
- X-Demo-Owner: {{ownerName}}
10
- end headers
11
-
12
- endpoints
13
- GetTraceId: GET {{baseUrl}}/uuid
14
- BrowseCustomer: GET {{baseUrl}}/anything/customers/{customerId}?region={{region}}
15
- SaveDraft: POST {{baseUrl}}/post
16
- QuotePreview: POST {{baseUrl}}/post
17
- end endpoints
@@ -1,16 +0,0 @@
1
- {
2
- "version": 1,
3
- "sql": {
4
- "connections": {
5
- "buyerDemoDb": {
6
- "adapter": "buyer-demo-sql-adapter",
7
- "profile": "buyerDemoDb"
8
- }
9
- },
10
- "adapters": {
11
- "buyer-demo-sql-adapter": {
12
- "command": ["node", "./scripts/fake-sql-adapter.js"]
13
- }
14
- }
15
- }
16
- }
@@ -1,15 +0,0 @@
1
- import "./ai_orchastration.nornagent"
2
-
3
- sequence SimpleNexusRun
4
-
5
- var nexusReply = run Nexus "Open any website for me need to see if the mcp connection is working"
6
-
7
- print "Result" | nexusReply
8
-
9
- end sequence
10
-
11
- sequence Test
12
- run mcp list Time
13
- run TimeTeller "what is the time"
14
-
15
- end sequence