@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 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
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@wenathlan/devthink",
3
- "version": "1.1.14",
3
+ "version": "1.1.16",
4
4
  "repository": {
5
5
  "type": "git",
6
6
  "url": "https://github.com/wenathlan/devthink"
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.14 — Ink shares the compact local workspace grammar, identity, destinations, settings and command language with the paired React workbench. */
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
- return [`userId ${identity.userId}`, `deviceId ${identity.deviceId}`, `theme ${preferences.theme || "dark"}`, `railMode ${preferences.railMode || "auto"}`, `interfaceZoom ${preferences.interfaceZoom || "100"}`, "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"];
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."];