@neuralis/brain-core 0.2.0 → 0.3.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/README.md +8 -3
- package/app/README.md +1 -1
- package/app/filesystem/README.md +3 -3
- package/app/filesystem/api/README.md +4 -4
- package/app/filesystem/api/index.ts +144 -139
- package/app/filesystem/domain/types.ts +12 -0
- package/app/filesystem/hooks/README.md +5 -5
- package/app/filesystem/hooks/useDiscoverableSources.ts +4 -2
- package/app/filesystem/hooks/useFilesystemSSE.ts +31 -23
- package/app/filesystem/hooks/useGitChangesInventory.ts +4 -2
- package/app/filesystem/host/README.md +3 -2
- package/app/filesystem/host/installFilesystemHostComponents.tsx +22 -9
- package/app/filesystem/store/README.md +12 -8
- package/app/filesystem/store/filesystemStore.ts +444 -163
- package/app/filesystem/store/gitSlice.ts +6 -6
- package/app/filesystem/store/listSlice.ts +9 -6
- package/app/filesystem/store/searchSlice.ts +3 -3
- package/app/filesystem/ui/FileEditor.tsx +90 -39
- package/app/filesystem/ui/FileTree.tsx +10 -9
- package/app/filesystem/ui/GitCommitChangesView.tsx +5 -3
- package/app/filesystem/ui/GitCommitGraph.tsx +6 -5
- package/app/filesystem/ui/GitControlPanel.tsx +14 -14
- package/app/filesystem/ui/GitDiffView.tsx +14 -6
- package/app/filesystem/ui/GitFileDiff.tsx +22 -15
- package/app/filesystem/ui/PendingChangesPanel.tsx +108 -44
- package/app/filesystem/ui/PendingReviewDialog.tsx +8 -5
- package/app/filesystem/ui/README.md +9 -9
- package/app/filesystem/ui/ReembedDialog.tsx +4 -2
- package/app/filesystem/ui/SourcesPanel.tsx +26 -28
- package/app/filesystem/ui/Toolbar.tsx +5 -4
- package/app/filesystem/ui/VectorHealthPanel.tsx +48 -17
- package/dist/app/host.js +46 -46
- package/dist/src/config/env.d.ts +4 -0
- package/dist/src/config/env.d.ts.map +1 -1
- package/dist/src/config/env.js +13 -0
- package/dist/src/config/env.js.map +1 -1
- package/dist/src/connectors/LocalDiskConnector.d.ts +9 -1
- package/dist/src/connectors/LocalDiskConnector.d.ts.map +1 -1
- package/dist/src/connectors/LocalDiskConnector.js +51 -2
- package/dist/src/connectors/LocalDiskConnector.js.map +1 -1
- package/dist/src/domain/healthTypes.d.ts +1 -7
- package/dist/src/domain/healthTypes.d.ts.map +1 -1
- package/dist/src/domain/pendingChange.d.ts +31 -0
- package/dist/src/domain/pendingChange.d.ts.map +1 -1
- package/dist/src/domain/pendingChange.js.map +1 -1
- package/dist/src/routes/health.js +2 -3
- package/dist/src/routes/health.js.map +1 -1
- package/dist/src/routes/pending.d.ts +7 -7
- package/dist/src/routes/pending.d.ts.map +1 -1
- package/dist/src/routes/pending.js +21 -21
- package/dist/src/routes/pending.js.map +1 -1
- package/dist/src/services/FilesystemService.d.ts +13 -61
- package/dist/src/services/FilesystemService.d.ts.map +1 -1
- package/dist/src/services/FilesystemService.js +47 -189
- package/dist/src/services/FilesystemService.js.map +1 -1
- package/dist/src/services/FilesystemUiService.d.ts +33 -1
- package/dist/src/services/FilesystemUiService.d.ts.map +1 -1
- package/dist/src/services/FilesystemUiService.js +50 -1
- package/dist/src/services/FilesystemUiService.js.map +1 -1
- package/dist/src/store/PendingChangeStore.d.ts +3 -0
- package/dist/src/store/PendingChangeStore.d.ts.map +1 -1
- package/dist/src/store/PendingChangeStore.js +84 -25
- package/dist/src/store/PendingChangeStore.js.map +1 -1
- package/dist/src/usecases/orphanedPending.d.ts +2 -2
- package/dist/src/usecases/orphanedPending.d.ts.map +1 -1
- package/dist/src/usecases/orphanedPending.js +5 -3
- package/dist/src/usecases/orphanedPending.js.map +1 -1
- package/dist/src/usecases/pendingListing.d.ts +34 -0
- package/dist/src/usecases/pendingListing.d.ts.map +1 -0
- package/dist/src/usecases/pendingListing.js +244 -0
- package/dist/src/usecases/pendingListing.js.map +1 -0
- package/dist/src/usecases/vectorMaintenance.d.ts +6 -9
- package/dist/src/usecases/vectorMaintenance.d.ts.map +1 -1
- package/dist/src/usecases/vectorMaintenance.js +4 -13
- package/dist/src/usecases/vectorMaintenance.js.map +1 -1
- package/dist/src/vector/InMemoryVectorIndex.d.ts.map +1 -1
- package/dist/src/vector/InMemoryVectorIndex.js +30 -9
- package/dist/src/vector/InMemoryVectorIndex.js.map +1 -1
- package/package.json +27 -5
- package/rules/brain-rules.md +1 -1
- package/skills/create-package/SKILL.md +3 -3
- package/skills/create-package/references/config-and-credentials.md +1 -1
- package/skills/create-package/references/manifest-and-discovery.md +1 -1
- package/skills/create-package/references/runtime-and-build.md +1 -1
- package/skills/create-package/references/skills-and-context.md +25 -12
- package/skills/create-package/references/surfaces-and-design.md +7 -5
- package/skills/create-package/references/test-and-ship.md +9 -16
- package/skills/create-package/scripts/check-package.sh +47 -1
- package/skills/create-package/scripts/verify-loaded.sh +18 -27
- package/skills/git/SKILL.md +27 -29
- package/skills/manage-files/SKILL.md +37 -32
- package/skills/manage-files/scripts/upload.sh +7 -9
- package/skills/manage-files/scripts/write.sh +2 -6
- package/skills/manage-sources/SKILL.md +93 -95
- package/skills/manage-sources/scripts/reembed.sh +2 -6
- package/skills/manage-uri-policy/SKILL.md +30 -58
- package/app/filesystem/hooks/useContainerWidth.ts +0 -39
- package/skills/git/scripts/git.sh +0 -48
- package/skills/manage-files/scripts/approve.sh +0 -9
- package/skills/manage-files/scripts/list.sh +0 -9
- package/skills/manage-files/scripts/pending.sh +0 -23
- package/skills/manage-files/scripts/raw.sh +0 -11
- package/skills/manage-files/scripts/read.sh +0 -9
- package/skills/manage-files/scripts/search.sh +0 -15
- package/skills/manage-sources/scripts/browse.sh +0 -12
- package/skills/manage-sources/scripts/cancel.sh +0 -14
- package/skills/manage-sources/scripts/create.sh +0 -13
- package/skills/manage-sources/scripts/delete.sh +0 -17
- package/skills/manage-sources/scripts/discoverable.sh +0 -6
- package/skills/manage-sources/scripts/get.sh +0 -7
- package/skills/manage-sources/scripts/kind-schema.sh +0 -7
- package/skills/manage-sources/scripts/kinds.sh +0 -6
- package/skills/manage-sources/scripts/list.sh +0 -6
- package/skills/manage-sources/scripts/purge-index.sh +0 -18
- package/skills/manage-sources/scripts/reindex.sh +0 -13
- package/skills/manage-sources/scripts/reset.sh +0 -11
- package/skills/manage-sources/scripts/set-enabled.sh +0 -17
- package/skills/manage-sources/scripts/sync-status.sh +0 -14
- package/skills/manage-sources/scripts/sync.sh +0 -13
- package/skills/manage-sources/scripts/update.sh +0 -18
- package/skills/manage-uri-policy/scripts/manifests.sh +0 -20
- package/skills/manage-uri-policy/scripts/set-uri.sh +0 -66
- package/skills/manage-uri-policy/scripts/show-uri.sh +0 -23
|
@@ -8,10 +8,13 @@ allowed-tools: execute fs_list fs_read fs_search
|
|
|
8
8
|
# Sources Management Skill
|
|
9
9
|
|
|
10
10
|
The `connect-business-data` skill owns common source listing, health checks, and
|
|
11
|
-
creation through `connect`; this skill remains the full route
|
|
11
|
+
creation through `connect`; this skill remains the full route lifecycle,
|
|
12
12
|
especially policy-preserving updates, sync, enablement, reset and deletion.
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
Covers `@neuralis/brain-core/sources/*`, called with `neuralis request` (the
|
|
15
|
+
session ticket inside an activated skill, `neuralis login` on your own machine;
|
|
16
|
+
a non-2xx prints the route's body and `HTTP <code>` on stderr and exits 1).
|
|
17
|
+
Useful for:
|
|
15
18
|
|
|
16
19
|
- Bootstrapping a project's sources from a script (`for slug in …`).
|
|
17
20
|
- Bulk-cancel + re-sync after a connector outage.
|
|
@@ -21,8 +24,7 @@ Wraps `/api/packages/@neuralis/brain-core/sources/*`. Useful for:
|
|
|
21
24
|
## Read / survey mode (sources + freshness)
|
|
22
25
|
|
|
23
26
|
To just **survey** the configured sources and their freshness (read-only, the
|
|
24
|
-
`drive.read` floor — no mutation), use the `fs_*` tools rather than the
|
|
25
|
-
scripts:
|
|
27
|
+
`drive.read` floor — no mutation), use the `fs_*` tools rather than the routes:
|
|
26
28
|
|
|
27
29
|
1. Call `fs_list` with `include_counts: true` (no `uri` — root registry) to
|
|
28
30
|
enumerate sources with `on_disk`, `indexed_count`, `unindexed`,
|
|
@@ -42,7 +44,7 @@ scripts:
|
|
|
42
44
|
semantic/filter search needs the source to be indexed. For unsynced content,
|
|
43
45
|
recommend `fs_search search_mode="grep"` scoped to the source URI.
|
|
44
46
|
|
|
45
|
-
(`
|
|
47
|
+
(`GET sources` below is the route-backed equivalent enriched with
|
|
46
48
|
`kind_label`/`kind_icon`/`kind_trust`/`orphan`; use it when you want the
|
|
47
49
|
server-side source rows rather than the index-count survey.)
|
|
48
50
|
|
|
@@ -52,41 +54,40 @@ server-side source rows rather than the index-count survey.)
|
|
|
52
54
|
**in-handler** to a stronger feature and 403 an under-privileged caller (see
|
|
53
55
|
**Feature gates** below). The `Feature` column is the gate actually enforced.
|
|
54
56
|
|
|
55
|
-
| Action | Method | Path |
|
|
57
|
+
| Action | Method | Path (`@neuralis/brain-core/…`) | Fields | Feature |
|
|
56
58
|
|---|---|---|---|---|
|
|
57
|
-
| List configured sources | GET |
|
|
58
|
-
| Get one source's config | GET |
|
|
59
|
-
| List registered kinds | GET |
|
|
60
|
-
| Get a kind's config schema | GET |
|
|
61
|
-
| Discoverable connectors (filesystem hints) | GET |
|
|
62
|
-
| Browse a filesystem path before adding it | GET |
|
|
63
|
-
| Create a new source | POST |
|
|
64
|
-
| Update an existing source | PATCH |
|
|
65
|
-
| Delete a source | DELETE |
|
|
66
|
-
| Enable / disable a source | POST |
|
|
67
|
-
| Trigger sync (202 + queue job snapshot) | POST |
|
|
68
|
-
| Cancel an in-flight sync
|
|
69
|
-
| Job status
|
|
70
|
-
| Forget sync state (next tick re-walks; deletes nothing) | POST |
|
|
71
|
-
| Rescan changes (full re-walk now; unchanged files keep their vectors; 202 + job) | POST |
|
|
72
|
-
| Clean a file / folder / source index (estimate first) | POST |
|
|
73
|
-
| Catch up embedding debt; FORCE=1 re-embeds (estimate first) | POST |
|
|
74
|
-
|
|
75
|
-
> **`update` takes no
|
|
59
|
+
| List configured sources | GET | `sources` | `scope?`, `observed?` | `drive.read` |
|
|
60
|
+
| Get one source's config | GET | `sources/<slug>` | | `drive.read` |
|
|
61
|
+
| List registered kinds | GET | `sources/kinds` | | `drive.read` |
|
|
62
|
+
| Get a kind's config schema | GET | `sources/kinds/<kind>/schema` | | `drive.read` |
|
|
63
|
+
| Discoverable connectors (filesystem hints) | GET | `sources/discoverable` | | `drive.mount` |
|
|
64
|
+
| Browse a filesystem path before adding it | GET | `sources/browse` | `path` | `drive.mount` |
|
|
65
|
+
| Create a new source | POST | `sources` | body (below) | `drive.mount` |
|
|
66
|
+
| Update an existing source | PATCH | `sources` | body (below) | `drive.mount` |
|
|
67
|
+
| Delete a source | DELETE | `sources/<slug>[?purge=1]` | | `drive.mount` |
|
|
68
|
+
| Enable / disable a source | POST | `sources/enabled` | `source`, `enabled` (`true`\|`false`\|`"auto"`) | `drive.mount` |
|
|
69
|
+
| Trigger sync (202 + queue job snapshot) | POST | `sources/sync` | `source`, `agentId?` | `drive.sync` |
|
|
70
|
+
| Cancel an in-flight sync | POST | `sources/cancel` | `source?` | `drive.sync` |
|
|
71
|
+
| Job status | GET | `sources/sync-status` | `source?` | `drive.sync` |
|
|
72
|
+
| Forget sync state (next tick re-walks; deletes nothing) | POST | `sources/reset` | `source` | `drive.sync` |
|
|
73
|
+
| Rescan changes (full re-walk now; unchanged files keep their vectors; 202 + job) | POST | `sources/reindex` | `source`, `agentId?` | `drive.sync` |
|
|
74
|
+
| Clean a file / folder / source index (estimate first) | POST | `sources/purge` | body (below) | `drive.mount` + `drive.sync` |
|
|
75
|
+
| Catch up embedding debt; FORCE=1 re-embeds (estimate first) | POST | `sources/reindex` + `embeddingOnly` or `force` — run `bash ${SKILL_DIR}/scripts/reembed.sh` | env | `drive.sync` |
|
|
76
|
+
|
|
77
|
+
> **`update` takes no `<slug>`.** PATCH targets the bare `sources` path; the
|
|
76
78
|
> source to patch is the body `source` field (the handler ignores the path).
|
|
77
79
|
|
|
78
|
-
`
|
|
80
|
+
`GET sources` returns each row enriched with `kind_label` / `kind_icon` /
|
|
79
81
|
`kind_trust` / `orphan` (an orphan row's contributing kind package is missing).
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
default project-visible set.
|
|
82
|
+
Without `-f scope=project|user|agent` or `-f observed=1` it returns the default
|
|
83
|
+
project-visible set.
|
|
83
84
|
|
|
84
85
|
**Output shape (jq) — read before piping.** `GET /sources` returns a **top-level
|
|
85
86
|
array** of source rows (NOT `{ sources: [...] }`). Pipe `jq '.[]'`, never
|
|
86
87
|
`jq '.sources[]'` (that errors `Cannot index array with string "sources"`). Each
|
|
87
88
|
element carries `slug`, `enabled`, `connection.kind`, `scope`, plus the enrichment
|
|
88
89
|
fields above. `connection.config` is `{}` unless you could attach the source or
|
|
89
|
-
read its root, and `sync.lastSyncResult.error` is a fixed text without `drive.sync`. `
|
|
90
|
+
read its root, and `sync.lastSyncResult.error` is a fixed text without `drive.sync`. `GET sources/<slug>` returns a single object, not an array.
|
|
90
91
|
|
|
91
92
|
## Feature gates
|
|
92
93
|
|
|
@@ -95,17 +96,17 @@ Everything that mutates, syncs, or ENUMERATES THE HOST enforces a **stronger**
|
|
|
95
96
|
feature server-side, beyond the `drive.read` floor — a caller holding only
|
|
96
97
|
`drive.read` gets a `403`:
|
|
97
98
|
|
|
98
|
-
- **`drive.mount`** —
|
|
99
|
-
|
|
99
|
+
- **`drive.mount`** — create, update, delete, enable/disable, browse and the
|
|
100
|
+
discoverable list. Browsing and the
|
|
100
101
|
discoverable list are the steps that PRECEDE attaching, and they enumerate the
|
|
101
102
|
host: you may browse exactly what you would be allowed to attach.
|
|
102
|
-
- **`drive.mount.privileged`** —
|
|
103
|
+
- **`drive.mount.privileged`** — browsing the filesystem root or any
|
|
103
104
|
protected host zone (the App Zone, the Neuralis tree), the same zones whose
|
|
104
105
|
ATTACH needs it. A protected directory is also omitted from the listing of a
|
|
105
106
|
parent you may browse, so an absent entry is not proof it does not exist.
|
|
106
|
-
- **`drive.sync`** —
|
|
107
|
+
- **`drive.sync`** — sync, cancel, reset, reindex, `reembed.sh`, sync-status.
|
|
107
108
|
|
|
108
|
-
|
|
109
|
+
The index purge requires both `drive.mount` and `drive.sync`, source-scope management authority and current READ visibility.
|
|
109
110
|
|
|
110
111
|
Create/update/delete/enable additionally enforce `canAccessScope(.., 'write')`
|
|
111
112
|
on the target source's scope, and create validates the kind's scope rules.
|
|
@@ -143,42 +144,37 @@ role or agent asking for a shell needs a policy row added with
|
|
|
143
144
|
|
|
144
145
|
## Async sync semantics
|
|
145
146
|
|
|
146
|
-
`sync
|
|
147
|
+
`sources/sync` and `sources/reindex` return **202 + a queue job snapshot**
|
|
147
148
|
(`{jobId, source, mode, status}`) immediately — the run executes on the
|
|
148
|
-
server-side sync queue. Poll `sync-status
|
|
149
|
+
server-side sync queue. Poll `sources/sync-status` (`-f source=<slug>`) until
|
|
149
150
|
`status` leaves `pending`/`running`; a `failed` job carries `error`, a
|
|
150
|
-
`cancelled` one is not an error (partial progress stays valid). `cancel
|
|
151
|
-
with `
|
|
151
|
+
`cancelled` one is not an error (partial progress stays valid). `sources/cancel`
|
|
152
|
+
with `source` stops one source's job mid-run; without it, EVERY job on
|
|
152
153
|
sources you can see.
|
|
153
154
|
|
|
154
155
|
An embedding job can end `paused`: report `result.embedding.pausedReason` and partial counts. Resume is a new explicitly authorized `reembed.sh` request, using durable point debt; no saved job ID or automatic paid restart.
|
|
155
156
|
|
|
156
|
-
`sync
|
|
157
|
+
`sources/sync` refuses in two ways worth telling apart. **404** — the slug does not
|
|
157
158
|
resolve for you (it does not exist, or it is outside your scope; the two answer
|
|
158
159
|
alike on purpose). **400** — the source exists but carries no `sync` block, so
|
|
159
|
-
there is nothing to trigger: add one with
|
|
160
|
+
there is nothing to trigger: add one with an update first. Neither is a server
|
|
160
161
|
fault, so neither should be retried unchanged.
|
|
161
162
|
|
|
162
|
-
##
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
`
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
resolves the source's open notifications (its unread failure warnings) for you and its creator.
|
|
174
|
-
- `SOURCE` — source name for `sync.sh`, `reindex.sh`, `reset.sh`, `reembed.sh` (required) and
|
|
175
|
-
`cancel.sh`, `sync-status.sh` (optional).
|
|
176
|
-
- `FOLDER` / `URI` — `reembed.sh` scope (one of them, inside `SOURCE`; neither = the whole
|
|
163
|
+
## Fields, bodies and script env
|
|
164
|
+
|
|
165
|
+
- `<slug>` is a real path segment for get and delete ONLY. The update does NOT
|
|
166
|
+
take a slug — it keys off the `source` field inside the body.
|
|
167
|
+
- `<kind>` in `sources/kinds/<kind>/schema` is a registry kind as listed by
|
|
168
|
+
`sources/kinds`, NOT a connector id or a UI label. An unregistered value is
|
|
169
|
+
`404 Unknown kind "<x>"` for every caller.
|
|
170
|
+
- `?purge=1` on delete enqueues an async vector purge. Delete then returns
|
|
171
|
+
**202 + `{purgeJob, …}`** (vs 200 normally). Any delete resolves the source's
|
|
172
|
+
open notifications (its unread failure warnings) for you and its creator.
|
|
173
|
+
- `reembed.sh` takes `SOURCE` (required) and `FOLDER` / `URI` — its scope (one of them, inside `SOURCE`; neither = the whole
|
|
177
174
|
source). `CONFIRM=1` starts debt catchup; without it the script only ESTIMATES. `FORCE=1` selects a forced connector re-embed instead.
|
|
178
175
|
`SCOPE=platform` (catch-up only, whole source, needs `platform.vector.maintain`) catches up EVERY
|
|
179
176
|
writer's points of the source, not only yours — the way back after an operator dense clear.
|
|
180
|
-
-
|
|
181
|
-
- `BODY_JSON` — POST/PATCH bodies (`create.sh`, `update.sh`). Both MUST include
|
|
177
|
+
- Create and update bodies (`--input -`) MUST include
|
|
182
178
|
`source` + `permissions`; create additionally requires `connection.kind`. May also
|
|
183
179
|
carry `recognizesPackages` (boolean; absent or `null` = unchanged, so a listing
|
|
184
180
|
round-tripped through jq never 400s on it) — see **Package sources** below. A `sync`
|
|
@@ -192,14 +188,14 @@ Per-action:
|
|
|
192
188
|
`permissions.paths[]` — so narrowing a wide source with `include` alone leaves every
|
|
193
189
|
file under that root readable. Re-root it, or add a path deny, or both.
|
|
194
190
|
|
|
195
|
-
|
|
191
|
+
**The update REPLACES `permissions` wholesale — it does not merge.** A PATCH body
|
|
196
192
|
carrying only `permissions.default` answers `200` and **silently drops every
|
|
197
193
|
`paths[]` rule the source was carrying** (`data` typically holds dozens of
|
|
198
194
|
per-package rules). Immutable `floor:true` rules are the one protected class — omitting
|
|
199
195
|
one returns `409` instead of destroying it — so a green `200` is NOT evidence that the
|
|
200
196
|
rest survived. Never hand-write a `permissions` object for an existing source: read the
|
|
201
|
-
current one with `
|
|
202
|
-
to change. Every
|
|
197
|
+
current one with `GET sources` and send it back unchanged, editing only the field you meant
|
|
198
|
+
to change. Every update example below does exactly that.
|
|
203
199
|
|
|
204
200
|
**`syncExcludes` is a PREFERENCE; the uri policy is the security half. Do not
|
|
205
201
|
confuse them.** A source's `sync.exclude` list is yours to edit — it is noise
|
|
@@ -218,28 +214,28 @@ theirs.
|
|
|
218
214
|
|
|
219
215
|
## Clean index without detaching the source
|
|
220
216
|
|
|
221
|
-
`purge
|
|
217
|
+
`POST sources/purge` takes `{source,selector:{kind:"source"|"folder"|"file",uri?},mode:"estimate"|"apply",obsoleteOnly:true|false}`. `source` and `mode` are required (no `mode` is a 400, never an implicit apply); a `folder` or `file` selector names a canonical URI inside the source; `kind:"source"` selects the whole source. It returns only authorized counts: `removedParents`, `removedChunks`, `retained`, `unresolved`, `canMaintain`. Unreadable children are withheld. Missing configuration, invalid provenance or read failures are not deletion evidence; unresolved points stay untouched. No source config, host bytes, journal or baseline is deleted and no embedding provider is called.
|
|
222
218
|
|
|
223
|
-
|
|
219
|
+
`obsoleteOnly:true` cleans only current include/exclude or disabled-media exclusions. `false` clears all selected searchable cache, preserving recovery payloads; later sync can rebuild it. Existing scoped recovery-only payloads can remain locally retained if source config is physically absent; that marker grants no READ or indexing permission, and unmarked missing input or invalid provenance still blocks generation switching. Already recovery-only eligible records with unavailable input stay fully preserved without vectors in the target, including when source I/O returns no input; verified input restores searchable embedding. Estimate first, show counts and the selection, then resend the same body with `mode:"apply"`. Apply rereads authority and eligibility; an estimate is not an authorization token. In the Sources panel, **Clean index…** exposes the same selection, counts and confirmation. An idle manual source otherwise waits until the next requested FULL sync; targeted sync and Enabled/auto changes do not clean it.
|
|
224
220
|
|
|
225
221
|
```bash
|
|
226
|
-
# Disposable source from the lifecycle walkthrough only;
|
|
227
|
-
|
|
222
|
+
# Disposable source from the lifecycle walkthrough only; estimate first.
|
|
223
|
+
neuralis request POST @neuralis/brain-core/sources/purge --input - <<<'{"source":"scratch-demo","mode":"estimate","obsoleteOnly":true,"selector":{"kind":"source"}}'
|
|
228
224
|
# Apply only after reviewing the same selection’s counts.
|
|
229
|
-
|
|
225
|
+
neuralis request POST @neuralis/brain-core/sources/purge --input - <<<'{"source":"scratch-demo","mode":"apply","obsoleteOnly":true,"selector":{"kind":"source"}}'
|
|
230
226
|
# A canonical folder selection, still estimate-only:
|
|
231
|
-
|
|
227
|
+
neuralis request POST @neuralis/brain-core/sources/purge --input - <<<'{"source":"scratch-demo","mode":"estimate","obsoleteOnly":false,"selector":{"kind":"folder","uri":"scratch-demo://docs"}}'
|
|
232
228
|
```
|
|
233
229
|
|
|
234
230
|
## Re-embed (a file, a folder, a source)
|
|
235
231
|
|
|
236
|
-
"Rescan changes" reuses unchanged indexed files, but rebuilds re-included recovery-only content. `reembed.sh` catches up missing/stale indexed embeddings, including brain-only and unchanged legacy records. Its read-only estimate returns `estimate_kind:scope_upper_bound`: authorized indexed scope counts are an upper bound, not a provider quote; no provider call or job starts. Show the estimate before `CONFIRM=1` (202 + embedding job; poll `sync-status
|
|
232
|
+
"Rescan changes" reuses unchanged indexed files, but rebuilds re-included recovery-only content. `reembed.sh` catches up missing/stale indexed embeddings, including brain-only and unchanged legacy records. Its read-only estimate returns `estimate_kind:scope_upper_bound`: authorized indexed scope counts are an upper bound, not a provider quote; no provider call or job starts. Show the estimate before `CONFIRM=1` (202 + embedding job; poll `sources/sync-status`). Disabled embedding refuses: each `GET sources` row's `embedding_enabled` is the live platform switch, and while it is `false` `reembed.sh` answers 409 `embedding_disabled`; without an active dense generation the estimate refuses and a submitted job pauses as `metadata_only`, never activating a model. `FORCE=1` instead rereads and re-embeds the connector scope; its estimate includes `{documents,estimate:{tokens,relStdErr,usd,seconds}}` (`usd:null` for an unpriced model). A single file you may not read answers
|
|
237
233
|
`404`, exactly like a missing one. Switching the platform to a DIFFERENT model is not this:
|
|
238
234
|
that is the owner's rebuild in the admin Vector section.
|
|
239
235
|
|
|
240
236
|
## Package sources (`recognizesPackages`)
|
|
241
237
|
|
|
242
|
-
|
|
238
|
+
Create and update accept `recognizesPackages` (boolean) in the body. It does
|
|
243
239
|
NOT switch markdown discovery on — a synced source's markdown becomes source-package
|
|
244
240
|
contributions (skill / instruction / rule / agent / docs) either way; the flag lets the host
|
|
245
241
|
load the source as a runtime package source (create-package
|
|
@@ -267,25 +263,25 @@ scope (a different run identity sees nothing — correct-by-design, not a load f
|
|
|
267
263
|
```bash
|
|
268
264
|
# NOT DISPOSABLE — promoting is only meaningful on a source that already exists
|
|
269
265
|
# and already holds markdown, so this edits a REAL source. `repo` is a stand-in:
|
|
270
|
-
# substitute a slug from list.
|
|
266
|
+
# substitute a slug from the sources list. The effect is live — every matching .md under
|
|
271
267
|
# it starts being advertised as a package contribution on the next sync — and it
|
|
272
268
|
# is reversible only by resending the same body with `recognizesPackages:false`.
|
|
273
269
|
# Needs drive.mount, then priority <= 2 (the admin anchor) or a '*' grant, and a
|
|
274
270
|
# local-kind source. The body carries the source's CURRENT permissions back —
|
|
275
271
|
# PATCH replaces them:
|
|
276
|
-
|
|
272
|
+
neuralis request GET @neuralis/brain-core/sources --jq '.[] | select(.source=="repo") | {source, permissions, recognizesPackages:true}' | neuralis request PATCH @neuralis/brain-core/sources --input -
|
|
277
273
|
```
|
|
278
274
|
|
|
279
275
|
## `description` field
|
|
280
276
|
|
|
281
|
-
Both create and update accept an optional `description` (string) in
|
|
277
|
+
Both create and update accept an optional `description` (string) in the body.
|
|
282
278
|
It is a one-line summary of what the source holds; it is persisted on the source
|
|
283
279
|
config and loaded into the agent system prompt's `<runtime_stack>` source table,
|
|
284
280
|
so keep it short and purpose-focused (e.g. `"Project data zone — working files"`).
|
|
285
281
|
|
|
286
282
|
**Leaving it unset is fine.** The description you see is RESOLVED, not
|
|
287
283
|
necessarily stored: the authored text, else what the owning package declared for
|
|
288
|
-
that source, else what the connector kind says it is.
|
|
284
|
+
that source, else what the connector kind says it is. The list and the get
|
|
289
285
|
return both — `description` is what is on disk, `description_effective` is what
|
|
290
286
|
the agent actually reads. So a blank `description` with a non-null
|
|
291
287
|
`description_effective` is a source described by its package, not an undescribed
|
|
@@ -298,18 +294,22 @@ each sync — you do not set them.
|
|
|
298
294
|
## Examples
|
|
299
295
|
|
|
300
296
|
```bash
|
|
301
|
-
|
|
302
|
-
#
|
|
297
|
+
neuralis request GET @neuralis/brain-core/sources
|
|
298
|
+
# a TOP-LEVEL ARRAY → filter with .[] (NOT .sources[]):
|
|
303
299
|
# Each row IS the source config: the slug lives in `.source` (there is no `.slug` key).
|
|
304
|
-
|
|
305
|
-
|
|
306
|
-
#
|
|
307
|
-
#
|
|
300
|
+
neuralis request GET @neuralis/brain-core/sources --jq '.[] | {source, enabled, kind: .connection.kind, orphan}'
|
|
301
|
+
neuralis request GET @neuralis/brain-core/sources --jq '.[] | select(.connection.kind=="local")'
|
|
302
|
+
# The kind is the registry KIND, not a connector id or a UI label. Enumerate them
|
|
303
|
+
# (today: brain, host, local, webtop); an unregistered value is 404
|
|
308
304
|
# `Unknown kind "<x>"` for EVERY caller, so it is never a permission problem.
|
|
309
305
|
# The on-disk connector's id is `local-disk` but its kind is `local` — send `local`.
|
|
310
|
-
|
|
311
|
-
|
|
312
|
-
|
|
306
|
+
neuralis request GET @neuralis/brain-core/sources/kinds --jq '.kinds[].kind'
|
|
307
|
+
neuralis request GET @neuralis/brain-core/sources/kinds/local/schema
|
|
308
|
+
neuralis request POST @neuralis/brain-core/sources/sync -f source=data # needs drive.sync
|
|
309
|
+
neuralis request GET @neuralis/brain-core/sources/sync-status -f source=data
|
|
310
|
+
# `"auto"` = live only while the source's runtime runs; a boolean is typed with -F
|
|
311
|
+
neuralis request POST @neuralis/brain-core/sources/enabled -f source=data -F enabled=true
|
|
312
|
+
neuralis request GET @neuralis/brain-core/sources/browse -f path=/tmp # needs drive.mount
|
|
313
313
|
```
|
|
314
314
|
|
|
315
315
|
### Lifecycle walkthrough — create → update → delete
|
|
@@ -327,26 +327,26 @@ the throwaway.
|
|
|
327
327
|
```bash
|
|
328
328
|
# 1. Create (needs drive.mount). source + connection.kind + permissions.default.* required.
|
|
329
329
|
# The root does not have to exist yet — create records the coordinate, sync walks it.
|
|
330
|
-
|
|
330
|
+
neuralis request POST @neuralis/brain-core/sources --input - <<<'{"source":"scratch-demo","connection":{"kind":"local","config":{"root":"/tmp/scratch-demo"}},"permissions":{"default":{"read":true,"write":true,"exec":false}}}'
|
|
331
331
|
# 2. Update — NO SLUG; the body `source` field is the key (needs drive.mount).
|
|
332
332
|
# Sets the description shown in the agent <runtime_stack>. `permissions` is
|
|
333
333
|
# REPLACED, so read the live object back and resend it unchanged, editing only
|
|
334
334
|
# the field you meant to change — a hand-written {"default":…} body here would
|
|
335
335
|
# delete every paths[] rule the source carried:
|
|
336
|
-
|
|
337
|
-
# 3. DESTRUCTIVE — deletes the source config, and with
|
|
336
|
+
neuralis request GET @neuralis/brain-core/sources --jq '.[] | select(.source=="scratch-demo") | {source, permissions, description:"Throwaway source — lifecycle demo"}' | neuralis request PATCH @neuralis/brain-core/sources --input -
|
|
337
|
+
# 3. DESTRUCTIVE — deletes the source config, and with ?purge=1 enqueues an async purge
|
|
338
338
|
# of every vector indexed under it. Returns 202 + {purgeJob} when purging, 200
|
|
339
339
|
# otherwise. There is no undo and no backup. Only ever aim this at a source you
|
|
340
340
|
# created yourself; never at `data`, `packages` or `brain`.
|
|
341
|
-
|
|
341
|
+
neuralis request DELETE '@neuralis/brain-core/sources/scratch-demo?purge=1'
|
|
342
342
|
```
|
|
343
343
|
|
|
344
344
|
## Vector health (index diagnostics)
|
|
345
345
|
|
|
346
346
|
The health route is SPLIT into a count-cheap path and a scan path (pattern `health/*`, feature
|
|
347
|
-
`drive.read`) — call it with
|
|
347
|
+
`drive.read`) — call it with `neuralis request`. **The two
|
|
348
348
|
read paths run on `drive.read`; the `gc` path does not** — it additionally requires `drive.write`
|
|
349
|
-
and is POST-only (see below). That covers
|
|
349
|
+
and is POST-only (see below). That covers its actions: `gc`, `repair-orphans` and `repair-pending`
|
|
350
350
|
mutate, and `deduplicate` is read-only but rides the same gate — its rows enumerate other agents'
|
|
351
351
|
`data://` paths.
|
|
352
352
|
|
|
@@ -359,14 +359,14 @@ mutate, and `deduplicate` is read-only but rides the same gate — its rows enum
|
|
|
359
359
|
`duplicateGroups` are COUNTS (numbers) — read them directly, never `|length`. The full duplicate
|
|
360
360
|
ROWS arrive only from `POST …/health/gc {action:deduplicate}` → `{ duplicates: DuplicateGroup[] }`
|
|
361
361
|
(each `{contentHash, source, paths, ids}`).
|
|
362
|
-
- **`POST …/brain-core/health/gc`** with `{action}` (`gc` / `repair-orphans` / `deduplicate`) —
|
|
363
|
-
`gc` and `repair-
|
|
362
|
+
- **`POST …/brain-core/health/gc`** with `{action}` (`gc` / `repair-orphans` / `repair-pending` / `deduplicate`) —
|
|
363
|
+
`gc`, `repair-orphans` and `repair-pending` MUTATE — run those only after a scan confirms a finding; `deduplicate`
|
|
364
364
|
removes nothing (it reports groups) but is gated identically. **POST only** — a GET answers
|
|
365
365
|
`405 Method GET not allowed`. It needs **`drive.write`** on top of the route's `drive.read`; a
|
|
366
366
|
caller without it gets `403 {"error":"Missing feature: drive.write (vector health repair)"}`.
|
|
367
367
|
That is a capability the caller lacks, not a broken call: report the finding and say that the
|
|
368
368
|
sweep needs `drive.write` (manager tier and up), rather than retrying.
|
|
369
|
-
`dryRun` DEFAULTS TO FALSE — pass `{"dryRun": true}` first when you want a preview.
|
|
369
|
+
`dryRun` DEFAULTS TO FALSE — pass `{"dryRun": true}` first when you want a preview. `repair-pending` processes one visible batch (default 50) and returns `scannedVisible`, `orphaned`, `attempted`, `discarded`, `refused`, `failed`, safe reason counts, `nextCursor`, `complete` and `partial`. Pass the returned `nextCursor` as `cursor` in the next POST only after checking the result; pause on partial/failure, retry explicitly, and restart on `restartRequired`. Each page reconstructs the complete projected inventory; the batch bounds mutations, not scan work. A terminal acknowledgement is not a newly discarded record.
|
|
370
370
|
- **`GET …/brain-core/health/hot-uris`** → the files the index rewrote most in the last hour:
|
|
371
371
|
`{windowMinutes, threshold, uris: [{uri, writes, points, lastWriteAt, hot}]}` (`writes` = file
|
|
372
372
|
writes, `points` = index points incl. chunks). Same `drive.write` gate; already filtered to the
|
|
@@ -377,11 +377,9 @@ mutate, and `deduplicate` is read-only but rides the same gate — its rows enum
|
|
|
377
377
|
|
|
378
378
|
```bash
|
|
379
379
|
# counts (cheap):
|
|
380
|
-
|
|
381
|
-
"${NEURALIS_API}/api/packages/@neuralis/brain-core/health"
|
|
380
|
+
neuralis request GET @neuralis/brain-core/health
|
|
382
381
|
# orphans / duplicate groups (scrolls — slower):
|
|
383
|
-
|
|
384
|
-
"${NEURALIS_API}/api/packages/@neuralis/brain-core/health/scan"
|
|
382
|
+
neuralis request GET @neuralis/brain-core/health/scan
|
|
385
383
|
```
|
|
386
384
|
|
|
387
385
|
### Health steps
|
|
@@ -1,7 +1,5 @@
|
|
|
1
1
|
#!/usr/bin/env bash
|
|
2
2
|
set -euo pipefail
|
|
3
|
-
API_BASE="${NEURALIS_API:?NEURALIS_API not set; activate skill first}"
|
|
4
|
-
TOKEN="${NEURALIS_SESSION_TOKEN:?missing session ticket; activate the skill via execute action=\"skill\"}"
|
|
5
3
|
# Requires drive.sync (403 otherwise). FORCE=1 re-embeds with the ACTIVE model; otherwise catches up durable embedding debt — a
|
|
6
4
|
# file (URI), a folder's indexed files (FOLDER) or, with neither, the whole
|
|
7
5
|
# source — even when nothing changed. Default = the ESTIMATE only (changes
|
|
@@ -21,7 +19,5 @@ BODY=$(jq -n --arg source "${SOURCE}" --arg folder "${FOLDER}" --arg uri "${URI}
|
|
|
21
19
|
+ (if $force == "1" then {force: ($confirm == "1")} else {embeddingOnly: true} end)
|
|
22
20
|
+ (if $scope == "" then {} else {scope: $scope} end)
|
|
23
21
|
+ (if $confirm == "1" then {} else {estimate: true} end)')
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
-H "Content-Type: application/json" -d "${BODY}" \
|
|
27
|
-
"${API_BASE}/api/packages/@neuralis/brain-core/sources/reindex"
|
|
22
|
+
# A non-2xx answer prints the route's body and `HTTP <code>` on stderr and exits 1.
|
|
23
|
+
neuralis request POST @neuralis/brain-core/sources/reindex --input - <<<"${BODY}"
|
|
@@ -12,10 +12,11 @@ Patch the `paths[]` rules on a brain-core source-config so subsequent
|
|
|
12
12
|
it edits the URI policy on any source (`data://`, `packages://`,
|
|
13
13
|
`brain://`, future remote connectors), not vector or embedding state.
|
|
14
14
|
|
|
15
|
-
|
|
16
|
-
per-stream session ticket
|
|
17
|
-
|
|
18
|
-
gate on your real granted features server-side
|
|
15
|
+
Covers the brain-core `policies/uri` routes, called with `neuralis request` —
|
|
16
|
+
inside an activated skill it authenticates with the per-stream session ticket
|
|
17
|
+
(your real identity), on your own machine with `neuralis login`. The routes
|
|
18
|
+
gate on your real granted features server-side; a non-2xx prints the route's
|
|
19
|
+
body and `HTTP <code>` on stderr and exits 1.
|
|
19
20
|
|
|
20
21
|
## When to use
|
|
21
22
|
|
|
@@ -27,69 +28,56 @@ gate on your real granted features server-side.
|
|
|
27
28
|
|
|
28
29
|
## Routes
|
|
29
30
|
|
|
30
|
-
| Method | Path
|
|
31
|
-
|
|
32
|
-
| GET |
|
|
33
|
-
| GET |
|
|
34
|
-
| POST |
|
|
31
|
+
| Method | Path (`@neuralis/brain-core/…`) |
|
|
32
|
+
|---|---|
|
|
33
|
+
| GET | `policies/uri/manifests` |
|
|
34
|
+
| GET | `policies/uri/<source>` |
|
|
35
|
+
| POST | `policies/uri` |
|
|
35
36
|
|
|
36
|
-
##
|
|
37
|
+
## Calls
|
|
37
38
|
|
|
38
39
|
### Show effective URI policy for a source
|
|
39
40
|
|
|
40
41
|
```bash
|
|
41
|
-
|
|
42
|
+
neuralis request GET @neuralis/brain-core/policies/uri/data
|
|
42
43
|
```
|
|
43
44
|
|
|
44
|
-
Required env vars (pass via `execute action="shell" env={...}`):
|
|
45
|
-
- `SOURCE` — source slug (e.g. `data`, `packages`).
|
|
46
|
-
|
|
47
45
|
### Add or remove a path rule
|
|
48
46
|
|
|
49
47
|
**`addRule` takes effect the moment it returns — on a REAL source.** There is no
|
|
50
48
|
staging, no preview and no dry run: the next `fs_read`, route call, UI listing or
|
|
51
49
|
shell command evaluated against that source already sees the new rule, for every
|
|
52
|
-
caller it names. `
|
|
50
|
+
caller it names. `removePatterns` is the only undo, and it matches on the `pattern`
|
|
53
51
|
string, so a rule you cannot spell exactly is a rule you cannot take back. Read
|
|
54
|
-
the current policy
|
|
52
|
+
the current policy before and after — the pair below is
|
|
55
53
|
written to be run top-to-bottom and leaves the policy exactly as it found it.
|
|
56
|
-
One caveat the rules do not show: a
|
|
54
|
+
One caveat the rules do not show: a removal is not always the last word
|
|
57
55
|
across a restart. The old cause is FIXED — the route no longer un-stamps
|
|
58
56
|
`baselineRepairVersion`, so a patch (a no-op included) does not re-arm the
|
|
59
57
|
baseline repair and cannot resurrect a rule you removed. What remains is the
|
|
60
58
|
legitimate case: a package that SHIPS a new manifest baseline, or a connector
|
|
61
59
|
that adds a `floor:true` row, still reaches an existing source on the next boot
|
|
62
60
|
by design — floors are reconciled on every boot, past the version stamp. So
|
|
63
|
-
re-check
|
|
61
|
+
re-check the policy after a restart when a package version changed, and
|
|
64
62
|
read a reappeared rule as a NEW declaration rather than as your removal being
|
|
65
63
|
undone.
|
|
66
64
|
|
|
67
65
|
```bash
|
|
68
66
|
# 0. Read the policy you are about to change, so you can prove you restored it.
|
|
69
|
-
|
|
67
|
+
neuralis request GET @neuralis/brain-core/policies/uri/data
|
|
70
68
|
# 1. Add the rule (LIVE — members lose read on this subtree immediately).
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
ROLES=member \
|
|
75
|
-
bash ${SKILL_DIR}/scripts/set-uri.sh
|
|
76
|
-
# 2. Take it back — same SOURCE, same PATTERN, byte for byte.
|
|
77
|
-
SOURCE=data \
|
|
78
|
-
PATTERN='data://agent-core/admin/**' \
|
|
79
|
-
OPERATION=removeRule \
|
|
80
|
-
bash ${SKILL_DIR}/scripts/set-uri.sh
|
|
69
|
+
neuralis request POST @neuralis/brain-core/policies/uri --input - <<<'{"source":"data","addPaths":[{"pattern":"data://agent-core/admin/**","permissions":{"read":false},"roles":["member"]}]}'
|
|
70
|
+
# 2. Take it back — same source, same pattern, byte for byte.
|
|
71
|
+
neuralis request POST @neuralis/brain-core/policies/uri --input - <<<'{"source":"data","removePatterns":["data://agent-core/admin/**"]}'
|
|
81
72
|
```
|
|
82
73
|
|
|
83
74
|
To keep a rule, run step 1 and stop; step 2 exists so the example is reversible
|
|
84
75
|
rather than a permanent edit to a live source's access policy.
|
|
85
76
|
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
- `DENY` — comma-list of capabilities to deny (`read,write,exec`).
|
|
91
|
-
- `ALLOW` — comma-list of capabilities to allow.
|
|
92
|
-
- `ROLES` — comma-list of roles to scope the rule to.
|
|
77
|
+
Body: `source` (slug, required) plus either `addPaths` — rules of `{pattern,
|
|
78
|
+
permissions, roles?}`, where `pattern` takes `**` wildcards, `permissions` maps
|
|
79
|
+
`read`/`write`/`exec` to `false` (deny) or `true` (allow) and `roles` scopes the
|
|
80
|
+
rule — or `removePatterns` (the patterns to take back).
|
|
93
81
|
|
|
94
82
|
`exec` decides whether a shell may START in that directory — on an exec-capable
|
|
95
83
|
source (a virtual desktop or any other one whose connector runs commands) as
|
|
@@ -101,34 +89,19 @@ refused" usually needs an `exec` ALLOW row for their role or agent here.
|
|
|
101
89
|
### List baseline URI policies from every loaded package's manifest
|
|
102
90
|
|
|
103
91
|
```bash
|
|
104
|
-
|
|
92
|
+
neuralis request GET @neuralis/brain-core/policies/uri/manifests
|
|
105
93
|
```
|
|
106
94
|
|
|
107
|
-
|
|
95
|
+
Returns every package's resolved `uriPolicies` baseline
|
|
108
96
|
(read-only). Useful for diffing the persisted source-config against the
|
|
109
97
|
package's seed.
|
|
110
98
|
|
|
111
|
-
## Substitution placeholders
|
|
112
|
-
|
|
113
|
-
When this skill is activated the host substitutes:
|
|
114
|
-
|
|
115
|
-
- `${SKILL_DIR}` → container path of this skill bundle
|
|
116
|
-
(e.g. `/neuralis/packages/brain-core/skills/manage-uri-policy`).
|
|
117
|
-
- `${NEURALIS_API}` → the host's internal API base URL.
|
|
118
|
-
- `${SKILL_URI}` → `neuralis://`-addressable URI if the `neuralis://`
|
|
119
|
-
source is enabled, otherwise a sentinel.
|
|
120
|
-
|
|
121
|
-
If `${SKILL_DIR}` resolves to a sentinel ("(no local containerDir)"),
|
|
122
|
-
there is no local script directory — unless the envelope printed a source directory URI to pass as `cwd`, read
|
|
123
|
-
`fs_read uri="${SKILL_URI}/SKILL.md"` for the procedure and call the
|
|
124
|
-
routes manually with `execute action="shell" command="curl ..."`.
|
|
125
|
-
|
|
126
99
|
## Notes
|
|
127
100
|
|
|
128
101
|
- **Two arms, both keyed on FEATURES — there is no role-name check on this
|
|
129
|
-
route.** Reading (`GET
|
|
102
|
+
route.** Reading (`GET policies/uri/...`) is
|
|
130
103
|
the module feature `drive.read`, which every built-in role holds down to
|
|
131
|
-
`viewer`. Patching (`POST
|
|
104
|
+
`viewer`. Patching (`POST policies/uri`) escalates in-handler to
|
|
132
105
|
`drive.policy` and otherwise returns
|
|
133
106
|
`403 Missing feature: drive.policy (URI policy editing)`. `drive.policy` has
|
|
134
107
|
no grant below the `admin` tier (enumerated for `admin`, `'*'` for `owner`)
|
|
@@ -155,9 +128,8 @@ routes manually with `execute action="shell" command="curl ..."`.
|
|
|
155
128
|
conversation's creator). It is accepted only on an allow rule with
|
|
156
129
|
`override: true` — the server refuses it on a deny. That is how agent-core
|
|
157
130
|
ships conversations: `*/conversations/**` denied, re-granted to the creator
|
|
158
|
-
and to owner/admin, so a member sees only their own.
|
|
159
|
-
|
|
160
|
-
policy editor.
|
|
131
|
+
and to owner/admin, so a member sees only their own. Widening who sees a
|
|
132
|
+
conversation is done in the source's policy editor.
|
|
161
133
|
- **Connector-agnostic.** A rule like `roles:["member"] deny:["write"]`
|
|
162
134
|
on `webtop://**` applies to a future WebtopConnector source just as
|
|
163
135
|
it does to `data://agent-core/**` today — the URI is the unit of
|
|
@@ -1,39 +0,0 @@
|
|
|
1
|
-
import { useEffect, useState, type RefObject } from 'react';
|
|
2
|
-
|
|
3
|
-
/**
|
|
4
|
-
* Reports whether a container is "wide" (≥ threshold), with hysteresis so a diff's
|
|
5
|
-
* auto unified↔split flip does not strobe while the user drags the widget across the
|
|
6
|
-
* boundary. Becomes wide at `wideThresholdPx`, flips back to narrow only below
|
|
7
|
-
* `wideThresholdPx − hysteresisPx`.
|
|
8
|
-
*
|
|
9
|
-
* It reads `clientWidth` ONLY — never `scrollWidth` — so the observer callback cannot
|
|
10
|
-
* force a layout flush of its own. (Its sibling `useElementFits` did compare the two
|
|
11
|
-
* and was deleted in 2026-08: it had no consumer anywhere in `packages/*`.)
|
|
12
|
-
*/
|
|
13
|
-
export function useContainerWidth<T extends HTMLElement>(
|
|
14
|
-
ref: RefObject<T | null>,
|
|
15
|
-
options?: { wideThresholdPx?: number; hysteresisPx?: number },
|
|
16
|
-
): boolean {
|
|
17
|
-
const wideThresholdPx = options?.wideThresholdPx ?? 900;
|
|
18
|
-
const hysteresisPx = options?.hysteresisPx ?? 60;
|
|
19
|
-
const [isWide, setIsWide] = useState(false);
|
|
20
|
-
|
|
21
|
-
useEffect(() => {
|
|
22
|
-
const element = ref.current;
|
|
23
|
-
if (!element) {
|
|
24
|
-
setIsWide(false);
|
|
25
|
-
return;
|
|
26
|
-
}
|
|
27
|
-
const update = () => {
|
|
28
|
-
const width = element.clientWidth;
|
|
29
|
-
setIsWide((prev) => (prev ? width >= wideThresholdPx - hysteresisPx : width >= wideThresholdPx));
|
|
30
|
-
};
|
|
31
|
-
update();
|
|
32
|
-
if (typeof ResizeObserver === 'undefined') return undefined;
|
|
33
|
-
const observer = new ResizeObserver(() => update());
|
|
34
|
-
observer.observe(element);
|
|
35
|
-
return () => observer.disconnect();
|
|
36
|
-
}, [ref, wideThresholdPx, hysteresisPx]);
|
|
37
|
-
|
|
38
|
-
return isWide;
|
|
39
|
-
}
|