@javierfrancoleal/plugin-authoring 0.0.0-stage → 1.0.1

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/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 J.Franco
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md CHANGED
@@ -1,3 +1,23 @@
1
- # Temporary Holding Version
1
+ # @javierfrancoleal/plugin-authoring
2
2
 
3
- This version is a temporary placeholder for this package. An operational version to replace this has been submitted for review and is awaiting a staged release.
3
+ Skill de **autoría de plugins** para DeepSeek Harness. Registra la skill
4
+ `plugin-authoring`, cuyo cuerpo (`assets/plugin-authoring.md`) contiene la guía
5
+ destilada para crear y publicar plugins sin redescubrir la arquitectura.
6
+
7
+ La skill cubre: los tres tipos de plugin (host / cliente / doble cara), la anatomía
8
+ de `package.json` + `cordis.patch.yml`, el half host (skills/comandos/efectos), el
9
+ half browser (`dsh.client` + `window.__ModuleLoader__` + slots), locale, tokens de
10
+ tema, instalación, gotchas y checklist de validación.
11
+
12
+ ## Uso
13
+
14
+ - **Agentes**: cargar la skill `plugin-authoring` antes de crear o extender un plugin.
15
+ - **Humanos**: leer `docs/PLUGIN-AUTHORING.md` (fuente canónica), copiar la plantilla
16
+ `templates/dsh-plugin/`, y usar `tools/new-plugin.sh` + `tools/check-plugin.sh`.
17
+
18
+ ## Instalación
19
+
20
+ Como cualquier bundle: añadir `@javierfrancoleal/plugin-authoring` a
21
+ `dsh.profile.bundles` (y su dependencia `link:`), `pnpm install`, y reiniciar la app.
22
+
23
+ Creado por **J.Franco**.
@@ -0,0 +1,186 @@
1
+ # How to author a DeepSeek Harness plugin (distilled)
2
+
3
+ DSH is a **Cordis** runtime. A plugin is an npm package with one or two halves:
4
+
5
+ - **Host half** `lib/index.js` (Node): skills, commands, services, scheduled work.
6
+ - **Browser half** `lib/client.js` (React): UI in the Web GUI.
7
+
8
+ Activation is via `cordis.patch.yml`, which inserts the plugin's row into the Loader.
9
+
10
+ ## Three kinds
11
+
12
+ | Kind | `dsh.bundle.patch` | `dsh.client` |
13
+ |---|---|---|
14
+ | Host-only (skill / command) | yes | no |
15
+ | Client-only (UI) | no | yes |
16
+ | Dual-face | yes | yes |
17
+
18
+ ## Files
19
+
20
+ ```
21
+ mi-plugin/
22
+ ├── package.json # exports + dsh.bundle.patch + dsh.client
23
+ ├── cordis.patch.yml # - insert: - id: mi-plugin name: '@scope/mi-plugin'
24
+ ├── lib/index.js # host half — export apply(ctx)
25
+ ├── lib/client.js # browser half — window.__ModuleLoader__.load(...)
26
+ ├── locale/*.json # meta.title / meta.description
27
+ ├── icon.svg
28
+ └── README.md
29
+ ```
30
+
31
+ ## package.json (dual-face minimum)
32
+
33
+ ```jsonc
34
+ {
35
+ "name": "@javierfrancoleal/mi-plugin",
36
+ "version": "1.0.0",
37
+ "type": "module",
38
+ "main": "lib/index.js",
39
+ "exports": {
40
+ ".": "./lib/index.js",
41
+ "./client": "./lib/client.js",
42
+ "./cordis.patch.yml": "./cordis.patch.yml",
43
+ "./package.json": "./package.json",
44
+ "./locale/*.json": "./locale/*.json"
45
+ },
46
+ "engines": { "node": ">=24", "dsh": ">=0.2.1-rc.0" },
47
+ "dsh": {
48
+ "manifestVersion": 1,
49
+ "bundle": { "patch": "./cordis.patch.yml" },
50
+ "client": {
51
+ "platform": "web",
52
+ "inject": ["@deepseek-ai/dsh-client-locale", "@deepseek-ai/dsh-client-ui-layout"]
53
+ }
54
+ },
55
+ "peerDependencies": { "@deepseek-ai/cordis": "~4.0.5" }
56
+ }
57
+ ```
58
+
59
+ ## Host half — register a skill (proven pattern)
60
+
61
+ ```js
62
+ import { readFile } from "node:fs/promises";
63
+ import { fileURLToPath } from "node:url";
64
+ import { BUNDLED_SKILL_RANK } from "@deepseek-ai/dsh-skill";
65
+
66
+ const PROVIDER_NAME = "javierfrancoleal-mi-plugin";
67
+ const SKILL_BODY_URL = new URL("../assets/mi-skill.md", import.meta.url);
68
+ const RESOURCE_BASE = { kind: "directory", path: fileURLToPath(new URL("../assets/", import.meta.url)) };
69
+ const CANDIDATE = {
70
+ name: "mi-skill",
71
+ description: "…",
72
+ invocation: { modelInvocable: true, userInvocable: true },
73
+ provider: PROVIDER_NAME, source: "bundled",
74
+ resourceBase: RESOURCE_BASE, rank: BUNDLED_SKILL_RANK, locator: SKILL_BODY_URL,
75
+ };
76
+ const provider = {
77
+ name: PROVIDER_NAME,
78
+ list: () => Promise.resolve([CANDIDATE]),
79
+ async get() { return { ...CANDIDATE, content: await readFile(SKILL_BODY_URL, "utf8") }; },
80
+ };
81
+ const name = "mi-plugin";
82
+ const inject = ["skills"];
83
+ function apply(ctx) { ctx.skills.registerProvider(() => provider); }
84
+ export { apply, inject, name };
85
+ ```
86
+
87
+ Commands: `ctx.get("commands")?.register({ definitionId, name, description, input, handler })`.
88
+ Timers: `ctx.effect(() => { const t = setTimeout(run, ms); return () => clearTimeout(t); }, "label")`.
89
+ Log: `ctx.logger.info/warn(...)`.
90
+
91
+ ## Browser half — the recipe (the hard part)
92
+
93
+ ```js
94
+ window.__ModuleLoader__.load({
95
+ id: "@javierfrancoleal/mi-plugin",
96
+ factory: (require) => {
97
+ var module = { exports: {} };
98
+ var exports = module.exports;
99
+ Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" });
100
+ const React = require("react"); // react + react/jsx-runtime are baseline
101
+
102
+ function MiComponente(_props) {
103
+ const t = _props && typeof _props.t === "function" ? _props.t : (k) => k;
104
+ return React.createElement("div", null, t("saludo"));
105
+ }
106
+
107
+ const inject = ["slots", "locale"];
108
+ function apply(ctx) {
109
+ ctx.effect(() => ctx.locale.register("miNs", { zh, en }), "mi-plugin: locale");
110
+ ctx.slots.inject("shell.bottom", () => ctx.slots.register({
111
+ name: "shell.bottom", id: "mi-plugin", order: 0, locale: "miNs"
112
+ }, MiComponente));
113
+ }
114
+
115
+ exports.MiComponente = MiComponente;
116
+ exports.apply = apply;
117
+ exports.inject = inject;
118
+ return module.exports;
119
+ }
120
+ });
121
+ ```
122
+
123
+ Rules:
124
+ - `exports["./client"]` → `./lib/client.js`.
125
+ - Write `lib/client.js` **already built** (this exact form); no build step for `link:` installs.
126
+ - No JSX — use `React.createElement` or `require("react/jsx-runtime")`.
127
+ - Inject CSS with a `<style data-plugin-css="…">` tag.
128
+ - Client `inject` lists **services** (`slots`, `locale`, `theme`, `remote`, …).
129
+
130
+ ## Slots
131
+
132
+ | Slot | Alcance | Para qué |
133
+ |---|---|---|
134
+ | `shell.bottom` | root | **global full-width bottom bar** (empty by default) |
135
+ | `shell.overlay` / `shell.leading` | root | overlay / top-left corner |
136
+ | `sidebar` / `rightbar` / `main` | root | columns / central panel |
137
+ | `conversation.input.dock` | sesión | bar above the composer |
138
+
139
+ `ctx.slots.inject(slot, () => ctx.slots.register(opts, Component))` is deferred.
140
+
141
+ ## Locale & theme
142
+
143
+ - `ctx.locale.register(ns, { zh, en })` — **both** dictionaries required.
144
+ - `locale: ns` in `register` → framework injects `t` as a prop.
145
+ - Theme tokens (light/dark aware, no hardcoded hex): `--dsw-alias-label-primary/secondary/tertiary`,
146
+ `--dsw-alias-state-success-primary` (green), `-warn-primary` (amber), `-error-primary` (red),
147
+ `--dsw-specific-menu`, `--dsw-alias-border-l1`, `--dsw-radius-md`, `--dsw-elevation-panel`,
148
+ `--dsw-menu-backdrop-filter`.
149
+
150
+ ## Install into the running app
151
+
152
+ **A) From npm** (another machine/profile without the local checkout):
153
+
154
+ ```bash
155
+ dsh plugin --profile <perfil> add @javierfrancoleal/mi-plugin
156
+ ```
157
+
158
+ This adds the dependency + bundle and runs pnpm for you; restart the app after.
159
+
160
+ **B) Local (`link:`) — developing in the monorepo:**
161
+
162
+ 1. `~/.dsh/profiles/<perfil>/package.json`: add `"@scope/nombre": "link:/abs/path"` to
163
+ `dependencies` and `"@scope/nombre"` to `dsh.profile.bundles`.
164
+ 2. `cd ~/.dsh/profiles/<perfil> && pnpm install`.
165
+ 3. **Restart the app** (a new bundle needs a host recomposition).
166
+
167
+ ## Gotchas
168
+
169
+ 1. The checkout lives inside `app.asar` — use `_dsh-inspect/asar-tool.mjs list|extract`.
170
+ 2. The `desktop` profile is Electron-managed: `dsh --profile desktop --dump-config` fails.
171
+ Validate with a throwaway profile.
172
+ 3. New bundles are NOT picked up by HMR on external edits — restart the app.
173
+ 4. `dsh.bundle.patch` + `dsh.client` can coexist (dual-face).
174
+ 5. React / slots / primitives are baseline; don't list them in `dsh.client.inject`.
175
+
176
+ ## Validation checklist
177
+
178
+ ```bash
179
+ node --check lib/index.js && node --check lib/client.js
180
+ node tools/check-client.mjs lib/client.js
181
+ dsh --profile testprices --dump-config | grep mi-plugin # throwaway profile, not desktop
182
+ curl -sS http://127.0.0.1:<puerto>/plugins/@scope/mi-plugin/client.js # 200 after restart
183
+ ```
184
+
185
+ Full reference: `docs/PLUGIN-AUTHORING.md`. Template: `templates/dsh-plugin/`.
186
+ Scaffold/validate: `tools/new-plugin.sh`, `tools/check-plugin.sh`.
@@ -0,0 +1,4 @@
1
+ # @javierfrancoleal/plugin-authoring — authoring skill for new DSH plugins.
2
+ - insert:
3
+ - id: plugin-authoring
4
+ name: '@javierfrancoleal/plugin-authoring'
package/icon.svg ADDED
@@ -0,0 +1,8 @@
1
+ <svg xmlns="http://www.w3.org/2000/svg" width="128" height="128" viewBox="0 0 128 128" fill="none">
2
+ <rect width="128" height="128" rx="24" fill="#7C5CFF"/>
3
+ <path d="M38 34 H90 V54 H38 Z" fill="#ffffff" opacity="0.35"/>
4
+ <path d="M38 62 H90 V82 H38 Z" fill="#ffffff" opacity="0.7"/>
5
+ <path d="M38 90 H90 V100 H38 Z" fill="#ffffff"/>
6
+ <circle cx="98" cy="44" r="7" fill="#ffffff"/>
7
+ <path d="M92 44 H104 M98 38 V50" stroke="#ffffff" stroke-width="3" stroke-linecap="round"/>
8
+ </svg>
package/lib/index.js ADDED
@@ -0,0 +1,53 @@
1
+ // @javierfrancoleal/plugin-authoring — host half.
2
+ // Registers the `plugin-authoring` skill so agents can load the distilled
3
+ // guide for building DeepSeek Harness plugins without re-discovering the
4
+ // architecture. The skill body lives in assets/plugin-authoring.md.
5
+ import { readFile } from "node:fs/promises";
6
+ import { fileURLToPath } from "node:url";
7
+ import { BUNDLED_SKILL_RANK } from "@deepseek-ai/dsh-skill";
8
+
9
+ const PROVIDER_NAME = "javierfrancoleal-plugin-authoring";
10
+ const SKILL_BODY_URL = new URL("../assets/plugin-authoring.md", import.meta.url);
11
+ const RESOURCE_BASE = {
12
+ kind: "directory",
13
+ path: fileURLToPath(new URL("../assets/", import.meta.url)),
14
+ };
15
+
16
+ const CANDIDATE = {
17
+ name: "plugin-authoring",
18
+ description: "Build and publish a DeepSeek Harness plugin (host-only, client-only, or dual-face) without re-discovering the architecture: package.json anatomy, cordis.patch.yml, the browser-half recipe (dsh.client + window.__ModuleLoader__ + slots), locale, theme tokens, install steps, gotchas, and the validation checklist. Load before creating or extending any DSH plugin.",
19
+ invocation: {
20
+ modelInvocable: true,
21
+ userInvocable: true,
22
+ },
23
+ provider: PROVIDER_NAME,
24
+ source: "bundled",
25
+ resourceBase: RESOURCE_BASE,
26
+ rank: BUNDLED_SKILL_RANK,
27
+ locator: SKILL_BODY_URL,
28
+ };
29
+
30
+ const provider = {
31
+ name: PROVIDER_NAME,
32
+ list: () => Promise.resolve([CANDIDATE]),
33
+ async get(_candidate) {
34
+ return {
35
+ name: CANDIDATE.name,
36
+ description: CANDIDATE.description,
37
+ invocation: CANDIDATE.invocation,
38
+ provider: CANDIDATE.provider,
39
+ source: CANDIDATE.source,
40
+ resourceBase: RESOURCE_BASE,
41
+ content: await readFile(SKILL_BODY_URL, "utf8"),
42
+ };
43
+ },
44
+ };
45
+
46
+ const name = "plugin-authoring";
47
+ const inject = ["skills"];
48
+
49
+ function apply(ctx) {
50
+ ctx.skills.registerProvider(() => provider);
51
+ }
52
+
53
+ export { apply, inject, name };
package/locale/en.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Plugin Authoring",
4
+ "description": "Skill that teaches how to build and publish DeepSeek Harness plugins (host, client, or dual-face) without re-discovering the architecture."
5
+ }
6
+ }
package/locale/es.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Autoría de plugins",
4
+ "description": "Skill que enseña a crear y publicar plugins de DeepSeek Harness (host, cliente o doble cara) sin redescubrir la arquitectura."
5
+ }
6
+ }
package/locale/fr.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "Création de plugins",
4
+ "description": "Compétence qui enseigne à créer et publier des plugins DeepSeek Harness (hôte, client ou double-face) sans redécouvrir l'architecture."
5
+ }
6
+ }
package/locale/zh.json ADDED
@@ -0,0 +1,6 @@
1
+ {
2
+ "meta": {
3
+ "title": "插件编写",
4
+ "description": "教授如何构建和发布 DeepSeek Harness 插件(宿主、客户端或双面),无需重新发现架构。"
5
+ }
6
+ }
package/package.json CHANGED
@@ -1,6 +1,47 @@
1
1
  {
2
2
  "name": "@javierfrancoleal/plugin-authoring",
3
- "version": "0.0.0-stage",
4
- "stub": true,
5
- "description": "Temporary package placeholder for staged publishing"
3
+ "version": "1.0.1",
4
+ "description": "Plugin-authoring skill for DeepSeek Harness: the distilled anatomy, client-UI recipe, slots, locale, theme tokens, install steps, gotchas, and validation checklist for building and publishing new DSH plugins.",
5
+ "author": "J.Franco",
6
+ "license": "MIT",
7
+ "type": "module",
8
+ "main": "lib/index.js",
9
+ "exports": {
10
+ ".": "./lib/index.js",
11
+ "./cordis.patch.yml": "./cordis.patch.yml",
12
+ "./package.json": "./package.json",
13
+ "./locale/*.json": "./locale/*.json"
14
+ },
15
+ "icon": "./icon.svg",
16
+ "files": [
17
+ "icon.svg",
18
+ "locale/*.json",
19
+ "lib/index.js",
20
+ "assets",
21
+ "cordis.patch.yml",
22
+ "README.md"
23
+ ],
24
+ "engines": {
25
+ "node": ">=24",
26
+ "dsh": ">=0.2.1-rc.0"
27
+ },
28
+ "keywords": [
29
+ "deepseek-harness",
30
+ "plugin-authoring",
31
+ "scaffold",
32
+ "skill"
33
+ ],
34
+ "dsh": {
35
+ "manifestVersion": 1,
36
+ "bundle": {
37
+ "patch": "./cordis.patch.yml"
38
+ }
39
+ },
40
+ "publishConfig": {
41
+ "access": "public"
42
+ },
43
+ "peerDependencies": {
44
+ "@deepseek-ai/cordis": "~4.0.5",
45
+ "@deepseek-ai/dsh-skill": ">=0.2.1-rc.5"
46
+ }
6
47
  }