@wenathlan/devthink 1.1.14 → 1.1.16
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/CHANGELOG.md +21 -0
- package/devthink.ts +13 -1
- package/package.json +1 -1
- package/server.ts +11 -0
- package/terminal-ui.tsx +5 -3
package/CHANGELOG.md
CHANGED
|
@@ -1,4 +1,25 @@
|
|
|
1
1
|
# DevThink release notes
|
|
2
|
+
## 1.1.16 — Browser-local data foundation
|
|
3
|
+
### Added
|
|
4
|
+
| Area | Addition |
|
|
5
|
+
| --- | --- |
|
|
6
|
+
| Browser-local workbench data | The static workbench now uses a native IndexedDB database named `devthink.db` for non-sensitive workspaces, sessions, tabs, messages and interface preferences. |
|
|
7
|
+
| Identity-scoped records | Browser-local records include public owner ID, browser device ID, update time, revision and tombstone state to prepare explicit future synchronization without transferring raw SQLite files. |
|
|
8
|
+
| Offline fallback | Home, Projects, Usage, Providers and Settings retain browser-local state when the paired CLI gateway is unavailable, while a successful paired read refreshes the local cache. |
|
|
9
|
+
| Sync state | Settings now distinguishes `local-only` browser persistence from the paired local gateway and makes clear that a remote adapter is optional and not configured. |
|
|
10
|
+
| Credential boundary | Provider selection is a non-secret local preference. Credentials remain CLI-owned by default; an explicit opt-in may save one in a separate browser-only vault that is never displayed, gatewayed or synchronized. |
|
|
11
|
+
| Public maintenance skills | The public `wenathlan/skills` repository now includes DevThink-specific skills for architecture, local data, paired gateway and release workflows. |
|
|
12
|
+
|
|
13
|
+
## 1.1.15 — Unified capabilities and Settings
|
|
14
|
+
### Added
|
|
15
|
+
| Area | Addition |
|
|
16
|
+
| --- | --- |
|
|
17
|
+
| Capability matrix | A renderer-neutral matrix now maps every safe local action across CLI commands, Ink destinations, authenticated gateway routes and web pages. |
|
|
18
|
+
| Shared Settings page | `/settings` is a dedicated browser page equivalent to `devthink config settings`, `devthink config set` and the Ink Settings view. |
|
|
19
|
+
| Settings summary | The authenticated `GET /settings` route returns identity, pairing session count, preferences, active provider summary and local database ownership metadata without secrets or filesystem paths. |
|
|
20
|
+
| Same database client | The paired browser operates as a temporary client of the CLI-owned `devthink.db` for one public ID; it does not create an independent static database. |
|
|
21
|
+
| Settings domain | Pairing controls now belong to `web/settings/`, and the common control navigation includes Settings alongside Providers, Projects, Routes and Usage. |
|
|
22
|
+
|
|
2
23
|
## 1.1.14 — Route and local identity refinement
|
|
3
24
|
|
|
4
25
|
### Added
|
package/devthink.ts
CHANGED
|
@@ -69,6 +69,7 @@ function printHelp(): void {
|
|
|
69
69
|
" modes List the 20 operational modes",
|
|
70
70
|
" config [key] [value] Read or write local configuration",
|
|
71
71
|
" config preferences Show shared workbench preferences",
|
|
72
|
+
" config settings Show shared identity, pairing, provider and database summary",
|
|
72
73
|
" config set <key> <value> Set theme, railMode, or interfaceZoom",
|
|
73
74
|
" auth login <provider> Save a user-provided official credential",
|
|
74
75
|
" auth status Show redacted configured credential sources",
|
|
@@ -155,6 +156,17 @@ async function runChat(prompt: string, parsed: ParsedArgs, runtime: ReturnType<t
|
|
|
155
156
|
|
|
156
157
|
async function handleConfig(parsed: ParsedArgs, runtime: ReturnType<typeof loadRuntime>): Promise<void> {
|
|
157
158
|
const action = parsed.positional[1];
|
|
159
|
+
if (action === "settings") {
|
|
160
|
+
const identity = getIdentity(runtime.paths);
|
|
161
|
+
const sessions = listSessions(runtime.paths);
|
|
162
|
+
return console.log(JSON.stringify({
|
|
163
|
+
identity,
|
|
164
|
+
pairing: pairingStatus(runtime.paths),
|
|
165
|
+
preferences: Object.fromEntries(Object.entries(readPreferences(runtime.paths)).map(([key, preference]) => [key, preference.value])),
|
|
166
|
+
provider: { activeProvider: runtime.config.activeProvider || runtime.config.provider || undefined, activeModel: runtime.config.activeModel || runtime.config.model || undefined },
|
|
167
|
+
database: { ownerUserId: identity.userId, local: true, persistence: "cli-owned-sqlite", workspaces: new Set(sessions.map((session) => session.workspaceId)).size, sessions: sessions.length },
|
|
168
|
+
}, null, 2));
|
|
169
|
+
}
|
|
158
170
|
if (action === "preferences") return console.log(JSON.stringify(Object.fromEntries(Object.entries(readPreferences(runtime.paths)).map(([key, preference]) => [key, preference.value])), null, 2));
|
|
159
171
|
if (action === "set") {
|
|
160
172
|
const key = parsed.positional[2];
|
|
@@ -280,7 +292,7 @@ function handleUsage(runtime: ReturnType<typeof loadRuntime>): void {
|
|
|
280
292
|
}
|
|
281
293
|
|
|
282
294
|
function handleRoutes(): void {
|
|
283
|
-
console.log(["web: /", "web: /providers", "web: /projects", "web: /routes", "web: /usage", "web: /w/:workspaceId/s/:sessionId/t/:tabId/:sectionId", "gateway: GET /health", "gateway: GET /identity", "gateway: PUT /identity", "gateway: GET /providers", "gateway: GET /workspaces", "gateway: GET /usage", "gateway: GET /preferences", "gateway: PATCH /preferences", "gateway: POST /sessions", "gateway: POST /chat"].join("\n"));
|
|
295
|
+
console.log(["web: /", "web: /providers", "web: /projects", "web: /routes", "web: /usage", "web: /settings", "web: /w/:workspaceId/s/:sessionId/t/:tabId/:sectionId", "gateway: GET /health", "gateway: GET /identity", "gateway: PUT /identity", "gateway: GET /settings", "gateway: GET /providers", "gateway: GET /workspaces", "gateway: GET /usage", "gateway: GET /preferences", "gateway: PATCH /preferences", "gateway: POST /sessions", "gateway: POST /chat"].join("\n"));
|
|
284
296
|
}
|
|
285
297
|
|
|
286
298
|
async function interactive(runtime: ReturnType<typeof loadRuntime>): Promise<void> {
|
package/package.json
CHANGED
package/server.ts
CHANGED
|
@@ -163,6 +163,17 @@ async function route(request: IncomingMessage, response: ServerResponse, config:
|
|
|
163
163
|
if (request.method === "GET" && url.pathname === "/preferences") {
|
|
164
164
|
return writeJson(response, 200, { preferences: Object.fromEntries(Object.entries(readPreferences(paths)).map(([key, preference]) => [key, preference.value])) }, origin);
|
|
165
165
|
}
|
|
166
|
+
if (request.method === "GET" && url.pathname === "/settings") {
|
|
167
|
+
const identity = getIdentity(paths);
|
|
168
|
+
const sessions = listSessions(paths);
|
|
169
|
+
return writeJson(response, 200, {
|
|
170
|
+
identity,
|
|
171
|
+
pairing: pairingStatus(paths),
|
|
172
|
+
preferences: Object.fromEntries(Object.entries(readPreferences(paths)).map(([key, preference]) => [key, preference.value])),
|
|
173
|
+
provider: { activeProvider: config.activeProvider || config.provider || undefined, activeModel: config.activeModel || config.model || undefined },
|
|
174
|
+
database: { ownerUserId: identity.userId, local: true, persistence: "cli-owned-sqlite", workspaces: new Set(sessions.map((session) => session.workspaceId)).size, sessions: sessions.length },
|
|
175
|
+
}, origin);
|
|
176
|
+
}
|
|
166
177
|
if (request.method === "PATCH" && url.pathname === "/preferences") {
|
|
167
178
|
const body = await readBody(request);
|
|
168
179
|
const key = typeof body.key === "string" ? body.key : "";
|
package/terminal-ui.tsx
CHANGED
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
/** Design: DevThink v1.1.
|
|
1
|
+
/** Design: DevThink v1.1.15 — Ink shares the compact local workspace grammar, identity, destinations, settings and command language with the paired React workbench. */
|
|
2
2
|
import { Box, Text, render, useApp, useInput, useWindowSize } from "ink";
|
|
3
3
|
import { useMemo, useState } from "react";
|
|
4
4
|
import { listProviders } from "./providers.ts";
|
|
5
5
|
import { listSessions, type Session } from "./session.ts";
|
|
6
6
|
import { readPreferences, savePreference } from "./storage.ts";
|
|
7
|
-
import { getIdentity } from "./identity.ts";
|
|
7
|
+
import { getIdentity, pairingStatus } from "./identity.ts";
|
|
8
8
|
import type { DevThinkConfig, DevThinkPaths } from "./config.ts";
|
|
9
9
|
import type { ChatEvent } from "./stream.ts";
|
|
10
10
|
import { isWorkspaceDestination, workspaceDestination, workspaceDestinations, type WorkspaceDestination } from "./workspace.ts";
|
|
@@ -47,7 +47,9 @@ function viewRows(view: WorkspaceDestination, runtime: Runtime, session: Session
|
|
|
47
47
|
if (view === "settings") {
|
|
48
48
|
const preferences = Object.fromEntries(Object.entries(readPreferences(runtime.paths)).map(([key, preference]) => [key, preference.value]));
|
|
49
49
|
const identity = getIdentity(runtime.paths);
|
|
50
|
-
|
|
50
|
+
const pairing = pairingStatus(runtime.paths);
|
|
51
|
+
const sessions = listSessions(runtime.paths);
|
|
52
|
+
return [`userId ${identity.userId}`, `deviceId ${identity.deviceId}`, `browser sessions ${pairing.activeSessions}`, `database cli-owned-sqlite · ${new Set(sessions.map((session) => session.workspaceId)).size} workspaces · ${sessions.length} sessions`, `provider ${runtime.config.activeProvider || runtime.config.provider || "not configured"}`, `theme ${preferences.theme || "dark"}`, `railMode ${preferences.railMode || "auto"}`, `interfaceZoom ${preferences.interfaceZoom || "100"}`, "inspect all: devthink config settings", "edit identity: devthink identity --id <10-15 lowercase chars>", "edit: /settings set theme dark|light", "edit: /settings set railMode always|auto|off", "edit: /settings set interfaceZoom 80-150", "credentials remain in ~/.config/devthink/auth.json"];
|
|
51
53
|
}
|
|
52
54
|
if (session) return [`workspace ${session.workspaceId}`, `session ${session.id}`, `tab ${session.activeTabId}`];
|
|
53
55
|
return ["Describe the next feature, bug or piece of work below."];
|