@coreness/dsh 0.2.0 → 0.2.2
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/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@coreness/dsh",
|
|
3
|
-
"version": "0.2.
|
|
3
|
+
"version": "0.2.2",
|
|
4
4
|
"description": "The Coreness kit for DeepSeek Harness: a page of its own, the journal, the picture and the form of the profile's MCP servers, and the Qoder route — one bundle for a profile.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"deepseek-harness",
|
package/plugins/page/README.md
CHANGED
|
@@ -18,6 +18,7 @@ The product's own surface in the web UI: a row in the left sidebar and the panel
|
|
|
18
18
|
## Dependencies
|
|
19
19
|
|
|
20
20
|
- **The web shell's seats.** The row registers into the `sidebar.panellist` list and the panel into the keyed `main` seat, both declared by the platform's own packages (`@deepseek-ai/dsh-client-ui-sidebar`, `@deepseek-ai/dsh-client-ui-layout`). The registrations go through `ctx.slots.inject`, which waits for a declaration, so the load order does not matter and a missing neighbour leaves the plugin mounted with no surface rather than failing.
|
|
21
|
+
- **A section is handed no id of its own row, and that is the platform's contract rather than a gap of ours.** The props a registered component receives are composed from the five framework shares named at `a:dsh-client-ui-slots/README.md:38` — the runtime share (`owner` from the parent's render call site, the session standard kit and the global seat), the child-render share, the Factory-render share, the store share and the business share — and an id of registration is not among them. What the shell keys a contribution by is the **address of the call** that renders it: `a:dsh-client-ui-renderer/lib/client.js:1148-1157` elects an entry by `opts?.entryKey` for a keyed slot and guards every entry by `entryKeyOf(entry)`. A section therefore knows the seat it was registered into and not the id of the row that registered it, so a namespace that **is** that id (the rate gate's `value.ns` is one) cannot be known without asking: it arrives with the route's own picture. The first round-trip is a property of this contract, not a defect to be fixed by reading harder.
|
|
21
22
|
- **The platform's remotes as the door to the profile's facts, read-only.** The overview reads `pluginManager.listBundles()` and `pluginManager.listPlugins()` and joins them by `entryId`, behind the `pluginInventory.list()` gate the platform's own Plugins page applies first. The version and the one-liner come from the bundle entry itself, so the browser half repeats neither. The read is invalidated as the host invalidates that page: `ctx.remote.$on('plugin-manager/changed')` and a reset connection make it read again while the page stands. The host half of this package stays empty: the profile's facts live in host-only services a browser half cannot see, and the remotes are the platform's own door to the same facts.
|
|
22
23
|
- **The platform's own doors to a route's facts, asked rather than known.** The Qoder section carries no list of its own: the route's declaration reaches it through `llm.listConfigurableProviders()`, the settings namespace that declaration names through `settings.describe()`, the presence of a value through `credentials.describe([ref])`, the two writes through `credentials.set()` and `settings.mutate()`, and the model the agent uses, its description and the effort that stands in force through `session.modelCatalog()`. **The vendor's live catalog comes through the route's own door** — `POST /api/coreness.qoder {action:'catalogue'}` — and not through the platform's discovery door the section used to ask: `llm.discoverModels` projects each entry onto five fields twice over (`a:dsh-llm/lib/index.js:2005-2011` and its remote schema), so the per-model reasoning menu died between the route and the page, and the route's own action answers the listing verbatim — one read gives the ids and the menus together, and two roads cannot drift apart. **The vendor's verdict on the value the store holds comes through that same door**: `POST /api/coreness.qoder {action:'verify'}` puts the value behind the row's reference to the exchange every turn enters by — one call — and answers with a closed vocabulary of three (`accepted`, `refused`, `unsettled`) carried as a result rather than as the route's refusal, because "the vendor does not take this value" is an answer to the question that was asked; the store can only say that a value is *there*, and a token that expired or was revoked read as configured until a turn failed, which is what sent the owner to replace a token that was never at fault. The check is asked when a value is handed over and when the reader presses again, never on a tick: one exchange per write, one per press, none on an open. The discovery door stays registered for the platform's own model picker, which is the surface that offers a model to adopt. The reference travels one path and only that path — the declaration's settings path down to `apiKeyEnv`, the route the platform's own Models page walks — because a composition read cannot stand in for it: the manager's entries carry no row config, so a key name derived here would be a key the route never reads. The catalog is asked once per mount and kept across every re-read of the settings, because it is the node's own answer and no write of ours changes it; a vendor that has added a model since the last mount is read on the next one.
|
|
23
24
|
- **The gate's own route, read as a picture and never written.** The rate gate's section asks the plugin's `GET /api/coreness.rateGate` for the live window and asks nothing else of the host half: the namespace it writes is the one the picture names (`value.ns`), not a constant of the page, because the namespace is the row's id and a second copy here would drift from the assembly that mounts the row. The write is the platform's own settings door — `settings.describe()` for the row and its revision, `settings.mutate(ns, ops, revision)` to write — the same door the platform's own Models page uses, and the route never carries one: a page that wrote through the plugin's route would be writing around the platform's conflict check. The picture is read again while the section stands, because the window moves with no session event: one read on the mount, one after every write, and a beat of two seconds that a hidden document skips — a glance at another tab is not a reason to ask the host for a picture nobody sees.
|
|
@@ -95,6 +96,12 @@ What that does not cover, named rather than left silent: the platform's own Mode
|
|
|
95
96
|
|
|
96
97
|
**The page's type is read, not assumed, and three of its readings differ from the host's on purpose.** The step `node scripts/page-form.mjs roles` prints every role of each section beside the same role on the host's own pages and lists the ones that differ; the list is short by decision and the decisions are named here, so a later session reads them as choices rather than as debt. The panel's own headline — the product's `Coreness` at 20/28 500 — is a **panel** title and not a card's, and the user keeps it as it stands; the panel itself carries neither padding nor radius for the same reason, **a panel is not a card**, and the shell's own panel is what it copies. Our chip reads **12/18 400** in the tertiary grey (`coreness-tag`, the element a `v0.1.0`-shaped value stands in): the page's small role, and the pair a label takes everywhere since the sizes were merged, with the weight and the tertiary grey a label keeps. The host's own status tag is **measurably** another thing — `10px/10px` at weight 500 in `rgb(65, 118, 230)`, padding `0/7/0/7`, on the element `_tag_brmue_4 fO69Vq_statusTag` and the word `Experimental` — and both readings come from the same step, `node scripts/page-form.mjs roles`. They are two surfaces and not a contradiction: that tag lives on the host's **own** pages (the plugin manager, `Settings → Models`), while "nothing below 12 px" was read in the shell and its sidebar. One detail worth keeping from the same reading: on the host **one element answers two roles** — its chip and its status word are one element. Our decision stands on the measurement: a blue tag is a **state of the platform**, not a label of ours, and taking it as the model would make every label on the page shout; and the product's own version pill — the `v0.1.0` in the panel's head — carries **no border** where the three chips of the sections carry a hairline, by the same reading: a version pill is drawn like the host's own tag and not like a value chip, and the user agreed to leave it so. And the page reserves nothing, by the user's own rule: "У нас есть тексты, между текстами просто интервалы, между карточками просто интервалы, и мы вообще в принципе ничего не резервируем, как правило… Никаких фикс-размеров нет." So a room that held a height for a state, a word or a peer that had not arrived yet is a defect and not a habit: a room takes the height of what it says, and the block around it grows — the Rate card lost its state room that way, and the Rate row's head lost its two reserved lines the same way. The **one** box that keeps a size is the answer's strip (`flex:0 0 160px`, drawn always, empty without a word): the user asked for that one himself so that an answer moves nothing, and it is named here as the exception a later session must not "unreserve" in the name of this rule. The Qoder **Connection** card is an exception to the form-pair rule and stands as it is: its actions are `Save token`, `Clear token` and `Check token`, its own three, and it carries **no** `Cancel`/`Apply` pair — the user's own words, "у неё просто свои специфические кнопки", after the lead offered to unify it. A later session that reads one page and one convention must not "unify" it: the rule "Cancel on the left, Apply on the right" belongs to the cards that submit a **form** — the MCP editor, Qoder's models card, the Rate card — and a card whose presses act on one value of their own keeps its own words. **A pair belongs to the card it stands in, and that is written down because it is not obvious:** the section's pair writes the section's own numbers, and a row's editor carries its own three actions — `Remove`, `Cancel`, `Apply` — on a line of their own at the bottom right under its fields, where `Remove` stands only for a row that already exists (a row just added has nothing to go back to, and its `Cancel` takes it out). The user's words: "кнопки «Cancel» и «Apply» принимаются к той карточке, в которой они находятся. Это лучше сразу записать и сделать, чтобы мы не ломали логику, которая должна быть по умолчанию, потому что она неочевидна." And two blocks left the Rate section by his word ("про rate limiter в самом низу какой-то мусор… это всё мусор"), and what a reader loses with them is named here rather than left to be discovered: the per-provider sum of ceilings (what one key faces, which this page alone showed, the platform's own pages showing no such sum) and the list of rows the gate would not use — the one place such a row was named **before** a press. That second loss is covered elsewhere: the refusal is the platform's own, it comes back on `Apply` in the card's own strip, and a row the schema will not take is refused at the write, which is where the reader meets it. The row's own counter line (`used of ceiling tokens · nothing waiting · not used: …`) left with them, and its numbers stand where they are edited: the gate's fields carry what it runs with, and the live spend is what the platform's own gate route answers. And where the host draws no field label at all (its own Settings page prints `field label: nothing stands there`), the rule that decides is this page's own: **a small line that names is 500, a small line that explains is 400, and the two share one size and one colour** — the field's name against the sentence under it, so a reader can tell "this is the field" from "this is about the field" without a size change, which is what the user asked for in the Rate card.
|
|
97
98
|
|
|
99
|
+
**Three classes of check, and what each of them cannot see (2026-10-10; both misses below were paid for in one day).** The **declaration** is read from the sheets with no browser at all: `node scripts/page-css-read.mjs` names the rules that bound a height, the distances in use and the type roles. The **geometry** is read from the drawn page: `widths`, `tiles`, `fit`, `gaps` and the frame walks `frames`, `steady` and `jump` read boxes, gaps and widths. The **content** is read from inside those boxes: `content` reads the value of every field and the word of every status, frame by frame. Each class is blind exactly where another sees. A check that asserted the **declaration** — "the field stretches with its container" — stood green while the drawn field read 590 px in a card holding 685 px, because a rule and the page it draws are two different facts. And every **geometric** check stood green while the rate gate's fields were drawn empty for two frames and filled after, because a value appearing inside a box that does not move is invisible to a reading of boxes; the content class is in turn blind to a move — a box that jumps under a value that stays is not its subject — which is what the frame walks are for. No one of the three is asked to stand for another.
|
|
100
|
+
|
|
101
|
+
**The level a value stands on is not a declaration fact** — and this is the sharpest form of the declaration's blindness, learned the same day. A value can be absent from the drawn page because it was **read** at the wrong level (a field read inside a wrapper that carries the unit suffix) and equally because it was **written** at the wrong level: the rate gate's memory was read at its mount and spread **beside** `view` instead of inside it, while every reading and writing of that section's state goes through `state.view` — so the first paint of a return was as empty as the first paint of a session, the shape of the cache was right and its place was wrong. Every declaration check stood green through it: a spread beside a key and a spread inside it are the same declaration. Only the guard that reads the **drawn** page, frame by frame, saw the empty place — which is why the three classes are kept beside each other and why a green here is never evidence about a level.
|
|
102
|
+
|
|
103
|
+
**Two rules every guard of this page keeps.** A guard **fails when it could not measure** — no card, no field, no frame, a section that never drew, a sampler that never stood in the page — because "I did not look" must not read as "all is well"; the refusal names what was missing, and the guards of the day were proved to refuse on exactly those shapes (an empty rail after a reload, a section drawn in no frame, a walk that measured no field). And a guard **says which run it took**, because the same numbers mean different things in different runs: `content` names its visit (`CONTENT_VISIT=first|return`) — on the **first** visit an empty field while the read is in flight is the norm, and only the geometry is judged (0 px of growth in the section and of movement of the add button), while on a **return** the numbers are known before the read and not one drawn frame may carry an empty field. `steady`'s own `STEADY_REQUIRE_WORD` and the values line `frames` prints exist for the same reason: a green whose subject is unknown is worth nothing.
|
|
104
|
+
|
|
98
105
|
## Boundaries
|
|
99
106
|
|
|
100
107
|
- **No route and no address of its own.** The panel is selected through the layout service, the selection lives in memory and does not survive a reload; the platform's web surface has no routes.
|
|
@@ -181,8 +181,18 @@ window.__ModuleLoader__.load({
|
|
|
181
181
|
.coreness-gate-line{margin:0;font-size:14px;line-height:22px;color:var(--dsw-alias-label-primary);overflow-wrap:anywhere}
|
|
182
182
|
.coreness-gate-fields{flex-direction:column;gap:8px;display:flex}
|
|
183
183
|
.coreness-gate-pair{flex-direction:column;gap:6px;display:flex}
|
|
184
|
-
|
|
185
|
-
.coreness-gate-row
|
|
184
|
+
/* The **row cards** — and only they — stand their three fields on one line; the section's own card (The limit) keeps
|
|
185
|
+
its fields one to a line and is untouched. Both kinds carry coreness-gate-row, which is how the drawing names a card
|
|
186
|
+
of this section's list, so the row cards carry a second class of their own and this rule names that one: a selector on
|
|
187
|
+
the shared class alone reached the section's card as well and narrowed its fields from 627 px to 560 — measured by the
|
|
188
|
+
driver's roundtrip step, which prints each field's width.
|
|
189
|
+
By the user's own reading of how it stood before ("раньше выбор провайдера, модели и окна стоял в одной строке"): the
|
|
190
|
+
line takes the card's whole inner width and the fields share it equally, so there is no empty space at either edge.
|
|
191
|
+
The pairs dissolve with display:contents and their fields become the line's own items; the equal share is written as
|
|
192
|
+
flex:1 1 0 on the field itself, which is what makes the three of them equal rather than sized by their content.
|
|
193
|
+
A backtick must not stand in these comments: this stylesheet is a template literal and one closes it. */
|
|
194
|
+
.coreness-gate-rowCard .coreness-gate-body{flex-direction:row;flex-wrap:wrap;align-items:flex-start}
|
|
195
|
+
.coreness-gate-rowCard .coreness-gate-body>.coreness-gate-pair{display:contents}
|
|
186
196
|
.coreness-gate-field{flex-direction:column;gap:6px;min-width:180px;flex:1 1 0;display:flex}
|
|
187
197
|
.coreness-gate-fieldLabel{color:var(--dsw-alias-label-secondary);align-items:center;gap:10px;font-size:12px;font-weight:500;line-height:18px;display:flex}
|
|
188
198
|
.coreness-gate-input{box-sizing:border-box;border:none;background:0 0;color:var(--dsw-alias-label-primary);flex:1 1 auto;min-width:0;font:inherit;padding:6px 10px;font-size:14px;line-height:22px}
|
|
@@ -610,7 +620,7 @@ window.__ModuleLoader__.load({
|
|
|
610
620
|
the draft draws no counters at all rather than a window of zero as a measured fact. */
|
|
611
621
|
|
|
612
622
|
const pairs = pairsOf(catalog);
|
|
613
|
-
return h('li', { key: `row${index}`, className: 'coreness-gate-row' }, [
|
|
623
|
+
return h('li', { key: `row${index}`, className: 'coreness-gate-row coreness-gate-rowCard' }, [
|
|
614
624
|
h('div', { key: 'card', className: 'coreness-gate-card', 'data-open': String(open) }, [
|
|
615
625
|
/* The card is fixed by the user's own word: it is small — a head and one row of fields — and a fold in
|
|
616
626
|
front of four fields costs a press and hides what the section is about. Its head therefore says what
|
|
@@ -794,17 +804,21 @@ window.__ModuleLoader__.load({
|
|
|
794
804
|
busy: false,
|
|
795
805
|
fault: null,
|
|
796
806
|
totals: totalsOf(null),
|
|
807
|
+
/* The picture and nothing else: what the file said, not what this visit did with it. It belongs **inside**
|
|
808
|
+
the view, which is the only thing the section reads — the first version of this memory spread it beside
|
|
809
|
+
`view`, on the top level of the state object, where no line ever read it: `view.read` stayed
|
|
810
|
+
`valuesOf(null)`, so a return visit painted an empty first frame exactly like a first one. One owner: what
|
|
811
|
+
the section reads lives where it reads it. */
|
|
812
|
+
...(held === null ? {} : {
|
|
813
|
+
status: held.picture.status,
|
|
814
|
+
picture: held.picture.picture,
|
|
815
|
+
settings: held.picture.settings,
|
|
816
|
+
read: held.picture.read,
|
|
817
|
+
catalog: held.picture.catalog,
|
|
818
|
+
totals: held.picture.totals,
|
|
819
|
+
fault: held.picture.fault,
|
|
820
|
+
}),
|
|
797
821
|
},
|
|
798
|
-
/* The picture and nothing else: what the file said, not what this visit did with it. */
|
|
799
|
-
...(held === null ? {} : {
|
|
800
|
-
status: held.picture.status,
|
|
801
|
-
picture: held.picture.picture,
|
|
802
|
-
settings: held.picture.settings,
|
|
803
|
-
read: held.picture.read,
|
|
804
|
-
catalog: held.picture.catalog,
|
|
805
|
-
totals: held.picture.totals,
|
|
806
|
-
fault: held.picture.fault,
|
|
807
|
-
}),
|
|
808
822
|
}));
|
|
809
823
|
const view = state.view;
|
|
810
824
|
|
|
@@ -283,7 +283,15 @@ window.__ModuleLoader__.load({
|
|
|
283
283
|
own card-to-card distance stays 8, which is the list's gap and not this row's margin). */
|
|
284
284
|
.coreness-mcp-addRow{margin-top:12px;display:flex}
|
|
285
285
|
.coreness-mcp-add:hover:not(:disabled){background:var(--dsw-alias-interactive-bg-hover)}
|
|
286
|
-
|
|
286
|
+
/* The editor stands where the cards of the list stand, so it keeps the page's card-to-card distance from whatever is
|
|
287
|
+
above it — a card, an empty state, or nothing at all. The first attempt hung that distance on what precedes the
|
|
288
|
+
editor (a sibling of the list), and that missed the state the user meets on a fresh machine: with no server declared
|
|
289
|
+
the list is not drawn, an empty state stands in its place, and the form touched it — 0 px against the 8 px the same
|
|
290
|
+
pair reads when a card is above. The distance belongs to the editor, not to its neighbour, so it is written there and
|
|
291
|
+
holds for every neighbour: card and form, empty state and form, form and form. What follows the editor keeps the same
|
|
292
|
+
value by the sibling rule. */
|
|
293
|
+
.coreness-mcp-rows + *,.coreness-mcp-editor + *{margin-top:8px}
|
|
294
|
+
.coreness-mcp-editor{border-radius:var(--dsw-radius-lg);background:var(--dsw-alias-bg-module-platform);flex-direction:column;gap:12px;padding:14px 16px;margin-top:8px;display:flex}
|
|
287
295
|
.coreness-mcp-editorHead{align-items:center;justify-content:space-between;gap:8px;display:flex}
|
|
288
296
|
.coreness-mcp-editorTitle{color:var(--dsw-alias-label-primary);font-size:14px;font-weight:500;line-height:22px}
|
|
289
297
|
.coreness-mcp-editorNote{flex:none;text-align:right;font-size:12px;line-height:18px}
|
|
@@ -202,7 +202,11 @@ window.__ModuleLoader__.load({
|
|
|
202
202
|
'models.text': 'Text',
|
|
203
203
|
'models.image': 'Image',
|
|
204
204
|
'models.remove': 'Remove',
|
|
205
|
-
'
|
|
205
|
+
/* The same word the limiter's own add control carries (`client.gate.js`, `control.add`): both add a model, and a
|
|
206
|
+
reader who meets the two sections one after the other must not be told they are different actions. The MCP
|
|
207
|
+
section's `Add a row` is a different act — it adds a row of headings — and it keeps its own key and its own
|
|
208
|
+
word. */
|
|
209
|
+
'models.addRow': 'Add a model',
|
|
206
210
|
'models.pick': 'Choose a model',
|
|
207
211
|
'models.unknown': 'not in the live catalog',
|
|
208
212
|
'models.catalogDown': 'live catalog unavailable',
|