@neurodock/core 0.0.1 → 0.2.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.
Files changed (57) hide show
  1. package/LICENSE +657 -7
  2. package/README.md +50 -3
  3. package/data/neurotype-addenda/v1.json +389 -0
  4. package/dist/index.d.ts +5 -0
  5. package/dist/index.d.ts.map +1 -0
  6. package/dist/index.js +7 -0
  7. package/dist/index.js.map +1 -0
  8. package/dist/index.test.d.ts +2 -0
  9. package/dist/index.test.d.ts.map +1 -0
  10. package/dist/index.test.js +29 -0
  11. package/dist/index.test.js.map +1 -0
  12. package/dist/neurotype-addenda.d.ts +91 -0
  13. package/dist/neurotype-addenda.d.ts.map +1 -0
  14. package/dist/neurotype-addenda.js +175 -0
  15. package/dist/neurotype-addenda.js.map +1 -0
  16. package/dist/neurotype-addenda.parity.test.d.ts +2 -0
  17. package/dist/neurotype-addenda.parity.test.d.ts.map +1 -0
  18. package/dist/neurotype-addenda.parity.test.js +69 -0
  19. package/dist/neurotype-addenda.parity.test.js.map +1 -0
  20. package/dist/neurotype-addenda.schema.test.d.ts +2 -0
  21. package/dist/neurotype-addenda.schema.test.d.ts.map +1 -0
  22. package/dist/neurotype-addenda.schema.test.js +83 -0
  23. package/dist/neurotype-addenda.schema.test.js.map +1 -0
  24. package/dist/neurotype-addenda.test.d.ts +2 -0
  25. package/dist/neurotype-addenda.test.d.ts.map +1 -0
  26. package/dist/neurotype-addenda.test.js +165 -0
  27. package/dist/neurotype-addenda.test.js.map +1 -0
  28. package/dist/profile.d.ts +128 -0
  29. package/dist/profile.d.ts.map +1 -0
  30. package/dist/profile.js +27 -0
  31. package/dist/profile.js.map +1 -0
  32. package/dist/profile.presets.test.d.ts +2 -0
  33. package/dist/profile.presets.test.d.ts.map +1 -0
  34. package/dist/profile.presets.test.js +43 -0
  35. package/dist/profile.presets.test.js.map +1 -0
  36. package/dist/profile.schema.test.d.ts +2 -0
  37. package/dist/profile.schema.test.d.ts.map +1 -0
  38. package/dist/profile.schema.test.js +282 -0
  39. package/dist/profile.schema.test.js.map +1 -0
  40. package/dist/profile.test.d.ts +2 -0
  41. package/dist/profile.test.d.ts.map +1 -0
  42. package/dist/profile.test.js +60 -0
  43. package/dist/profile.test.js.map +1 -0
  44. package/dist/test-helpers/ajv.d.ts +22 -0
  45. package/dist/test-helpers/ajv.d.ts.map +1 -0
  46. package/dist/test-helpers/ajv.js +38 -0
  47. package/dist/test-helpers/ajv.js.map +1 -0
  48. package/package.json +16 -9
  49. package/schemas/neurotype-addenda.schema.json +167 -0
  50. package/schemas/plugin.example.yaml +116 -71
  51. package/schemas/plugin.minimal.yaml +18 -12
  52. package/schemas/plugin.schema.json +13 -2
  53. package/schemas/profile.example.yaml +112 -64
  54. package/schemas/profile.minimal.yaml +15 -7
  55. package/schemas/profile.schema.json +116 -0
  56. package/src/index.test.ts +0 -8
  57. package/src/index.ts +0 -1
@@ -1,112 +1,160 @@
1
- # NeuroDock Profile — worked example ("T" profile from plan.md §6)
1
+ # ==============================================================================
2
+ # WELCOME TO YOUR NEURODOCK PROFILE
3
+ # ==============================================================================
4
+ # Think of this as a quick instruction manual to teach the app how your brain works.
2
5
  #
3
- # This file is the template copied to ~/.neurodock/profile.yaml by
4
- # `npx neurodock init`. Every block except `identity` is optional and
5
- # falls back to the safe defaults documented in profile.schema.json.
6
+ # TIPS FOR FILLING THIS OUT:
7
+ # - Take your time. You don't have to finish it all at once.
8
+ # - Almost everything is OPTIONAL. If you aren't sure, just leave it as is.
9
+ # - Your data is safe. Nothing leaves your computer without your permission.
10
+ # - You can always come back and change these later. You can't break anything.
6
11
  #
7
- # Loader precedence (highest wins):
8
- # 1. $NEURODOCK_PROFILE_PATH (testing override)
9
- # 2. $XDG_CONFIG_HOME/neurodock/profile.yaml
10
- # 3. ~/.neurodock/profile.yaml (default)
11
- # 4. ./profile.yaml (project-local override)
12
+ # Where does this file live?
13
+ # ~/.neurodock/profile.yaml (your machine, your private copy)
12
14
  #
13
- # Forward-compatibility: unknown keys at any level are preserved by
14
- # loaders, not stripped. A v0.1.0 install can round-trip a v0.2.0
15
- # profile without data loss. Run `neurodock profile validate` to catch
16
- # typos that permissive parsing would otherwise swallow.
17
-
18
- # Optional. Declares which schema version this file targets. Loaders
19
- # accept any version; they only warn when the file is newer than they
20
- # understand.
15
+ # How to check it's valid after editing:
16
+ # neurodock profile validate
17
+ # ==============================================================================
18
+
19
+ # Leave this exactly as "0.1.0". It just helps the app read this file.
21
20
  schema_version: "0.1.0"
22
21
 
23
- # Required. Self-declared identity. No PII is required.
22
+ # ------------------------------------------------------------------------------
23
+ # 1. WHO YOU ARE (Required)
24
+ # ------------------------------------------------------------------------------
24
25
  identity:
25
- # How NeuroDock addresses you. Free-form; one letter is fine.
26
+ # What should we call you? A nickname or even just a single letter is totally fine.
26
27
  display_name: "T"
27
28
 
28
- # Self-identified neurotypes. Self-ID is sufficient — diagnosis is
29
- # never required and is never used to gate features. Skills targeted
30
- # at a neurotype activate when the tag appears here.
29
+ # Which of these describe you?
30
+ # Self-ID is enough you do NOT need a diagnosis to use any feature.
31
+ # Skills targeted at a neurotype activate when the tag appears here.
31
32
  # Allowed: adhd | asd | audhd | ocd | dyslexia | dyspraxia | tourette | other
32
33
  neurotypes:
33
34
  - "adhd"
34
35
  - "asd"
35
36
 
36
- # Optional free-form notes. Surfaced only when a skill explicitly
37
- # asks; never logged or transmitted.
37
+ # Is there anything else you want the app to know about how to talk to you?
38
+ # (For example: "I get overwhelmed by long paragraphs" or "Please be direct".)
39
+ # Only surfaced when a skill explicitly asks; never logged or transmitted.
38
40
  # additional_notes: "sensory-sensitive to motion; prefers terse output"
39
41
 
40
- # Optional. Output and reading preferences.
42
+ # ------------------------------------------------------------------------------
43
+ # 2. HOW YOU LIKE TO READ & WORK (Optional)
44
+ # ------------------------------------------------------------------------------
41
45
  preferences:
42
- # answer_first | conventional | bullet_first (default: answer_first)
46
+ # How do you want the AI to structure its answers?
47
+ # Options:
48
+ # answer_first — verdict first, reasoning after. Good for ADHD triage.
49
+ # conventional — explanation first, then verdict.
50
+ # bullet_first — verdict as a bullet list.
43
51
  output_format: "answer_first"
44
52
 
45
- # Max items in any list/group/step sequence. 1..20. Default 7
46
- # (Miller's-number neighbourhood); 5 is the ADHD-tuned manifesto value.
53
+ # Max items shown in any list / group / step sequence.
54
+ # Range 1..20. Default 7 (Miller's number).
55
+ # 5 is the ADHD-tuned manifesto value — change to your comfort.
47
56
  max_chunk_size: 5
48
57
 
49
- # atkinson_hyperlegible | lexend | system_default
50
- # Default: atkinson_hyperlegible (evidence-based for dyslexia).
51
- # 'lexend' is evidence-based for ADHD readability.
58
+ # Which font style is easiest for your eyes?
59
+ # Options:
60
+ # atkinson_hyperlegible — evidence-based for dyslexia (default)
61
+ # lexend — evidence-based for ADHD readability
62
+ # system_default — your OS choice
52
63
  reading_font_hint: "atkinson_hyperlegible"
53
64
 
54
- # reduced | system | full (default: reduced)
55
- # 'reduced' disables animation/transitions; 'system' follows the OS
56
- # prefers-reduced-motion setting.
65
+ # How much space do you want between lines of text?
66
+ # This is a hint for apps that show NeuroDock's output as styled text.
67
+ # Options:
68
+ # compact — lines sit closer together (more text fits on screen)
69
+ # default — the app's own everyday spacing
70
+ # relaxed — extra space between lines; pairs with atkinson_hyperlegible
71
+ # Leave it out and the app just uses its own spacing.
72
+ line_height_hint: "relaxed"
73
+
74
+ # Do you want visual animations turned on?
75
+ # Options:
76
+ # reduced — no animations (default; safest for vestibular sensitivity)
77
+ # system — match your OS prefers-reduced-motion setting
78
+ # full — animations on
57
79
  motion: "reduced"
58
80
 
59
- # Optional. Thresholds consumed by mcp-chronometric.
81
+ # ------------------------------------------------------------------------------
82
+ # 3. TIME & FOCUS ALERTS (Optional)
83
+ # ------------------------------------------------------------------------------
84
+ # Helps if you tend to hyperfocus or lose track of time.
60
85
  chronometric:
61
- # Continuous-session length, in minutes, at which the hyperfocus
62
- # nudge fires. 15..240. Default 90. The 60/+30/+60 escalation ladder
63
- # shape itself is fixed in v0.1.0; this only re-anchors the 'nudge' rung.
86
+ # How many minutes of straight work before we gently remind you to take a break?
87
+ # Range 15..240. Default 90.
88
+ # The 60/+30/+60 escalation ladder shape itself is fixed; this only
89
+ # re-anchors the 'nudge' rung in the ladder.
64
90
  hyperfocus_break_minutes: 90
65
91
 
66
- # Optional. Your self-declared end-of-day time, local clock, 24h.
67
- # When present, the hyperfocus monitor uses this for the
68
- # "after end_of_day" nudge.
92
+ # What time do you want to officially "clock out" for the day?
93
+ # 24-hour clock (e.g. "18:30" for 6:30 PM, "22:00" for 10 PM).
94
+ # When set, the hyperfocus nudge gets stricter after this time.
69
95
  end_of_day_local: "18:30"
70
96
 
71
- # Optional override of the energy_zone clock-band heuristic from
72
- # ADR 0001. Omit unless you want to redraw your own bands.
97
+ # (Advanced) Re-draw your personal energy bands during the day.
98
+ # Leave commented out unless you specifically want to override
99
+ # the default clock-band heuristic.
73
100
  # zones:
74
101
  # morning_peak: "06:00-10:30"
75
102
  # afternoon_dip: "14:00-16:00"
76
103
 
77
- # auto_close | error (default: auto_close)
78
- # What mark_session_start does when a prior session is still open.
79
- # 'auto_close' is charitable to forgotten sessions; the closed
80
- # session metadata is returned so the skill can surface it.
104
+ # What should the app do if you start a new work session but forgot
105
+ # to close your last one?
106
+ # Options:
107
+ # auto_close — safely closes the old one for you (default, charitable)
108
+ # error — stops and tells you the old session is still open
81
109
  session_overlap_policy: "auto_close"
82
110
 
83
- # Optional. Thresholds for mcp-guardrail detectors. Heuristics are
84
- # public and auditable per ETHICS; detection never blocks silently.
111
+ # ------------------------------------------------------------------------------
112
+ # 4. GENTLE NUDGES (Optional)
113
+ # ------------------------------------------------------------------------------
114
+ # Helps the app notice if you are getting stuck in a loop or overthinking.
115
+ # Heuristics are public and auditable in ETHICS.md; detection never blocks
116
+ # silently.
85
117
  guardrails:
86
- # Number of semantically-equivalent queries in the window that
87
- # triggers the rumination signal. 1..20. Default 3.
118
+ # How many semantically-similar questions in the window before we gently
119
+ # check in on you?
120
+ # Range 1..20. Default 3.
88
121
  rumination_threshold: 3
89
122
 
90
- # Rolling window in minutes for rumination counting. 5..1440.
91
- # Default 90.
123
+ # Over how many minutes do we count those repeated questions?
124
+ # Range 5..1440. Default 90.
92
125
  rumination_window_minutes: 90
93
126
 
94
- # off | warn | refuse (default: warn)
127
+ # Should we warn you if the AI is just agreeing with you too much instead
128
+ # of being helpful?
129
+ # Options:
130
+ # off — never flag sycophancy
131
+ # warn — flag it, you decide (default)
132
+ # refuse — refuse to send the over-validating draft
95
133
  sycophancy_check: "warn"
96
134
 
97
- # Optional. Consent and data-flow. Defaults are local-first; nothing
98
- # leaves your machine without an explicit opt-in here.
135
+ # ------------------------------------------------------------------------------
136
+ # 5. PRIVACY (Optional)
137
+ # ------------------------------------------------------------------------------
138
+ # You are in complete control. By default, everything stays on your computer.
99
139
  privacy:
100
- # local | cloud_voyage | cloud_openai (default: local)
101
- # Cloud options trigger a visible "cloud embeddings enabled" notice
102
- # at session start.
140
+ # Where should the cognitive-graph compute embeddings (for fuzzy recall)?
141
+ # Options:
142
+ # local — on your machine (default; uses fastembed)
143
+ # cloud_voyage — Voyage AI (opt-in; triggers a visible "cloud" notice)
144
+ # cloud_openai — OpenAI embeddings (opt-in)
103
145
  embeddings: "local"
104
146
 
105
- # off | local_otel_only | full (default: off)
106
- # 'full' is reserved in v0.1.0; do not use until a future ADR lands.
147
+ # Do you want to send anonymous crash/bug reports to help improve the app?
148
+ # Options:
149
+ # off — nothing collected (default)
150
+ # local_otel_only — local-only OpenTelemetry traces; nothing leaves
151
+ # full — reserved for a future ADR; do not use yet
107
152
  telemetry: "off"
108
153
 
109
- # Consent for mcp-chronometric.idle_status to read OS idle time.
110
- # When false (default), idle_status returns consent_granted=false
111
- # and hyperfocus_signal=unknown without error.
154
+ # Can the app check if your computer mouse/keyboard has been completely
155
+ # still? This helps it automatically pause your focus timers if you walk
156
+ # away from your desk.
157
+ # Options:
158
+ # false — no (default; idle_status returns consent_granted=false)
159
+ # true — yes, share OS idle time with the chronometric server
112
160
  os_idle_consent: false
@@ -1,10 +1,11 @@
1
- # NeuroDock Profile — minimal valid example.
1
+ # ==============================================================================
2
+ # YOUR NEURODOCK PROFILE — minimal starter
3
+ # ==============================================================================
4
+ # This is the smallest valid profile. The app fills in safe defaults for
5
+ # everything else. Open profile.example.yaml if you want to see all the
6
+ # knobs you CAN tune.
2
7
  #
3
- # Only `identity` is required. Every other top-level block is optional
4
- # and falls back to safe, lived-experience-led defaults applied by the
5
- # loader (see profile.schema.json for the per-field default).
6
- #
7
- # Defaults applied when the rest of this file is omitted:
8
+ # Safe defaults applied when you leave the other blocks out:
8
9
  # preferences.output_format = "answer_first"
9
10
  # preferences.max_chunk_size = 7
10
11
  # preferences.reading_font_hint = "atkinson_hyperlegible"
@@ -17,10 +18,17 @@
17
18
  # privacy.embeddings = "local"
18
19
  # privacy.telemetry = "off"
19
20
  # privacy.os_idle_consent = false
21
+ #
22
+ # To check it's valid after editing: neurodock profile validate
23
+ # ==============================================================================
20
24
 
21
25
  identity:
26
+ # What should we call you? A nickname or even just a single letter is fine.
22
27
  display_name: "your-name"
28
+
29
+ # Which of these describe you?
30
+ # Self-ID is enough — no diagnosis required.
23
31
  # Any subset of: adhd | asd | audhd | ocd | dyslexia | dyspraxia | tourette | other
24
- # Empty list ([]) is valid and opts out of neurotype-tagged skill activation.
32
+ # An empty list [] is valid and opts out of neurotype-tagged skill activation.
25
33
  neurotypes:
26
34
  - "adhd"
@@ -90,6 +90,17 @@
90
90
  "enum": ["reduced", "system", "full"],
91
91
  "default": "reduced",
92
92
  "description": "Animation policy hint. 'reduced' = no animation, no transitions, no auto-scroll (default). 'system' = follow the OS prefers-reduced-motion setting. 'full' = animations allowed."
93
+ },
94
+ "line_height_hint": {
95
+ "type": "string",
96
+ "enum": ["compact", "default", "relaxed"],
97
+ "description": "Optional (added v0.1.x per ADR 0011). Line-height hint for any client that renders NeuroDock output as HTML or rich text, sitting alongside 'reading_font_hint'. A categorical band rather than a raw multiplier so each client maps it to its own CSS line-height. CONFORMANCE FLOOR: clients MUST NOT render body-paragraph line spacing below 1.5 regardless of band (WCAG 1.4.8 Visual Presentation / 1.4.12 Text Spacing). The bands are advisory line-height ratios relative to font size for body paragraphs; headings and other non-body text MAY be tighter. Per-band anchors: 'compact' ≈ 1.5 — the floor itself, a power-user opt-in for more text per viewport that still respects the 1.5 minimum (for readers who find generous spacing scatters their eye-line and prefer denser text, the dual of why 'relaxed' exists); 'default' ≈ 1.5–1.6 — the client's own comfortable default within the conformant range; 'relaxed' ≈ 1.65–1.8 — generous line spacing (~1.65 is the project body line-height) and the evidence-based pairing with 'atkinson_hyperlegible' for dyslexia, which is why dyslexia-aware presets set it. Read-when-present, neutral-when-absent: an untailored client ignores it; absence is NOT an error. The loader applies no value when absent. Self-ID never gates this (ADR 0004/0011).",
98
+ "examples": ["relaxed", "default"]
99
+ },
100
+ "voice_input_preferred": {
101
+ "type": "boolean",
102
+ "description": "Optional (added v0.1.x per ADR 0011). When true, the user predominantly dictates rather than types for sustained work (common for dyspraxic users). Downstream skills that emit code or structured text MUST NOT assume the user can hand-edit fiddly punctuation cheaply: keep examples copy-pasteable as a single block rather than scattered across inline edits. Read by the shaping layer; absence means 'no preference' and is the same as today's behaviour. Consumer pending; schema-only in this release.",
103
+ "examples": [true]
93
104
  }
94
105
  }
95
106
  },
@@ -121,6 +132,62 @@
121
132
  "enum": ["auto_close", "error"],
122
133
  "default": "auto_close",
123
134
  "description": "Behaviour of mark_session_start when a prior session is still open. 'auto_close' (default, charitable) closes the prior session and returns its metadata so the skill can surface it. 'error' refuses to start a new session until the prior one is explicitly closed. See ADR 0001, open question 3."
135
+ },
136
+ "calendar_phase": {
137
+ "type": "string",
138
+ "enum": ["teaching", "marking", "exam", "deadlines", "break"],
139
+ "description": "Optional (added v0.1.x per ADR 0011). Self-declared phase of the user's term/semester so skills can shift defaults across the calendar: tighter break cadence during 'marking' / 'exam', deadline-cluster awareness during 'deadlines' (e.g. week 12), looser during 'break'. Surfaced by the educator-semester and student-university presets. The neurotype is never a branch point (ADR 0004/0011); this is a user input the shaping layer reads, neutral-when-absent. Consumer pending (mcp-chronometric); schema-only in this release.",
140
+ "examples": ["teaching", "marking"]
141
+ },
142
+ "weekday_overrides": {
143
+ "type": "object",
144
+ "description": "Optional (added v0.1.x per ADR 0011). Per-weekday overrides for 'end_of_day_local' and 'hyperfocus_break_minutes', covering late-office-hours, Wednesday-afternoon-class, and library-day-vs-lecture-day patterns without forcing a whole-profile swap. Keys are lowercase English weekday names; only the seven weekdays are accepted (a misspelt key is a silent no-op, so unknown keys are rejected here rather than preserved). Each value is an override object reusing the same patterns/ranges as the top-level chronometric fields; an empty override object is valid. A weekday absent from the map inherits the top-level chronometric values. Consumer pending (mcp-chronometric); schema-only in this release.",
145
+ "additionalProperties": false,
146
+ "properties": {
147
+ "monday": { "$ref": "#/$defs/weekdayOverride" },
148
+ "tuesday": { "$ref": "#/$defs/weekdayOverride" },
149
+ "wednesday": { "$ref": "#/$defs/weekdayOverride" },
150
+ "thursday": { "$ref": "#/$defs/weekdayOverride" },
151
+ "friday": { "$ref": "#/$defs/weekdayOverride" },
152
+ "saturday": { "$ref": "#/$defs/weekdayOverride" },
153
+ "sunday": { "$ref": "#/$defs/weekdayOverride" }
154
+ },
155
+ "examples": [
156
+ {
157
+ "wednesday": { "end_of_day_local": "18:30" },
158
+ "saturday": { "hyperfocus_break_minutes": 120 }
159
+ }
160
+ ]
161
+ },
162
+ "protected_windows": {
163
+ "type": "array",
164
+ "description": "Optional (added v0.1.x per ADR 0011). Local-time ranges (lunch, post-EOD evening, scheduled lectures, lab times) where the hyperfocus monitor should HARD-SURFACE rather than nudge — the strict rung of the escalation ladder, applied because the window itself is protected, not because a session has run long. Each entry is a 'HH:MM'-'HH:MM' range with an optional human label; ranges are interpreted in the user's local timezone and a range whose 'end' is earlier than its 'start' is treated as wrapping past midnight by the consumer. An empty list is valid. Consumer pending (mcp-chronometric); schema-only in this release.",
165
+ "items": { "$ref": "#/$defs/protectedWindow" },
166
+ "examples": [
167
+ [
168
+ { "start": "12:00", "end": "12:30", "label": "lunch" },
169
+ { "start": "17:00", "end": "23:59", "label": "evening" }
170
+ ]
171
+ ]
172
+ },
173
+ "deadline_cluster_awareness": {
174
+ "type": "boolean",
175
+ "description": "Optional (added v0.1.x per ADR 0011). When true, planning skills surface deadline proximity and shift the break-cadence math when work clusters (e.g. three assignments due in a single week). Set by the student-university preset. Read by planning skills; absence means today's behaviour (no clustering adjustment). Consumer pending (task-fractionator); schema-only in this release.",
176
+ "examples": [true]
177
+ },
178
+ "time_buffer_multiplier": {
179
+ "type": "number",
180
+ "minimum": 1.0,
181
+ "maximum": 3.0,
182
+ "default": 1.0,
183
+ "description": "Optional (added v0.1.x per ADR 0011). Multiplier that pads presented time estimates because real-world execution time for motor-heavy tasks is systematically underestimated (e.g. 1.3 = +30%, the value the dyspraxia preset sets). Range 1.0..3.0; the neutral default 1.0 reproduces today's unpadded behaviour so an untouched profile is unchanged. Read by planning skills to scale the estimates they present; the underlying estimate is not altered. Consumer pending (task-fractionator); schema-only in this release.",
184
+ "examples": [1.0, 1.3]
185
+ },
186
+ "motor_fatigue_aware": {
187
+ "type": "boolean",
188
+ "default": false,
189
+ "description": "Optional (added v0.1.x per ADR 0011). When true, the hyperfocus monitor weights motor activity (click / keystroke / window-switch volume) into the fatigue signal rather than relying on continuous-session length alone — cognitive sharpness and motor exhaustion can coexist (set by the dyspraxia preset). The neutral default false reproduces today's session-length-only behaviour. Reading motor activity is still gated by 'privacy.os_idle_consent' and the relevant OS-input consents; this flag only declares the preference. Consumer pending (mcp-chronometric); schema-only in this release.",
190
+ "examples": [true]
124
191
  }
125
192
  }
126
193
  },
@@ -176,6 +243,55 @@
176
243
  }
177
244
  }
178
245
  },
246
+ "$defs": {
247
+ "weekdayOverride": {
248
+ "type": "object",
249
+ "description": "Per-weekday override for the chronometric fields that vary by day. Both members are optional and reuse the same validation as their top-level counterparts; an empty object means 'this weekday is named but inherits the top-level values'. additionalProperties is false because an unknown key here is almost always a typo that would silently do nothing.",
250
+ "additionalProperties": false,
251
+ "properties": {
252
+ "end_of_day_local": {
253
+ "type": "string",
254
+ "pattern": "^([01][0-9]|2[0-3]):[0-5][0-9]$",
255
+ "description": "Override of 'chronometric.end_of_day_local' for this weekday, as 'HH:MM' (24h) in the user's local timezone. Same pattern as the top-level field.",
256
+ "examples": ["17:00", "18:30"]
257
+ },
258
+ "hyperfocus_break_minutes": {
259
+ "type": "integer",
260
+ "minimum": 15,
261
+ "maximum": 240,
262
+ "description": "Override of 'chronometric.hyperfocus_break_minutes' for this weekday. Same 15..240 range as the top-level field; re-anchors the 'nudge' rung for this day only.",
263
+ "examples": [60, 120]
264
+ }
265
+ }
266
+ },
267
+ "protectedWindow": {
268
+ "type": "object",
269
+ "description": "A single local-time range where the hyperfocus monitor hard-surfaces. 'start' and 'end' are required 'HH:MM' (24h) strings; 'label' is an optional human-readable name. additionalProperties is false to catch typos in this small, fixed shape.",
270
+ "additionalProperties": false,
271
+ "required": ["start", "end"],
272
+ "properties": {
273
+ "start": {
274
+ "type": "string",
275
+ "pattern": "^([01][0-9]|2[0-3]):[0-5][0-9]$",
276
+ "description": "Window start, 'HH:MM' (24h), local timezone.",
277
+ "examples": ["12:00", "17:00"]
278
+ },
279
+ "end": {
280
+ "type": "string",
281
+ "pattern": "^([01][0-9]|2[0-3]):[0-5][0-9]$",
282
+ "description": "Window end, 'HH:MM' (24h), local timezone. An 'end' earlier than 'start' is treated by the consumer as wrapping past midnight.",
283
+ "examples": ["12:30", "23:59"]
284
+ },
285
+ "label": {
286
+ "type": "string",
287
+ "minLength": 1,
288
+ "maxLength": 80,
289
+ "description": "Optional human-readable label for the window, surfaced in any notice the monitor emits.",
290
+ "examples": ["lunch", "evening", "lecture"]
291
+ }
292
+ }
293
+ }
294
+ },
179
295
  "examples": [
180
296
  {
181
297
  "identity": {
package/src/index.test.ts DELETED
@@ -1,8 +0,0 @@
1
- import { describe, expect, test } from "vitest";
2
- import { version } from "./index";
3
-
4
- describe("@neurodock/core", () => {
5
- test("exports a version constant", () => {
6
- expect(version).toBe("0.0.0");
7
- });
8
- });
package/src/index.ts DELETED
@@ -1 +0,0 @@
1
- export const version = "0.0.0";