@aitne-sh/aitne 0.1.4 → 0.1.5
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/agent-assets/agent-profiles/_safety.md +14 -0
- package/agent-assets/skills/observations/SKILL.md +22 -4
- package/agent-assets/skills/roadmap/SKILL.md +12 -4
- package/agent-assets/skills/today/SKILL.md +25 -6
- package/agent-assets/task-flows/routine.roadmap_refresh.md +7 -3
- package/agent-assets/task-flows/setup.initial.md +50 -23
- package/package.json +47 -23
- package/scripts/check-redaction-coverage.mjs +0 -109
- package/scripts/commands.md +0 -0
- package/scripts/message-discipline-digest.mjs +0 -535
- package/scripts/poc/google-connector-inheritance/REPORT.md +0 -197
- package/scripts/poc/google-connector-inheritance/claude-sdk-probe.mjs +0 -79
- package/scripts/regen-skill-fixtures.mjs +0 -39
- package/scripts/remint-roadmap-ids.mjs +0 -257
- package/scripts/smoke-obsidian-api.mjs +0 -166
|
@@ -24,3 +24,17 @@
|
|
|
24
24
|
- **Read-before-write**: PATCH `mode=replace` replaces the entire section.
|
|
25
25
|
Always GET first, merge your changes into the existing content, then PATCH.
|
|
26
26
|
Prefer `mode=append` when simply adding new entries.
|
|
27
|
+
- **Daemon-API body submission** (`curl -d` on `/api/context/*`,
|
|
28
|
+
`/api/observations`, `/api/schedule`, etc.). Two safe shapes:
|
|
29
|
+
- Inline JSON — `-d '{"key":"value"}'`. Use for small / single-line
|
|
30
|
+
bodies. Escape internal newlines as `\n`.
|
|
31
|
+
- Stdin heredoc — `-d @- <<'JSON' … JSON`. Use for multi-line or
|
|
32
|
+
large bodies. `@-` is curl's stdin marker (a literal two-character
|
|
33
|
+
token), distinct from the file-read forms below.
|
|
34
|
+
|
|
35
|
+
Never use `-d @<filepath>` / `--data-raw '@<filepath>'` /
|
|
36
|
+
`-F field=@<filepath>`. They are file-read shapes — safe mode
|
|
37
|
+
hook-blocks them, and a request that slips through sends the literal
|
|
38
|
+
`@/path/...` text as the body, which the daemon rejects with
|
|
39
|
+
`invalid_json_body`. There is no agent-facing reason to read a body
|
|
40
|
+
off the filesystem; pipe stdin via `@-` instead.
|
|
@@ -26,8 +26,10 @@ the update.
|
|
|
26
26
|
- Update `roadmap.md` or `projects/*.md` only for material project-state changes
|
|
27
27
|
- Schedule a wake-up if the observation implies a future reminder
|
|
28
28
|
5. Apply the smallest meaningful set of context updates.
|
|
29
|
-
6. Mark processed observations consumed
|
|
30
|
-
`
|
|
29
|
+
6. Mark processed observations consumed via the bulk endpoint
|
|
30
|
+
(`POST /api/observations/consume`) — see "POST /api/observations/consume"
|
|
31
|
+
in the API Reference below for the exact body shape and the
|
|
32
|
+
`correlationId` rule. There is no per-id variant.
|
|
31
33
|
|
|
32
34
|
## Skip Criteria
|
|
33
35
|
|
|
@@ -133,13 +135,29 @@ etc.) and are picked up by the prefix match on the GET route.
|
|
|
133
135
|
|
|
134
136
|
### POST /api/observations/consume
|
|
135
137
|
|
|
138
|
+
Marks one or more observations consumed. **Bulk-only** — there is no
|
|
139
|
+
per-id endpoint (`POST /api/observations/<id>/consume` returns 404).
|
|
140
|
+
Always use this shape, even for a single id.
|
|
141
|
+
|
|
142
|
+
Copy the `correlationId` value verbatim from the
|
|
143
|
+
`<event_correlation_id>…</event_correlation_id>` tag in your turn
|
|
144
|
+
context — do not paste the angle-bracket placeholder.
|
|
145
|
+
|
|
136
146
|
```bash
|
|
147
|
+
# Example: <event_correlation_id>hourly-2026-04-23T15:00:00Z-7af3</event_correlation_id>
|
|
148
|
+
# arrived in context, and observations 14 and 17 were processed.
|
|
137
149
|
curl -s -X POST http://localhost:8321/api/observations/consume \
|
|
138
150
|
-H 'Content-Type: application/json' \
|
|
139
|
-
-d '{"ids":
|
|
151
|
+
-d '{"ids":[14,17],"correlationId":"hourly-2026-04-23T15:00:00Z-7af3"}'
|
|
140
152
|
```
|
|
141
153
|
|
|
142
|
-
|
|
154
|
+
| Field | Type | Required | Notes |
|
|
155
|
+
|---|---|---|---|
|
|
156
|
+
| `ids` | `number[]` | yes | Integers, not strings. `["14"]` is rejected. |
|
|
157
|
+
| `correlationId` | `string` | yes | Verbatim from the `<event_correlation_id>` context tag. Non-string or missing → 400. |
|
|
158
|
+
|
|
159
|
+
Response: `{ "consumed": <count> }`. Validation failures return 400
|
|
160
|
+
`{"error":"validation_error"}`.
|
|
143
161
|
|
|
144
162
|
### GET /api/observations/stats
|
|
145
163
|
|
|
@@ -246,6 +246,12 @@ mid-session refresh is not interleaved with a DM handler PATCH.
|
|
|
246
246
|
|
|
247
247
|
## roadmap.md API
|
|
248
248
|
|
|
249
|
+
Body submission follows `_safety.md` "Daemon-API body submission":
|
|
250
|
+
small POST / PATCH bodies use inline `-d '{...}'`; the full-file PUT
|
|
251
|
+
runs multi-KB and uses the stdin heredoc `-d @- <<'JSON'` shape.
|
|
252
|
+
Include `X-Lock-Id: <roadmap_write_lock_id>` on every PUT / PATCH
|
|
253
|
+
when that tag is in your context.
|
|
254
|
+
|
|
249
255
|
```bash
|
|
250
256
|
# Read
|
|
251
257
|
curl -s http://localhost:8321/api/context/roadmap
|
|
@@ -254,19 +260,21 @@ curl -s http://localhost:8321/api/context/roadmap
|
|
|
254
260
|
curl -s -X POST http://localhost:8321/api/context/roadmap/id \
|
|
255
261
|
-H 'Content-Type: application/json' \
|
|
256
262
|
-H 'X-Lock-Id: <roadmap_write_lock_id>' \
|
|
257
|
-
-d '{"creationDate":
|
|
263
|
+
-d '{"creationDate":"YYYY-MM-DD"}'
|
|
258
264
|
|
|
259
|
-
# Full replace (roadmap refresh —
|
|
265
|
+
# Full replace (roadmap refresh) — multi-KB body, use heredoc.
|
|
260
266
|
curl -s -X PUT http://localhost:8321/api/context/roadmap \
|
|
261
267
|
-H 'Content-Type: application/json' \
|
|
262
268
|
-H 'X-Lock-Id: <roadmap_write_lock_id>' \
|
|
263
|
-
-d
|
|
269
|
+
-d @- <<'JSON'
|
|
270
|
+
{"content":"# Roadmap\n> Last synced: 2026-04-23\n\n## Annual Goals\n- ...\n\n## Quarterly Focus\n- ...\n\n## Long-term Plans\n- [2026-Q3] ... <!-- id: rm-20260419-b8e7d4 -->\n\n## Agent Action Plan\n\n## Recurring\n- Every Friday: weekly review\n"}
|
|
271
|
+
JSON
|
|
264
272
|
|
|
265
273
|
# Section PATCH
|
|
266
274
|
curl -s -X PATCH http://localhost:8321/api/context/roadmap \
|
|
267
275
|
-H 'Content-Type: application/json' \
|
|
268
276
|
-H 'X-Lock-Id: <roadmap_write_lock_id>' \
|
|
269
|
-
-d '{"section":
|
|
277
|
+
-d '{"section":"long_term_plans","mode":"append","content":"- [2026-Q3] ...\n"}'
|
|
270
278
|
```
|
|
271
279
|
|
|
272
280
|
Snapshotting, mtime updates, and path validation are handled by the
|
|
@@ -186,15 +186,34 @@ PUT today.md must contain the H1 date line, day-type header quote, and all six s
|
|
|
186
186
|
|
|
187
187
|
## today.md API (subset of context API)
|
|
188
188
|
|
|
189
|
+
Body submission follows the rule in `_safety.md` "Daemon-API body
|
|
190
|
+
submission": small section PATCHes use inline `-d '{...}'`; full-file
|
|
191
|
+
PUT uses the stdin heredoc `-d @- <<'JSON'` shape because the body
|
|
192
|
+
runs multi-KB. Add `X-Lock-Id: <today_write_lock_id>` on every
|
|
193
|
+
PUT / PATCH when that tag is in your context.
|
|
194
|
+
|
|
189
195
|
```bash
|
|
190
|
-
|
|
191
|
-
curl -s
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
196
|
+
# Read
|
|
197
|
+
curl -s http://localhost:8321/api/context/today
|
|
198
|
+
|
|
199
|
+
# Full replace — Morning Routine only. Multi-KB body → heredoc.
|
|
200
|
+
curl -s -X PUT http://localhost:8321/api/context/today \
|
|
201
|
+
-H 'Content-Type: application/json' \
|
|
202
|
+
-H 'X-Lock-Id: <today_write_lock_id>' \
|
|
203
|
+
-d @- <<'JSON'
|
|
204
|
+
{"content":"# 2026-04-02 (Thursday)\n> Day type: Weekday | Work focus: on | Study focus: on | Personal focus: on\n\n## User Schedule\n- 14:00–15:00 Design review [work]\n\n## User Tasks\n- [ ] 11:00 Finalize Q2 draft [work]\n\n## Agent Plan\n- [ ] 08:55 DM reminder: standup [work] →DM\n\n## Agent Notes\n\n## Agent Log\n- 04:00 Morning Routine completed (day-type: Weekday)\n\n## Handoff\n- (none)\n"}
|
|
205
|
+
JSON
|
|
206
|
+
|
|
207
|
+
# Section operation — small body, inline `-d` is fine.
|
|
208
|
+
curl -s -X PATCH http://localhost:8321/api/context/today \
|
|
209
|
+
-H 'Content-Type: application/json' \
|
|
210
|
+
-H 'X-Lock-Id: <today_write_lock_id>' \
|
|
211
|
+
-d '{"section":"agent_log","mode":"append","content":"- 09:35 ..."}'
|
|
195
212
|
```
|
|
196
213
|
|
|
197
|
-
|
|
214
|
+
The H1 date and the `> Day type:` quote line are validated by exact
|
|
215
|
+
regex on PUT — keep both English-shaped exactly as the template. See
|
|
216
|
+
context skill for the full endpoint reference.
|
|
198
217
|
|
|
199
218
|
## Knowledge map — section shape (auto-curated)
|
|
200
219
|
|
|
@@ -176,11 +176,15 @@ coordinates the high-level gather → analyze → write loop.
|
|
|
176
176
|
consult that ID before emitting a new entry or matching by text.
|
|
177
177
|
|
|
178
178
|
7. Consume the observations whose candidate was incorporated or
|
|
179
|
-
deliberately dropped
|
|
180
|
-
|
|
179
|
+
deliberately dropped. Copy the `correlationId` value verbatim from
|
|
180
|
+
the `<event_correlation_id>…</event_correlation_id>` tag in your
|
|
181
|
+
turn context — do not paste the placeholder. Bulk-only; the per-id
|
|
182
|
+
form does not exist. Field contract is in the `observations`
|
|
183
|
+
skill ("POST /api/observations/consume").
|
|
184
|
+
```bash
|
|
181
185
|
curl -s -X POST http://localhost:8321/api/observations/consume \
|
|
182
186
|
-H 'Content-Type: application/json' \
|
|
183
|
-
-d '{"ids":[<id>, ...],
|
|
187
|
+
-d '{"ids":[<id>, ...],"correlationId":"<copied-from-event_correlation_id-tag>"}'
|
|
184
188
|
```
|
|
185
189
|
Observations left pending here will re-appear on the next refresh.
|
|
186
190
|
|
|
@@ -7,8 +7,9 @@ Vault step already captured `settings.primary_language` (BCP-47 tag, e.g.
|
|
|
7
7
|
`en` or `es`) and `settings.vault_mode` (`plain` or `obsidian`) — the
|
|
8
8
|
latter controls how the **primary management vault** is laid out, not the
|
|
9
9
|
separate external Obsidian integration. Do NOT re-ask those questions.
|
|
10
|
-
Output language for
|
|
11
|
-
follow
|
|
10
|
+
Output language for everything written to disk in this flow
|
|
11
|
+
(`user/profile.md`, `user/*.md`, `rules/management.md` body): follow
|
|
12
|
+
`<output_language_policy>`.
|
|
12
13
|
|
|
13
14
|
SETUP-FLOW-REDESIGN-PLAN §5.8 — the legacy "tool selections" form was
|
|
14
15
|
removed. Steps 4–6 of the wizard (Mail, Calendar, Note) already
|
|
@@ -68,6 +69,15 @@ about all four rows rather than fabricating defaults. Do not retry
|
|
|
68
69
|
with a curl.
|
|
69
70
|
|
|
70
71
|
### Instructions
|
|
72
|
+
|
|
73
|
+
Steps 3–8 all happen in the same agent turn. They are ordered to match
|
|
74
|
+
the actual emission sequence: the two staged code blocks (rules then
|
|
75
|
+
character) land in the stream first; the silent curl writes follow. The
|
|
76
|
+
dashboard reveals the preview as soon as the rules block lands but
|
|
77
|
+
keeps "Save & Finish" disabled until the whole turn ends, so emitting
|
|
78
|
+
blocks before curls minimizes how long the user waits on a disabled
|
|
79
|
+
button.
|
|
80
|
+
|
|
71
81
|
1. Run Step 0 silently. Greet the user in one line, introducing
|
|
72
82
|
yourself by the name in `<agent_identity>` display_name. Then
|
|
73
83
|
present the derived Source-of-Truth table and ask any remaining
|
|
@@ -78,28 +88,30 @@ with a curl.
|
|
|
78
88
|
- Project-management method preferences (anything you want the agent
|
|
79
89
|
to follow when handling your projects?)
|
|
80
90
|
Either answer may be "no preference" / "skip" — accept that cleanly.
|
|
81
|
-
3.
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
91
|
+
3. Generate rules/management.md inside a ```management-rules code
|
|
92
|
+
block. This is the FIRST thing emitted in the turn — the dashboard
|
|
93
|
+
reveals the preview as soon as it lands.
|
|
94
|
+
4. If the user requests changes, revise (return to step 3). Complete
|
|
95
|
+
within **at most 2 revision rounds**.
|
|
85
96
|
5. **Do NOT put communication style inside rules/management.md, and do NOT
|
|
86
97
|
put it inside `user/profile.md` either.** Tone / style / voice / emoji
|
|
87
98
|
/ language preferences live in the `character` runtime-config field
|
|
88
|
-
only — emitted as a ```character``` code block (see step 6
|
|
99
|
+
only — emitted as a ```character``` code block (see step 6). See
|
|
89
100
|
`docs/design/15-character.md` for the split rule.
|
|
90
|
-
6.
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
|
|
94
|
-
|
|
95
|
-
|
|
96
|
-
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
101
|
+
6. If the user stated a communication-style preference in step 2, emit
|
|
102
|
+
a ```character``` code block immediately after the rules block (see
|
|
103
|
+
"Character code block format" below). If the user skipped, omit the
|
|
104
|
+
block.
|
|
105
|
+
7. After the staged blocks, silently call PUT /api/context/user/profile
|
|
106
|
+
using the template in "user/profile.md Format" below. Working hours
|
|
107
|
+
and quiet hours are pre-populated with defaults (Weekdays 09:00–18:00,
|
|
108
|
+
Quiet hours 22:00–08:00) — do not ask about them. Fill Platforms
|
|
109
|
+
from the **derived Source-of-Truth table** (Step 0) — the row values
|
|
110
|
+
you confirmed with the user. Leave Identity blank — setup does not
|
|
111
|
+
collect name or timezone.
|
|
112
|
+
8. If the conversation surfaced detail-heavy facts that belong in the
|
|
113
|
+
detailed profile layer, also PATCH the matching user/*.md file (still
|
|
114
|
+
the same turn, after step 7). Typical Q&A → file mappings:
|
|
103
115
|
- Named colleagues, family, friends → user/people.md
|
|
104
116
|
- Current company, role specifics, ongoing projects → user/work.md
|
|
105
117
|
- Specific frameworks, years of experience → user/expertise.md
|
|
@@ -109,7 +121,7 @@ with a curl.
|
|
|
109
121
|
Only seed what the user actually stated — do not invent or infer. If
|
|
110
122
|
nothing came up for a given file, do not touch it. See the user-profile
|
|
111
123
|
skill for the read-before-write PATCH recipe.
|
|
112
|
-
|
|
124
|
+
9. Keep steps 7–8 silent — the dashboard handles saving
|
|
113
125
|
rules/management.md separately when the user approves the preview. Do
|
|
114
126
|
not create or modify any other context files; the daemon seeds the
|
|
115
127
|
rest of the primary-vault scaffold automatically.
|
|
@@ -218,6 +230,18 @@ write tone/style preferences into user/profile.md.
|
|
|
218
230
|
|
|
219
231
|
### rules/management.md Format
|
|
220
232
|
|
|
233
|
+
Output language: follow `<output_language_policy>`. rules/management.md
|
|
234
|
+
is Policy B — the section headers (`## Agent Identity`, `## Source of
|
|
235
|
+
Truth`, `## Autonomy Levels`, `## Notification Rules`, `## Schedule`,
|
|
236
|
+
`## Project Management`) are skeleton and stay English; the descriptive
|
|
237
|
+
bullets under `## Autonomy Levels`, `## Notification Rules`, `## Schedule`,
|
|
238
|
+
and `## Project Management` are written in `<settings primary_language>`.
|
|
239
|
+
File-specific carve-outs that also stay English: the `## Agent Identity`
|
|
240
|
+
field labels (`- AI name:`, `- WhatsApp label:`) — the daemon parses and
|
|
241
|
+
rewrites this section; the Source of Truth table column headers and
|
|
242
|
+
Domain-column row labels; and product/brand cells (`Google Calendar`,
|
|
243
|
+
`Obsidian`, `Notion`, `today.md`, `projects/*.md`).
|
|
244
|
+
|
|
221
245
|
Fill the Source of Truth table from the **derived rows you confirmed
|
|
222
246
|
with the user in Step 0** (Schedule / Tasks / Notes / Projects).
|
|
223
247
|
Generate using this format:
|
|
@@ -274,5 +298,8 @@ heading onto the end of the previous list item (e.g. `- Label:
|
|
|
274
298
|
<value>## Next Section` on one line). Copy user-provided values as-is,
|
|
275
299
|
then newline, blank line, then the next heading.
|
|
276
300
|
|
|
277
|
-
**Important**:
|
|
278
|
-
The dashboard
|
|
301
|
+
**Important**: Do NOT curl-write rules/management.md to disk yourself.
|
|
302
|
+
The dashboard persists it via `POST /setup/save-rules` when the user
|
|
303
|
+
clicks Save & Finish. (The silent curl PUT to /api/context/user/profile
|
|
304
|
+
in step 7 and the user/*.md PATCHes in step 8 ARE required — only the
|
|
305
|
+
rules file is saved by the dashboard.)
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@aitne-sh/aitne",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "Aitne — a local-first, proactive personal AI agent. A long-running TypeScript daemon is the nervous system; Claude Code (or Codex / Gemini CLI) is the brain. All persistent memory lives in local Markdown files.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"ai",
|
|
@@ -31,16 +31,39 @@
|
|
|
31
31
|
},
|
|
32
32
|
"files": [
|
|
33
33
|
"bin",
|
|
34
|
-
"scripts",
|
|
35
34
|
"personal-agent.mjs",
|
|
36
35
|
"agent-assets",
|
|
36
|
+
"scripts/start.mjs",
|
|
37
|
+
"scripts/run-node.mjs",
|
|
38
|
+
"scripts/browser.mjs",
|
|
39
|
+
"scripts/rm-paths.mjs",
|
|
40
|
+
"scripts/lib/",
|
|
41
|
+
"scripts/commands/*.mjs",
|
|
37
42
|
"LICENSE",
|
|
38
43
|
"README.md"
|
|
39
44
|
],
|
|
45
|
+
"scripts": {
|
|
46
|
+
"build": "turbo run build",
|
|
47
|
+
"start": "node bin/aitne.mjs start",
|
|
48
|
+
"stop": "node bin/aitne.mjs stop",
|
|
49
|
+
"restart": "node bin/aitne.mjs restart",
|
|
50
|
+
"status": "node bin/aitne.mjs status",
|
|
51
|
+
"logs": "node bin/aitne.mjs logs",
|
|
52
|
+
"dev": "node bin/aitne.mjs dev",
|
|
53
|
+
"doctor": "node bin/aitne.mjs doctor",
|
|
54
|
+
"audit": "node bin/aitne.mjs audit",
|
|
55
|
+
"test": "node scripts/check-redaction-coverage.mjs && vitest run --coverage",
|
|
56
|
+
"test:watch": "vitest",
|
|
57
|
+
"check:redaction": "node scripts/check-redaction-coverage.mjs",
|
|
58
|
+
"lint": "turbo run lint",
|
|
59
|
+
"typecheck:tests": "turbo run typecheck:tests",
|
|
60
|
+
"clean": "turbo run clean && node scripts/rm-paths.mjs node_modules .buildstamp",
|
|
61
|
+
"prepublishOnly": "pnpm run build"
|
|
62
|
+
},
|
|
40
63
|
"dependencies": {
|
|
41
|
-
"@aitne/daemon": "
|
|
42
|
-
"@aitne/dashboard": "
|
|
43
|
-
"@aitne/shared": "
|
|
64
|
+
"@aitne/daemon": "workspace:*",
|
|
65
|
+
"@aitne/dashboard": "workspace:*",
|
|
66
|
+
"@aitne/shared": "workspace:*"
|
|
44
67
|
},
|
|
45
68
|
"devDependencies": {
|
|
46
69
|
"@typescript-eslint/eslint-plugin": "^8.58.1",
|
|
@@ -52,27 +75,28 @@
|
|
|
52
75
|
"typescript-eslint": "^8.58.1",
|
|
53
76
|
"vitest": "^3.2.0"
|
|
54
77
|
},
|
|
78
|
+
"packageManager": "pnpm@10.12.1",
|
|
79
|
+
"pnpm": {
|
|
80
|
+
"onlyBuiltDependencies": [
|
|
81
|
+
"esbuild",
|
|
82
|
+
"better-sqlite3",
|
|
83
|
+
"ffmpeg-static",
|
|
84
|
+
"onnxruntime-node",
|
|
85
|
+
"protobufjs"
|
|
86
|
+
],
|
|
87
|
+
"overrides": {
|
|
88
|
+
"dompurify": ">=3.4.0",
|
|
89
|
+
"vite": "7.3.2",
|
|
90
|
+
"@anthropic-ai/sdk": ">=0.81.0",
|
|
91
|
+
"protobufjs": ">=7.5.5",
|
|
92
|
+
"axios": ">=1.16.0",
|
|
93
|
+
"fast-uri": ">=3.1.2"
|
|
94
|
+
}
|
|
95
|
+
},
|
|
55
96
|
"publishConfig": {
|
|
56
97
|
"access": "public"
|
|
57
98
|
},
|
|
58
99
|
"engines": {
|
|
59
100
|
"node": ">=22.0.0"
|
|
60
|
-
},
|
|
61
|
-
"scripts": {
|
|
62
|
-
"build": "turbo run build",
|
|
63
|
-
"start": "node bin/aitne.mjs start",
|
|
64
|
-
"stop": "node bin/aitne.mjs stop",
|
|
65
|
-
"restart": "node bin/aitne.mjs restart",
|
|
66
|
-
"status": "node bin/aitne.mjs status",
|
|
67
|
-
"logs": "node bin/aitne.mjs logs",
|
|
68
|
-
"dev": "node bin/aitne.mjs dev",
|
|
69
|
-
"doctor": "node bin/aitne.mjs doctor",
|
|
70
|
-
"audit": "node bin/aitne.mjs audit",
|
|
71
|
-
"test": "node scripts/check-redaction-coverage.mjs && vitest run --coverage",
|
|
72
|
-
"test:watch": "vitest",
|
|
73
|
-
"check:redaction": "node scripts/check-redaction-coverage.mjs",
|
|
74
|
-
"lint": "turbo run lint",
|
|
75
|
-
"typecheck:tests": "turbo run typecheck:tests",
|
|
76
|
-
"clean": "turbo run clean && node scripts/rm-paths.mjs node_modules .buildstamp"
|
|
77
101
|
}
|
|
78
|
-
}
|
|
102
|
+
}
|
|
@@ -1,109 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env node
|
|
2
|
-
// Roadmap §2.5 / §9.2 — redaction static guard.
|
|
3
|
-
//
|
|
4
|
-
// Fails (exit 1) if any production source file outside the single
|
|
5
|
-
// permitted module (`auth-health-monitor.ts`) contains a raw SQL
|
|
6
|
-
// assignment to `auth_detail` or `last_error`. The permitted module
|
|
7
|
-
// owns the `writeAuthFailureDetail` / `writeAuthOkDetail` helpers,
|
|
8
|
-
// which apply `redactSensitiveString` unconditionally — every other
|
|
9
|
-
// caller is required to go through them.
|
|
10
|
-
//
|
|
11
|
-
// Exemptions:
|
|
12
|
-
// - test files (*.test.ts) — they seed raw fixtures, not
|
|
13
|
-
// production writes
|
|
14
|
-
// - `auth-health-monitor.ts` — the helpers themselves
|
|
15
|
-
//
|
|
16
|
-
// A match prints file:line:matching-line and exits non-zero. The full
|
|
17
|
-
// scan runs in well under a second; it is intended to be wired into
|
|
18
|
-
// `pnpm test`'s preamble (or a CI step) so that a new offending write
|
|
19
|
-
// cannot silently land alongside a green test suite.
|
|
20
|
-
|
|
21
|
-
import { execFileSync } from "node:child_process";
|
|
22
|
-
import { fileURLToPath } from "node:url";
|
|
23
|
-
import { dirname, relative, resolve } from "node:path";
|
|
24
|
-
import { existsSync } from "node:fs";
|
|
25
|
-
|
|
26
|
-
const here = dirname(fileURLToPath(import.meta.url));
|
|
27
|
-
const root = resolve(here, "..");
|
|
28
|
-
const searchRoot = resolve(root, "packages/daemon/src");
|
|
29
|
-
|
|
30
|
-
if (!existsSync(searchRoot)) {
|
|
31
|
-
console.error(`check-redaction-coverage: ${searchRoot} does not exist`);
|
|
32
|
-
process.exit(1);
|
|
33
|
-
}
|
|
34
|
-
|
|
35
|
-
// Pattern matches any assignment target `auth_detail =` or
|
|
36
|
-
// `last_error =`, regardless of placeholder style (`?` / `@name` /
|
|
37
|
-
// `:name` / `NULL` / literal). The rg -P flag uses PCRE so we can
|
|
38
|
-
// write a single union.
|
|
39
|
-
const PATTERN = String.raw`(auth_detail|last_error)\s*=`;
|
|
40
|
-
|
|
41
|
-
const EXEMPT_PATHS = new Set([
|
|
42
|
-
"packages/daemon/src/core/backends/auth-health-monitor.ts",
|
|
43
|
-
// `mail_accounts.last_error` is a separate column from the `backends`
|
|
44
|
-
// table's `last_error` that the redaction helpers guard. The redaction
|
|
45
|
-
// helper enforces scrubbing of model-auth detail strings; mail-poll
|
|
46
|
-
// errors are IMAP/Graph status messages that never carry secrets
|
|
47
|
-
// (credentials live in the encrypted blob store and are never inlined
|
|
48
|
-
// into error text — see mail-poller.ts `handlePollError`).
|
|
49
|
-
"packages/daemon/src/services/mail/account-registry.ts",
|
|
50
|
-
]);
|
|
51
|
-
|
|
52
|
-
let rgOutput = "";
|
|
53
|
-
try {
|
|
54
|
-
rgOutput = execFileSync(
|
|
55
|
-
"rg",
|
|
56
|
-
[
|
|
57
|
-
"--no-heading",
|
|
58
|
-
"--line-number",
|
|
59
|
-
"--with-filename",
|
|
60
|
-
"--glob",
|
|
61
|
-
"!**/*.test.ts",
|
|
62
|
-
"--glob",
|
|
63
|
-
"!**/*.d.ts",
|
|
64
|
-
"-e",
|
|
65
|
-
PATTERN,
|
|
66
|
-
searchRoot,
|
|
67
|
-
],
|
|
68
|
-
{ encoding: "utf8" },
|
|
69
|
-
);
|
|
70
|
-
} catch (err) {
|
|
71
|
-
// rg exits 1 when there are zero matches — that is the success case.
|
|
72
|
-
if (err.status === 1 && !err.stdout) {
|
|
73
|
-
process.exit(0);
|
|
74
|
-
}
|
|
75
|
-
// rg exits 2 on actual errors. Surface them.
|
|
76
|
-
console.error("check-redaction-coverage: rg failed");
|
|
77
|
-
console.error(err.stderr?.toString() ?? err.message);
|
|
78
|
-
process.exit(2);
|
|
79
|
-
}
|
|
80
|
-
|
|
81
|
-
const lines = rgOutput.split("\n").filter((line) => line.length > 0);
|
|
82
|
-
const offenders = [];
|
|
83
|
-
for (const line of lines) {
|
|
84
|
-
// Each rg line is `absolute-path:line:content`. Convert to a repo
|
|
85
|
-
// relative path so the exemption check is stable.
|
|
86
|
-
const firstColon = line.indexOf(":");
|
|
87
|
-
const secondColon = line.indexOf(":", firstColon + 1);
|
|
88
|
-
if (firstColon < 0 || secondColon < 0) continue;
|
|
89
|
-
const absPath = line.slice(0, firstColon);
|
|
90
|
-
const relPath = relative(root, absPath).replace(/\\/g, "/");
|
|
91
|
-
if (EXEMPT_PATHS.has(relPath)) continue;
|
|
92
|
-
offenders.push(`${relPath}:${line.slice(firstColon + 1)}`);
|
|
93
|
-
}
|
|
94
|
-
|
|
95
|
-
if (offenders.length > 0) {
|
|
96
|
-
console.error(
|
|
97
|
-
"check-redaction-coverage: found raw auth_detail / last_error writes outside the helper module.",
|
|
98
|
-
);
|
|
99
|
-
console.error(
|
|
100
|
-
"All writes must go through writeAuthFailureDetail / writeAuthOkDetail in packages/daemon/src/core/backends/auth-health-monitor.ts (roadmap §9.2).",
|
|
101
|
-
);
|
|
102
|
-
console.error("");
|
|
103
|
-
for (const line of offenders) {
|
|
104
|
-
console.error(` ${line}`);
|
|
105
|
-
}
|
|
106
|
-
process.exit(1);
|
|
107
|
-
}
|
|
108
|
-
|
|
109
|
-
process.exit(0);
|
package/scripts/commands.md
DELETED
|
File without changes
|