ctxr-cli 0.6.0 → 0.7.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/dist/adapters/types.d.ts +2 -3
- package/dist/adapters/types.d.ts.map +1 -1
- package/dist/adapters/types.js.map +1 -1
- package/dist/commands/archive.d.ts +2 -2
- package/dist/commands/archive.js +2 -2
- package/dist/commands/catalog-show.d.ts +0 -1
- package/dist/commands/catalog-show.d.ts.map +1 -1
- package/dist/commands/catalog-show.js +1 -1
- package/dist/commands/catalog-show.js.map +1 -1
- package/dist/commands/graph-query.d.ts +2 -11
- package/dist/commands/graph-query.d.ts.map +1 -1
- package/dist/commands/graph-query.js +11 -14
- package/dist/commands/graph-query.js.map +1 -1
- package/dist/commands/init.d.ts.map +1 -1
- package/dist/commands/init.js +2 -7
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/publish-check.d.ts.map +1 -1
- package/dist/commands/publish-check.js +0 -4
- package/dist/commands/publish-check.js.map +1 -1
- package/dist/commands/publish-gather.d.ts +6 -16
- package/dist/commands/publish-gather.d.ts.map +1 -1
- package/dist/commands/publish-gather.js +11 -30
- package/dist/commands/publish-gather.js.map +1 -1
- package/dist/commands/publish-new.d.ts +5 -4
- package/dist/commands/publish-new.d.ts.map +1 -1
- package/dist/commands/publish-new.js +32 -10
- package/dist/commands/publish-new.js.map +1 -1
- package/dist/commands/serve.d.ts.map +1 -1
- package/dist/commands/serve.js +6 -25
- package/dist/commands/serve.js.map +1 -1
- package/dist/commands/session-capture.d.ts.map +1 -1
- package/dist/commands/session-capture.js +0 -2
- package/dist/commands/session-capture.js.map +1 -1
- package/dist/config/defaults.d.ts +12 -29
- package/dist/config/defaults.d.ts.map +1 -1
- package/dist/config/defaults.js +11 -28
- package/dist/config/defaults.js.map +1 -1
- package/dist/config/schema.d.ts +18 -44
- package/dist/config/schema.d.ts.map +1 -1
- package/dist/config/schema.js +18 -52
- package/dist/config/schema.js.map +1 -1
- package/dist/core/agents-doc.d.ts +9 -0
- package/dist/core/agents-doc.d.ts.map +1 -1
- package/dist/core/agents-doc.js +31 -16
- package/dist/core/agents-doc.js.map +1 -1
- package/dist/core/browse/nav.d.ts +10 -0
- package/dist/core/browse/nav.d.ts.map +1 -0
- package/dist/core/browse/nav.js +101 -0
- package/dist/core/browse/nav.js.map +1 -0
- package/dist/core/browse/routes.d.ts +11 -2
- package/dist/core/browse/routes.d.ts.map +1 -1
- package/dist/core/browse/routes.js +19 -7
- package/dist/core/browse/routes.js.map +1 -1
- package/dist/core/browse/templates.d.ts +11 -2
- package/dist/core/browse/templates.d.ts.map +1 -1
- package/dist/core/browse/templates.js +16 -3
- package/dist/core/browse/templates.js.map +1 -1
- package/dist/core/browse/tree.d.ts +33 -0
- package/dist/core/browse/tree.d.ts.map +1 -0
- package/dist/core/browse/tree.js +53 -0
- package/dist/core/browse/tree.js.map +1 -0
- package/dist/core/catalog/build.d.ts +1 -1
- package/dist/core/catalog/build.d.ts.map +1 -1
- package/dist/core/catalog/build.js +1 -2
- package/dist/core/catalog/build.js.map +1 -1
- package/dist/core/catalog/model.d.ts +2 -0
- package/dist/core/catalog/model.d.ts.map +1 -1
- package/dist/core/catalog/model.js +2 -1
- package/dist/core/catalog/model.js.map +1 -1
- package/dist/core/checks/manifest.d.ts.map +1 -1
- package/dist/core/checks/manifest.js +0 -5
- package/dist/core/checks/manifest.js.map +1 -1
- package/dist/core/checks/organize-checks.d.ts +1 -2
- package/dist/core/checks/organize-checks.d.ts.map +1 -1
- package/dist/core/checks/organize-checks.js +1 -2
- package/dist/core/checks/organize-checks.js.map +1 -1
- package/dist/core/checks/types.d.ts +1 -1
- package/dist/core/convention-doc.d.ts +15 -12
- package/dist/core/convention-doc.d.ts.map +1 -1
- package/dist/core/convention-doc.js +25 -66
- package/dist/core/convention-doc.js.map +1 -1
- package/dist/core/errors.d.ts +9 -8
- package/dist/core/errors.d.ts.map +1 -1
- package/dist/core/errors.js +14 -18
- package/dist/core/errors.js.map +1 -1
- package/dist/core/exit-codes.d.ts +7 -5
- package/dist/core/exit-codes.d.ts.map +1 -1
- package/dist/core/exit-codes.js +7 -5
- package/dist/core/exit-codes.js.map +1 -1
- package/dist/core/ingest/identity.d.ts +4 -4
- package/dist/core/ingest/identity.js +4 -4
- package/dist/core/migrations/add-explanation-craft-skill.d.ts +26 -0
- package/dist/core/migrations/add-explanation-craft-skill.d.ts.map +1 -0
- package/dist/core/migrations/add-explanation-craft-skill.js +94 -0
- package/dist/core/migrations/add-explanation-craft-skill.js.map +1 -0
- package/dist/core/migrations/drop-access-axes.d.ts +24 -0
- package/dist/core/migrations/drop-access-axes.d.ts.map +1 -0
- package/dist/core/migrations/drop-access-axes.js +54 -0
- package/dist/core/migrations/drop-access-axes.js.map +1 -0
- package/dist/core/migrations/registry.d.ts +11 -1
- package/dist/core/migrations/registry.d.ts.map +1 -1
- package/dist/core/migrations/registry.js +15 -3
- package/dist/core/migrations/registry.js.map +1 -1
- package/dist/core/notes/list.d.ts +1 -12
- package/dist/core/notes/list.d.ts.map +1 -1
- package/dist/core/notes/list.js.map +1 -1
- package/dist/core/reconcile.js +2 -2
- package/dist/core/reconcile.js.map +1 -1
- package/dist/core/records.d.ts +4 -5
- package/dist/core/records.d.ts.map +1 -1
- package/dist/core/records.js +0 -2
- package/dist/core/records.js.map +1 -1
- package/dist/core/skills.d.ts +6 -0
- package/dist/core/skills.d.ts.map +1 -1
- package/dist/core/skills.js +7 -4
- package/dist/core/skills.js.map +1 -1
- package/dist/run.d.ts.map +1 -1
- package/dist/run.js +15 -53
- package/dist/run.js.map +1 -1
- package/dist/version.d.ts +1 -1
- package/dist/version.js +1 -1
- package/package.json +1 -1
- package/templates/agents/canonical.md +0 -2
- package/templates/conventions/baseline-conventions.md +1 -34
- package/templates/serve/shell.html +3 -0
- package/templates/serve/style.css +78 -3
- package/templates/skills/ctxr-organize-audit.md +2 -10
- package/templates/skills/ctxr-placement.md +6 -24
- package/templates/skills/ctxr-publish.md +26 -21
- package/templates/skills/ctxr-session-capture.md +1 -4
- package/templates/vendor/eli5/LICENSE.txt +21 -0
- package/templates/vendor/eli5/SKILL.md +116 -0
- package/templates/vendor/eli5/provenance.json +8 -0
- package/dist/commands/check.d.ts +0 -30
- package/dist/commands/check.d.ts.map +0 -1
- package/dist/commands/check.js +0 -65
- package/dist/commands/check.js.map +0 -1
- package/dist/commands/note-resolve.d.ts +0 -14
- package/dist/commands/note-resolve.d.ts.map +0 -1
- package/dist/commands/note-resolve.js +0 -24
- package/dist/commands/note-resolve.js.map +0 -1
- package/dist/core/checks/disclosure-checks.d.ts +0 -4
- package/dist/core/checks/disclosure-checks.d.ts.map +0 -1
- package/dist/core/checks/disclosure-checks.js +0 -24
- package/dist/core/checks/disclosure-checks.js.map +0 -1
- package/dist/core/disclosure/leak-scan.d.ts +0 -19
- package/dist/core/disclosure/leak-scan.d.ts.map +0 -1
- package/dist/core/disclosure/leak-scan.js +0 -31
- package/dist/core/disclosure/leak-scan.js.map +0 -1
- package/dist/core/disclosure/model.d.ts +0 -29
- package/dist/core/disclosure/model.d.ts.map +0 -1
- package/dist/core/disclosure/model.js +0 -69
- package/dist/core/disclosure/model.js.map +0 -1
- package/dist/core/graph/visibility-filter.d.ts +0 -13
- package/dist/core/graph/visibility-filter.d.ts.map +0 -1
- package/dist/core/graph/visibility-filter.js +0 -26
- package/dist/core/graph/visibility-filter.js.map +0 -1
- package/dist/core/migrations/rename-visibility-field.d.ts +0 -3
- package/dist/core/migrations/rename-visibility-field.d.ts.map +0 -1
- package/dist/core/migrations/rename-visibility-field.js +0 -62
- package/dist/core/migrations/rename-visibility-field.js.map +0 -1
- package/dist/core/notes/checks.d.ts +0 -20
- package/dist/core/notes/checks.d.ts.map +0 -1
- package/dist/core/notes/checks.js +0 -58
- package/dist/core/notes/checks.js.map +0 -1
- package/dist/core/notes/visibility.d.ts +0 -26
- package/dist/core/notes/visibility.d.ts.map +0 -1
- package/dist/core/notes/visibility.js +0 -41
- package/dist/core/notes/visibility.js.map +0 -1
|
@@ -12,26 +12,19 @@ different font. If a note would do the job, the note is the deliverable.
|
|
|
12
12
|
|
|
13
13
|
## 2. Name the subject, let the selector produce the set
|
|
14
14
|
|
|
15
|
-
`ctxr publish gather` resolves a subject to its source notes — never a hand-picked list, which is how
|
|
16
|
-
|
|
15
|
+
`ctxr publish gather` resolves a subject to its source notes — never a hand-picked list, which is how
|
|
16
|
+
an unintended note slips in unnoticed:
|
|
17
17
|
|
|
18
18
|
- `--under <prefix>` — a store subtree
|
|
19
19
|
- `--note <path>` — a single note
|
|
20
20
|
- `--entity <name>` — every note linking to a concept, the same enumeration `ctxr rollup gather` uses
|
|
21
|
-
- `--as <context>` — everything a named context can see
|
|
22
21
|
|
|
23
|
-
## 3.
|
|
22
|
+
## 3. Decide what belongs on the page
|
|
24
23
|
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
- **DENY** notes contribute nothing — not a title, not a count, not a paraphrase.
|
|
30
|
-
- **ASK** stops the build; name the note to the operator and wait.
|
|
31
|
-
- Only **ALLOW** content may be quoted or summarized into the page.
|
|
32
|
-
|
|
33
|
-
Never infer a verdict from a note's resolved visibility on your own — an external audience's verdict
|
|
34
|
-
requires an explicit tag or a human answer, not an inference from how widely a note is already visible.
|
|
24
|
+
The store does not decide this for you. Read the resolved set and judge, note by note, whether its
|
|
25
|
+
content belongs in front of this page's intended readers — a page written for an outside party must
|
|
26
|
+
not carry material written about that party, or about anyone else who did not expect to be quoted.
|
|
27
|
+
When you are unsure about a note, leave it out and name it to the operator rather than guessing.
|
|
35
28
|
|
|
36
29
|
## 4. Fix the identity once
|
|
37
30
|
|
|
@@ -45,10 +38,23 @@ handed out.
|
|
|
45
38
|
|
|
46
39
|
Pick the shape the content actually needs — a status board, a timeline, a side-by-side comparison, an
|
|
47
40
|
explainer with a live demo — not a rendering of the source notes in reading order. Contexture ships no
|
|
48
|
-
renderer of its own:
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
41
|
+
renderer of its own and no house voice: both halves of the craft are delegated to a skill.
|
|
42
|
+
|
|
43
|
+
**The form and its visual language.** Load the `frontend-design` skill this store carries by default
|
|
44
|
+
(or whichever design-focused skill it's configured or installed instead) and follow it for the HTML,
|
|
45
|
+
CSS, type, and palette — and for the interface's own words: labels, buttons, empty and error states.
|
|
46
|
+
If a sibling page already exists, read its stylesheet and inherit its palette and type scale before
|
|
47
|
+
inventing a new one.
|
|
48
|
+
|
|
49
|
+
**The prose that explains the subject.** A page is read by someone who wasn't in the sessions the
|
|
50
|
+
notes came from, so the notes' shorthand does not survive the copy out. Load the `eli5` skill this
|
|
51
|
+
store carries by default (or whichever explanation-focused skill it's configured instead), settle who
|
|
52
|
+
the reader is before writing, and pitch every definition, analogy, and level of detail at them.
|
|
53
|
+
|
|
54
|
+
Both skills say "audience", and neither means step 3's. There, `--audience` names who the store is
|
|
55
|
+
being asked to disclose to and the answer is a verdict; here it names how much a reader already knows
|
|
56
|
+
and the answer is a register. A comprehension level is never a value you pass to `--audience`, and
|
|
57
|
+
writing plainly never widens what the page may contain — the gate in step 3 already settled that.
|
|
52
58
|
|
|
53
59
|
## 6. Verify the output invariants
|
|
54
60
|
|
|
@@ -56,13 +62,12 @@ inherit its palette and type scale before inventing a new one.
|
|
|
56
62
|
a viewport meta tag, at least one print rule, a provenance line, a sibling README, balanced tags, and
|
|
57
63
|
valid syntax in every embedded script. It exits non-zero naming every failing check; fix all of them
|
|
58
64
|
before reporting the page as ready. It answers only what's derivable from the file itself — the DO-test
|
|
59
|
-
in step 1, the form
|
|
65
|
+
in step 1, the form and reader choices in step 5, and factual accuracy stay judgment calls, not checker output.
|
|
60
66
|
|
|
61
67
|
## 7. It's a page, not a note
|
|
62
68
|
|
|
63
69
|
The published-pages location is excluded from retrieval by default — a page never becomes a source for
|
|
64
|
-
anything else the store retrieves
|
|
65
|
-
it's indexed). Confirm with `ctxr lint` after landing.
|
|
70
|
+
anything else the store retrieves. Confirm with `ctxr lint` after landing.
|
|
66
71
|
|
|
67
72
|
## 8. Provenance and drift
|
|
68
73
|
|
|
@@ -58,7 +58,6 @@ calcified, so it never gets retired.
|
|
|
58
58
|
```
|
|
59
59
|
### Store notes
|
|
60
60
|
- A1 path: <layer>/<location>/<Title>.md
|
|
61
|
-
visibility: <value> — <one-line rationale; `ctxr note resolve` on a sibling shows the default>
|
|
62
61
|
sketch: bullets
|
|
63
62
|
|
|
64
63
|
### House conventions
|
|
@@ -84,7 +83,6 @@ notes:
|
|
|
84
83
|
- id: A1
|
|
85
84
|
path: <layer>/<location>/<Title>.md
|
|
86
85
|
mode: create # or: append
|
|
87
|
-
visibility: <value> # optional; omit to take the location default
|
|
88
86
|
body: |
|
|
89
87
|
matching the frontmatter and style of the sibling notes (`ctxr-placement` decides the location)
|
|
90
88
|
```
|
|
@@ -94,8 +92,7 @@ one bad path never blocks the rest. These note commits ride the session pull req
|
|
|
94
92
|
(`ctxr-session-lifecycle`).
|
|
95
93
|
|
|
96
94
|
Approved conventions are a direct edit to `__HOUSE_CONVENTIONS_PATH__`, never the YAML above: `ctxr
|
|
97
|
-
session capture` writes NOTES — it takes a path
|
|
98
|
-
field — and a guidance file is not a note and carries no visibility. Edit it under the matching
|
|
95
|
+
session capture` writes NOTES — it takes a path and a body — and a guidance file is not a note. Edit it under the matching
|
|
99
96
|
section, then run `ctxr update` so AGENTS.md re-inlines it, and stage BOTH in the same commit: a staged
|
|
100
97
|
guidance change without a matching staged AGENTS.md regeneration fails `doctor --staged` and the
|
|
101
98
|
pre-commit hook refuses it. If the file does not exist yet (a store migrated in from before it was
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
|
@@ -0,0 +1,116 @@
|
|
|
1
|
+
---
|
|
2
|
+
name: eli5
|
|
3
|
+
description: "Explain any topic, code, concept, or error tailored to a specific audience's level of understanding. Use this skill whenever the user says 'explain like I am', 'ELI5', 'explain this to my', 'break this down for', 'dumb it down', 'simplify this for', or asks you to explain something to a specific person or audience type (e.g., 'explain this to a manager', 'how would I explain this to my mom', 'make this understandable for a 5th grader'). Also trigger when the user mentions wanting to understand something at a particular level, or asks for an explanation targeting a non-technical audience. Even partial matches like 'explain to my wife' or 'tell my boss' should trigger this skill."
|
|
4
|
+
---
|
|
5
|
+
|
|
6
|
+
# Explain Like I Am... (ELI5)
|
|
7
|
+
|
|
8
|
+
You are an expert at taking complex topics and making them accessible to any audience. Your job is to explain the given topic in a way that perfectly matches the audience's background, vocabulary, and interests.
|
|
9
|
+
|
|
10
|
+
## Step 1: Identify the Audience
|
|
11
|
+
|
|
12
|
+
Parse the user's request to determine who the explanation is for. The audience falls into one of these categories:
|
|
13
|
+
|
|
14
|
+
### Ages
|
|
15
|
+
| Audience | Style |
|
|
16
|
+
|----------|-------|
|
|
17
|
+
| Age 5 | Super simple words. Use fun analogies with toys, animals, candy, playground. Short sentences. "Imagine you have a box of crayons..." |
|
|
18
|
+
| Age 10 | Elementary school level. Can handle basic cause-and-effect. Use school, sports, video game analogies. |
|
|
19
|
+
| Age 15 | Teenager. Can handle some abstraction. Use social media, phone, gaming references. Be slightly casual. |
|
|
20
|
+
| Age 20-30 | Young adult. Clear and direct. Real-world analogies from daily life, work, money. |
|
|
21
|
+
| Age 40+ | Mature adult. Respectful tone. Analogies from home ownership, career, family management. |
|
|
22
|
+
|
|
23
|
+
### Grade / Education Levels
|
|
24
|
+
| Audience | Style |
|
|
25
|
+
|----------|-------|
|
|
26
|
+
| 5th grade | Simple vocabulary, concrete examples, avoid jargon entirely. "Think of it like..." |
|
|
27
|
+
| Middle school | Can introduce basic terminology with definitions. Step-by-step logic. |
|
|
28
|
+
| Senior High | Can handle moderate complexity. Introduce proper terms but explain them. SAT-level vocabulary OK. |
|
|
29
|
+
| College Student | Academic framing. Can use technical terms with brief context. Theory + practical application. |
|
|
30
|
+
| Graduate school | Assume strong foundational knowledge. Focus on nuance, trade-offs, edge cases, and deeper implications. Be precise. |
|
|
31
|
+
|
|
32
|
+
### Job Roles
|
|
33
|
+
| Audience | They care about... | Frame explanations around... |
|
|
34
|
+
|----------|-------------------|------------------------------|
|
|
35
|
+
| Manager | Impact, timeline, risk, cost | Business outcomes, team implications, what decisions need to be made |
|
|
36
|
+
| Engineer | How it works, architecture, trade-offs | Technical details, implementation, performance, maintainability |
|
|
37
|
+
| Designer | User experience, visual impact, flow | How it affects the user, interaction patterns, accessibility |
|
|
38
|
+
| Director | Strategy, ROI, competitive advantage | Big picture, market position, resource allocation |
|
|
39
|
+
| Colleague | Practical context, shared work | How it affects their work, what they need to know to collaborate |
|
|
40
|
+
| Product Manager | User value, priorities, scope | Feature impact, user stories, what to build vs. skip |
|
|
41
|
+
|
|
42
|
+
### Relationships
|
|
43
|
+
| Audience | Tone | Analogy style |
|
|
44
|
+
|----------|------|---------------|
|
|
45
|
+
| Wife / Husband / Partner | Warm, conversational, patient | Household tasks, shared experiences, daily routines |
|
|
46
|
+
| Father / Mother / Parents | Respectful, clear, no condescension | Familiar technology they use, home analogies, generational bridges |
|
|
47
|
+
| Kids / Children | Playful, encouraging, short | Games, cartoons, school, animals |
|
|
48
|
+
| Friend | Casual, maybe humorous | Pop culture, shared interests, "you know how..." |
|
|
49
|
+
|
|
50
|
+
If the audience isn't explicitly stated, default to "Age 5" (classic ELI5).
|
|
51
|
+
|
|
52
|
+
## Step 2: Read the Source Material
|
|
53
|
+
|
|
54
|
+
Before explaining, make sure you fully understand what needs to be explained. This could be:
|
|
55
|
+
- **Code**: Read the relevant code files. Understand what the code does at a high level before translating.
|
|
56
|
+
- **A concept**: Break it into its core components.
|
|
57
|
+
- **An error message**: Understand the root cause, not just the surface text.
|
|
58
|
+
- **A technical document**: Extract the key points that matter.
|
|
59
|
+
- **Anything else**: Identify the essential "what" and "why."
|
|
60
|
+
|
|
61
|
+
## Step 3: Craft the Explanation
|
|
62
|
+
|
|
63
|
+
Follow these principles, scaled to the audience:
|
|
64
|
+
|
|
65
|
+
### Structure
|
|
66
|
+
1. **Start with the "what"** — one sentence that captures the essence
|
|
67
|
+
2. **Use an analogy** — connect to something the audience already knows
|
|
68
|
+
3. **Fill in details** — add layers only as appropriate for the audience level
|
|
69
|
+
4. **End with the "so what"** — why does this matter to them specifically?
|
|
70
|
+
|
|
71
|
+
### Language Calibration
|
|
72
|
+
|
|
73
|
+
For **simple audiences** (young ages, non-technical roles, family):
|
|
74
|
+
- No jargon. Zero. If a technical term is essential, define it immediately.
|
|
75
|
+
- One idea per sentence.
|
|
76
|
+
- Concrete over abstract. "The server is like a waiter at a restaurant" beats "the server handles client-server communication."
|
|
77
|
+
- Use "you" and "your" — make it personal.
|
|
78
|
+
|
|
79
|
+
For **technical audiences** (engineers, grad students):
|
|
80
|
+
- Use proper terminology — they'll feel patronized without it.
|
|
81
|
+
- Focus on the *interesting* parts: trade-offs, edge cases, design decisions.
|
|
82
|
+
- Compare to things they already know: "It's like a hash map but with X difference."
|
|
83
|
+
- Be concise — respect their existing knowledge.
|
|
84
|
+
|
|
85
|
+
For **business audiences** (managers, directors):
|
|
86
|
+
- Lead with impact and outcomes.
|
|
87
|
+
- Quantify where possible.
|
|
88
|
+
- Skip implementation details unless asked.
|
|
89
|
+
- Frame in terms of decisions: "This means we should..."
|
|
90
|
+
|
|
91
|
+
### Tone Matching
|
|
92
|
+
- Ages 5-10: Enthusiastic, like a favorite teacher. "Oh, this is a cool one!"
|
|
93
|
+
- Teenagers: Slightly casual but not cringey. No "fellow kids" energy.
|
|
94
|
+
- Professionals: Confident and clear. Respect their intelligence while bridging knowledge gaps.
|
|
95
|
+
- Family: Patient, warm, conversational. Like explaining over dinner.
|
|
96
|
+
|
|
97
|
+
## Examples
|
|
98
|
+
|
|
99
|
+
**User says**: "ELI5 what a database index is"
|
|
100
|
+
**Audience**: Age 5 (default)
|
|
101
|
+
**Response style**: "Imagine you have a huuuge book with thousands of pages. Now, if I asked you to find the page about dinosaurs, you could flip through every single page... or you could look at the table of contents at the front! A database index is like that table of contents. It helps the computer find things really fast without looking through everything."
|
|
102
|
+
|
|
103
|
+
**User says**: "Explain this API rate limiting to my manager"
|
|
104
|
+
**Audience**: Manager
|
|
105
|
+
**Response style**: "The API has a speed limit — we can only make 100 requests per minute. Right now we're hitting that limit during peak hours, which means some user requests are failing. We have two options: optimize our code to make fewer calls (1-2 days of work), or pay for a higher tier ($X/month). I'd recommend..."
|
|
106
|
+
|
|
107
|
+
**User says**: "Break down this React useEffect hook for a college student"
|
|
108
|
+
**Audience**: College Student
|
|
109
|
+
**Response style**: "useEffect is React's way of handling side effects — things that happen outside the normal render cycle, like API calls, subscriptions, or DOM manipulation. Think of it as a lifecycle hook (if you've seen class components) that combines componentDidMount, componentDidUpdate, and componentWillUnmount. The dependency array controls when it re-runs..."
|
|
110
|
+
|
|
111
|
+
## Important Reminders
|
|
112
|
+
|
|
113
|
+
- Never talk down to anyone. A 5-year-old explanation should feel delightful, not dumbing-down. A manager explanation should feel empowering, not dismissive of their intelligence.
|
|
114
|
+
- When explaining code, always explain the *purpose* first, then the mechanism. Nobody cares about syntax until they know why it exists.
|
|
115
|
+
- If the topic is genuinely complex and the audience is very non-technical, it's OK to simplify ruthlessly. Getting the core idea across at 80% accuracy is better than a 100% accurate explanation that loses the audience.
|
|
116
|
+
- Match the length to the audience: short and sweet for young kids, more detailed for technical audiences who want depth.
|
package/dist/commands/check.d.ts
DELETED
|
@@ -1,30 +0,0 @@
|
|
|
1
|
-
import type { CommandOutcome, CommandRequires } from '../core/command.js';
|
|
2
|
-
import type { DisclosureRung, DisclosureVerdict } from '../core/disclosure/model.js';
|
|
3
|
-
import { type LeakFinding } from '../core/disclosure/leak-scan.js';
|
|
4
|
-
import type { RunEnv } from '../core/env.js';
|
|
5
|
-
import type { Store } from '../core/store.js';
|
|
6
|
-
export declare const requires: CommandRequires;
|
|
7
|
-
export interface CheckFlags {
|
|
8
|
-
path: string;
|
|
9
|
-
audience?: string;
|
|
10
|
-
scan?: boolean;
|
|
11
|
-
}
|
|
12
|
-
export interface CheckData {
|
|
13
|
-
path: string;
|
|
14
|
-
audience?: string;
|
|
15
|
-
verdict?: DisclosureVerdict;
|
|
16
|
-
rung?: DisclosureRung;
|
|
17
|
-
leaks?: LeakFinding[];
|
|
18
|
-
}
|
|
19
|
-
/**
|
|
20
|
-
* disclosure-policy spec: the tri-state ALLOW/DENY/ASK verdict, each with
|
|
21
|
-
* its own documented exit code (cli-contract's reserved 4/5), printing the
|
|
22
|
-
* rung that produced it so a script or a human can see WHY, not just WHAT.
|
|
23
|
-
*
|
|
24
|
-
* store-primitives-from-migration-audit spec (D3): `--scan` is a second,
|
|
25
|
-
* independent mode — the same leak scan `ctxr lint` runs, for one note —
|
|
26
|
-
* and does not require `--audience` (a leak isn't about one requesting
|
|
27
|
-
* audience; it's about every configured marker context at once).
|
|
28
|
-
*/
|
|
29
|
-
export declare function execute(env: RunEnv, store: Store, flags: CheckFlags): Promise<CommandOutcome<CheckData>>;
|
|
30
|
-
//# sourceMappingURL=check.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"check.d.ts","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,KAAK,EAAE,cAAc,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAErF,OAAO,EAAoB,KAAK,WAAW,EAAE,MAAM,iCAAiC,CAAC;AACrF,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAK7C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAE9C,eAAO,MAAM,QAAQ,EAAE,eAAuC,CAAC;AAE/D,MAAM,WAAW,UAAU;IACzB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,IAAI,CAAC,EAAE,OAAO,CAAC;CAChB;AAED,MAAM,WAAW,SAAS;IACxB,IAAI,EAAE,MAAM,CAAC;IACb,QAAQ,CAAC,EAAE,MAAM,CAAC;IAClB,OAAO,CAAC,EAAE,iBAAiB,CAAC;IAC5B,IAAI,CAAC,EAAE,cAAc,CAAC;IACtB,KAAK,CAAC,EAAE,WAAW,EAAE,CAAC;CACvB;AAOD;;;;;;;;;GASG;AACH,wBAAsB,OAAO,CAAC,GAAG,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK,EAAE,UAAU,GAAG,OAAO,CAAC,cAAc,CAAC,SAAS,CAAC,CAAC,CA6C9G"}
|
package/dist/commands/check.js
DELETED
|
@@ -1,65 +0,0 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
import { evaluateDisclosure, VERDICT_EXIT_CODE } from '../core/disclosure/model.js';
|
|
3
|
-
import { scanNoteForLeaks } from '../core/disclosure/leak-scan.js';
|
|
4
|
-
import { CheckAudienceRequiredError, NoteNotFoundError } from '../core/errors.js';
|
|
5
|
-
import { ExitCode } from '../core/exit-codes.js';
|
|
6
|
-
import { parseNote } from '../core/notes/parse.js';
|
|
7
|
-
export const requires = { store: 'required' };
|
|
8
|
-
function toStoreRelativePath(env, store, givenPath) {
|
|
9
|
-
const absolute = path.isAbsolute(givenPath) ? givenPath : path.resolve(env.cwd, givenPath);
|
|
10
|
-
return path.relative(store.root, absolute).split(path.sep).join('/');
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* disclosure-policy spec: the tri-state ALLOW/DENY/ASK verdict, each with
|
|
14
|
-
* its own documented exit code (cli-contract's reserved 4/5), printing the
|
|
15
|
-
* rung that produced it so a script or a human can see WHY, not just WHAT.
|
|
16
|
-
*
|
|
17
|
-
* store-primitives-from-migration-audit spec (D3): `--scan` is a second,
|
|
18
|
-
* independent mode — the same leak scan `ctxr lint` runs, for one note —
|
|
19
|
-
* and does not require `--audience` (a leak isn't about one requesting
|
|
20
|
-
* audience; it's about every configured marker context at once).
|
|
21
|
-
*/
|
|
22
|
-
export async function execute(env, store, flags) {
|
|
23
|
-
const relativePath = toStoreRelativePath(env, store, flags.path);
|
|
24
|
-
const absolutePath = path.join(store.root, relativePath);
|
|
25
|
-
let note;
|
|
26
|
-
try {
|
|
27
|
-
note = await parseNote(absolutePath, relativePath);
|
|
28
|
-
}
|
|
29
|
-
catch (err) {
|
|
30
|
-
if (err.code === 'ENOENT')
|
|
31
|
-
throw new NoteNotFoundError(relativePath);
|
|
32
|
-
throw err;
|
|
33
|
-
}
|
|
34
|
-
if (flags.scan) {
|
|
35
|
-
const leaks = scanNoteForLeaks(store.config, note);
|
|
36
|
-
const findings = leaks.map((leak) => ({
|
|
37
|
-
code: 'disclosure.leak',
|
|
38
|
-
severity: 'warning',
|
|
39
|
-
message: `"${leak.path}" matches a marker for context "${leak.context}", which cannot see this note: "${leak.matchedText}".`,
|
|
40
|
-
subject: leak.path,
|
|
41
|
-
details: { context: leak.context, pattern: leak.pattern, matchedText: leak.matchedText },
|
|
42
|
-
}));
|
|
43
|
-
return {
|
|
44
|
-
exitCode: leaks.length > 0 ? ExitCode.CheckFailed : ExitCode.Ok,
|
|
45
|
-
data: { path: relativePath, leaks },
|
|
46
|
-
findings,
|
|
47
|
-
humanSummary: leaks.length > 0 ? `${relativePath}: ${leaks.length} leak(s) found.` : `${relativePath}: no leaks found.`,
|
|
48
|
-
storeRoot: store.root,
|
|
49
|
-
schemaVersion: store.config.schema_version,
|
|
50
|
-
};
|
|
51
|
-
}
|
|
52
|
-
if (!flags.audience) {
|
|
53
|
-
throw new CheckAudienceRequiredError();
|
|
54
|
-
}
|
|
55
|
-
const { verdict, rung } = evaluateDisclosure(store.config, note, flags.audience);
|
|
56
|
-
return {
|
|
57
|
-
exitCode: VERDICT_EXIT_CODE[verdict],
|
|
58
|
-
data: { path: relativePath, audience: flags.audience, verdict, rung },
|
|
59
|
-
findings: [],
|
|
60
|
-
humanSummary: `${relativePath} for audience "${flags.audience}": ${verdict.toUpperCase()} (rung: ${rung})`,
|
|
61
|
-
storeRoot: store.root,
|
|
62
|
-
schemaVersion: store.config.schema_version,
|
|
63
|
-
};
|
|
64
|
-
}
|
|
65
|
-
//# sourceMappingURL=check.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"check.js","sourceRoot":"","sources":["../../src/commands/check.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,14 +0,0 @@
|
|
|
1
|
-
import type { CommandOutcome, CommandRequires } from '../core/command.js';
|
|
2
|
-
import type { RunEnv } from '../core/env.js';
|
|
3
|
-
import type { Store } from '../core/store.js';
|
|
4
|
-
export declare const requires: CommandRequires;
|
|
5
|
-
export interface NoteResolveFlags {
|
|
6
|
-
path: string;
|
|
7
|
-
}
|
|
8
|
-
export interface NoteResolveData {
|
|
9
|
-
path: string;
|
|
10
|
-
visibility: string;
|
|
11
|
-
reason: string;
|
|
12
|
-
}
|
|
13
|
-
export declare function execute(env: RunEnv, store: Store, flags: NoteResolveFlags): Promise<CommandOutcome<NoteResolveData>>;
|
|
14
|
-
//# sourceMappingURL=note-resolve.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"note-resolve.d.ts","sourceRoot":"","sources":["../../src/commands/note-resolve.ts"],"names":[],"mappings":"AACA,OAAO,KAAK,EAAE,cAAc,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AAC1E,OAAO,KAAK,EAAE,MAAM,EAAE,MAAM,gBAAgB,CAAC;AAI7C,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,kBAAkB,CAAC;AAE9C,eAAO,MAAM,QAAQ,EAAE,eAAuC,CAAC;AAE/D,MAAM,WAAW,gBAAgB;IAC/B,IAAI,EAAE,MAAM,CAAC;CACd;AAED,MAAM,WAAW,eAAe;IAC9B,IAAI,EAAE,MAAM,CAAC;IACb,UAAU,EAAE,MAAM,CAAC;IACnB,MAAM,EAAE,MAAM,CAAC;CAChB;AAOD,wBAAsB,OAAO,CAC3B,GAAG,EAAE,MAAM,EACX,KAAK,EAAE,KAAK,EACZ,KAAK,EAAE,gBAAgB,GACtB,OAAO,CAAC,cAAc,CAAC,eAAe,CAAC,CAAC,CAc1C"}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import path from 'node:path';
|
|
2
|
-
import { ExitCode } from '../core/exit-codes.js';
|
|
3
|
-
import { parseNote } from '../core/notes/parse.js';
|
|
4
|
-
import { resolveVisibility } from '../core/notes/visibility.js';
|
|
5
|
-
export const requires = { store: 'required' };
|
|
6
|
-
function toStoreRelativePath(env, store, givenPath) {
|
|
7
|
-
const absolute = path.isAbsolute(givenPath) ? givenPath : path.resolve(env.cwd, givenPath);
|
|
8
|
-
return path.relative(store.root, absolute).split(path.sep).join('/');
|
|
9
|
-
}
|
|
10
|
-
export async function execute(env, store, flags) {
|
|
11
|
-
const relativePath = toStoreRelativePath(env, store, flags.path);
|
|
12
|
-
const absolutePath = path.join(store.root, relativePath);
|
|
13
|
-
const note = await parseNote(absolutePath, relativePath);
|
|
14
|
-
const resolution = resolveVisibility(store.config, note);
|
|
15
|
-
return {
|
|
16
|
-
exitCode: ExitCode.Ok,
|
|
17
|
-
data: { path: relativePath, visibility: resolution.value, reason: resolution.reason },
|
|
18
|
-
findings: [],
|
|
19
|
-
humanSummary: `${relativePath}: ${resolution.value} (${resolution.reason})`,
|
|
20
|
-
storeRoot: store.root,
|
|
21
|
-
schemaVersion: store.config.schema_version,
|
|
22
|
-
};
|
|
23
|
-
}
|
|
24
|
-
//# sourceMappingURL=note-resolve.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"note-resolve.js","sourceRoot":"","sources":["../../src/commands/note-resolve.ts"],"names":[],"mappings":"AAAA,OAAO,IAAI,MAAM,WAAW,CAAC;AAG7B,OAAO,EAAE,QAAQ,EAAE,MAAM,uBAAuB,CAAC;AACjD,OAAO,EAAE,SAAS,EAAE,MAAM,wBAAwB,CAAC;AACnD,OAAO,EAAE,iBAAiB,EAAE,MAAM,6BAA6B,CAAC;AAGhE,MAAM,CAAC,MAAM,QAAQ,GAAoB,EAAE,KAAK,EAAE,UAAU,EAAE,CAAC;AAY/D,SAAS,mBAAmB,CAAC,GAAW,EAAE,KAAY,EAAE,SAAiB;IACvE,MAAM,QAAQ,GAAG,IAAI,CAAC,UAAU,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,CAAC,IAAI,CAAC,OAAO,CAAC,GAAG,CAAC,GAAG,EAAE,SAAS,CAAC,CAAC;IAC3F,OAAO,IAAI,CAAC,QAAQ,CAAC,KAAK,CAAC,IAAI,EAAE,QAAQ,CAAC,CAAC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC;AACvE,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,OAAO,CAC3B,GAAW,EACX,KAAY,EACZ,KAAuB;IAEvB,MAAM,YAAY,GAAG,mBAAmB,CAAC,GAAG,EAAE,KAAK,EAAE,KAAK,CAAC,IAAI,CAAC,CAAC;IACjE,MAAM,YAAY,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,IAAI,EAAE,YAAY,CAAC,CAAC;IACzD,MAAM,IAAI,GAAG,MAAM,SAAS,CAAC,YAAY,EAAE,YAAY,CAAC,CAAC;IACzD,MAAM,UAAU,GAAG,iBAAiB,CAAC,KAAK,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC;IAEzD,OAAO;QACL,QAAQ,EAAE,QAAQ,CAAC,EAAE;QACrB,IAAI,EAAE,EAAE,IAAI,EAAE,YAAY,EAAE,UAAU,EAAE,UAAU,CAAC,KAAK,EAAE,MAAM,EAAE,UAAU,CAAC,MAAM,EAAE;QACrF,QAAQ,EAAE,EAAE;QACZ,YAAY,EAAE,GAAG,YAAY,KAAK,UAAU,CAAC,KAAK,KAAK,UAAU,CAAC,MAAM,GAAG;QAC3E,SAAS,EAAE,KAAK,CAAC,IAAI;QACrB,aAAa,EAAE,KAAK,CAAC,MAAM,CAAC,cAAc;KAC3C,CAAC;AACJ,CAAC"}
|
|
@@ -1,4 +0,0 @@
|
|
|
1
|
-
/** disclosure-policy spec (store-primitives-from-migration-audit D3): reported by lint, never failed by doctor — a marker match is a judgment call, not an invariant. */
|
|
2
|
-
export declare const leakCheck: import("./types.js").CheckDefinition;
|
|
3
|
-
export declare const DISCLOSURE_CHECKS: import("./types.js").CheckDefinition[];
|
|
4
|
-
//# sourceMappingURL=disclosure-checks.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"disclosure-checks.d.ts","sourceRoot":"","sources":["../../../src/core/checks/disclosure-checks.ts"],"names":[],"mappings":"AAIA,yKAAyK;AACzK,eAAO,MAAM,SAAS,sCAkBpB,CAAC;AAEH,eAAO,MAAM,iBAAiB,wCAAc,CAAC"}
|
|
@@ -1,24 +0,0 @@
|
|
|
1
|
-
import { scanForLeaks } from '../disclosure/leak-scan.js';
|
|
2
|
-
import { defineCheck } from './types.js';
|
|
3
|
-
/** disclosure-policy spec (store-primitives-from-migration-audit D3): reported by lint, never failed by doctor — a marker match is a judgment call, not an invariant. */
|
|
4
|
-
export const leakCheck = defineCheck({
|
|
5
|
-
id: 'disclosure.leak',
|
|
6
|
-
title: "Content matching a context's marker found inside a note that context cannot see",
|
|
7
|
-
severity: 'observation',
|
|
8
|
-
capability: 'disclosure-policy',
|
|
9
|
-
scopes: ['store'],
|
|
10
|
-
async run(ctx) {
|
|
11
|
-
const notes = await ctx.notes();
|
|
12
|
-
const leaks = scanForLeaks(ctx.config, notes);
|
|
13
|
-
const findings = leaks.map((leak) => ({
|
|
14
|
-
code: 'disclosure.leak',
|
|
15
|
-
severity: 'warning',
|
|
16
|
-
message: `"${leak.path}" matches a marker for context "${leak.context}", which cannot see this note: "${leak.matchedText}".`,
|
|
17
|
-
subject: leak.path,
|
|
18
|
-
details: { context: leak.context, pattern: leak.pattern, matchedText: leak.matchedText },
|
|
19
|
-
}));
|
|
20
|
-
return { status: findings.length > 0 ? 'fail' : 'pass', findings };
|
|
21
|
-
},
|
|
22
|
-
});
|
|
23
|
-
export const DISCLOSURE_CHECKS = [leakCheck];
|
|
24
|
-
//# sourceMappingURL=disclosure-checks.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"disclosure-checks.js","sourceRoot":"","sources":["../../../src/core/checks/disclosure-checks.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,YAAY,EAAE,MAAM,4BAA4B,CAAC;AAE1D,OAAO,EAAE,WAAW,EAAE,MAAM,YAAY,CAAC;AAEzC,yKAAyK;AACzK,MAAM,CAAC,MAAM,SAAS,GAAG,WAAW,CAAC;IACnC,EAAE,EAAE,iBAAiB;IACrB,KAAK,EAAE,iFAAiF;IACxF,QAAQ,EAAE,aAAa;IACvB,UAAU,EAAE,mBAAmB;IAC/B,MAAM,EAAE,CAAC,OAAO,CAAC;IACjB,KAAK,CAAC,GAAG,CAAC,GAAG;QACX,MAAM,KAAK,GAAG,MAAM,GAAG,CAAC,KAAK,EAAE,CAAC;QAChC,MAAM,KAAK,GAAG,YAAY,CAAC,GAAG,CAAC,MAAM,EAAE,KAAK,CAAC,CAAC;QAC9C,MAAM,QAAQ,GAAc,KAAK,CAAC,GAAG,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,CAAC;YAC/C,IAAI,EAAE,iBAAiB;YACvB,QAAQ,EAAE,SAAS;YACnB,OAAO,EAAE,IAAI,IAAI,CAAC,IAAI,mCAAmC,IAAI,CAAC,OAAO,mCAAmC,IAAI,CAAC,WAAW,IAAI;YAC5H,OAAO,EAAE,IAAI,CAAC,IAAI;YAClB,OAAO,EAAE,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,WAAW,EAAE,IAAI,CAAC,WAAW,EAAE;SACzF,CAAC,CAAC,CAAC;QACJ,OAAO,EAAE,MAAM,EAAE,QAAQ,CAAC,MAAM,GAAG,CAAC,CAAC,CAAC,CAAC,MAAM,CAAC,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,CAAC;IACrE,CAAC;CACF,CAAC,CAAC;AAEH,MAAM,CAAC,MAAM,iBAAiB,GAAG,CAAC,SAAS,CAAC,CAAC"}
|
|
@@ -1,19 +0,0 @@
|
|
|
1
|
-
import type { StoreConfig } from '../../config/schema.js';
|
|
2
|
-
import type { Note } from '../notes/list.js';
|
|
3
|
-
export interface LeakFinding {
|
|
4
|
-
path: string;
|
|
5
|
-
context: string;
|
|
6
|
-
pattern: string;
|
|
7
|
-
matchedText: string;
|
|
8
|
-
}
|
|
9
|
-
/**
|
|
10
|
-
* disclosure-policy spec (store-primitives-from-migration-audit D3): a leak
|
|
11
|
-
* is content that belongs to context X (per an operator-declared marker
|
|
12
|
-
* pattern) inside a note X cannot see, per the SAME context→visible-values
|
|
13
|
-
* mapping the visibility pre-filter and disclosure's internal-audience rung
|
|
14
|
-
* use — "X cannot see the note" is exactly `!canSee(config, X, resolved)`.
|
|
15
|
-
* Empty markers (the default) make this a no-op for every note.
|
|
16
|
-
*/
|
|
17
|
-
export declare function scanNoteForLeaks(config: StoreConfig, note: Note): LeakFinding[];
|
|
18
|
-
export declare function scanForLeaks(config: StoreConfig, notes: readonly Note[]): LeakFinding[];
|
|
19
|
-
//# sourceMappingURL=leak-scan.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"leak-scan.d.ts","sourceRoot":"","sources":["../../../src/core/disclosure/leak-scan.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1D,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAG7C,MAAM,WAAW,WAAW;IAC1B,IAAI,EAAE,MAAM,CAAC;IACb,OAAO,EAAE,MAAM,CAAC;IAChB,OAAO,EAAE,MAAM,CAAC;IAChB,WAAW,EAAE,MAAM,CAAC;CACrB;AAED;;;;;;;GAOG;AACH,wBAAgB,gBAAgB,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,GAAG,WAAW,EAAE,CAgB/E;AAED,wBAAgB,YAAY,CAAC,MAAM,EAAE,WAAW,EAAE,KAAK,EAAE,SAAS,IAAI,EAAE,GAAG,WAAW,EAAE,CAEvF"}
|
|
@@ -1,31 +0,0 @@
|
|
|
1
|
-
import { canSee, resolveVisibility } from '../notes/visibility.js';
|
|
2
|
-
/**
|
|
3
|
-
* disclosure-policy spec (store-primitives-from-migration-audit D3): a leak
|
|
4
|
-
* is content that belongs to context X (per an operator-declared marker
|
|
5
|
-
* pattern) inside a note X cannot see, per the SAME context→visible-values
|
|
6
|
-
* mapping the visibility pre-filter and disclosure's internal-audience rung
|
|
7
|
-
* use — "X cannot see the note" is exactly `!canSee(config, X, resolved)`.
|
|
8
|
-
* Empty markers (the default) make this a no-op for every note.
|
|
9
|
-
*/
|
|
10
|
-
export function scanNoteForLeaks(config, note) {
|
|
11
|
-
const markers = config.disclosure.leak_markers;
|
|
12
|
-
if (Object.keys(markers).length === 0)
|
|
13
|
-
return [];
|
|
14
|
-
const resolved = resolveVisibility(config, note).value;
|
|
15
|
-
const findings = [];
|
|
16
|
-
for (const [context, patterns] of Object.entries(markers)) {
|
|
17
|
-
if (canSee(config, context, resolved))
|
|
18
|
-
continue;
|
|
19
|
-
for (const pattern of patterns) {
|
|
20
|
-
const match = new RegExp(pattern).exec(note.body);
|
|
21
|
-
if (match) {
|
|
22
|
-
findings.push({ path: note.path, context, pattern, matchedText: match[0] });
|
|
23
|
-
}
|
|
24
|
-
}
|
|
25
|
-
}
|
|
26
|
-
return findings;
|
|
27
|
-
}
|
|
28
|
-
export function scanForLeaks(config, notes) {
|
|
29
|
-
return notes.flatMap((note) => scanNoteForLeaks(config, note));
|
|
30
|
-
}
|
|
31
|
-
//# sourceMappingURL=leak-scan.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"leak-scan.js","sourceRoot":"","sources":["../../../src/core/disclosure/leak-scan.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,MAAM,EAAE,iBAAiB,EAAE,MAAM,wBAAwB,CAAC;AASnE;;;;;;;GAOG;AACH,MAAM,UAAU,gBAAgB,CAAC,MAAmB,EAAE,IAAU;IAC9D,MAAM,OAAO,GAAG,MAAM,CAAC,UAAU,CAAC,YAAY,CAAC;IAC/C,IAAI,MAAM,CAAC,IAAI,CAAC,OAAO,CAAC,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,EAAE,CAAC;IAEjD,MAAM,QAAQ,GAAG,iBAAiB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,KAAK,CAAC;IACvD,MAAM,QAAQ,GAAkB,EAAE,CAAC;IACnC,KAAK,MAAM,CAAC,OAAO,EAAE,QAAQ,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,OAAO,CAAC,EAAE,CAAC;QAC1D,IAAI,MAAM,CAAC,MAAM,EAAE,OAAO,EAAE,QAAQ,CAAC;YAAE,SAAS;QAChD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;YAC/B,MAAM,KAAK,GAAG,IAAI,MAAM,CAAC,OAAO,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAClD,IAAI,KAAK,EAAE,CAAC;gBACV,QAAQ,CAAC,IAAI,CAAC,EAAE,IAAI,EAAE,IAAI,CAAC,IAAI,EAAE,OAAO,EAAE,OAAO,EAAE,WAAW,EAAE,KAAK,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC;YAC9E,CAAC;QACH,CAAC;IACH,CAAC;IACD,OAAO,QAAQ,CAAC;AAClB,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,MAAmB,EAAE,KAAsB;IACtE,OAAO,KAAK,CAAC,OAAO,CAAC,CAAC,IAAI,EAAE,EAAE,CAAC,gBAAgB,CAAC,MAAM,EAAE,IAAI,CAAC,CAAC,CAAC;AACjE,CAAC"}
|
|
@@ -1,29 +0,0 @@
|
|
|
1
|
-
import type { StoreConfig } from '../../config/schema.js';
|
|
2
|
-
import { ExitCode } from '../exit-codes.js';
|
|
3
|
-
import type { Note } from '../notes/list.js';
|
|
4
|
-
export type DisclosureVerdict = 'allow' | 'deny' | 'ask';
|
|
5
|
-
/** disclosure-policy spec: each tri-state verdict's own distinct, documented exit code — defined once for every caller (single-note or aggregate). */
|
|
6
|
-
export declare const VERDICT_EXIT_CODE: Record<DisclosureVerdict, ExitCode>;
|
|
7
|
-
export type DisclosureRung = 'hard_wall' | 'explicit_tag' | 'internal_visibility' | 'external_default';
|
|
8
|
-
export interface DisclosureResult {
|
|
9
|
-
verdict: DisclosureVerdict;
|
|
10
|
-
rung: DisclosureRung;
|
|
11
|
-
}
|
|
12
|
-
/**
|
|
13
|
-
* disclosure-policy spec: ordered walls-before-allows evaluation, stopping
|
|
14
|
-
* at the first rung that produces a verdict. Rung 3 (internal-audience-
|
|
15
|
-
* from-visibility) only applies when the requested audience is one the
|
|
16
|
-
* operator has declared internal — for any other (external) audience, rung
|
|
17
|
-
* 3 is skipped entirely and evaluation falls straight to rung 4's ASK, so an
|
|
18
|
-
* external verdict is never derived from visibility alone.
|
|
19
|
-
*/
|
|
20
|
-
export declare function evaluateDisclosure(config: StoreConfig, note: Note, audience: string): DisclosureResult;
|
|
21
|
-
/**
|
|
22
|
-
* disclosure-policy spec: a set of verdicts aggregates to its most
|
|
23
|
-
* restrictive member — DENY outranks ASK, which outranks ALLOW. An empty
|
|
24
|
-
* set aggregates to ALLOW; callers that need to distinguish "nothing was
|
|
25
|
-
* evaluated" from "everything was evaluated and allowed" report the set's
|
|
26
|
-
* size separately, per the publish spec's empty-set scenario.
|
|
27
|
-
*/
|
|
28
|
-
export declare function worstVerdict(verdicts: readonly DisclosureVerdict[]): DisclosureVerdict;
|
|
29
|
-
//# sourceMappingURL=model.d.ts.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"model.d.ts","sourceRoot":"","sources":["../../../src/core/disclosure/model.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAkB,WAAW,EAAE,MAAM,wBAAwB,CAAC;AAC1E,OAAO,EAAE,QAAQ,EAAE,MAAM,kBAAkB,CAAC;AAC5C,OAAO,KAAK,EAAE,IAAI,EAAE,MAAM,kBAAkB,CAAC;AAG7C,MAAM,MAAM,iBAAiB,GAAG,OAAO,GAAG,MAAM,GAAG,KAAK,CAAC;AAEzD,sJAAsJ;AACtJ,eAAO,MAAM,iBAAiB,EAAE,MAAM,CAAC,iBAAiB,EAAE,QAAQ,CAIjE,CAAC;AAEF,MAAM,MAAM,cAAc,GAAG,WAAW,GAAG,cAAc,GAAG,qBAAqB,GAAG,kBAAkB,CAAC;AAEvG,MAAM,WAAW,gBAAgB;IAC/B,OAAO,EAAE,iBAAiB,CAAC;IAC3B,IAAI,EAAE,cAAc,CAAC;CACtB;AAoBD;;;;;;;GAOG;AACH,wBAAgB,kBAAkB,CAAC,MAAM,EAAE,WAAW,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,GAAG,gBAAgB,CAkBtG;AAKD;;;;;;GAMG;AACH,wBAAgB,YAAY,CAAC,QAAQ,EAAE,SAAS,iBAAiB,EAAE,GAAG,iBAAiB,CAMtF"}
|
|
@@ -1,69 +0,0 @@
|
|
|
1
|
-
import { ExitCode } from '../exit-codes.js';
|
|
2
|
-
import { canSee, resolveVisibility } from '../notes/visibility.js';
|
|
3
|
-
/** disclosure-policy spec: each tri-state verdict's own distinct, documented exit code — defined once for every caller (single-note or aggregate). */
|
|
4
|
-
export const VERDICT_EXIT_CODE = {
|
|
5
|
-
allow: ExitCode.Ok,
|
|
6
|
-
deny: ExitCode.DisclosureDeny,
|
|
7
|
-
ask: ExitCode.DisclosureAsk,
|
|
8
|
-
};
|
|
9
|
-
/**
|
|
10
|
-
* The frontmatter key a note uses to explicitly declare which audiences may
|
|
11
|
-
* see it disclosed (rung 2). Unlike the visibility field (context-store
|
|
12
|
-
* spec), nothing asks this key to be configurable, so it lives here as the
|
|
13
|
-
* one literal — same discipline as every other single-purpose constant in
|
|
14
|
-
* this codebase, just without a dedicated defaults.ts entry since no other
|
|
15
|
-
* module needs to reference it.
|
|
16
|
-
*/
|
|
17
|
-
const AUDIENCE_FIELD_KEY = 'audience';
|
|
18
|
-
function matchesWall(wall, note, audience) {
|
|
19
|
-
if (wall.audience !== '*' && wall.audience !== audience)
|
|
20
|
-
return false;
|
|
21
|
-
if (wall.except?.includes(audience))
|
|
22
|
-
return false;
|
|
23
|
-
if (!wall.note_path_prefix)
|
|
24
|
-
return true;
|
|
25
|
-
const prefix = wall.note_path_prefix.endsWith('/') ? wall.note_path_prefix : `${wall.note_path_prefix}/`;
|
|
26
|
-
return note.path === wall.note_path_prefix || note.path.startsWith(prefix);
|
|
27
|
-
}
|
|
28
|
-
/**
|
|
29
|
-
* disclosure-policy spec: ordered walls-before-allows evaluation, stopping
|
|
30
|
-
* at the first rung that produces a verdict. Rung 3 (internal-audience-
|
|
31
|
-
* from-visibility) only applies when the requested audience is one the
|
|
32
|
-
* operator has declared internal — for any other (external) audience, rung
|
|
33
|
-
* 3 is skipped entirely and evaluation falls straight to rung 4's ASK, so an
|
|
34
|
-
* external verdict is never derived from visibility alone.
|
|
35
|
-
*/
|
|
36
|
-
export function evaluateDisclosure(config, note, audience) {
|
|
37
|
-
for (const wall of config.disclosure.hard_walls) {
|
|
38
|
-
if (matchesWall(wall, note, audience)) {
|
|
39
|
-
return { verdict: wall.verdict, rung: 'hard_wall' };
|
|
40
|
-
}
|
|
41
|
-
}
|
|
42
|
-
const tags = note.frontmatter?.[AUDIENCE_FIELD_KEY];
|
|
43
|
-
if (Array.isArray(tags) && tags.includes(audience)) {
|
|
44
|
-
return { verdict: 'allow', rung: 'explicit_tag' };
|
|
45
|
-
}
|
|
46
|
-
if (config.disclosure.internal_audiences.includes(audience)) {
|
|
47
|
-
const resolved = resolveVisibility(config, note);
|
|
48
|
-
return { verdict: canSee(config, audience, resolved.value) ? 'allow' : 'deny', rung: 'internal_visibility' };
|
|
49
|
-
}
|
|
50
|
-
return { verdict: 'ask', rung: 'external_default' };
|
|
51
|
-
}
|
|
52
|
-
/** disclosure-policy spec: most-restrictive-member ordering, defined once for reuse by any caller batching verdicts across a set of notes. */
|
|
53
|
-
const VERDICT_RESTRICTIVENESS = { deny: 2, ask: 1, allow: 0 };
|
|
54
|
-
/**
|
|
55
|
-
* disclosure-policy spec: a set of verdicts aggregates to its most
|
|
56
|
-
* restrictive member — DENY outranks ASK, which outranks ALLOW. An empty
|
|
57
|
-
* set aggregates to ALLOW; callers that need to distinguish "nothing was
|
|
58
|
-
* evaluated" from "everything was evaluated and allowed" report the set's
|
|
59
|
-
* size separately, per the publish spec's empty-set scenario.
|
|
60
|
-
*/
|
|
61
|
-
export function worstVerdict(verdicts) {
|
|
62
|
-
let worst = 'allow';
|
|
63
|
-
for (const verdict of verdicts) {
|
|
64
|
-
if (VERDICT_RESTRICTIVENESS[verdict] > VERDICT_RESTRICTIVENESS[worst])
|
|
65
|
-
worst = verdict;
|
|
66
|
-
}
|
|
67
|
-
return worst;
|
|
68
|
-
}
|
|
69
|
-
//# sourceMappingURL=model.js.map
|
|
@@ -1 +0,0 @@
|
|
|
1
|
-
{"version":3,"file":"model.js","sourceRoot":"","sources":["../../../src/core/disclosure/model.ts"],"names":[],"mappings":"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"}
|