diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..21aaa4a --- /dev/null +++ b/.gitattributes @@ -0,0 +1,7 @@ +# Pin the line ending the working tree gets, on every platform. +# +# `lib/` is generated by `tsc` and therefore always LF, while `core.autocrlf=true` +# on Windows checks everything else out as CRLF — so after every build, every lib +# file `tsc` rewrote showed up as modified with no content change. With `eol=lf` +# the checkout bytes match the build output and the status stays honest. +* text=auto eol=lf diff --git a/CHANGELOG.md b/CHANGELOG.md index 93ec9af..8033dca 100644 --- a/CHANGELOG.md +++ b/CHANGELOG.md @@ -68,9 +68,14 @@ project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0.html). ## [Unreleased] +### Added + +- **`githubToken` — a token field the Plugins page can edit.** DSH 0.2.1 serves a settings namespace only for a plugin whose Config marks at least one field `.volatile()`; `dsh-github` had none, so the settings service skipped the whole namespace and the row had no editable form. The card now writes this field, and `tokenSource` gains a `config` member that `auto` tries before the credentials file, the environment, and the gh CLI. The value sits in the profile configuration as plain text; the credentials file and `gh auth login` remain the alternatives. + ### Fixed - **The shipped browser bundle registers under the package name.** `scripts/bundle-client.mjs` hardcoded `id: "dsh-github"`; DSH 0.2.1 keys client rows by package name (`@perrylink/dsh-github`), so the loader fell back to the single-resource URL and re-executed the bundle, aborting web boot with `duplicate factory registration`. The wrapper now reads `package.json.name`, and `verify:artifacts` + `test/client-bundle.test.ts` assert the registration id. +- **The GitHub card mounts again on DSH 0.2.1.** The browser half required the browser-side credentials remote, which 0.2.1 removed (`@deepseek-ai/dsh-credentials` ships no `./remote`): the client entry stayed pending — a fatal web boot in 0.2.x — and the defensive variant returned before `ctx.slots.register`, so no card appeared in the Plugins panel. It now reads the page-supplied `form` (`{ state, mutate }`), registers on `plugins.item` unconditionally, renders through `SettingsForm` / `SettingsSecretField` so themes and installed skins restyle it, and adds a short guide to both GitHub token pages. ## [0.7.18] - 2026-10-05 diff --git a/README-es.md b/README-es.md index dc24086..0b0f42f 100644 --- a/README-es.md +++ b/README-es.md @@ -172,12 +172,13 @@ created pull request #7: https://github.com/o/r/pull/7 (main ← feat/shiny) ## Configuración -Todos los ajustes son campos `Config` de Schemastery (modificables desde cordis.yml). Una anulación dirigida por id reemplaza toda la fila — vuelve a indicar cada clave que necesites. `cordis.patch.yml` documenta cada clave en línea. En la GUI, la **tarjeta de configuración de la página Plugins** (grupo Official) lee `tokenRef` del propio formulario de configuración de la entrada — el host `0.1.7-alpha.1` eliminó el enlace `ctx.settingsScope` y la costura de registro de namespaces que había detrás, así que la tarjeta ya no posee un namespace de configuración. El token de GitHub no es un campo de configuración: la tarjeta informa si la credencial referenciada está puesta y la escribe mediante el archivo de credenciales, que es de donde la resuelve la mitad host. +Todos los ajustes son campos `Config` de Schemastery (modificables desde cordis.yml). Una anulación dirigida por id reemplaza toda la fila — vuelve a indicar cada clave que necesites. `cordis.patch.yml` documenta cada clave en línea. En la GUI, la **tarjeta de configuración de la página Plugins** (grupo Official) lee `tokenRef` del propio formulario de configuración de la entrada — el host `0.1.7-alpha.1` eliminó el enlace `ctx.settingsScope` y la costura de registro de namespaces que había detrás, así que la tarjeta ya no posee un namespace de configuración. El token en sí es el campo `githubToken` de la entrada: la tarjeta lo escribe ahí y la mitad host lo resuelve antes que el archivo de credenciales, el entorno y el CLI gh. | Clave | Por defecto | Significado | |---|---|---| -| `tokenSource` | `auto` | `auto` (credenciales → env → gh) o uno de `credentials` / `env` / `gh` | +| `tokenSource` | `auto` | `auto` (campo de la página → credenciales → env → gh) o uno de `config` / `credentials` / `env` / `gh` | | `tokenRef` | `GITHUB_TOKEN` | Referencia de la capa de credenciales / nombre de la variable de entorno | +| `githubToken` | — | Token guardado desde la página Plugins; texto plano en la configuración del perfil, se usa primero mientras no esté vacío | | `defaultOwnerRepo` | — | `owner/repo` de respaldo cuando una llamada no indica ninguno y git no tiene origen | | `autoCommit` | `false` | Si `/pr create` puede indicar al modelo que haga commit+push primero | | `maxDiffChars` | `8000` | Límite de caracteres para los diffs de PR leídos en las revisiones | diff --git a/README-hi.md b/README-hi.md index 2416e26..6440ce9 100644 --- a/README-hi.md +++ b/README-hi.md @@ -172,12 +172,13 @@ created pull request #7: https://github.com/o/r/pull/7 (main ← feat/shiny) ## कॉन्फ़िगरेशन -सभी tunables Schemastery `Config` fields हैं (cordis.yml से बदले जा सकते हैं)। एक id-लक्षित override पूरी row को बदल देता है — जो key आपको चाहिए उसे दोबारा लिखें। `cordis.patch.yml` हर key को inline दस्तावेज़ित करता है। GUI में, **Plugins पेज settings card** (Official समूह) `tokenRef` उस entry के अपने configuration form से पढ़ता है — `0.1.7-alpha.1` host ने `ctx.settingsScope` binding और उसके पीछे का namespace-registration seam हटा दिया, इसलिए कार्ड अब कोई settings namespace नहीं रखता। GitHub token configuration field नहीं है: कार्ड बताता है कि referenced credential सेट है या नहीं, और उसे credentials फ़ाइल के ज़रिए लिखता है — host half वहीं से resolve करता है। +सभी tunables Schemastery `Config` fields हैं (cordis.yml से बदले जा सकते हैं)। एक id-लक्षित override पूरी row को बदल देता है — जो key आपको चाहिए उसे दोबारा लिखें। `cordis.patch.yml` हर key को inline दस्तावेज़ित करता है। GUI में, **Plugins पेज settings card** (Official समूह) `tokenRef` उस entry के अपने configuration form से पढ़ता है — `0.1.7-alpha.1` host ने `ctx.settingsScope` binding और उसके पीछे का namespace-registration seam हटा दिया, इसलिए कार्ड अब कोई settings namespace नहीं रखता। token स्वयं उस entry का `githubToken` field है: कार्ड उसे वहीं लिखता है, और host half उसे credentials फ़ाइल, environment और gh CLI से पहले resolve करता है। | कुंजी | डिफ़ॉल्ट | अर्थ | |---|---|---| -| `tokenSource` | `auto` | `auto` (credentials → env → gh) या `credentials` / `env` / `gh` में से कोई एक | +| `tokenSource` | `auto` | `auto` (पेज field → credentials → env → gh) या `config` / `credentials` / `env` / `gh` में से कोई एक | | `tokenRef` | `GITHUB_TOKEN` | Credential-seam reference / environment-variable नाम | +| `githubToken` | — | Plugins पेज से सहेजा गया token; profile configuration में plain text, खाली न होने पर पहले इस्तेमाल होता है | | `defaultOwnerRepo` | — | जब कोई call कोई नाम न दे और git के पास कोई origin न हो तो Fallback `owner/repo` | | `autoCommit` | `false` | क्या `/pr create` model को पहले commit+push करने का निर्देश दे सकता है | | `maxDiffChars` | `8000` | reviews में पढ़े जाने वाले PR diffs की character सीमा | diff --git a/README-pt.md b/README-pt.md index 6ae151c..0ff5c46 100644 --- a/README-pt.md +++ b/README-pt.md @@ -172,12 +172,13 @@ created pull request #7: https://github.com/o/r/pull/7 (main ← feat/shiny) ## Configuração -Todos os ajustes são campos `Config` do Schemastery (modificáveis a partir do cordis.yml). Uma substituição direcionada por id troca toda a linha — redeclare cada chave de que você precisa. O `cordis.patch.yml` documenta cada chave em linha. Na GUI, o **cartão de configurações da página Plugins** (grupo Official) lê `tokenRef` do próprio formulário de configuração da entrada — o host `0.1.7-alpha.1` removeu a vinculação `ctx.settingsScope` e a costura de registro de namespace por trás dela, então o cartão não possui mais um namespace de configuração. O token do GitHub não é um campo de configuração: o cartão informa se a credencial referenciada está definida e a grava pelo arquivo de credenciais, que é de onde a metade host a resolve. +Todos os ajustes são campos `Config` do Schemastery (modificáveis a partir do cordis.yml). Uma substituição direcionada por id troca toda a linha — redeclare cada chave de que você precisa. O `cordis.patch.yml` documenta cada chave em linha. Na GUI, o **cartão de configurações da página Plugins** (grupo Official) lê `tokenRef` do próprio formulário de configuração da entrada — o host `0.1.7-alpha.1` removeu a vinculação `ctx.settingsScope` e a costura de registro de namespace por trás dela, então o cartão não possui mais um namespace de configuração. O token em si é o campo `githubToken` da entrada: o cartão o grava ali e a metade host o resolve antes do arquivo de credenciais, do ambiente e do CLI gh. | Chave | Padrão | Significado | |---|---|---| -| `tokenSource` | `auto` | `auto` (credenciais → ambiente → gh) ou um de `credentials` / `env` / `gh` | +| `tokenSource` | `auto` | `auto` (campo da página → credenciais → ambiente → gh) ou um de `config` / `credentials` / `env` / `gh` | | `tokenRef` | `GITHUB_TOKEN` | Referência da camada de credenciais / nome da variável de ambiente | +| `githubToken` | — | Token salvo pela página Plugins; texto puro na configuração do perfil, usado primeiro enquanto não estiver vazio | | `defaultOwnerRepo` | — | Fallback `owner/repo` quando uma chamada não nomeia nenhum e o git não tem origin | | `autoCommit` | `false` | Se `/pr create` pode instruir o modelo a fazer commit+push primeiro | | `maxDiffChars` | `8000` | Limite de caracteres para diffs de PR lidos nas revisões | diff --git a/README-zh.md b/README-zh.md index 17ff77f..ae61569 100644 --- a/README-zh.md +++ b/README-zh.md @@ -174,12 +174,13 @@ created pull request #7: https://github.com/o/r/pull/7 (main ← feat/shiny) ## 配置 -所有可调项都是 Schemastery `Config` 字段(可从 cordis.yml 修改)。以 id 定位的覆盖会替换整行 —— 需要重新声明你所需的每个键。`cordis.patch.yml` 逐键内联说明。在图形界面中,**Plugins 页设置卡**(Official 组)从该条目自己的配置表单读取 `tokenRef`:`0.1.7-alpha.1` 宿主已删除 `ctx.settingsScope` 绑定及其背后的命名空间注册缝,卡片因此不再拥有设置命名空间。GitHub 令牌根本不是配置字段:卡片只报告所引用凭证是否已配置,并通过凭证文件写入它——宿主半部正是从那里解析的。 +所有可调项都是 Schemastery `Config` 字段(可从 cordis.yml 修改)。以 id 定位的覆盖会替换整行 —— 需要重新声明你所需的每个键。`cordis.patch.yml` 逐键内联说明。在图形界面中,**Plugins 页设置卡**(Official 组)从该条目自己的配置表单读取 `tokenRef`:`0.1.7-alpha.1` 宿主已删除 `ctx.settingsScope` 绑定及其背后的命名空间注册缝,卡片因此不再拥有设置命名空间。令牌本身就是该条目的 `githubToken` 字段:卡片写到这里,宿主半部按「页面字段 → 凭证文件 → 环境变量 → gh」的顺序解析。 | 键 | 默认值 | 含义 | |---|---|---| -| `tokenSource` | `auto` | `auto`(credentials → env → gh)或指定 `credentials` / `env` / `gh` | +| `tokenSource` | `auto` | `auto`(页面字段 → credentials → env → gh)或指定 `config` / `credentials` / `env` / `gh` | | `tokenRef` | `GITHUB_TOKEN` | credentials seam 引用名 / 环境变量名 | +| `githubToken` | — | 从插件页保存的令牌;以明文存于 profile 配置,非空时优先使用 | | `defaultOwnerRepo` | — | 调用未指定且 git 无 origin 时的兜底 `owner/repo` | | `autoCommit` | `false` | `/pr create` 是否允许指示模型先 commit+push | | `maxDiffChars` | `8000` | 审查读取 PR diff 的字符数上限 | diff --git a/README.md b/README.md index fcaa5d4..4311db1 100644 --- a/README.md +++ b/README.md @@ -174,12 +174,13 @@ created pull request #7: https://github.com/o/r/pull/7 (main ← feat/shiny) ## Configuration -All tunables are Schemastery `Config` fields (changeable from cordis.yml). An id-targeted override replaces the whole row — restate every key you need. `cordis.patch.yml` documents each key inline. In the GUI, the **Plugins page settings card** (Official group) reads `tokenRef` from the entry's own configuration form — the `0.1.7-alpha.1` host removed the `ctx.settingsScope` binding and the namespace-registration seam behind it, so the card no longer owns a settings namespace. The GitHub token is not a configuration field at all: the card reports whether the referenced credential is set and writes it through the credentials file, which is where the host half resolves it. +All tunables are Schemastery `Config` fields (changeable from cordis.yml). An id-targeted override replaces the whole row — restate every key you need. `cordis.patch.yml` documents each key inline. In the GUI, the **Plugins page settings card** (Official group) reads `tokenRef` from the entry's own configuration form — the `0.1.7-alpha.1` host removed the `ctx.settingsScope` binding and the namespace-registration seam behind it, so the card no longer owns a settings namespace. The token itself is the entry's `githubToken` field: the card writes it there, and the host half resolves it ahead of the credentials file, the environment, and the gh CLI. | Key | Default | Meaning | |---|---|---| -| `tokenSource` | `auto` | `auto` (credentials → env → gh) or one of `credentials` / `env` / `gh` | +| `tokenSource` | `auto` | `auto` (page field → credentials → env → gh) or one of `config` / `credentials` / `env` / `gh` | | `tokenRef` | `GITHUB_TOKEN` | Credential-seam reference / environment-variable name | +| `githubToken` | — | Token saved from the Plugins page; plain text in the profile configuration, tried first while non-empty | | `defaultOwnerRepo` | — | Fallback `owner/repo` when a call names none and git has no origin | | `autoCommit` | `false` | Whether `/pr create` may instruct the model to commit+push first | | `maxDiffChars` | `8000` | Character cap for PR diffs read into reviews | diff --git a/lib/client.d.ts b/lib/client.d.ts index e4da811..7440350 100644 --- a/lib/client.d.ts +++ b/lib/client.d.ts @@ -1,93 +1,38 @@ /** - * dsh-github browser half — one card in the Plugins page's Official group. + * dsh-github browser half — one card in the Plugins panel's Official group. * - * The card reports and edits the GitHub token. The token literal never rides - * the settings document: it is written through the credentials domain, - * addressed by the reference the plugin's cordis.yml `Config.tokenRef` names - * (default `GITHUB_TOKEN`), which is exactly where the host half resolves it — - * per operation, no restart needed. + * The card reads and writes the plugin's own `Config.githubToken` through the + * configuration form the page hands a `plugins.item` entry (`form.state` and + * `form.mutate`), so the token stays one host-owned field and the host half + * resolves it on every operation. The browser half deliberately depends on no + * credentials remote: DSH 0.2.1 no longer exposes one (`remote.credentials` / + * `remote.credentialsController` are gone), and a missing required client + * service leaves the whole entry pending, which fails the web boot. * - * Since host 0.1.7-alpha.1 the page owns configuration: the card renders the - * `summary` one-liner and the `page` body from the `plugins.item` owner props - * (`view`, and the `form` the Plugins page supplies), instead of binding a - * `settingsScope` itself — that service, `settings.plugin.item`'s old shape, - * and the `dsh-settings-file` package behind them were all removed. The card - * therefore reads `tokenRef` from `form.state.value` and never writes the - * settings document; the credential is written through the credentials - * domain, which is a different seam and stayed. + * Rendering uses the shipped `SettingsForm` / `SettingsSecretField`, so the + * card inherits the standard settings layout and every theme token a skin + * overrides; the only local CSS is the guidance list below. * * The shipped `lib/client.js` is the built bundle of this module. The browser * module loader executes that bundle, not this file. * @module @perrylink/dsh-github/client */ import { type ReactNode } from 'react'; -/** - * The configuration-form contract the card consumes, declared locally: a - * client package must not import a Host package, and the browser half of the - * seam lives in `@deepseek-ai/dsh-client-ui-settings`, which is an optional - * peer. Mirrors that package's `ConfigForm`/`ConfigFormSnapshot` faces — the - * ones the Plugins page hands a `plugins.item` entry as `form`. - */ -/** Client-side sync state of one configuration entry. */ -export interface ConfigFormSnapshot { - /** `loading` until the first accepted section, `ready` while one stands, `unavailable` otherwise. */ - status: 'loading' | 'ready' | 'unavailable'; - /** Last accepted schema-resolved section; undefined before the first acceptance. */ - value: T | undefined; - /** Composition layer the Host resolved the value over, when the owning plugin declared one. */ - base: unknown; - /** Raw user layer as stored, when one exists. */ - user: unknown; - /** Namespace revision fencing the next write; undefined before the first Host view. */ - revision: number | undefined; - /** Whether the Host document accepts writes; memory mode never does. */ - writable: boolean; - /** `host` syncs with the Host document; `memory` keeps a remote browser process-local. */ - mode: 'host' | 'memory'; -} -/** Reactive owner handle over one configuration entry's accepted values. */ -export interface ConfigForm { - /** @returns the current sync snapshot (stable reference until the next change). */ - getSnapshot(): ConfigFormSnapshot; - /** - * Observe snapshot replacements. - * @param listener - invoked after each snapshot change. - * @returns the disposer removing this listener. - */ - subscribe(listener: () => void): () => void; -} -/** - * Minimal writable snapshot store the card's slot hooks consume. Declared and - * implemented locally: its previous home `dsh-client-store` is not on the - * published `0.1.1-rc.2` line, and the card only needs the bare observable - * contract plus whole-value replacement (no drafts, no persistence) — the - * framework synthesizes the selector hook from `getSnapshot`/`subscribe`. - */ -export interface SnapshotStore { - /** @returns the current snapshot reference. */ - getSnapshot(): T; - /** - * Subscribe to snapshot replacements. - * @param listener - invoked after each change. - * @returns the disposer removing this listener. - */ - subscribe(listener: () => void): () => void; - /** - * Replace the state wholesale. - * @param next - next state. - */ - set(next: T): void; +/** Dictionary namespace owned by this plugin. */ +export declare const NS = "dsh-github"; +/** Client services this half requires; both are provided by the web shell. */ +export declare const inject: string[]; +export interface ClientContextLike { + effect(disposer: () => void, label: string): void; + locale: { + bind(namespace: string): (key: keyof GithubCardLocale) => string; + register(namespace: string, dictionaries: Record): void; + }; + slots: { + inject(slot: string, factory: () => unknown): unknown; + register(options: Record, component: unknown): unknown; + }; } -/** - * Create the minimal card store. - * @param init - initial state. - * @returns the store. - */ -export declare function createSnapshotStore(init: T): SnapshotStore; -/** Namespace of the GitHub capability. Spelled here rather than imported: a client package must not depend on a Host package. */ -export declare const GITHUB_NS = "dsh-github"; -/** Credential reference the provider resolves when the configuration names none. */ -export declare const DEFAULT_TOKEN_REF = "GITHUB_TOKEN"; /** Locale copy the card renders. */ export interface GithubCardLocale { githubTitle: string; @@ -96,177 +41,67 @@ export interface GithubCardLocale { tokenHint: string; tokenSet: string; tokenUnset: string; - unsaved: string; + unavailable: string; readOnly: string; save: string; saving: string; - discard: string; saveFailed: string; + guideIntro: string; + guideClassic: string; + guideFineGrained: string; + guideStorage: string; } /** English copy. */ export declare const en: GithubCardLocale; /** Simplified Chinese copy. */ export declare const zh: GithubCardLocale; -/** The card's full state, as projected into its snapshot store. */ -export interface GithubCardState { +/** Sync state of one configuration entry, as the Plugins page projects it. */ +export interface ConfigFormSnapshot { + /** `loading` until the first accepted section, `ready` while one stands, `unavailable` otherwise. */ + status: 'loading' | 'ready' | 'unavailable'; + /** Last accepted schema-resolved section; undefined before the first acceptance. */ + value: T | undefined; + /** Namespace revision fencing the next write; undefined before the first Host view. */ + revision: number | undefined; /** Whether the Host configuration document accepts writes. */ writable: boolean; - /** Whether the referenced credential is configured. */ - configured: boolean; - /** Whether the credentials domain accepts writes. */ - credentialWritable: boolean; - /** Whether a save is crossing the wire. */ - saving: boolean; - /** Whether the last save did not land as staged. */ - failed: boolean; - /** The credential reference the card addresses. */ - ref: string; } -/** Source and writability facts for one credential reference (never the value). */ -interface CredentialView { - /** Whether resolving the reference would currently return a value. */ - configured: boolean; - /** Source layer currently supplying the value; absent while unconfigured. */ - source?: string; - /** Whether the active provider can write this reference. */ - writable: boolean; +/** One ordered mutation the configuration form applies to its namespace. */ +export interface ConfigFormOp { + op: 'set' | 'unset'; + path: string[]; + value?: unknown; } /** - * The credentials-domain wire face the card uses: the host `credentials` Remote - * namespace (`remote.credentials`). The token literal crosses the wire on - * `set` only — no read path returns it. + * The configuration-form face the Plugins page hands a `plugins.item` entry. + * Mirrors the page's own `ConfigPageForm`: a snapshot plus the write action. */ -export interface CredentialsApi { - /** - * Ask the credentials domain about references; one view per requested name, - * keyed by that name. - */ - describe(refs: string[]): Promise<{ - readonly ok: true; - readonly value: Record; - } | { - readonly ok: false; - readonly error: { - readonly code: string; - readonly message: string; - }; - }>; - /** - * Store one non-empty value under a reference. - */ - set(ref: string, value: string): Promise; +export interface ConfigPageForm { + state: ConfigFormSnapshot; + mutate(ops: ConfigFormOp[], revision?: number): Promise; } -/** The configuration the card reads its credential reference from (the plugin's own `Config` subset). */ -interface GithubCardConfig { - tokenRef?: string; -} -/** - * Bridges the page-supplied configuration form and the credentials domain onto - * the card. The token is the one control that does not live in the - * configuration: its literal never rides a response, so the card learns only - * whether one is configured and writes it through the credentials domain, - * addressed by the reference `Config.tokenRef` names. - */ -export declare class GithubCardController { - private readonly form; - private readonly api; - private readonly store; - private saving; - private failed; - private credential; - /** - * @param form - the configuration form the Plugins page hands this entry, or - * `undefined` when the page supplied none (the card then reads the default - * reference and offers the credential control alone). - * @param api - the credentials Remote namespace. - */ - constructor(form: ConfigForm | undefined, api: CredentialsApi); - /** Whether the Host configuration document accepts writes. */ - writable(): boolean; - /** The configuration form this controller reads (identity-compared by the caller). */ - formOf(): ConfigForm | undefined; - /** Project the card's full state for its snapshot store. */ - projection(): GithubCardState; - /** The credential reference the configuration names, or the provider default. */ - refOf(): string; - /** - * Ask the credentials domain about the reference the section names. A - * response is published only while it still answers for the reference in - * force, so two reads settling out of order cannot clobber each other. - */ - readCredential(): Promise; - /** - * Re-read after the Host reports a change to the reference this card - * watches — a token can be written from elsewhere, and the section does not - * change when it is. - * @param ref - the reference the Host reports as changed. - */ - refreshCredential(ref: string): void; - /** - * Write the staged token, then re-read whether the Host now holds one. A - * blank value writes nothing, which keeps the stored key. - * @param value - the staged credential literal. - * @returns whether the Host reports a configured credential afterwards. - */ - save(value: string): Promise; - /** Build the face the card's slot registration injects. */ - inject(): { - hooks: { - githubCard: SnapshotStore; - }; - submit: (value: string) => Promise; - }; - private publish; +/** The plugin configuration subset this card reads and writes. */ +export interface GithubCardConfig { + githubToken?: string; } /** Props the slot system injects into the card component. */ export interface GithubCardProps { t: (key: keyof GithubCardLocale) => string; - useGithubCard: (selector: (snapshot: GithubCardState) => GithubCardState) => GithubCardState; - submit: (value: string) => Promise; /** The view the Plugins page asks for: the one-liner under the title, or the page body. */ view: 'summary' | 'page'; + /** The form for this entry; absent when the page has no editable configuration for it. */ + form?: ConfigPageForm | undefined; } /** - * Render the GitHub card. `summary` renders the one-liner the Plugins page - * places under the card's title (the description plus the token state badge); - * `page` renders the token control and the save/discard row on the plugin's - * own page. The page supplies the configuration form, so the card never - * depends on a served namespace to render. + * Render the GitHub card: the one-liner the page shows under the card's title, + * or the token control on the plugin's own page. + * @param props - locale, view, and the page-supplied configuration form. + * @returns the card's React node. */ export declare function GithubCard(props: GithubCardProps): ReactNode; -/** Dictionary namespace owned by this plugin. */ -export declare const NS = "dsh-github"; -/** - * Required services (cordis fiber inject). `settingsScope` is gone: host - * 0.1.7-alpha.1 removed it, and the Plugins page now hands the configuration - * form to the `plugins.item` entry instead. `@deepseek-ai/dsh-client-ui-plugin-manager` - * owns that slot, so it must be composed for the card to mount at all. - */ -export declare const inject: string[]; -export interface ClientContextLike { - get(service: string): unknown; - effect(disposer: () => void, label: string): void; - locale: { - bind(namespace: string): (key: keyof GithubCardLocale) => string; - register(namespace: string, dictionaries: Record): void; - }; - remote: { - $on(event: string, listener: (ref: string) => void): unknown; - credentials: CredentialsApi; - }; - slots: { - inject(slot: string, factory: () => unknown): unknown; - register(options: Record, component: unknown): unknown; - }; -} /** - * Mount the GitHub configuration card into the Plugins page's Official group. - * - * The form arrives per render, so the controller is rebuilt whenever the page - * supplies a different one — the page's own form owner stays authoritative and - * the card keeps no second copy of the accepted values. + * Mount the GitHub configuration card into the Plugins panel's Official group. * @param ctx - the browser plugin context. */ export declare function apply(ctx: ClientContextLike): void; -export {}; //# sourceMappingURL=client.d.ts.map \ No newline at end of file diff --git a/lib/client.d.ts.map b/lib/client.d.ts.map index 45fa86c..ab5d32a 100644 --- a/lib/client.d.ts.map +++ b/lib/client.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"client.d.ts","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/client.js b/lib/client.js index 0d022a1..6ac33ff 100755 --- a/lib/client.js +++ b/lib/client.js @@ -5,24 +5,21 @@ window.__ModuleLoader__.load({ var exports = module.exports; Object.defineProperty(exports, Symbol.toStringTag, { value: "Module" }); const { createElement, useState } = require("react"); - const { Button, IconLoadingOutlineRegular, } = require("@deepseek-ai/dsh-client-ui-primitives"); + const { SettingsForm, SettingsSecretField } = require("@deepseek-ai/dsh-client-ui-primitives"); /** - * dsh-github browser half — one card in the Plugins page's Official group. + * dsh-github browser half — one card in the Plugins panel's Official group. * - * The card reports and edits the GitHub token. The token literal never rides - * the settings document: it is written through the credentials domain, - * addressed by the reference the plugin's cordis.yml `Config.tokenRef` names - * (default `GITHUB_TOKEN`), which is exactly where the host half resolves it — - * per operation, no restart needed. + * The card reads and writes the plugin's own `Config.githubToken` through the + * configuration form the page hands a `plugins.item` entry (`form.state` and + * `form.mutate`), so the token stays one host-owned field and the host half + * resolves it on every operation. The browser half deliberately depends on no + * credentials remote: DSH 0.2.1 no longer exposes one (`remote.credentials` / + * `remote.credentialsController` are gone), and a missing required client + * service leaves the whole entry pending, which fails the web boot. * - * Since host 0.1.7-alpha.1 the page owns configuration: the card renders the - * `summary` one-liner and the `page` body from the `plugins.item` owner props - * (`view`, and the `form` the Plugins page supplies), instead of binding a - * `settingsScope` itself — that service, `settings.plugin.item`'s old shape, - * and the `dsh-settings-file` package behind them were all removed. The card - * therefore reads `tokenRef` from `form.state.value` and never writes the - * settings document; the credential is written through the credentials - * domain, which is a different seam and stayed. + * Rendering uses the shipped `SettingsForm` / `SettingsSecretField`, so the + * card inherits the standard settings layout and every theme token a skin + * overrides; the only local CSS is the guidance list below. * * The shipped `lib/client.js` is the built bundle of this module. The browser * module loader executes that bundle, not this file. @@ -30,282 +27,162 @@ window.__ModuleLoader__.load({ */ - /** - * Create the minimal card store. - * @param init - initial state. - * @returns the store. - */ - function createSnapshotStore(init) { - let state = init; - const listeners = new Set(); - return { - getSnapshot: () => state, - subscribe: (listener) => { - listeners.add(listener); - return () => { listeners.delete(listener); }; - }, - set: (next) => { - state = next; - for (const listener of [...listeners]) - listener(); - }, - }; - } - /** Namespace of the GitHub capability. Spelled here rather than imported: a client package must not depend on a Host package. */ - const GITHUB_NS = 'dsh-github'; - /** Credential reference the provider resolves when the configuration names none. */ - const DEFAULT_TOKEN_REF = 'GITHUB_TOKEN'; + /** Dictionary namespace owned by this plugin. */ + const NS = 'dsh-github'; + /** Client services this half requires; both are provided by the web shell. */ + const inject = ['slots', 'locale']; /** English copy. */ const en = { githubTitle: 'GitHub', githubDescription: 'GitHub pull requests, issues, and CI through the agent.', tokenLabel: 'GitHub token', - tokenHint: 'Stored in the credentials file, not here. Applied immediately; leave blank to keep the current token.', - tokenSet: 'A token is configured.', - tokenUnset: 'No token is configured; GitHub tools are unavailable until one is.', - unsaved: 'Unsaved', + tokenHint: 'Save writes this plugin\'s configuration in plain text and applies on the next GitHub operation; leave it blank to keep the current token.', + tokenSet: 'Token configured', + tokenUnset: 'No token', + unavailable: 'This page has no editable configuration form; set `githubToken` in the profile configuration instead.', readOnly: 'This deployment stores settings read-only.', save: 'Save', saving: 'Saving…', - discard: 'Discard', saveFailed: 'The deployment did not accept this value; it was left for you to correct.', + guideIntro: 'No token yet? Create a personal access token on GitHub:', + guideClassic: 'Classic token — Settings → Developer settings → Personal access tokens (classic), scope `repo`:', + guideFineGrained: 'Fine-grained token — pick the repositories and grant Contents, Issues, and Pull requests read/write:', + guideStorage: 'Paste the whole string (ghp_… or github_pat_…). A token is a password: never commit it or share it.', }; /** Simplified Chinese copy. */ const zh = { githubTitle: 'GitHub', githubDescription: '通过 agent 操作 GitHub 的 PR、issue 与 CI。', tokenLabel: 'GitHub Token', - tokenHint: '写入凭证文件而非设置文件;保存后立即生效。留空表示保持现有令牌。', - tokenSet: '已配置令牌。', - tokenUnset: '未配置令牌;配置之前 GitHub 工具不可用。', - unsaved: '未保存', + tokenHint: '保存后以明文写入本插件配置,下一次 GitHub 操作即生效;留空表示保持现有令牌。', + tokenSet: '已配置', + tokenUnset: '未配置', + unavailable: '本页没有可编辑的配置表单;请在 profile 配置里填写 `githubToken`。', readOnly: '本部署的设置为只读。', save: '保存', saving: '保存中…', - discard: '放弃修改', saveFailed: '本部署没有接受该值,已保留供你修改。', + guideIntro: '还没有令牌?先在 GitHub 生成一个个人访问令牌(PAT):', + guideClassic: '经典令牌:Settings → Developer settings → Personal access tokens (classic),勾选 `repo`:', + guideFineGrained: '细粒度令牌:Personal access tokens (fine-grained),选好仓库并给 Contents、Issues、Pull requests 读写:', + guideStorage: '把整串(ghp_… 或 github_pat_…)粘到上面的输入框。令牌等同于密码,不要提交进仓库或贴到公开的地方。', }; + /** Guidance list styling; everything else comes from the shipped settings primitives. */ + const CARD_CSS = [ + '.ghc-guide{margin-top:12px;font-size:12px;line-height:1.6;color:var(--dsw-alias-label-secondary);}', + '.ghc-guide p{margin:0 0 4px;}', + '.ghc-guide ul{margin:0 0 4px;padding-left:18px;}', + '.ghc-guide li{margin:0 0 2px;}', + '.ghc-guide a{color:var(--dsw-alias-brand-primary);text-decoration:none;}', + '.ghc-guide a:hover{text-decoration:underline;}', + ].join(''); /** - * Bridges the page-supplied configuration form and the credentials domain onto - * the card. The token is the one control that does not live in the - * configuration: its literal never rides a response, so the card learns only - * whether one is configured and writes it through the credentials domain, - * addressed by the reference `Config.tokenRef` names. + * Render the GitHub card: the one-liner the page shows under the card's title, + * or the token control on the plugin's own page. + * @param props - locale, view, and the page-supplied configuration form. + * @returns the card's React node. */ - class GithubCardController { - form; - api; - store; - saving = false; - failed = false; - credential = { ref: '', configured: false, writable: true }; - /** - * @param form - the configuration form the Plugins page hands this entry, or - * `undefined` when the page supplied none (the card then reads the default - * reference and offers the credential control alone). - * @param api - the credentials Remote namespace. - */ - constructor(form, api) { - this.form = form; - this.api = api; - this.store = createSnapshotStore(this.projection()); - form?.subscribe(() => { - void this.readCredential(); - this.publish(); - }); - void this.readCredential(); - } - /** Whether the Host configuration document accepts writes. */ - writable() { - return this.form?.getSnapshot().writable ?? true; - } - /** The configuration form this controller reads (identity-compared by the caller). */ - formOf() { - return this.form; - } - /** Project the card's full state for its snapshot store. */ - projection() { - return { - writable: this.writable(), - configured: this.credential.configured, - credentialWritable: this.credential.writable, - saving: this.saving, - failed: this.failed, - ref: this.credential.ref, - }; - } - /** The credential reference the configuration names, or the provider default. */ - refOf() { - const declared = this.form?.getSnapshot().value?.tokenRef; - return declared !== undefined && declared.length > 0 ? declared : DEFAULT_TOKEN_REF; - } - /** - * Ask the credentials domain about the reference the section names. A - * response is published only while it still answers for the reference in - * force, so two reads settling out of order cannot clobber each other. - */ - async readCredential() { - const ref = this.refOf(); - if (ref !== this.credential.ref) { - this.credential = { ref, configured: false, writable: true }; - this.publish(); - } - let response; - try { - response = await this.api.describe([ref]); - } - catch { - return; - } - if (!response.ok || ref !== this.refOf()) - return; - const view = response.value[ref]; - const next = { ref, configured: view?.configured ?? false, writable: view?.writable ?? true }; - if (next.configured === this.credential.configured && next.writable === this.credential.writable) - return; - this.credential = next; - this.publish(); - } - /** - * Re-read after the Host reports a change to the reference this card - * watches — a token can be written from elsewhere, and the section does not - * change when it is. - * @param ref - the reference the Host reports as changed. - */ - refreshCredential(ref) { - if (ref !== this.credential.ref) + function GithubCard(props) { + const { t, form } = props; + const [draft, setDraft] = useState(''); + const [saving, setSaving] = useState(false); + const [failed, setFailed] = useState(false); + const stored = (form?.state.value?.githubToken ?? '').trim(); + const configured = stored.length > 0; + // A summary render receives no `form` (the page hands it only to the detail + // view), so it must not claim a token state it cannot read; the badge on the + // page view is the single source of that answer. + if (props.view === 'summary') + return t('githubDescription'); + const writable = form?.state.writable ?? false; + const staged = draft.trim(); + const save = async () => { + if (form === undefined || staged === '' || saving) return; - void this.readCredential(); - } - /** - * Write the staged token, then re-read whether the Host now holds one. A - * blank value writes nothing, which keeps the stored key. - * @param value - the staged credential literal. - * @returns whether the Host reports a configured credential afterwards. - */ - async save(value) { - const text = (value ?? '').trim(); - if (text === '' || this.saving) - return false; - this.saving = true; - this.failed = false; - this.publish(); + setSaving(true); + setFailed(false); + let landed = false; try { - await this.api.set(this.refOf(), text); + // No explicit revision: the form fences the write with the latest one it + // knows, so a save queued behind another write cannot be rejected as stale. + landed = await form.mutate([{ op: 'set', path: ['githubToken'], value: staged }]); } catch { - // handled below by re-reading the configured state + landed = false; } - await this.readCredential(); - const landed = this.credential.configured; - this.saving = false; - this.failed = !landed; - this.publish(); - return landed; - } - /** Build the face the card's slot registration injects. */ - inject() { - return { - hooks: { githubCard: this.store }, - submit: (value) => this.save(value), - }; - } - publish() { - this.store.set(this.projection()); - } - } - /** - * Render the GitHub card. `summary` renders the one-liner the Plugins page - * places under the card's title (the description plus the token state badge); - * `page` renders the token control and the save/discard row on the plugin's - * own page. The page supplies the configuration form, so the card never - * depends on a served namespace to render. - */ - function GithubCard(props) { - const { t } = props; - const state = props.useGithubCard((snapshot) => snapshot); - const [draft, setDraft] = useState(''); - if (props.view === 'summary') { - return createElement('span', { className: 'ghc-summary' }, createElement('span', null, t('githubDescription')), createElement('span', { className: state.configured ? 'ghc-badge' : 'ghc-badgeMuted' }, state.configured ? t('tokenSet') : t('tokenUnset'))); - } - const dirty = draft.trim() !== ''; - const saveLabel = state.saving ? t('saving') : t('save'); - return createElement('div', { className: 'ghc-card ghc-cardPage' }, !state.writable - ? createElement('p', { className: 'ghc-readOnly', role: 'status' }, t('readOnly')) - : null, createElement('div', { className: 'ghc-field' }, createElement('div', { className: 'ghc-head' }, createElement('label', { className: 'ghc-label', htmlFor: 'plugin-config-github-token' }, t('tokenLabel')), createElement('span', { className: 'ghc-badges' }, createElement('span', { className: state.configured ? 'ghc-badge' : 'ghc-badgeMuted' }, state.configured ? t('tokenSet') : t('tokenUnset')))), createElement('input', { - id: 'plugin-config-github-token', - className: 'ghc-input', - type: 'password', - autoComplete: 'off', - value: draft, - disabled: !state.credentialWritable, - onChange: (event) => setDraft(event.target.value), - }), createElement('p', { className: 'ghc-hint' }, t('tokenHint'))), createElement('div', { className: 'ghc-actions' }, state.failed ? createElement('p', { className: 'ghc-failed', role: 'status' }, t('saveFailed')) : null, createElement(Button, { - variant: 'ghost', - size: 'sm', - disabled: !dirty || state.saving, - onClick: () => setDraft(''), - }, t('discard')), createElement(Button, { - variant: 'primary', - size: 'sm', - disabled: !state.writable || !dirty || state.saving, - icon: state.saving - ? createElement('span', { className: 'ghc-spin' }, createElement(IconLoadingOutlineRegular, { size: 16 })) - : undefined, - onClick: async () => { - const landed = await props.submit(draft); - if (landed) - setDraft(''); + setSaving(false); + if (landed) + setDraft(''); + else + setFailed(true); + }; + return createElement(SettingsForm, { + labels: { + unavailable: t('unavailable'), + readOnly: t('readOnly'), + saveFailed: t('saveFailed'), + save: t('save'), + saving: t('saving'), + }, + state: { + available: form !== undefined, + writable, + dirty: staged !== '', + invalid: false, + saving, + failed, }, - }, saveLabel))); + onSave: () => { void save(); }, + // SettingsForm calls this only on unmount; the draft belongs to the + // component instance, so a fresh mount starts clean either way. + onDiscard: () => { }, + children: [ + createElement(SettingsSecretField, { + id: 'plugin-config-github-token', + label: t('tokenLabel'), + configured, + stateLabel: configured ? t('tokenSet') : t('tokenUnset'), + text: draft, + hint: t('tokenHint'), + disabled: !writable || saving, + onEdit: (text) => setDraft(text), + }), + createElement('div', { className: 'ghc-guide' }, createElement('p', null, t('guideIntro')), createElement('ul', null, createElement('li', null, t('guideClassic'), ' ', createElement('a', { href: 'https://github.com/settings/tokens', target: '_blank', rel: 'noreferrer noopener' }, 'github.com/settings/tokens')), createElement('li', null, t('guideFineGrained'), ' ', createElement('a', { href: 'https://github.com/settings/personal-access-tokens/new', target: '_blank', rel: 'noreferrer noopener' }, 'github.com/settings/personal-access-tokens/new'))), createElement('p', null, t('guideStorage'))), + ], + }); } - /** Dictionary namespace owned by this plugin. */ - const NS = 'dsh-github'; /** - * Required services (cordis fiber inject). `settingsScope` is gone: host - * 0.1.7-alpha.1 removed it, and the Plugins page now hands the configuration - * form to the `plugins.item` entry instead. `@deepseek-ai/dsh-client-ui-plugin-manager` - * owns that slot, so it must be composed for the card to mount at all. - */ - const inject = ['slots', 'locale', 'connection', 'remote', 'remote.credentials']; - /** - * Mount the GitHub configuration card into the Plugins page's Official group. - * - * The form arrives per render, so the controller is rebuilt whenever the page - * supplies a different one — the page's own form owner stays authoritative and - * the card keeps no second copy of the accepted values. + * Mount the GitHub configuration card into the Plugins panel's Official group. * @param ctx - the browser plugin context. */ function apply(ctx) { const t = ctx.locale.bind(NS); ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-github: card dictionaries'); - let github; - const controllerFor = (form) => { - if (github === undefined || github.formOf() !== form) { - github = new GithubCardController(form, ctx.remote.credentials); - } - return github; - }; - ctx.effect(() => ctx.remote.$on('credentials/reference-updated', (ref) => github?.refreshCredential(ref)), 'dsh-github: credential invalidations'); + ctx.effect(() => { + const tagId = `${NS}/card.css`; + if (document.querySelector(`style[data-plugin-css="${tagId}"]`) !== null) + return () => { }; + const tag = document.createElement('style'); + tag.dataset.plugin = NS; + tag.dataset.pluginCss = tagId; + tag.textContent = CARD_CSS; + document.head.appendChild(tag); + return () => { tag.remove(); }; + }, 'dsh-github: card styles'); ctx.slots.inject('plugins.item', () => ctx.slots.register({ name: 'plugins.item', id: NS, order: 100, label: () => t('githubTitle'), locale: NS, - inject: () => controllerFor(github?.formOf()).inject(), }, GithubCard)); } - exports.createSnapshotStore = createSnapshotStore; - exports.GithubCardController = GithubCardController; exports.GithubCard = GithubCard; exports.apply = apply; - exports.GITHUB_NS = GITHUB_NS; - exports.DEFAULT_TOKEN_REF = DEFAULT_TOKEN_REF; - exports.en = en; - exports.zh = zh; exports.NS = NS; exports.inject = inject; + exports.en = en; + exports.zh = zh; return module.exports; } }); diff --git a/lib/client.js.map b/lib/client.js.map index e8bb1fc..ea11cf4 100644 --- a/lib/client.js.map +++ b/lib/client.js.map @@ -1 +1 @@ -{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"client.js","sourceRoot":"","sources":["../src/client.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/config.d.ts b/lib/config.d.ts index 97b9de8..ff57950 100644 --- a/lib/config.d.ts +++ b/lib/config.d.ts @@ -11,7 +11,7 @@ import z from '@deepseek-ai/schemastery'; /** GitHub write actions the plugin may perform (each still requires approval). */ export type GithubAction = 'pr.create' | 'review.post' | 'issue.create' | 'issue.comment' | 'issue.close' | 'pr.merge' | 'pr.update' | 'ci.run'; /** Where a GitHub token is looked up. `auto` tries them in order. */ -export type TokenSource = 'auto' | 'credentials' | 'env' | 'gh'; +export type TokenSource = 'auto' | 'config' | 'credentials' | 'env' | 'gh'; /** * The CI surface: the one-shot `ci_run` tool, the polling review bot, the * `/ci` command family, and the status-check gate. Every tunable is a Schema @@ -68,6 +68,12 @@ export interface Config { tokenSource: TokenSource; /** Credentials-seam reference / environment-variable name for the token. */ tokenRef: string; + /** + * Token typed into the Plugins page configuration form. It sits in the profile + * configuration as plain text, which is what the credentials file is too; + * leave it empty when the configuration is shared with other tools. + */ + githubToken: string; /** `owner/repo` used when a call does not name one and git has no origin. */ defaultOwnerRepo?: string; /** Whether `/pr create` may instruct the model to commit and push first. */ @@ -120,5 +126,18 @@ export declare const DEFAULT_CODE_EXTENSIONS: string[]; /** Default test-path globs for the test-existence rule. */ export declare const DEFAULT_TEST_PATTERNS: string[]; export declare const CiConfig: z; +/** + * Read one configuration value a volatile field hands over as a live reference. + * + * Such a field arrives as an object carrying `get()` instead of the stored + * value, and a Settings write updates that object in place — reading it per + * operation is what lets a token saved on the page apply without reloading the + * plugin. + * @param value - plain value or live reference. + * @returns the current value. + */ +export declare function liveValue(value: T | { + get(): T; +}): T; export declare const Config: z; //# sourceMappingURL=config.d.ts.map \ No newline at end of file diff --git a/lib/config.d.ts.map b/lib/config.d.ts.map index 56d7535..e98994f 100644 --- a/lib/config.d.ts.map +++ b/lib/config.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,CAAC,MAAM,0BAA0B,CAAA;AAExC,kFAAkF;AAClF,MAAM,MAAM,YAAY,GAAG,WAAW,GAAG,aAAa,GAAG,cAAc,GAAG,eAAe,GAAG,aAAa,GAAG,UAAU,GAAG,WAAW,GAAG,QAAQ,CAAA;AAE/I,qEAAqE;AACrE,MAAM,MAAM,WAAW,GAAG,MAAM,GAAG,aAAa,GAAG,KAAK,GAAG,IAAI,CAAA;AAE/D;;;;GAIG;AACH,MAAM,WAAW,QAAQ;IACvB,uFAAuF;IACvF,OAAO,EAAE,OAAO,CAAA;IAChB,uHAAuH;IACvH,MAAM,EAAE,QAAQ,GAAG,OAAO,CAAA;IAC1B;;;;OAIG;IACH,WAAW,EAAE,YAAY,EAAE,CAAA;IAC3B,uEAAuE;IACvE,SAAS,EAAE,MAAM,CAAA;IACjB,qHAAqH;IACrH,QAAQ,EAAE,OAAO,CAAA;IACjB,iEAAiE;IACjE,MAAM,EAAE,OAAO,GAAG,SAAS,CAAA;IAC3B,sFAAsF;IACtF,cAAc,EAAE,MAAM,CAAA;IACtB,iFAAiF;IACjF,YAAY,EAAE,MAAM,EAAE,CAAA;IACtB,uGAAuG;IACvG,WAAW,EAAE,MAAM,EAAE,CAAA;IACrB,uGAAuG;IACvG,qBAAqB,EAAE,MAAM,EAAE,CAAA;IAC/B,2CAA2C;IAC3C,iBAAiB,EAAE,OAAO,GAAG,SAAS,CAAA;IACtC,qFAAqF;IACrF,cAAc,EAAE,MAAM,EAAE,CAAA;IACxB,8DAA8D;IAC9D,gBAAgB,EAAE,MAAM,EAAE,CAAA;IAC1B,qEAAqE;IACrE,eAAe,EAAE,MAAM,CAAA;IACvB,aAAa,EAAE,MAAM,CAAA;IACrB,eAAe,EAAE,MAAM,CAAA;IACvB,4DAA4D;IAC5D,aAAa,EAAE,MAAM,CAAA;IACrB,oFAAoF;IACpF,YAAY,EAAE,OAAO,CAAA;IACrB,kGAAkG;IAClG,SAAS,EAAE,MAAM,CAAA;CAClB;AAED,MAAM,WAAW,MAAM;IACrB;;;;OAIG;IACH,WAAW,EAAE,WAAW,CAAA;IACxB,4EAA4E;IAC5E,QAAQ,EAAE,MAAM,CAAA;IAChB,6EAA6E;IAC7E,gBAAgB,CAAC,EAAE,MAAM,CAAA;IACzB,4EAA4E;IAC5E,UAAU,EAAE,OAAO,CAAA;IACnB,0EAA0E;IAC1E,YAAY,EAAE,MAAM,CAAA;IACpB,oEAAoE;IACpE,kBAAkB,EAAE,MAAM,CAAA;IAC1B,+CAA+C;IAC/C,WAAW,EAAE,MAAM,CAAA;IACnB,8EAA8E;IAC9E,kBAAkB,EAAE,MAAM,CAAA;IAC1B,gFAAgF;IAChF,gBAAgB,EAAE,MAAM,CAAA;IACxB,6CAA6C;IAC7C,YAAY,EAAE,MAAM,CAAA;IACpB,4CAA4C;IAC5C,WAAW,EAAE,MAAM,CAAA;IACnB,uEAAuE;IACvE,aAAa,EAAE,MAAM,CAAA;IACrB;;;;OAIG;IACH,UAAU,EAAE,QAAQ,GAAG,OAAO,CAAA;IAC9B,0FAA0F;IAC1F,mBAAmB,CAAC,EAAE,MAAM,CAAA;IAC5B,yDAAyD;IACzD,UAAU,EAAE,MAAM,CAAA;IAClB,0DAA0D;IAC1D,WAAW,EAAE,MAAM,CAAA;IACnB,qCAAqC;IACrC,cAAc,EAAE,MAAM,CAAA;IACtB,gEAAgE;IAChE,gBAAgB,EAAE,MAAM,CAAA;IACxB,0DAA0D;IAC1D,UAAU,EAAE,MAAM,CAAA;IAClB,6EAA6E;IAC7E,cAAc,EAAE,YAAY,EAAE,CAAA;IAC9B,mFAAmF;IACnF,YAAY,CAAC,EAAE,MAAM,CAAA;IACrB,6EAA6E;IAC7E,EAAE,EAAE,QAAQ,CAAA;CACb;AAID,gEAAgE;AAChE,eAAO,MAAM,0BAA0B,UAKtC,CAAA;AAED,8EAA8E;AAC9E,eAAO,MAAM,uBAAuB,UAInC,CAAA;AAED,2DAA2D;AAC3D,eAAO,MAAM,qBAAqB,UAGjC,CAAA;AAID,eAAO,MAAM,QAAQ,EAAE,CAAC,CAAC,QAAQ,CAuC/B,CAAA;AAEF,eAAO,MAAM,MAAM,EAAE,CAAC,CAAC,MAAM,CAiE3B,CAAA"} \ No newline at end of file +{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/config.js b/lib/config.js index 7628aa4..ba6bb18 100644 --- a/lib/config.js +++ b/lib/config.js @@ -68,14 +68,44 @@ export const CiConfig = z.object({ reportDir: z.string().default('') .description('Report-file directory; defaults to DSH_GITHUB_CI_OUTPUT_DIR, then the workspace directory.'), }); +/** + * A string field the Plugins page may edit. + * + * `.volatile()` is what makes the field reachable from the browser at all: DSH + * serves a settings namespace only when its Config exposes at least one + * volatile field, and accepts a write only beneath a volatile node. A volatile + * schema types its output as `Volatile` because the plugin receives a + * live reference rather than the stored value; {@link liveValue} reads that + * reference, so the schema keeps the plain face its consumers use. + * @param description - schema description the settings form shows. + * @returns the schema field. + */ +function editableString(description) { + return z.string().default('').volatile().description(description); +} +/** + * Read one configuration value a volatile field hands over as a live reference. + * + * Such a field arrives as an object carrying `get()` instead of the stored + * value, and a Settings write updates that object in place — reading it per + * operation is what lets a token saved on the page apply without reloading the + * plugin. + * @param value - plain value or live reference. + * @returns the current value. + */ +export function liveValue(value) { + const getter = value.get; + return typeof getter === 'function' ? value.get() : value; +} export const Config = z.object({ - tokenSource: z.union(['auto', 'credentials', 'env', 'gh']) + tokenSource: z.union(['auto', 'config', 'credentials', 'env', 'gh']) .default('auto') - .description('Token lookup source: auto tries credentials → env → gh in order.'), + .description('Token lookup source: auto tries this page → credentials → env → gh in order.'), tokenRef: z.string() .pattern(/^[A-Za-z_][A-Za-z0-9_]*$/) .default('GITHUB_TOKEN') .description('Credential reference / environment variable name holding the token.'), + githubToken: editableString('Token set from this page; used before the credentials file when non-empty. Stored in the profile configuration in plain text.'), defaultOwnerRepo: z.string() .pattern(OWNER_REPO_PATTERN) .description('Fallback owner/repo when neither the call nor git names one.'), diff --git a/lib/config.js.map b/lib/config.js.map index 4a1c14e..d291022 100644 --- a/lib/config.js.map +++ b/lib/config.js.map @@ -1 +1 @@ -{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA;;;;;;;;GAQG;AACH,OAAO,CAAC,MAAM,0BAA0B,CAAA;AAqHxC,MAAM,kBAAkB,GAAG,oCAAoC,CAAA;AAE/D,gEAAgE;AAChE,MAAM,CAAC,MAAM,0BAA0B,GAAG;IACxC,MAAM,EAAE,QAAQ,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO,EAAE,OAAO;IACpD,SAAS,EAAE,aAAa,EAAE,SAAS;IACnC,sBAAsB,EAAE,eAAe,EAAE,WAAW,EAAE,YAAY;IAClE,yBAAyB,EAAE,0BAA0B;CACtD,CAAA;AAED,8EAA8E;AAC9E,MAAM,CAAC,MAAM,uBAAuB,GAAG;IACrC,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,KAAK;IACjE,OAAO,EAAE,KAAK,EAAE,IAAI,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,EAAE,KAAK,EAAE,KAAK,EAAE,MAAM;IAChE,QAAQ,EAAE,QAAQ,EAAE,KAAK,EAAE,MAAM;CAClC,CAAA;AAED,2DAA2D;AAC3D,MAAM,CAAC,MAAM,qBAAqB,GAAG;IACnC,YAAY,EAAE,aAAa,EAAE,iBAAiB,EAAE,YAAY,EAAE,WAAW;IACzE,aAAa,EAAE,aAAa,EAAE,WAAW,EAAE,aAAa;CACzD,CAAA;AAED,MAAM,gBAAgB,GAAG,CAAC,WAAW,EAAE,aAAa,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ,CAAU,CAAA;AAEjJ,MAAM,CAAC,MAAM,QAAQ,GAAgB,CAAC,CAAC,MAAM,CAAC;IAC5C,OAAO,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,KAAK,CAAC;SAChC,WAAW,CAAC,8FAA8F,CAAC;IAC9G,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAU,CAAC,CAAC,OAAO,CAAC,QAAQ,CAAC;SAC5D,WAAW,CAAC,mGAAmG,CAAC;IACnH,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;SACxD,WAAW,CAAC,sHAAsH,CAAC;IACtI,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,mBAAmB,CAAC;SAC/C,WAAW,CAAC,6CAA6C,CAAC;IAC7D,QAAQ,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;SAChC,WAAW,CAAC,6FAA6F,CAAC;IAC7G,MAAM,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,SAAS,CAAU,CAAC,CAAC,OAAO,CAAC,OAAO,CAAC;SAC5D,WAAW,CAAC,kEAAkE,CAAC;IAClF,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,MAAM,CAAC;SACtD,WAAW,CAAC,6EAA6E,CAAC;IAC7F,YAAY,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;SAC1C,WAAW,CAAC,uGAAuG,CAAC;IACvH,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;SACzC,WAAW,CAAC,+GAA+G,CAAC;IAC/H,qBAAqB,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,0BAA0B,CAAC;SAC3E,WAAW,CAAC,0DAA0D,CAAC;IAC1E,iBAAiB,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,OAAO,EAAE,SAAS,CAAU,CAAC,CAAC,OAAO,CAAC,SAAS,CAAC;SACzE,WAAW,CAAC,sCAAsC,CAAC;IACtD,cAAc,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,uBAAuB,CAAC;SACjE,WAAW,CAAC,sEAAsE,CAAC;IACtF,gBAAgB,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,MAAM,EAAE,CAAC,CAAC,OAAO,CAAC,qBAAqB,CAAC;SACjE,WAAW,CAAC,yDAAyD,CAAC;IACzE,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,EAAE,CAAC;SACnD,WAAW,CAAC,+CAA+C,CAAC;IAC/D,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;SACnD,WAAW,CAAC,+CAA+C,CAAC;IAC/D,eAAe,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,IAAI,CAAC;SACrD,WAAW,CAAC,iDAAiD,CAAC;IACjE,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,OAAO,CAAC,CAAC,CAAC;SAChD,WAAW,CAAC,uDAAuD,CAAC;IACvE,YAAY,EAAE,CAAC,CAAC,OAAO,EAAE,CAAC,OAAO,CAAC,IAAI,CAAC;SACpC,WAAW,CAAC,yFAAyF,CAAC;IACzG,SAAS,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC;SAC9B,WAAW,CAAC,4FAA4F,CAAC;CAC7G,CAAC,CAAA;AAEF;;;;;;;;;;;GAWG;AACH,SAAS,cAAc,CAAC,WAAmB;IACzC,OAAO,CAAC,CAAC,MAAM,EAAE,CAAC,OAAO,CAAC,EAAE,CAAC,CAAC,QAAQ,EAAE,CAAC,WAAW,CAAC,WAAW,CAAyB,CAAA;AAC3F,CAAC;AAED;;;;;;;;;GASG;AACH,MAAM,UAAU,SAAS,CAAI,KAAuB;IAClD,MAAM,MAAM,GAAI,KAA2B,CAAC,GAAG,CAAA;IAC/C,OAAO,OAAO,MAAM,KAAK,UAAU,CAAC,CAAC,CAAE,KAAsB,CAAC,GAAG,EAAE,CAAC,CAAC,CAAE,KAAW,CAAA;AACpF,CAAC;AAED,MAAM,CAAC,MAAM,MAAM,GAAc,CAAC,CAAC,MAAM,CAAC;IACxC,WAAW,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,MAAM,EAAE,QAAQ,EAAE,aAAa,EAAE,KAAK,EAAE,IAAI,CAAU,CAAC;SAC1E,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,8EAA8E,CAAC;IAC9F,QAAQ,EAAE,CAAC,CAAC,MAAM,EAAE;SACjB,OAAO,CAAC,0BAA0B,CAAC;SACnC,OAAO,CAAC,cAAc,CAAC;SACvB,WAAW,CAAC,qEAAqE,CAAC;IACrF,WAAW,EAAE,cAAc,CAAC,+HAA+H,CAAC;IAC5J,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE;SACzB,OAAO,CAAC,kBAAkB,CAAC;SAC3B,WAAW,CAAC,8DAA8D,CAAC;IAC9E,UAAU,EAAE,CAAC,CAAC,OAAO,EAAE;SACpB,OAAO,CAAC,KAAK,CAAC;SACd,WAAW,CAAC,qEAAqE,CAAC;IACrF,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;SACpC,OAAO,CAAC,IAAI,CAAC;SACb,WAAW,CAAC,gDAAgD,CAAC;IAChE,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;SAC1C,OAAO,CAAC,IAAI,CAAC;SACb,WAAW,CAAC,+DAA+D,CAAC;IAC/E,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;SACnC,OAAO,CAAC,EAAE,CAAC;SACX,WAAW,CAAC,0CAA0C,CAAC;IAC1D,kBAAkB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;SAC7C,OAAO,CAAC,OAAO,CAAC;SAChB,WAAW,CAAC,yCAAyC,CAAC;IACzD,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;SACxC,OAAO,CAAC,EAAE,CAAC;SACX,WAAW,CAAC,2EAA2E,CAAC;IAC3F,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;SACpC,OAAO,CAAC,KAAK,CAAC;SACd,WAAW,CAAC,kDAAkD,CAAC;IAClE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;SACnC,OAAO,CAAC,EAAE,CAAC;SACX,WAAW,CAAC,uCAAuC,CAAC;IACvD,aAAa,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;SACrC,OAAO,CAAC,GAAG,CAAC;SACZ,WAAW,CAAC,kEAAkE,CAAC;IAClF,UAAU,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAU,CAAC;SAC9C,OAAO,CAAC,QAAQ,CAAC;SACjB,WAAW,CAAC,yGAAyG,CAAC;IACzH,mBAAmB,EAAE,CAAC,CAAC,MAAM,EAAE;SAC5B,WAAW,CAAC,qFAAqF,CAAC;IACrG,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;SAClC,OAAO,CAAC,CAAC,CAAC;SACV,WAAW,CAAC,oDAAoD,CAAC;IACpE,WAAW,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;SACnC,OAAO,CAAC,GAAG,CAAC;SACZ,WAAW,CAAC,qDAAqD,CAAC;IACrE,cAAc,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC;SACtC,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,gCAAgC,CAAC;IAChD,gBAAgB,EAAE,CAAC,CAAC,MAAM,EAAE,CAAC,IAAI,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,IAAI,CAAC;SAC3C,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,2DAA2D,CAAC;IAC3E,UAAU,EAAE,CAAC,CAAC,MAAM,EAAE;SACnB,OAAO,CAAC,wBAAwB,CAAC;SACjC,WAAW,CAAC,sDAAsD,CAAC;IACtE,cAAc,EAAE,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,KAAK,CAAC,gBAAgB,CAAC,CAAC;SAC/C,OAAO,CAAC,CAAC,WAAW,EAAE,aAAa,EAAE,cAAc,EAAE,eAAe,EAAE,aAAa,EAAE,UAAU,EAAE,WAAW,EAAE,QAAQ,CAAC,CAAC;SACxH,WAAW,CAAC,sEAAsE,CAAC;IACtF,YAAY,EAAE,CAAC,CAAC,MAAM,EAAE;SACrB,WAAW,CAAC,2EAA2E,CAAC;IAC3F,EAAE,EAAE,QAAQ;SACT,WAAW,CAAC,8EAA8E,CAAC;CAC/F,CAAC,CAAA"} \ No newline at end of file diff --git a/lib/credential.d.ts b/lib/credential.d.ts index d27923c..fddda79 100644 --- a/lib/credential.d.ts +++ b/lib/credential.d.ts @@ -29,14 +29,16 @@ export declare function runGhCli(args: string[], signal?: AbortSignal): Promise< /** * Resolve the GitHub token for one operation. * - * `auto` order: credentials seam → `GITHUB_TOKEN`-style environment variable → - * `gh` CLI logged-in token. An explicit source restricts to that one source. + * `auto` order: configuration field set on the plugin's page → credentials seam + * → `GITHUB_TOKEN`-style environment variable → `gh` CLI logged-in token. An + * explicit source restricts to that one source. * @param credentials - the credentials seam (`ctx.credentials`). * @param tokenSource - configured lookup policy. * @param tokenRef - reference / environment-variable name. * @param runGh - `gh` CLI runner; the real one by default. * @param signal - aborts the `gh` lookup. + * @param configuredToken - token typed into the Plugins page configuration form. * @returns the token with its source, or a structured error with guidance. */ -export declare function resolveToken(credentials: CredentialProvider, tokenSource: TokenSource, tokenRef: string, runGh?: GhRunner, signal?: AbortSignal): Promise; +export declare function resolveToken(credentials: CredentialProvider, tokenSource: TokenSource, tokenRef: string, runGh?: GhRunner, signal?: AbortSignal, configuredToken?: string): Promise; //# sourceMappingURL=credential.d.ts.map \ No newline at end of file diff --git a/lib/credential.d.ts.map b/lib/credential.d.ts.map index 7934595..a931a7f 100644 --- a/lib/credential.d.ts.map +++ b/lib/credential.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"credential.d.ts","sourceRoot":"","sources":["../src/credential.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAA;AAEtE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAE9C,wEAAwE;AACxE,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,CAAA;CACrC;AAED,iEAAiE;AACjE,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,UAAU,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,MAAM,eAAe,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,aAAa,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,oBAAoB,CAAA;CAAE,CAAA;AAE7G,0DAA0D;AAC1D,MAAM,MAAM,QAAQ,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAA;AAO5F,iEAAiE;AACjE,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAO1F;AAED;;;;;;;;;;;GAWG;AACH,wBAAsB,YAAY,CAChC,WAAW,EAAE,kBAAkB,EAC/B,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,MAAM,EAChB,KAAK,GAAE,QAAmB,EAC1B,MAAM,CAAC,EAAE,WAAW,GACnB,OAAO,CAAC,eAAe,CAAC,CAsC1B"} \ No newline at end of file +{"version":3,"file":"credential.d.ts","sourceRoot":"","sources":["../src/credential.ts"],"names":[],"mappings":"AAWA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,8BAA8B,CAAA;AAEtE,OAAO,KAAK,EAAE,WAAW,EAAE,MAAM,aAAa,CAAA;AAE9C,wEAAwE;AACxE,MAAM,WAAW,aAAa;IAC5B,KAAK,EAAE,MAAM,CAAA;IACb,MAAM,EAAE,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,CAAA;CACrC;AAED,iEAAiE;AACjE,MAAM,WAAW,oBAAoB;IACnC,IAAI,EAAE,UAAU,CAAA;IAChB,OAAO,EAAE,MAAM,CAAA;IACf,QAAQ,EAAE,MAAM,CAAA;CACjB;AAED,MAAM,MAAM,eAAe,GAAG;IAAE,EAAE,EAAE,IAAI,CAAC;IAAC,KAAK,EAAE,aAAa,CAAA;CAAE,GAAG;IAAE,EAAE,EAAE,KAAK,CAAC;IAAC,KAAK,EAAE,oBAAoB,CAAA;CAAE,CAAA;AAE7G,0DAA0D;AAC1D,MAAM,MAAM,QAAQ,GAAG,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,MAAM,CAAC,EAAE,WAAW,KAAK,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAAA;AAQ5F,iEAAiE;AACjE,wBAAgB,QAAQ,CAAC,IAAI,EAAE,MAAM,EAAE,EAAE,MAAM,CAAC,EAAE,WAAW,GAAG,OAAO,CAAC;IAAE,MAAM,EAAE,MAAM,CAAA;CAAE,CAAC,CAO1F;AAED;;;;;;;;;;;;;GAaG;AACH,wBAAsB,YAAY,CAChC,WAAW,EAAE,kBAAkB,EAC/B,WAAW,EAAE,WAAW,EACxB,QAAQ,EAAE,MAAM,EAChB,KAAK,GAAE,QAAmB,EAC1B,MAAM,CAAC,EAAE,WAAW,EACpB,eAAe,CAAC,EAAE,MAAM,GACvB,OAAO,CAAC,eAAe,CAAC,CA8C1B"} \ No newline at end of file diff --git a/lib/credential.js b/lib/credential.js index 353e1c0..48d0d4b 100644 --- a/lib/credential.js +++ b/lib/credential.js @@ -10,9 +10,10 @@ */ import { credentialRef } from '@deepseek-ai/dsh-credentials'; import { execFile } from 'node:child_process'; -const NO_TOKEN_GUIDANCE = 'Configure one of: 1) a dsh credential for this reference (recommended; ' + - '$DSH_HOME/.credentials.yaml), 2) the same-named environment variable, or ' + - '3) `gh auth login` for the gh CLI. Set `tokenSource` in cordis.yml to pin one source.'; +const NO_TOKEN_GUIDANCE = 'Configure one of: 1) the GitHub token field on this plugin\'s page in the Plugins panel, ' + + '2) a dsh credential for this reference (' + + '$DSH_HOME/.credentials.yaml), 3) the same-named environment variable, or ' + + '4) `gh auth login` for the gh CLI. Set `tokenSource` in cordis.yml to pin one source.'; /** Run the real `gh` CLI with stdout captured (never logged). */ export function runGhCli(args, signal) { return new Promise((resolve, reject) => { @@ -27,18 +28,29 @@ export function runGhCli(args, signal) { /** * Resolve the GitHub token for one operation. * - * `auto` order: credentials seam → `GITHUB_TOKEN`-style environment variable → - * `gh` CLI logged-in token. An explicit source restricts to that one source. + * `auto` order: configuration field set on the plugin's page → credentials seam + * → `GITHUB_TOKEN`-style environment variable → `gh` CLI logged-in token. An + * explicit source restricts to that one source. * @param credentials - the credentials seam (`ctx.credentials`). * @param tokenSource - configured lookup policy. * @param tokenRef - reference / environment-variable name. * @param runGh - `gh` CLI runner; the real one by default. * @param signal - aborts the `gh` lookup. + * @param configuredToken - token typed into the Plugins page configuration form. * @returns the token with its source, or a structured error with guidance. */ -export async function resolveToken(credentials, tokenSource, tokenRef, runGh = runGhCli, signal) { - const order = tokenSource === 'auto' ? ['credentials', 'env', 'gh'] : [tokenSource]; +export async function resolveToken(credentials, tokenSource, tokenRef, runGh = runGhCli, signal, configuredToken) { + const typed = configuredToken?.trim(); + const configured = typed === undefined || typed === '' ? undefined : typed; + const order = tokenSource === 'auto' + ? [...(configured === undefined ? [] : ['config']), 'credentials', 'env', 'gh'] + : [tokenSource]; for (const source of order) { + if (source === 'config') { + if (configured !== undefined) + return { ok: true, token: { value: configured, source: 'config' } }; + continue; + } if (source === 'credentials') { let ref; try { @@ -72,7 +84,7 @@ export async function resolveToken(credentials, tokenSource, tokenRef, runGh = r ok: false, error: { code: 'no-token', - message: `no GitHub token found (source: ${tokenSource === 'auto' ? 'credentials/env/gh' : tokenSource})`, + message: `no GitHub token found (source: ${tokenSource === 'auto' ? 'config/credentials/env/gh' : tokenSource})`, guidance: NO_TOKEN_GUIDANCE, }, }; diff --git a/lib/credential.js.map b/lib/credential.js.map index 77876b4..d8d352a 100644 --- a/lib/credential.js.map +++ b/lib/credential.js.map @@ -1 +1 @@ -{"version":3,"file":"credential.js","sourceRoot":"","sources":["../src/credential.ts"],"names":[],"mappings":"AAAA;;;;;;;;;GASG;AACH,OAAO,EAAE,aAAa,EAAE,MAAM,8BAA8B,CAAA;AAE5D,OAAO,EAAE,QAAQ,EAAE,MAAM,oBAAoB,CAAA;AAqB7C,MAAM,iBAAiB,GACrB,yEAAyE;IACzE,2EAA2E;IAC3E,uFAAuF,CAAA;AAEzF,iEAAiE;AACjE,MAAM,UAAU,QAAQ,CAAC,IAAc,EAAE,MAAoB;IAC3D,OAAO,IAAI,OAAO,CAAC,CAAC,OAAO,EAAE,MAAM,EAAE,EAAE;QACrC,QAAQ,CAAC,IAAI,EAAE,IAAI,EAAE,EAAE,WAAW,EAAE,IAAI,EAAE,MAAM,EAAE,SAAS,EAAE,IAAI,GAAG,IAAI,EAAE,EAAE,CAAC,KAAK,EAAE,MAAM,EAAE,EAAE;YAC5F,IAAI,KAAK;gBAAE,MAAM,CAAC,KAAK,CAAC,CAAA;;gBACnB,OAAO,CAAC,EAAE,MAAM,EAAE,CAAC,CAAA;QAC1B,CAAC,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC;AAED;;;;;;;;;;;GAWG;AACH,MAAM,CAAC,KAAK,UAAU,YAAY,CAChC,WAA+B,EAC/B,WAAwB,EACxB,QAAgB,EAChB,QAAkB,QAAQ,EAC1B,MAAoB;IAEpB,MAAM,KAAK,GACT,WAAW,KAAK,MAAM,CAAC,CAAC,CAAC,CAAC,aAAa,EAAE,KAAK,EAAE,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,WAAW,CAAC,CAAA;IAEvE,KAAK,MAAM,MAAM,IAAI,KAAK,EAAE,CAAC;QAC3B,IAAI,MAAM,KAAK,aAAa,EAAE,CAAC;YAC7B,IAAI,GAAqC,CAAA;YACzC,IAAI,CAAC;gBACH,GAAG,GAAG,aAAa,CAAC,QAAQ,CAAC,CAAA;YAC/B,CAAC;YAAC,MAAM,CAAC;gBACP,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,KAAK,EAAE,EAAE,IAAI,EAAE,UAAU,EAAE,OAAO,EAAE,mBAAmB,QAAQ,6BAA6B,EAAE,QAAQ,EAAE,iBAAiB,EAAE,EAAE,CAAA;YACnJ,CAAC;YACD,MAAM,QAAQ,GAAG,MAAM,WAAW,CAAC,OAAO,CAAC,GAAG,CAAC,CAAA;YAC/C,IAAI,QAAQ;gBAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,QAAQ,CAAC,KAAK,EAAE,MAAM,EAAE,aAAa,EAAE,EAAE,CAAA;YAC1F,SAAQ;QACV,CAAC;QACD,IAAI,MAAM,KAAK,KAAK,EAAE,CAAC;YACrB,MAAM,KAAK,GAAG,OAAO,CAAC,GAAG,CAAC,QAAQ,CAAC,CAAA;YACnC,IAAI,KAAK,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;gBAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,KAAK,EAAE,EAAE,CAAA;YACnF,SAAQ;QACV,CAAC;QACD,IAAI,CAAC;YACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,KAAK,CAAC,CAAC,MAAM,EAAE,OAAO,CAAC,EAAE,MAAM,CAAC,CAAA;YACzD,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,EAAE,CAAA;YAC3B,IAAI,KAAK,CAAC,MAAM,GAAG,CAAC;gBAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,KAAK,EAAE,EAAE,KAAK,EAAE,MAAM,EAAE,IAAI,EAAE,EAAE,CAAA;QAC3E,CAAC;QAAC,MAAM,CAAC;YACP,qEAAqE;QACvE,CAAC;IACH,CAAC;IAED,OAAO;QACL,EAAE,EAAE,KAAK;QACT,KAAK,EAAE;YACL,IAAI,EAAE,UAAU;YAChB,OAAO,EAAE,kCAAkC,WAAW,KAAK,MAAM,CAAC,CAAC,CAAC,oBAAoB,CAAC,CAAC,CAAC,WAAW,GAAG;YACzG,QAAQ,EAAE,iBAAiB;SAC5B;KACF,CAAA;AACH,CAAC"} \ No newline at end of file +{"version":3,"file":"credential.js","sourceRoot":"","sources":["../src/credential.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/state.d.ts.map b/lib/state.d.ts.map index 2158479..2c5ea76 100644 --- a/lib/state.d.ts.map +++ b/lib/state.d.ts.map @@ -1 +1 @@ -{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"state.d.ts","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"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"} \ No newline at end of file diff --git a/lib/state.js b/lib/state.js index 34d5ad5..be2eb13 100644 --- a/lib/state.js +++ b/lib/state.js @@ -1,7 +1,7 @@ import { GithubClient, GithubGraphqlClient, clientOptionsFromConfig } from "./github.js"; import { repoFromRemoteUrl } from "./git.js"; import { resolveToken } from "./credential.js"; -import { CiConfig } from "./config.js"; +import { CiConfig, liveValue } from "./config.js"; const REPO_GUIDANCE = 'Name the repository with the ownerRepo parameter, set defaultOwnerRepo in cordis.yml, or run inside a checkout with a GitHub origin remote.'; const REPO_PATTERN = /^[A-Za-z0-9_.-]+\/[A-Za-z0-9_.-]+$/; /** @@ -30,7 +30,7 @@ export function createState(ctx, config, runGit, runGh, fetchImpl) { workspaceDir: normalizedConfig.workspaceDir ?? process.cwd(), apiHost, isCiDriver: process.env.DSH_GITHUB_CI_DRIVER === '1', - resolveToken: (signal) => resolveToken(ctx.credentials, normalizedConfig.tokenSource, normalizedConfig.tokenRef, runGh, signal), + resolveToken: (signal) => resolveToken(ctx.credentials, normalizedConfig.tokenSource, normalizedConfig.tokenRef, runGh, signal, liveValue(normalizedConfig.githubToken)), client: (token) => new GithubClient(token, clientOptions), graphqlClient: (token) => new GithubGraphqlClient(token, clientOptions), resolveRepo: (ownerRepo, signal) => resolveRepo(state, ownerRepo, signal), diff --git a/lib/state.js.map b/lib/state.js.map index 18c6092..c7b5a13 100644 --- a/lib/state.js.map +++ b/lib/state.js.map @@ -1 +1 @@ -{"version":3,"file":"state.js","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"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"} \ No newline at end of file +{"version":3,"file":"state.js","sourceRoot":"","sources":["../src/state.ts"],"names":[],"mappings":"AAWA,OAAO,EAAE,YAAY,EAAE,mBAAmB,EAAE,uBAAuB,EAAsB,MAAM,aAAa,CAAA;AAC5G,OAAO,EAAE,iBAAiB,EAAkB,MAAM,UAAU,CAAA;AAC5D,OAAO,EAAE,YAAY,EAAuC,MAAM,iBAAiB,CAAA;AAGnF,OAAO,EAAE,QAAQ,EAAE,SAAS,EAAe,MAAM,aAAa,CAAA;AAyD9D,MAAM,aAAa,GAAG,6IAA6I,CAAA;AAEnK,MAAM,YAAY,GAAG,oCAAoC,CAAA;AAEzD;;;;;;;;GAQG;AACH,MAAM,UAAU,WAAW,CAAC,GAAsE,EAAE,MAAc,EAAE,MAAiB,EAAE,KAAe,EAAE,SAAwB;IAC9K,6EAA6E;IAC7E,qEAAqE;IACrE,MAAM,gBAAgB,GAAW,EAAE,GAAG,MAAM,EAAE,EAAE,EAAE,QAAQ,CAAC,MAAM,CAAC,EAAE,IAAI,EAAE,CAAa,EAAE,CAAA;IACzF,MAAM,aAAa,GAAG,uBAAuB,CAAC,gBAAgB,EAAE,SAAS,CAAC,CAAA;IAC1E,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,gBAAgB,CAAC,UAAU,CAAC,CAAC,QAAQ,CAAC,WAAW,EAAE,CAAA;IAC3E,MAAM,OAAO,GAAG,IAAI,GAAG,EAA2B,CAAA;IAClD,MAAM,KAAK,GAAgB;QACzB,MAAM,EAAE,gBAAgB;QACxB,WAAW,EAAE,GAAG,CAAC,WAAW;QAC5B,SAAS,EAAE,GAAG,CAAC,SAAS;QACxB,OAAO;QACP,MAAM;QACN,KAAK;QACL,YAAY,EAAE,gBAAgB,CAAC,YAAY,IAAI,OAAO,CAAC,GAAG,EAAE;QAC5D,OAAO;QACP,UAAU,EAAE,OAAO,CAAC,GAAG,CAAC,oBAAoB,KAAK,GAAG;QACpD,YAAY,EAAE,CAAC,MAAoB,EAAE,EAAE,CAAC,YAAY,CAAC,GAAG,CAAC,WAAW,EAAE,gBAAgB,CAAC,WAAW,EAAE,gBAAgB,CAAC,QAAQ,EAAE,KAAK,EAAE,MAAM,EAAE,SAAS,CAAC,gBAAgB,CAAC,WAAW,CAAC,CAAC;QACtL,MAAM,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,IAAI,YAAY,CAAC,KAAK,EAAE,aAAa,CAAC;QACjE,aAAa,EAAE,CAAC,KAAa,EAAE,EAAE,CAAC,IAAI,mBAAmB,CAAC,KAAK,EAAE,aAAa,CAAC;QAC/E,WAAW,EAAE,CAAC,SAA6B,EAAE,MAAoB,EAAE,EAAE,CAAC,WAAW,CAAC,KAAK,EAAE,SAAS,EAAE,MAAM,CAAC;QAC3G,UAAU,EAAE,UAAU;QACtB,cAAc,EAAE,CAAC,EAAE,EAAE,MAAM,EAAE,EAAE;YAC7B,OAAO,CAAC,GAAG,CAAC,EAAE,EAAE,MAAM,CAAC,CAAA;YACvB,OAAO,OAAO,CAAC,IAAI,GAAG,gBAAgB,CAAC,gBAAgB,EAAE,CAAC;gBACxD,MAAM,aAAa,GAAG,CAAC,GAAG,OAAO,CAAC,OAAO,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,IAAI,CAAC,EAAE,EAAE,CAAC,IAAI,CAAC,MAAM,KAAK,SAAS,CAAC,CAAA;gBAC1F,IAAI,aAAa,KAAK,SAAS;oBAAE,MAAK,CAAC,mDAAmD;gBAC1F,OAAO,CAAC,MAAM,CAAC,aAAa,CAAC,CAAC,CAAC,CAAC,CAAA;YAClC,CAAC;QACH,CAAC;KACF,CAAA;IACD,OAAO,KAAK,CAAA;AACd,CAAC;AAED,oFAAoF;AACpF,MAAM,CAAC,KAAK,UAAU,WAAW,CAAC,KAAkB,EAAE,SAA6B,EAAE,MAAoB;IACvG,MAAM,SAAS,GAAG,SAAS,EAAE,IAAI,EAAE,CAAA;IACnC,IAAI,SAAS,KAAK,SAAS,IAAI,SAAS,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACpD,OAAO,YAAY,CAAC,IAAI,CAAC,SAAS,CAAC;YACjC,CAAC,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,SAAS,EAAE;YAC/B,CAAC,CAAC,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,IAAI,SAAS,6BAA6B,EAAE,QAAQ,EAAE,aAAa,EAAE,CAAA;IACvH,CAAC;IACD,MAAM,QAAQ,GAAG,KAAK,CAAC,MAAM,CAAC,gBAAgB,EAAE,IAAI,EAAE,CAAA;IACtD,IAAI,QAAQ,KAAK,SAAS,IAAI,QAAQ,CAAC,MAAM,GAAG,CAAC;QAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,CAAA;IACtF,MAAM,EAAE,cAAc,EAAE,GAAG,MAAM,YAAY,CAAC,KAAK,EAAE,KAAK,CAAC,YAAY,EAAE,MAAM,CAAC,CAAA;IAChF,IAAI,cAAc,KAAK,IAAI;QAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,IAAI,EAAE,cAAc,EAAE,CAAA;IACtE,OAAO,EAAE,EAAE,EAAE,KAAK,EAAE,IAAI,EAAE,cAAc,EAAE,OAAO,EAAE,2CAA2C,EAAE,QAAQ,EAAE,aAAa,EAAE,CAAA;AAC3H,CAAC;AAUD,4EAA4E;AAC5E,MAAM,UAAU,UAAU,CAAC,KAAa;IACtC,MAAM,OAAO,GAAG,KAAK,CAAC,IAAI,EAAE,CAAA;IAC5B,MAAM,QAAQ,GAAG,wEAAwE,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACvG,IAAI,QAAQ;QAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,QAAQ,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,QAAQ,CAAC,CAAC,CAAC,EAAE,CAAA;IACvE,MAAM,SAAS,GAAG,iDAAiD,CAAC,IAAI,CAAC,OAAO,CAAC,CAAA;IACjF,IAAI,SAAS;QAAE,OAAO,SAAS,CAAC,CAAC,CAAC,KAAK,SAAS,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,EAAE,MAAM,EAAE,MAAM,CAAC,SAAS,CAAC,CAAC,CAAC,CAAC,EAAE,IAAI,EAAE,SAAS,CAAC,CAAC,CAAC,EAAE,CAAA;IAC1I,IAAI,OAAO,CAAC,IAAI,CAAC,OAAO,CAAC;QAAE,OAAO,EAAE,MAAM,EAAE,MAAM,CAAC,OAAO,CAAC,EAAE,CAAA;IAC7D,OAAO,IAAI,CAAA;AACb,CAAC;AAED,2DAA2D;AAC3D,KAAK,UAAU,YAAY,CAAa,KAAoB,EAAE,GAAW,EAAE,MAAoB;IAC7F,IAAI,CAAC;QACH,MAAM,EAAE,MAAM,EAAE,GAAG,MAAM,KAAK,CAAC,MAAM,CAAC,CAAC,QAAQ,EAAE,SAAS,EAAE,QAAQ,CAAC,EAAE,EAAE,GAAG,EAAE,MAAM,EAAE,CAAC,CAAA;QACvF,OAAO,EAAE,cAAc,EAAE,iBAAiB,CAAC,MAAM,EAAE,KAAK,CAAC,OAAO,CAAC,EAAE,CAAA;IACrE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,cAAc,EAAE,IAAI,EAAE,CAAA;IACjC,CAAC;AACH,CAAC;AAQD,MAAM,UAAU,cAAc,CAAC,IAAmB;IAChD,OAAO,EAAE,SAAS,EAAE,IAAI,CAAC,SAAS,EAAE,OAAO,EAAE,IAAI,CAAC,OAAO,EAAE,CAAA;AAC7D,CAAC"} \ No newline at end of file diff --git a/package.json b/package.json index d22177f..786a2d8 100644 --- a/package.json +++ b/package.json @@ -72,10 +72,8 @@ }, "client": { "inject": [ - "@deepseek-ai/dsh-client-connection", "@deepseek-ai/dsh-client-locale", "@deepseek-ai/dsh-client-ui-plugin-manager", - "@deepseek-ai/dsh-client-ui-settings", "@deepseek-ai/dsh-client-ui-slots" ], "platform": "web" diff --git a/src/client.ts b/src/client.ts index 32ae7b3..1eb0289 100644 --- a/src/client.ts +++ b/src/client.ts @@ -1,117 +1,43 @@ /** - * dsh-github browser half — one card in the Plugins page's Official group. + * dsh-github browser half — one card in the Plugins panel's Official group. * - * The card reports and edits the GitHub token. The token literal never rides - * the settings document: it is written through the credentials domain, - * addressed by the reference the plugin's cordis.yml `Config.tokenRef` names - * (default `GITHUB_TOKEN`), which is exactly where the host half resolves it — - * per operation, no restart needed. + * The card reads and writes the plugin's own `Config.githubToken` through the + * configuration form the page hands a `plugins.item` entry (`form.state` and + * `form.mutate`), so the token stays one host-owned field and the host half + * resolves it on every operation. The browser half deliberately depends on no + * credentials remote: DSH 0.2.1 no longer exposes one (`remote.credentials` / + * `remote.credentialsController` are gone), and a missing required client + * service leaves the whole entry pending, which fails the web boot. * - * Since host 0.1.7-alpha.1 the page owns configuration: the card renders the - * `summary` one-liner and the `page` body from the `plugins.item` owner props - * (`view`, and the `form` the Plugins page supplies), instead of binding a - * `settingsScope` itself — that service, `settings.plugin.item`'s old shape, - * and the `dsh-settings-file` package behind them were all removed. The card - * therefore reads `tokenRef` from `form.state.value` and never writes the - * settings document; the credential is written through the credentials - * domain, which is a different seam and stayed. + * Rendering uses the shipped `SettingsForm` / `SettingsSecretField`, so the + * card inherits the standard settings layout and every theme token a skin + * overrides; the only local CSS is the guidance list below. * * The shipped `lib/client.js` is the built bundle of this module. The browser * module loader executes that bundle, not this file. * @module @perrylink/dsh-github/client */ -import { createElement, useState, type ChangeEvent, type ReactNode } from 'react' -import { - Button, IconLoadingOutlineRegular, -} from '@deepseek-ai/dsh-client-ui-primitives' +import { createElement, useState, type ReactNode } from 'react' +import { SettingsForm, SettingsSecretField } from '@deepseek-ai/dsh-client-ui-primitives' -/** - * The configuration-form contract the card consumes, declared locally: a - * client package must not import a Host package, and the browser half of the - * seam lives in `@deepseek-ai/dsh-client-ui-settings`, which is an optional - * peer. Mirrors that package's `ConfigForm`/`ConfigFormSnapshot` faces — the - * ones the Plugins page hands a `plugins.item` entry as `form`. - */ - -/** Client-side sync state of one configuration entry. */ -export interface ConfigFormSnapshot { - /** `loading` until the first accepted section, `ready` while one stands, `unavailable` otherwise. */ - status: 'loading' | 'ready' | 'unavailable' - /** Last accepted schema-resolved section; undefined before the first acceptance. */ - value: T | undefined - /** Composition layer the Host resolved the value over, when the owning plugin declared one. */ - base: unknown - /** Raw user layer as stored, when one exists. */ - user: unknown - /** Namespace revision fencing the next write; undefined before the first Host view. */ - revision: number | undefined - /** Whether the Host document accepts writes; memory mode never does. */ - writable: boolean - /** `host` syncs with the Host document; `memory` keeps a remote browser process-local. */ - mode: 'host' | 'memory' -} - -/** Reactive owner handle over one configuration entry's accepted values. */ -export interface ConfigForm { - /** @returns the current sync snapshot (stable reference until the next change). */ - getSnapshot(): ConfigFormSnapshot - /** - * Observe snapshot replacements. - * @param listener - invoked after each snapshot change. - * @returns the disposer removing this listener. - */ - subscribe(listener: () => void): () => void -} +/** Dictionary namespace owned by this plugin. */ +export const NS = 'dsh-github' -/** - * Minimal writable snapshot store the card's slot hooks consume. Declared and - * implemented locally: its previous home `dsh-client-store` is not on the - * published `0.1.1-rc.2` line, and the card only needs the bare observable - * contract plus whole-value replacement (no drafts, no persistence) — the - * framework synthesizes the selector hook from `getSnapshot`/`subscribe`. - */ -export interface SnapshotStore { - /** @returns the current snapshot reference. */ - getSnapshot(): T - /** - * Subscribe to snapshot replacements. - * @param listener - invoked after each change. - * @returns the disposer removing this listener. - */ - subscribe(listener: () => void): () => void - /** - * Replace the state wholesale. - * @param next - next state. - */ - set(next: T): void -} +/** Client services this half requires; both are provided by the web shell. */ +export const inject = ['slots', 'locale'] -/** - * Create the minimal card store. - * @param init - initial state. - * @returns the store. - */ -export function createSnapshotStore(init: T): SnapshotStore { - let state = init - const listeners = new Set<() => void>() - return { - getSnapshot: () => state, - subscribe: (listener) => { - listeners.add(listener) - return () => { listeners.delete(listener) } - }, - set: (next) => { - state = next - for (const listener of [...listeners]) listener() - }, +export interface ClientContextLike { + effect(disposer: () => void, label: string): void + locale: { + bind(namespace: string): (key: keyof GithubCardLocale) => string + register(namespace: string, dictionaries: Record): void + } + slots: { + inject(slot: string, factory: () => unknown): unknown + register(options: Record, component: unknown): unknown } } -/** Namespace of the GitHub capability. Spelled here rather than imported: a client package must not depend on a Host package. */ -export const GITHUB_NS = 'dsh-github' -/** Credential reference the provider resolves when the configuration names none. */ -export const DEFAULT_TOKEN_REF = 'GITHUB_TOKEN' - /** Locale copy the card renders. */ export interface GithubCardLocale { githubTitle: string @@ -120,12 +46,15 @@ export interface GithubCardLocale { tokenHint: string tokenSet: string tokenUnset: string - unsaved: string + unavailable: string readOnly: string save: string saving: string - discard: string saveFailed: string + guideIntro: string + guideClassic: string + guideFineGrained: string + guideStorage: string } /** English copy. */ @@ -133,15 +62,18 @@ export const en: GithubCardLocale = { githubTitle: 'GitHub', githubDescription: 'GitHub pull requests, issues, and CI through the agent.', tokenLabel: 'GitHub token', - tokenHint: 'Stored in the credentials file, not here. Applied immediately; leave blank to keep the current token.', - tokenSet: 'A token is configured.', - tokenUnset: 'No token is configured; GitHub tools are unavailable until one is.', - unsaved: 'Unsaved', + tokenHint: 'Save writes this plugin\'s configuration in plain text and applies on the next GitHub operation; leave it blank to keep the current token.', + tokenSet: 'Token configured', + tokenUnset: 'No token', + unavailable: 'This page has no editable configuration form; set `githubToken` in the profile configuration instead.', readOnly: 'This deployment stores settings read-only.', save: 'Save', saving: 'Saving…', - discard: 'Discard', saveFailed: 'The deployment did not accept this value; it was left for you to correct.', + guideIntro: 'No token yet? Create a personal access token on GitHub:', + guideClassic: 'Classic token — Settings → Developer settings → Personal access tokens (classic), scope `repo`:', + guideFineGrained: 'Fine-grained token — pick the repositories and grant Contents, Issues, and Pull requests read/write:', + guideStorage: 'Paste the whole string (ghp_… or github_pat_…). A token is a password: never commit it or share it.', } /** Simplified Chinese copy. */ @@ -149,359 +81,186 @@ export const zh: GithubCardLocale = { githubTitle: 'GitHub', githubDescription: '通过 agent 操作 GitHub 的 PR、issue 与 CI。', tokenLabel: 'GitHub Token', - tokenHint: '写入凭证文件而非设置文件;保存后立即生效。留空表示保持现有令牌。', - tokenSet: '已配置令牌。', - tokenUnset: '未配置令牌;配置之前 GitHub 工具不可用。', - unsaved: '未保存', + tokenHint: '保存后以明文写入本插件配置,下一次 GitHub 操作即生效;留空表示保持现有令牌。', + tokenSet: '已配置', + tokenUnset: '未配置', + unavailable: '本页没有可编辑的配置表单;请在 profile 配置里填写 `githubToken`。', readOnly: '本部署的设置为只读。', save: '保存', saving: '保存中…', - discard: '放弃修改', saveFailed: '本部署没有接受该值,已保留供你修改。', + guideIntro: '还没有令牌?先在 GitHub 生成一个个人访问令牌(PAT):', + guideClassic: '经典令牌:Settings → Developer settings → Personal access tokens (classic),勾选 `repo`:', + guideFineGrained: '细粒度令牌:Personal access tokens (fine-grained),选好仓库并给 Contents、Issues、Pull requests 读写:', + guideStorage: '把整串(ghp_… 或 github_pat_…)粘到上面的输入框。令牌等同于密码,不要提交进仓库或贴到公开的地方。', } -/** The card's full state, as projected into its snapshot store. */ -export interface GithubCardState { +/** Sync state of one configuration entry, as the Plugins page projects it. */ +export interface ConfigFormSnapshot { + /** `loading` until the first accepted section, `ready` while one stands, `unavailable` otherwise. */ + status: 'loading' | 'ready' | 'unavailable' + /** Last accepted schema-resolved section; undefined before the first acceptance. */ + value: T | undefined + /** Namespace revision fencing the next write; undefined before the first Host view. */ + revision: number | undefined /** Whether the Host configuration document accepts writes. */ writable: boolean - /** Whether the referenced credential is configured. */ - configured: boolean - /** Whether the credentials domain accepts writes. */ - credentialWritable: boolean - /** Whether a save is crossing the wire. */ - saving: boolean - /** Whether the last save did not land as staged. */ - failed: boolean - /** The credential reference the card addresses. */ - ref: string } -/** Source and writability facts for one credential reference (never the value). */ -interface CredentialView { - /** Whether resolving the reference would currently return a value. */ - configured: boolean - /** Source layer currently supplying the value; absent while unconfigured. */ - source?: string - /** Whether the active provider can write this reference. */ - writable: boolean +/** One ordered mutation the configuration form applies to its namespace. */ +export interface ConfigFormOp { + op: 'set' | 'unset' + path: string[] + value?: unknown } /** - * The credentials-domain wire face the card uses: the host `credentials` Remote - * namespace (`remote.credentials`). The token literal crosses the wire on - * `set` only — no read path returns it. + * The configuration-form face the Plugins page hands a `plugins.item` entry. + * Mirrors the page's own `ConfigPageForm`: a snapshot plus the write action. */ -export interface CredentialsApi { - /** - * Ask the credentials domain about references; one view per requested name, - * keyed by that name. - */ - describe(refs: string[]): Promise< - | { readonly ok: true; readonly value: Record } - | { readonly ok: false; readonly error: { readonly code: string; readonly message: string } } - > - /** - * Store one non-empty value under a reference. - */ - set(ref: string, value: string): Promise +export interface ConfigPageForm { + state: ConfigFormSnapshot + mutate(ops: ConfigFormOp[], revision?: number): Promise } -/** The configuration the card reads its credential reference from (the plugin's own `Config` subset). */ -interface GithubCardConfig { - tokenRef?: string -} - -/** - * Bridges the page-supplied configuration form and the credentials domain onto - * the card. The token is the one control that does not live in the - * configuration: its literal never rides a response, so the card learns only - * whether one is configured and writes it through the credentials domain, - * addressed by the reference `Config.tokenRef` names. - */ -export class GithubCardController { - private readonly form: ConfigForm | undefined - private readonly api: CredentialsApi - private readonly store: SnapshotStore - private saving = false - private failed = false - private credential: { ref: string; configured: boolean; writable: boolean } = { ref: '', configured: false, writable: true } - - /** - * @param form - the configuration form the Plugins page hands this entry, or - * `undefined` when the page supplied none (the card then reads the default - * reference and offers the credential control alone). - * @param api - the credentials Remote namespace. - */ - constructor(form: ConfigForm | undefined, api: CredentialsApi) { - this.form = form - this.api = api - this.store = createSnapshotStore(this.projection()) - form?.subscribe(() => { - void this.readCredential() - this.publish() - }) - void this.readCredential() - } - - /** Whether the Host configuration document accepts writes. */ - writable(): boolean { - return this.form?.getSnapshot().writable ?? true - } - - /** The configuration form this controller reads (identity-compared by the caller). */ - formOf(): ConfigForm | undefined { - return this.form - } - - /** Project the card's full state for its snapshot store. */ - projection(): GithubCardState { - return { - writable: this.writable(), - configured: this.credential.configured, - credentialWritable: this.credential.writable, - saving: this.saving, - failed: this.failed, - ref: this.credential.ref, - } - } - - /** The credential reference the configuration names, or the provider default. */ - refOf(): string { - const declared = this.form?.getSnapshot().value?.tokenRef - return declared !== undefined && declared.length > 0 ? declared : DEFAULT_TOKEN_REF - } - - /** - * Ask the credentials domain about the reference the section names. A - * response is published only while it still answers for the reference in - * force, so two reads settling out of order cannot clobber each other. - */ - async readCredential(): Promise { - const ref = this.refOf() - if (ref !== this.credential.ref) { - this.credential = { ref, configured: false, writable: true } - this.publish() - } - let response - try { - response = await this.api.describe([ref]) - } catch { - return - } - if (!response.ok || ref !== this.refOf()) return - const view = response.value[ref] - const next = { ref, configured: view?.configured ?? false, writable: view?.writable ?? true } - if (next.configured === this.credential.configured && next.writable === this.credential.writable) return - this.credential = next - this.publish() - } - - /** - * Re-read after the Host reports a change to the reference this card - * watches — a token can be written from elsewhere, and the section does not - * change when it is. - * @param ref - the reference the Host reports as changed. - */ - refreshCredential(ref: string): void { - if (ref !== this.credential.ref) return - void this.readCredential() - } - - /** - * Write the staged token, then re-read whether the Host now holds one. A - * blank value writes nothing, which keeps the stored key. - * @param value - the staged credential literal. - * @returns whether the Host reports a configured credential afterwards. - */ - async save(value: string): Promise { - const text = (value ?? '').trim() - if (text === '' || this.saving) return false - this.saving = true - this.failed = false - this.publish() - try { - await this.api.set(this.refOf(), text) - } catch { - // handled below by re-reading the configured state - } - await this.readCredential() - const landed = this.credential.configured - this.saving = false - this.failed = !landed - this.publish() - return landed - } - - /** Build the face the card's slot registration injects. */ - inject(): { hooks: { githubCard: SnapshotStore }; submit: (value: string) => Promise } { - return { - hooks: { githubCard: this.store }, - submit: (value) => this.save(value), - } - } - - private publish(): void { - this.store.set(this.projection()) - } +/** The plugin configuration subset this card reads and writes. */ +export interface GithubCardConfig { + githubToken?: string } /** Props the slot system injects into the card component. */ export interface GithubCardProps { t: (key: keyof GithubCardLocale) => string - useGithubCard: (selector: (snapshot: GithubCardState) => GithubCardState) => GithubCardState - submit: (value: string) => Promise /** The view the Plugins page asks for: the one-liner under the title, or the page body. */ view: 'summary' | 'page' + /** The form for this entry; absent when the page has no editable configuration for it. */ + form?: ConfigPageForm | undefined } +/** Guidance list styling; everything else comes from the shipped settings primitives. */ +const CARD_CSS = [ + '.ghc-guide{margin-top:12px;font-size:12px;line-height:1.6;color:var(--dsw-alias-label-secondary);}', + '.ghc-guide p{margin:0 0 4px;}', + '.ghc-guide ul{margin:0 0 4px;padding-left:18px;}', + '.ghc-guide li{margin:0 0 2px;}', + '.ghc-guide a{color:var(--dsw-alias-brand-primary);text-decoration:none;}', + '.ghc-guide a:hover{text-decoration:underline;}', +].join('') + /** - * Render the GitHub card. `summary` renders the one-liner the Plugins page - * places under the card's title (the description plus the token state badge); - * `page` renders the token control and the save/discard row on the plugin's - * own page. The page supplies the configuration form, so the card never - * depends on a served namespace to render. + * Render the GitHub card: the one-liner the page shows under the card's title, + * or the token control on the plugin's own page. + * @param props - locale, view, and the page-supplied configuration form. + * @returns the card's React node. */ export function GithubCard(props: GithubCardProps): ReactNode { - const { t } = props - const state = props.useGithubCard((snapshot) => snapshot) + const { t, form } = props const [draft, setDraft] = useState('') - if (props.view === 'summary') { - return createElement( - 'span', - { className: 'ghc-summary' }, - createElement('span', null, t('githubDescription')), - createElement( - 'span', - { className: state.configured ? 'ghc-badge' : 'ghc-badgeMuted' }, - state.configured ? t('tokenSet') : t('tokenUnset'), - ), - ) + const [saving, setSaving] = useState(false) + const [failed, setFailed] = useState(false) + const stored = (form?.state.value?.githubToken ?? '').trim() + const configured = stored.length > 0 + // A summary render receives no `form` (the page hands it only to the detail + // view), so it must not claim a token state it cannot read; the badge on the + // page view is the single source of that answer. + if (props.view === 'summary') return t('githubDescription') + const writable = form?.state.writable ?? false + const staged = draft.trim() + const save = async (): Promise => { + if (form === undefined || staged === '' || saving) return + setSaving(true) + setFailed(false) + let landed = false + try { + // No explicit revision: the form fences the write with the latest one it + // knows, so a save queued behind another write cannot be rejected as stale. + landed = await form.mutate([{ op: 'set', path: ['githubToken'], value: staged }]) + } catch { + landed = false + } + setSaving(false) + if (landed) setDraft('') + else setFailed(true) } - const dirty = draft.trim() !== '' - const saveLabel = state.saving ? t('saving') : t('save') return createElement( - 'div', - { className: 'ghc-card ghc-cardPage' }, - !state.writable - ? createElement('p', { className: 'ghc-readOnly', role: 'status' }, t('readOnly')) - : null, - createElement( - 'div', - { className: 'ghc-field' }, - createElement( - 'div', - { className: 'ghc-head' }, - createElement('label', { className: 'ghc-label', htmlFor: 'plugin-config-github-token' }, t('tokenLabel')), + SettingsForm, + { + labels: { + unavailable: t('unavailable'), + readOnly: t('readOnly'), + saveFailed: t('saveFailed'), + save: t('save'), + saving: t('saving'), + }, + state: { + available: form !== undefined, + writable, + dirty: staged !== '', + invalid: false, + saving, + failed, + }, + onSave: () => { void save() }, + // SettingsForm calls this only on unmount; the draft belongs to the + // component instance, so a fresh mount starts clean either way. + onDiscard: () => {}, + children: [ + createElement(SettingsSecretField, { + id: 'plugin-config-github-token', + label: t('tokenLabel'), + configured, + stateLabel: configured ? t('tokenSet') : t('tokenUnset'), + text: draft, + hint: t('tokenHint'), + disabled: !writable || saving, + onEdit: (text: string) => setDraft(text), + }), createElement( - 'span', - { className: 'ghc-badges' }, + 'div', + { className: 'ghc-guide' }, + createElement('p', null, t('guideIntro')), createElement( - 'span', - { className: state.configured ? 'ghc-badge' : 'ghc-badgeMuted' }, - state.configured ? t('tokenSet') : t('tokenUnset'), + 'ul', + null, + createElement( + 'li', + null, + t('guideClassic'), + ' ', + createElement('a', { href: 'https://github.com/settings/tokens', target: '_blank', rel: 'noreferrer noopener' }, 'github.com/settings/tokens'), + ), + createElement( + 'li', + null, + t('guideFineGrained'), + ' ', + createElement('a', { href: 'https://github.com/settings/personal-access-tokens/new', target: '_blank', rel: 'noreferrer noopener' }, 'github.com/settings/personal-access-tokens/new'), + ), ), + createElement('p', null, t('guideStorage')), ), - ), - createElement('input', { - id: 'plugin-config-github-token', - className: 'ghc-input', - type: 'password', - autoComplete: 'off', - value: draft, - disabled: !state.credentialWritable, - onChange: (event: ChangeEvent) => setDraft(event.target.value), - }), - createElement('p', { className: 'ghc-hint' }, t('tokenHint')), - ), - createElement( - 'div', - { className: 'ghc-actions' }, - state.failed ? createElement('p', { className: 'ghc-failed', role: 'status' }, t('saveFailed')) : null, - createElement( - Button, - { - variant: 'ghost', - size: 'sm', - disabled: !dirty || state.saving, - onClick: () => setDraft(''), - }, - t('discard'), - ), - createElement( - Button, - { - variant: 'primary', - size: 'sm', - disabled: !state.writable || !dirty || state.saving, - icon: state.saving - ? createElement('span', { className: 'ghc-spin' }, createElement(IconLoadingOutlineRegular, { size: 16 })) - : undefined, - onClick: async () => { - const landed = await props.submit(draft) - if (landed) setDraft('') - }, - }, - saveLabel, - ), - ), + ], + }, ) } -/** Dictionary namespace owned by this plugin. */ -export const NS = 'dsh-github' -/** - * Required services (cordis fiber inject). `settingsScope` is gone: host - * 0.1.7-alpha.1 removed it, and the Plugins page now hands the configuration - * form to the `plugins.item` entry instead. `@deepseek-ai/dsh-client-ui-plugin-manager` - * owns that slot, so it must be composed for the card to mount at all. - */ -export const inject = ['slots', 'locale', 'connection', 'remote', 'remote.credentials'] - -export interface ClientContextLike { - get(service: string): unknown - effect(disposer: () => void, label: string): void - locale: { - bind(namespace: string): (key: keyof GithubCardLocale) => string - register(namespace: string, dictionaries: Record): void - } - remote: { - $on(event: string, listener: (ref: string) => void): unknown - credentials: CredentialsApi - } - slots: { - inject(slot: string, factory: () => unknown): unknown - register(options: Record, component: unknown): unknown - } -} - -/** The `form` member the Plugins page hands a `plugins.item` entry. */ -interface PluginConfigViewProps { - readonly view: 'summary' | 'page' - readonly form?: ConfigForm | undefined -} - /** - * Mount the GitHub configuration card into the Plugins page's Official group. - * - * The form arrives per render, so the controller is rebuilt whenever the page - * supplies a different one — the page's own form owner stays authoritative and - * the card keeps no second copy of the accepted values. + * Mount the GitHub configuration card into the Plugins panel's Official group. * @param ctx - the browser plugin context. */ export function apply(ctx: ClientContextLike): void { const t = ctx.locale.bind(NS) ctx.effect(() => ctx.locale.register(NS, { zh, en }), 'dsh-github: card dictionaries') - let github: GithubCardController | undefined - const controllerFor = (form: PluginConfigViewProps['form']): GithubCardController => { - if (github === undefined || github.formOf() !== form) { - github = new GithubCardController(form, ctx.remote.credentials) - } - return github - } - ctx.effect( - () => ctx.remote.$on('credentials/reference-updated', (ref) => github?.refreshCredential(ref)), - 'dsh-github: credential invalidations', - ) + ctx.effect(() => { + const tagId = `${NS}/card.css` + if (document.querySelector(`style[data-plugin-css="${tagId}"]`) !== null) return () => {} + const tag = document.createElement('style') + tag.dataset.plugin = NS + tag.dataset.pluginCss = tagId + tag.textContent = CARD_CSS + document.head.appendChild(tag) + return () => { tag.remove() } + }, 'dsh-github: card styles') ctx.slots.inject('plugins.item', () => ctx.slots.register( { name: 'plugins.item', @@ -509,7 +268,6 @@ export function apply(ctx: ClientContextLike): void { order: 100, label: () => t('githubTitle'), locale: NS, - inject: () => controllerFor(github?.formOf()).inject(), }, GithubCard, )) diff --git a/src/config.ts b/src/config.ts index 242c00b..708495b 100644 --- a/src/config.ts +++ b/src/config.ts @@ -13,7 +13,7 @@ import z from '@deepseek-ai/schemastery' export type GithubAction = 'pr.create' | 'review.post' | 'issue.create' | 'issue.comment' | 'issue.close' | 'pr.merge' | 'pr.update' | 'ci.run' /** Where a GitHub token is looked up. `auto` tries them in order. */ -export type TokenSource = 'auto' | 'credentials' | 'env' | 'gh' +export type TokenSource = 'auto' | 'config' | 'credentials' | 'env' | 'gh' /** * The CI surface: the one-shot `ci_run` tool, the polling review bot, the @@ -72,6 +72,12 @@ export interface Config { tokenSource: TokenSource /** Credentials-seam reference / environment-variable name for the token. */ tokenRef: string + /** + * Token typed into the Plugins page configuration form. It sits in the profile + * configuration as plain text, which is what the credentials file is too; + * leave it empty when the configuration is shared with other tools. + */ + githubToken: string /** `owner/repo` used when a call does not name one and git has no origin. */ defaultOwnerRepo?: string /** Whether `/pr create` may instruct the model to commit and push first. */ @@ -184,14 +190,46 @@ export const CiConfig: z = z.object({ .description('Report-file directory; defaults to DSH_GITHUB_CI_OUTPUT_DIR, then the workspace directory.'), }) +/** + * A string field the Plugins page may edit. + * + * `.volatile()` is what makes the field reachable from the browser at all: DSH + * serves a settings namespace only when its Config exposes at least one + * volatile field, and accepts a write only beneath a volatile node. A volatile + * schema types its output as `Volatile` because the plugin receives a + * live reference rather than the stored value; {@link liveValue} reads that + * reference, so the schema keeps the plain face its consumers use. + * @param description - schema description the settings form shows. + * @returns the schema field. + */ +function editableString(description: string): z { + return z.string().default('').volatile().description(description) as unknown as z +} + +/** + * Read one configuration value a volatile field hands over as a live reference. + * + * Such a field arrives as an object carrying `get()` instead of the stored + * value, and a Settings write updates that object in place — reading it per + * operation is what lets a token saved on the page apply without reloading the + * plugin. + * @param value - plain value or live reference. + * @returns the current value. + */ +export function liveValue(value: T | { get(): T }): T { + const getter = (value as { get?: unknown }).get + return typeof getter === 'function' ? (value as { get(): T }).get() : (value as T) +} + export const Config: z = z.object({ - tokenSource: z.union(['auto', 'credentials', 'env', 'gh'] as const) + tokenSource: z.union(['auto', 'config', 'credentials', 'env', 'gh'] as const) .default('auto') - .description('Token lookup source: auto tries credentials → env → gh in order.'), + .description('Token lookup source: auto tries this page → credentials → env → gh in order.'), tokenRef: z.string() .pattern(/^[A-Za-z_][A-Za-z0-9_]*$/) .default('GITHUB_TOKEN') .description('Credential reference / environment variable name holding the token.'), + githubToken: editableString('Token set from this page; used before the credentials file when non-empty. Stored in the profile configuration in plain text.'), defaultOwnerRepo: z.string() .pattern(OWNER_REPO_PATTERN) .description('Fallback owner/repo when neither the call nor git names one.'), diff --git a/src/credential.ts b/src/credential.ts index edbf6c1..68f95d1 100644 --- a/src/credential.ts +++ b/src/credential.ts @@ -32,9 +32,10 @@ export type TokenResolution = { ok: true; token: ResolvedToken } | { ok: false; export type GhRunner = (args: string[], signal?: AbortSignal) => Promise<{ stdout: string }> const NO_TOKEN_GUIDANCE = - 'Configure one of: 1) a dsh credential for this reference (recommended; ' + - '$DSH_HOME/.credentials.yaml), 2) the same-named environment variable, or ' + - '3) `gh auth login` for the gh CLI. Set `tokenSource` in cordis.yml to pin one source.' + 'Configure one of: 1) the GitHub token field on this plugin\'s page in the Plugins panel, ' + + '2) a dsh credential for this reference (' + + '$DSH_HOME/.credentials.yaml), 3) the same-named environment variable, or ' + + '4) `gh auth login` for the gh CLI. Set `tokenSource` in cordis.yml to pin one source.' /** Run the real `gh` CLI with stdout captured (never logged). */ export function runGhCli(args: string[], signal?: AbortSignal): Promise<{ stdout: string }> { @@ -49,13 +50,15 @@ export function runGhCli(args: string[], signal?: AbortSignal): Promise<{ stdout /** * Resolve the GitHub token for one operation. * - * `auto` order: credentials seam → `GITHUB_TOKEN`-style environment variable → - * `gh` CLI logged-in token. An explicit source restricts to that one source. + * `auto` order: configuration field set on the plugin's page → credentials seam + * → `GITHUB_TOKEN`-style environment variable → `gh` CLI logged-in token. An + * explicit source restricts to that one source. * @param credentials - the credentials seam (`ctx.credentials`). * @param tokenSource - configured lookup policy. * @param tokenRef - reference / environment-variable name. * @param runGh - `gh` CLI runner; the real one by default. * @param signal - aborts the `gh` lookup. + * @param configuredToken - token typed into the Plugins page configuration form. * @returns the token with its source, or a structured error with guidance. */ export async function resolveToken( @@ -64,11 +67,20 @@ export async function resolveToken( tokenRef: string, runGh: GhRunner = runGhCli, signal?: AbortSignal, + configuredToken?: string, ): Promise { + const typed = configuredToken?.trim() + const configured = typed === undefined || typed === '' ? undefined : typed const order: Array> = - tokenSource === 'auto' ? ['credentials', 'env', 'gh'] : [tokenSource] + tokenSource === 'auto' + ? [...(configured === undefined ? [] : (['config'] as const)), 'credentials', 'env', 'gh'] + : [tokenSource] for (const source of order) { + if (source === 'config') { + if (configured !== undefined) return { ok: true, token: { value: configured, source: 'config' } } + continue + } if (source === 'credentials') { let ref: ReturnType try { @@ -98,7 +110,7 @@ export async function resolveToken( ok: false, error: { code: 'no-token', - message: `no GitHub token found (source: ${tokenSource === 'auto' ? 'credentials/env/gh' : tokenSource})`, + message: `no GitHub token found (source: ${tokenSource === 'auto' ? 'config/credentials/env/gh' : tokenSource})`, guidance: NO_TOKEN_GUIDANCE, }, } diff --git a/src/state.ts b/src/state.ts index 219754d..03743cd 100644 --- a/src/state.ts +++ b/src/state.ts @@ -14,7 +14,7 @@ import { repoFromRemoteUrl, type GitRunner } from './git.ts' import { resolveToken, type GhRunner, type TokenResolution } from './credential.ts' import type { SubagentsService } from './types.ts' import type { ReviewReport } from './review.ts' -import { CiConfig, type Config } from './config.ts' +import { CiConfig, liveValue, type Config } from './config.ts' /** Result of resolving which repository a call targets. */ export type RepoResolution = { ok: true; repo: string } | { ok: false; code: string; message: string; guidance: string } @@ -101,7 +101,7 @@ export function createState(ctx: { credentials: CredentialProvider; subagents?: workspaceDir: normalizedConfig.workspaceDir ?? process.cwd(), apiHost, isCiDriver: process.env.DSH_GITHUB_CI_DRIVER === '1', - resolveToken: (signal?: AbortSignal) => resolveToken(ctx.credentials, normalizedConfig.tokenSource, normalizedConfig.tokenRef, runGh, signal), + resolveToken: (signal?: AbortSignal) => resolveToken(ctx.credentials, normalizedConfig.tokenSource, normalizedConfig.tokenRef, runGh, signal, liveValue(normalizedConfig.githubToken)), client: (token: string) => new GithubClient(token, clientOptions), graphqlClient: (token: string) => new GithubGraphqlClient(token, clientOptions), resolveRepo: (ownerRepo: string | undefined, signal?: AbortSignal) => resolveRepo(state, ownerRepo, signal), diff --git a/test/config.test.ts b/test/config.test.ts index 581ade1..aae889d 100644 --- a/test/config.test.ts +++ b/test/config.test.ts @@ -1,11 +1,14 @@ import { describe, expect, it } from 'vitest' import { Config } from '../src/index.ts' +import { liveValue } from '../src/config.ts' describe('Config schema', () => { it('applies defaults for an empty object', () => { const resolved = Config({}) as Record expect(resolved.tokenSource).toBe('auto') expect(resolved.tokenRef).toBe('GITHUB_TOKEN') + // A volatile field validates to its live reference, not to the stored value. + expect(liveValue(resolved.githubToken as string | { get(): string })).toBe('') expect(resolved.autoCommit).toBe(false) expect(resolved.maxDiffChars).toBe(8000) expect(resolved.renderExcerptChars).toBe(2000) @@ -24,6 +27,16 @@ describe('Config schema', () => { expect(resolved.workspaceDir).toBeUndefined() }) + it('marks the token field volatile so the settings page can serve it', () => { + const field = (Config as unknown as { dict: Record }).dict.githubToken + expect(field?.meta.volatile).toBe(true) + }) + + it('reads a value through its live reference, or as a plain value', () => { + expect(liveValue({ get: () => 'typed' })).toBe('typed') + expect(liveValue('plain')).toBe('plain') + }) + it('fails loud on an invalid tokenSource', () => { expect(() => Config({ tokenSource: 'cloud' })).toThrowError(/tokenSource/) }) diff --git a/test/credential.test.ts b/test/credential.test.ts index 9814372..5774198 100644 --- a/test/credential.test.ts +++ b/test/credential.test.ts @@ -47,6 +47,29 @@ describe('resolveToken', () => { expect(result.ok).toBe(false) }) + it('prefers the token configured on the Plugins page over every other source', async () => { + process.env.GITHUB_TOKEN = TOKEN + const seam = { + resolve: async () => ({ value: `${TOKEN}-seam`, source: 'env' }), + } as unknown as CredentialProvider + const result = await resolveToken(seam, 'auto', 'GITHUB_TOKEN', ghRunner(), undefined, ` ${TOKEN}-page `) + expect(result.ok).toBe(true) + if (result.ok) expect(result.token).toEqual({ value: `${TOKEN}-page`, source: 'config' }) + }) + + it('falls through a blank configured token', async () => { + process.env.GITHUB_TOKEN = TOKEN + const result = await resolveToken(credentials, 'auto', 'GITHUB_TOKEN', ghRunner('fail'), undefined, ' ') + expect(result.ok).toBe(true) + if (result.ok) expect(result.token.source).toBe('env') + }) + + it('fails closed when config is pinned but no token was typed', async () => { + const result = await resolveToken(credentials, 'config', 'GITHUB_TOKEN', ghRunner(), undefined, '') + expect(result.ok).toBe(false) + if (!result.ok) expect(result.error.message).toContain('config') + }) + it('returns a structured error with guidance when nothing resolves', async () => { const result = await resolveToken(credentials, 'auto', 'GITHUB_TOKEN', ghRunner('fail')) expect(result.ok).toBe(false)