@stravica-ai/digital-operator-pa 0.1.35 → 0.1.36

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.
@@ -21,7 +21,10 @@ Implemented: `generate`, `generate --dry-run`, `--help`.
21
21
  Bundled templates:
22
22
 
23
23
  - `dave-boot` — the original use case. Six-section operator-boot card aimed
24
- at single-operator PA instances like Dave.
24
+ at single-operator PA instances like Dave. Sections: Operator basics,
25
+ Mission framing, Active relationships, Operational constraints, Tools at
26
+ your disposal, Live state. Post-generate lint enforces the 2026-09-03
27
+ contract (w-2026-07-15-012 / w-2026-09-04-dave-003).
25
28
 
26
29
  Custom templates are loaded with `--template <path>`.
27
30
 
@@ -59,14 +62,26 @@ Optional inputs:
59
62
  with `shell: false` — no shell interpolation, the inputs are safe even if
60
63
  they contain shell metacharacters.
61
64
  4. Validate the response against the required-headers contract (six
62
- sections: Operator basics, Mission framing, Active projects, Active
63
- relationships, Load-bearing rules right now, State of play). A response
65
+ sections: Operator basics, Mission framing, Active relationships,
66
+ Operational constraints, Tools at your disposal, Live state). A response
64
67
  missing any required header is treated as a generator failure (exit 2)
65
- and no file is written.
68
+ and no file is written. The 2026-09-03 rewrite (w-2026-07-15-012)
69
+ retired the Active projects and Load-bearing rules sections: live boot
70
+ state is injected by the `boot-context` hook, and operational rules live
71
+ in `operator/knowledge/operator-interface/operational-constraints.md`.
66
72
  5. Validate the size against the 2 KB soft budget. Over-budget responses
67
- produce a stderr warning but are written anyway — better to ship a 3 KB
68
- slice than skip a regeneration.
69
- 6. Write the response to the configured `--output` path. Parent directories
73
+ produce a stderr warning; the slice is still written when the byte
74
+ count sits inside the lint hard ceiling (`SIZE_LINT_HARD_BYTES`, 3000
75
+ B). Above that ceiling the post-generate lint refuses the write.
76
+ 6. Run the template-specific post-generate lint (dave-boot: names the
77
+ platform package `@stravica-ai/digital-operator-pa`, points at the
78
+ constraints doc, carries no `## Active projects` or `## In-flight work`
79
+ block, size within the hard ceiling). A lint failure refuses the write
80
+ with exit 2 so a defective regeneration cannot clobber the good slice
81
+ in place. Pass `--no-lint` to bypass. Custom templates loaded with
82
+ `--template <path>` have no template-specific checks and always
83
+ proceed to write. w-2026-09-04-dave-003.
84
+ 7. Write the response to the configured `--output` path. Parent directories
70
85
  are created if missing.
71
86
 
72
87
  #### Flags
@@ -80,6 +95,8 @@ Optional inputs:
80
95
  this file. Default-off. See **Audit log** below.
81
96
  - `--dry-run` Build the prompt and report; skip the claude
82
97
  call and the file write.
98
+ - `--no-lint` Bypass the post-generate template-specific
99
+ lint. See step 6 above.
83
100
  - `-h`, `--help` Show usage.
84
101
 
85
102
  ### Exit codes
@@ -105,6 +122,9 @@ Status vocabulary (closed):
105
122
  - `noop-dry-run` — `--dry-run` path; no claude call, no file write.
106
123
  - `fail-claude` — claude exited non-zero (transport failure, exit 3).
107
124
  - `fail-validation` — claude returned content missing required headers (exit 2).
125
+ - `fail-lint`: post-generate template lint refused the write (exit 2). The
126
+ regeneration was blocked from clobbering the good slice in place.
127
+ w-2026-09-04-dave-003.
108
128
  - `fail-prereq` — input loading failed (missing profile / observations / template, exit 2).
109
129
  - `fail-write` — writing the slice output file failed (permissions, ENOSPC, etc., exit 2).
110
130
  - `fail-usage` — early arg-validation failed (missing required option, exit 1).
@@ -134,8 +154,9 @@ A single markdown file at the `--output` path. Plain markdown, no
134
154
  front-matter, no JSON envelope. The PA's boot rule reads it the same way it
135
155
  reads the full profile.
136
156
 
137
- Soft target: under 2 KB / ~30 lines. Hard requirement: the six section
138
- headers must be present.
157
+ Soft target: under 2 KB / ~30 lines. Hard requirements: the six section
158
+ headers must be present, and (for the bundled `dave-boot` template) the
159
+ post-generate lint contract in step 6.
139
160
 
140
161
  ## Design notes
141
162
 
@@ -33,6 +33,16 @@ Options for "generate":
33
33
  slice runs on a schedule, point this at a
34
34
  per-task runs.jsonl. Optional.
35
35
  --dry-run Build the prompt and report; skip claude call + write.
36
+ --no-lint Bypass the post-generate template-specific lint.
37
+ The lint refuses to write a slice that fails the
38
+ template's contract checks (dave-boot: names the
39
+ platform package, points at the constraints doc,
40
+ no baked in-flight state, size within ceiling).
41
+ The scheduled nightly leaves this OFF so a
42
+ defective regeneration cannot clobber the good
43
+ slice; hand-invocations may pass it when the
44
+ checks are known to be wrong for the current
45
+ contract.
36
46
  -h, --help Show this help.
37
47
 
38
48
  Exit codes:
@@ -89,6 +99,7 @@ async function route(argv, { stderr, stdout, exit }) {
89
99
  template: { type: 'string' },
90
100
  'runs-log': { type: 'string' },
91
101
  'dry-run': { type: 'boolean', default: false },
102
+ 'no-lint': { type: 'boolean', default: false },
92
103
  help: { type: 'boolean', short: 'h', default: false },
93
104
  },
94
105
  strict: true,
@@ -126,6 +137,7 @@ async function route(argv, { stderr, stdout, exit }) {
126
137
  outputPath: values.output,
127
138
  runsLog: values['runs-log'],
128
139
  dryRun: values['dry-run'],
140
+ noLint: values['no-lint'],
129
141
  runner: defaultRunner,
130
142
  stderr,
131
143
  });
@@ -1,33 +1,32 @@
1
- You are operating as a compression assistant. Your job is to produce a compact "boot slice" of the operator's profile — a short markdown document that loads into the PA's context at every session start, in place of the full profile.
1
+ You are operating as a compression assistant. Your job is to produce a compact "boot slice" of the operator's profile: a short markdown document that loads into the PA's context at every session start, in place of the full profile.
2
2
 
3
3
  The full profile is the source of truth. This slice is a fresh snapshot, regenerated periodically. Stale content in the slice is acceptable for ~24 hours.
4
4
 
5
5
  ## What the slice is for
6
6
 
7
- When the PA boots, it needs to know — in roughly 1–2 KB of context — *who it is working for*. Not every preference, not every historical decision, not every technical opinion. Just enough that:
7
+ When the PA boots, it needs to know, in roughly 1 to 2 KB of context, *who it is working for*. Not every preference, not every historical decision, not every technical opinion. Just enough that:
8
8
 
9
9
  - It addresses the operator correctly (name, register, tone).
10
10
  - It knows the operator's mission framing this year.
11
- - It knows what's in flight right now (active projects, active relationships).
11
+ - It knows the standing relationships that carry across sessions.
12
12
  - It is aware of the tools and capabilities already built and available.
13
- - It avoids the highest-cost mistakes (5–10 most load-bearing recent corrections / rules).
14
- - It can read the rest of the profile or knowledge base when it needs detail.
13
+ - It picks up operational constraints from the canonical constraints doc, not from a stale slice copy.
15
14
 
16
- This is a navigation card, not the territory. **Prefer pointers to canonical sources over baked-in content** that will go stale between regenerations.
15
+ This is a navigation card, not the territory. **Prefer pointers to canonical sources over baked-in content** that will go stale between regenerations. Live boot state (active projects, in-flight work) is injected by the `boot-context` hook at session start, so the slice must NOT carry that state.
17
16
 
18
17
  ## Inputs you have
19
18
 
20
19
  You are given:
21
20
 
22
- 1. **The full operator profile** (`profile.md`) — the source of truth, ~18 KB.
23
- 2. **Recent corrections / load-bearing rules** (optional, `learned-rules.md`) — ~50 KB of operational rules accumulated from corrections.
24
- 3. **Recent observations** (optional) — a concatenated dump of raw observation files filed in the last 2–4 weeks, useful for "what's been on his mind lately" but not authoritative.
21
+ 1. **The full operator profile** (`profile.md`): the source of truth, ~18 KB.
22
+ 2. **Recent corrections / load-bearing rules** (optional, `learned-rules.md`): ~50 KB of operational rules accumulated from corrections. Use only to inform vocabulary and register; do NOT bake rules into the slice.
23
+ 3. **Recent observations** (optional): a concatenated dump of raw observation files filed in the last 2 to 4 weeks, useful for "what's been on his mind lately" but not authoritative.
25
24
 
26
- Treat the profile as authoritative. Treat learned-rules as second-tier authoritative (they ARE rules). Treat observations as raw signal — synthesise, do not quote.
25
+ Treat the profile as authoritative. Treat learned-rules as second-tier authoritative (they ARE rules, but they live in their own file: do not re-state them here). Treat observations as raw signal: synthesise, do not quote.
27
26
 
28
27
  ## Output structure
29
28
 
30
- Produce a markdown document with exactly these seven sections, in this order:
29
+ Produce a markdown document with exactly these six sections, in this order:
31
30
 
32
31
  ```
33
32
  # Operator Boot Slice -- <Operator Name>
@@ -35,56 +34,59 @@ Produce a markdown document with exactly these seven sections, in this order:
35
34
  _Generated <ISO timestamp>. Refreshed periodically. Source of truth: operator/profile/profile.md._
36
35
 
37
36
  ## Operator basics
38
- <3-5 bullets: name, what they go by, communication register, tone preferences, sensitivities>
37
+ <3 to 5 bullets: name, what they go by, communication register, tone preferences, sensitivities>
39
38
 
40
39
  ## Mission framing
41
- <1-2 lines: the north-star / what we're building toward this year>
42
-
43
- ## Active projects
44
- <3-6 bullets, one line each: project name -- one-line status>
40
+ <1 to 2 lines: the north-star and what the operator is building toward this year. Name the PA platform's ship-vehicle plainly. The platform ships as `@stravica-ai/digital-operator-pa` on npm; if the profile confirms this, say so.>
45
41
 
46
42
  ## Active relationships
47
- <2-4 bullets, one line each: who -- relationship context>
43
+ <2 to 4 bullets, one line each: who -- relationship context. Standing relationships only, not one-off collaborations.>
44
+
45
+ ## Operational constraints (session-load)
46
+
47
+ Read `operator/knowledge/operator-interface/operational-constraints.md` on every boot. That doc carries network, infrastructure, tooling, estate and voice constraints and standing corrections. It is the one place these live; anything you find restated in this slice or in `profile.md` is a defect, escalate it under the routing rule in `operator/knowledge/knowledge-memory/share-scope-routing.md`.
48
48
 
49
49
  ## Tools at your disposal
50
- <2-3 lines: a one-line summary of the HQ-built operator-extension tools you have available (look for evidence of these in the inputs — names like wsd-ingest, dispatch, svc, monitoring, scheduled cron tasks, etc.), followed by a pointer line to the canonical list:>
51
- For the canonical inventory of operator-built tools and scheduled tasks, read `operator/knowledge/systems/operator-tools.md`.
52
50
 
53
- ## Load-bearing rules right now
54
- <5-10 bullets, one line each: most-cited or most-recent operational rules from learned-rules and the profile preferences section. Pick rules whose violation would be most costly>
51
+ <2 to 3 lines: a one-line summary of the platform bins (via `pnpm exec <bin>`; the platform ships as `@stravica-ai/digital-operator-pa`) and the HQ operator-extension tools available, followed by a pointer line:>
52
+ For the current tool surface each session, discover via `ls operator/extensions/tools/` and `pnpm exec pa --help`; never rely on memory.
53
+
54
+ ## Live state -- fetch on boot
55
55
 
56
- ## Live state — fetch on boot
57
- For current project and work-item state, run: `pnpm exec desk overview`.
58
- Do not bake state into this slice — it will be wrong by the time it is read.
56
+ For current projects and in-flight work items: `pnpm exec desk overview`.
57
+ For the last session's boundary notes: `agents/dave/next-session.md`.
58
+ For recent dispatches: tail `agents/dave/spawn-log.json`.
59
+ The `boot-context` hook injects a live `workState` block on session start; trust that first, hunt files only if the hook did not fire.
60
+ Do not bake state into this slice, it will be wrong by the time it is read.
59
61
  ```
60
62
 
61
- The last section is a **fixed instruction**, not generated content. Reproduce it verbatim. The whole point is to send the PA to the live tool for any state question rather than relying on a frozen snapshot.
63
+ The **Operational constraints** section and the **Live state** section are **fixed instructions**, not generated content. Reproduce them verbatim. The point is to send the PA to the canonical constraints doc for any operational rule, and to the live tools for any state question, rather than relying on a frozen snapshot.
62
64
 
63
65
  ## Budget
64
66
 
65
- **Soft target: under 2 KB total output.** Aim for ~1.2–1.8 KB. If you can't fit a section in the budget, prefer fewer items over shorter items — better to give 3 sharp project lines than 6 mushy ones. Over-budget is warned but not blocked; under-information is more costly.
67
+ **Soft target: under 2 KB total output.** Aim for ~1.2 to 1.8 KB. If a section will not fit in the budget, prefer fewer items over shorter items: better to give 3 sharp lines than 6 mushy ones. Over-budget is warned; under-information is more costly.
66
68
 
67
69
  ## Style
68
70
 
69
71
  - No emojis (the operator has a strict no-emoji rule for persisted artefacts).
70
- - No em-dashes — use double-hyphens (`--`) instead.
72
+ - No em-dashes anywhere. Use a comma, a full stop, or a colon. The double-hyphen `--` in the file title and the "Live state -- fetch on boot" heading is intentional and must be reproduced verbatim.
71
73
  - Use the operator's own vocabulary where you can pull it cleanly from the profile.
72
- - Don't editorialise. State, don't sell.
74
+ - Do not editorialise. State, do not sell.
73
75
  - "Operator" not "user". "PA" or the PA's name, not "the assistant".
74
76
 
75
77
  ## What NOT to include
76
78
 
77
- - Technical opinions (the full Technical Opinions section of profile.md).
79
+ - Technical opinions (the full Technical Opinions section of `profile.md`).
78
80
  - Historical decision patterns.
79
- - Communication-style examples that aren't load-bearing.
81
+ - A "Load-bearing rules" or "Active projects" or "In-flight work" block: the constraints doc and the `boot-context` hook cover those; a baked copy here goes stale within hours.
82
+ - Communication-style examples that are not load-bearing.
80
83
  - Anything the PA can look up at the moment it needs it (this is what the pointers are for).
81
- - A baked snapshot of project state — the Live-state section's pointer covers that.
82
84
 
83
- The test for "should this be in the slice": *if this is wrong or missing, will the PA make a costly mistake in its first 5 messages?* If yes, include it. If no, leave it out.
85
+ The test for "should this be in the slice": *if this is wrong or missing, will the PA make a costly mistake in its first 5 messages, AND is it something the constraints doc plus the boot-context hook cannot cover?* If yes to both, include it. If no, leave it out.
84
86
 
85
87
  ## Now produce the slice
86
88
 
87
- The inputs follow below. Read them, then produce the slice. Output ONLY the slice markdown — no preamble, no postscript, no explanation. Your entire response is what gets written to disk.
89
+ The inputs follow below. Read them, then produce the slice. Output ONLY the slice markdown: no preamble, no postscript, no explanation. Your entire response is what gets written to disk.
88
90
 
89
91
  ---
90
92
 
@@ -24,15 +24,114 @@ import { buildSlicePrompt, claudeArgs } from './prompt.mjs';
24
24
  const REQUIRED_HEADERS = [
25
25
  '## Operator basics',
26
26
  '## Mission framing',
27
- '## Active projects',
28
27
  '## Active relationships',
28
+ '## Operational constraints',
29
29
  '## Tools at your disposal',
30
- '## Load-bearing rules right now',
31
30
  '## Live state',
32
31
  ];
33
32
 
34
33
  const SIZE_BUDGET_BYTES = 2048;
35
34
 
35
+ // Post-generate lint (w-2026-09-04-dave-003). Runs after the required-header
36
+ // structural check and before the file write. Refuses to write on any hard
37
+ // failure so a defective regeneration cannot clobber the hand-rewritten slice
38
+ // in place (the safe fallback). `--no-lint` bypasses.
39
+ //
40
+ // Checks are per-template. The dave-boot slice contract (2026-09-03 rewrite,
41
+ // w-2026-07-15-012) requires:
42
+ // 1. Names the platform package `@stravica-ai/digital-operator-pa` (the
43
+ // slice must not describe the platform without naming it).
44
+ // 2. Points at the operational-constraints doc rather than restating rules
45
+ // inline (constraints live in exactly one place).
46
+ // 3. Carries NO "## Active projects" or "## In-flight work" block: live
47
+ // boot state is injected by the boot-context hook, not baked in.
48
+ // 4. Stays inside the byte budget. Budget is soft (SIZE_BUDGET_BYTES,
49
+ // 2048) with a hard ceiling that refuses the write on defective
50
+ // regenerations. The hand-rewritten reference is 2888 B; the current
51
+ // pre-rewrite nightly is 3291 B; the ceiling sits between them at
52
+ // 3000 B so the reference passes and a wildly-over-budget slice is
53
+ // refused rather than overwriting the good slice.
54
+ const SIZE_LINT_HARD_BYTES = 3000;
55
+ const DAVE_BOOT_LINT_CHECKS = [
56
+ {
57
+ id: 'package-name',
58
+ description: 'names the platform package @stravica-ai/digital-operator-pa',
59
+ check: (text) => text.includes('@stravica-ai/digital-operator-pa'),
60
+ },
61
+ {
62
+ id: 'constraints-pointer',
63
+ description:
64
+ 'points at operator/knowledge/operator-interface/operational-constraints.md',
65
+ check: (text) =>
66
+ text.includes(
67
+ 'operator/knowledge/operator-interface/operational-constraints.md',
68
+ ),
69
+ },
70
+ {
71
+ id: 'no-active-projects-block',
72
+ description:
73
+ 'carries no "## Active projects" or "## In-flight work" block (boot-context injects live state)',
74
+ check: (text) =>
75
+ !/^##\s+(Active projects|In-flight work)\b/im.test(text),
76
+ },
77
+ {
78
+ id: 'size-hard-ceiling',
79
+ description: `size within hard ceiling of ${SIZE_LINT_HARD_BYTES} B (soft budget ${SIZE_BUDGET_BYTES} B)`,
80
+ check: (text) => Buffer.byteLength(text, 'utf8') <= SIZE_LINT_HARD_BYTES,
81
+ },
82
+ ];
83
+
84
+ const LINT_CHECKS_BY_TEMPLATE = {
85
+ 'dave-boot': DAVE_BOOT_LINT_CHECKS,
86
+ };
87
+
88
+ /**
89
+ * Return the lint checks for a template name. Custom template paths (anything
90
+ * that does not resolve to a bundled name) get an empty check-set so
91
+ * `--template <path>` is opt-in and never breaks a caller that ships its
92
+ * own contract.
93
+ *
94
+ * The name is the caller's `template` value stripped of any extension: for a
95
+ * bundled name that is the name itself ("dave-boot"); for a custom path we
96
+ * do not attempt to match. This is deliberate: template-specific lint checks
97
+ * are baked into this file because they encode a slice contract that only
98
+ * this repo knows.
99
+ *
100
+ * @param {string} template
101
+ * @returns {Array<{id: string, description: string, check: (t: string) => boolean}>}
102
+ */
103
+ export function lintChecksFor(template) {
104
+ if (typeof template !== 'string') return [];
105
+ if (Object.prototype.hasOwnProperty.call(LINT_CHECKS_BY_TEMPLATE, template)) {
106
+ return LINT_CHECKS_BY_TEMPLATE[template];
107
+ }
108
+ return [];
109
+ }
110
+
111
+ /**
112
+ * Run the template-specific post-generate lint. Returns { ok, failures }
113
+ * where `failures` is a list of `{ id, description }` for every failing
114
+ * check. An empty check-set (custom template) is always ok.
115
+ *
116
+ * @param {string} sliceText
117
+ * @param {string} template
118
+ * @returns {{ ok: boolean, failures: Array<{id: string, description: string}> }}
119
+ */
120
+ export function lintSlice(sliceText, template) {
121
+ const checks = lintChecksFor(template);
122
+ const failures = [];
123
+ for (const c of checks) {
124
+ let passed = false;
125
+ try {
126
+ passed = c.check(sliceText) === true;
127
+ } catch {
128
+ passed = false;
129
+ }
130
+ if (!passed) failures.push({ id: c.id, description: c.description });
131
+ }
132
+ return { ok: failures.length === 0, failures };
133
+ }
134
+
36
135
  function opError(msg, code = 2) {
37
136
  const err = new Error(msg);
38
137
  err.sliceExitCode = code;
@@ -51,6 +150,9 @@ function log(line, { stderr = process.stderr } = {}) {
51
150
  * noop-dry-run — dry-run path; no claude call, no write.
52
151
  * fail-usage — caller-side input error (missing arg, bad path).
53
152
  * fail-validation — claude returned content missing required headers.
153
+ * fail-lint : post-generate lint refused the write (a defective
154
+ * regeneration was blocked from clobbering the
155
+ * good slice in place). w-2026-09-04-dave-003.
54
156
  * fail-claude — claude exited non-zero (transport failure).
55
157
  * fail-prereq — input loading failed (missing profile / observations / template).
56
158
  * fail-write — writing the slice output file failed.
@@ -132,6 +234,11 @@ function sessionName(now) {
132
234
  * @param {string} opts.outputPath Where to write the slice.
133
235
  * @param {boolean} [opts.dryRun=false] If true, build the prompt and report,
134
236
  * but skip the claude call and file write.
237
+ * @param {boolean} [opts.noLint=false] Bypass the post-generate lint. Written
238
+ * as an escape hatch when the caller
239
+ * knows better than the checks; the
240
+ * scheduled nightly path leaves it off
241
+ * so the lint guards the live slice.
135
242
  * @param {object} opts.runner Shared runner (spawn/now/ts/tsIso).
136
243
  * @param {object} [opts.stderr] Capture stream for tests.
137
244
  * @returns {Promise<number>} Exit code.
@@ -144,6 +251,7 @@ export async function runSlice({
144
251
  outputPath,
145
252
  runsLog,
146
253
  dryRun = false,
254
+ noLint = false,
147
255
  runner,
148
256
  stderr = process.stderr,
149
257
  } = {}) {
@@ -286,11 +394,41 @@ export async function runSlice({
286
394
  const bytes = Buffer.byteLength(sliceText, 'utf8');
287
395
  if (bytes > SIZE_BUDGET_BYTES) {
288
396
  log(
289
- `WARN: slice is ${bytes}B, exceeds soft budget of ${SIZE_BUDGET_BYTES}B — writing anyway`,
397
+ `WARN: slice is ${bytes}B, exceeds soft budget of ${SIZE_BUDGET_BYTES}B`,
290
398
  { stderr },
291
399
  );
292
400
  }
293
401
 
402
+ // Step 4b: post-generate lint (w-2026-09-04-dave-003).
403
+ //
404
+ // Template-specific checks that catch the "regeneration produces a
405
+ // slice that structurally validates but violates the slice contract"
406
+ // failure mode. On failure the write is refused so the good slice
407
+ // stays in place; the caller can bypass with --no-lint when the
408
+ // checks are wrong for the current contract.
409
+ const lintResult = lintSlice(sliceText, template);
410
+ if (!lintResult.ok) {
411
+ const summary = lintResult.failures
412
+ .map((f) => `${f.id} (${f.description})`)
413
+ .join('; ');
414
+ if (noLint) {
415
+ log(`lint failed but --no-lint set, writing anyway: ${summary}`, {
416
+ stderr,
417
+ });
418
+ } else {
419
+ log(
420
+ `lint refused write: ${lintResult.failures.length} check(s) failed: ${summary}`,
421
+ { stderr },
422
+ );
423
+ await emitAudit({
424
+ status: 'fail-lint',
425
+ exitCode: 2,
426
+ reason: `lint failed: ${summary}`,
427
+ });
428
+ return 2;
429
+ }
430
+ }
431
+
294
432
  // Step 5 — write.
295
433
  try {
296
434
  await mkdir(dirname(outputPath), { recursive: true });
@@ -331,4 +469,4 @@ export async function runSlice({
331
469
  }
332
470
  }
333
471
 
334
- export { REQUIRED_HEADERS, SIZE_BUDGET_BYTES };
472
+ export { REQUIRED_HEADERS, SIZE_BUDGET_BYTES, SIZE_LINT_HARD_BYTES };
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stravica-ai/digital-operator-pa",
3
- "version": "0.1.35",
3
+ "version": "0.1.36",
4
4
  "description": "Digital Operator PA — single-bundled public package surface (bins + library) for the platform.",
5
5
  "type": "module",
6
6
  "main": "./index.mjs",