@wenathlan/devthink 2.0.15 → 2.0.20
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 +54 -0
- package/{dist/bridge.d.ts → bridge.d.ts} +1 -1
- package/bridge.d.ts.map +1 -0
- package/bridge.js +1877 -0
- package/bun.d.ts.map +1 -0
- package/bun.js +52329 -0
- package/caps/background.json +712 -0
- package/caps/cli.json +360 -0
- package/caps/library.json +3611 -0
- package/caps/mcp.json +126 -0
- package/caps/pagebridge.json +377 -0
- package/caps/popup.json +51 -0
- package/caps/sidepanel.json +522 -0
- package/checksums.txt +142 -0
- package/cli.d.ts.map +1 -0
- package/{dist/cli.js → cli.js} +2 -2
- package/companion.d.ts.map +1 -0
- package/companion.js +389 -0
- package/crossbrowser.d.ts.map +1 -0
- package/crossbrowser.js +1191 -0
- package/dashdone.d.ts.map +1 -0
- package/dashdone.js +368 -0
- package/deno.d.ts.map +1 -0
- package/deno.js +52325 -0
- package/devthink.umd.js +52346 -0
- package/fixtures/bun.ts +7 -0
- package/fixtures/cjs.js +6 -0
- package/fixtures/deno.ts +6 -0
- package/fixtures/example-org-pagestate.json +22 -0
- package/fixtures/importers/automa-workflow.json +18 -0
- package/fixtures/importers/selenium-side.json +20 -0
- package/fixtures/importers/tabular-plan.csv +7 -0
- package/fixtures/importers/uivision-macro.json +10 -0
- package/fixtures/importers/v1-plan.json +13 -0
- package/fixtures/mcp-client.mjs +14 -0
- package/fixtures/pages/checkout.html +192 -0
- package/fixtures/pages/dashboard.html +110 -0
- package/fixtures/pages/feed.html +113 -0
- package/fixtures/pages/product-grid.html +150 -0
- package/fixtures/plans/form-inventory-plan.json +11 -0
- package/fixtures/plans/release-notes-plan.json +11 -0
- package/fixtures/recipes/agentscompete.json +11 -0
- package/fixtures/recipes/agentsforms.json +11 -0
- package/fixtures/recipes/agentsmonitor.json +11 -0
- package/fixtures/recipes/agentsreview.json +29 -0
- package/fixtures/recipes/agentswarm.json +11 -0
- package/fixtures/recipes/fillcalendar.json +12 -0
- package/fixtures/recipes/fillcheckout.json +13 -0
- package/fixtures/recipes/filldependentdropdowns.json +12 -0
- package/fixtures/recipes/fillfromcsv.json +13 -0
- package/fixtures/recipes/fillloginform.json +12 -0
- package/fixtures/recipes/fillmultistepwizard.json +13 -0
- package/fixtures/recipes/fillregistration.json +12 -0
- package/fixtures/recipes/fillsearchfilters.json +12 -0
- package/fixtures/recipes/filltypeahead.json +11 -0
- package/fixtures/recipes/monitoralerts.json +12 -0
- package/fixtures/recipes/monitoravailability.json +11 -0
- package/fixtures/recipes/monitornetworkquiet.json +12 -0
- package/fixtures/recipes/monitorpagechanges.json +11 -0
- package/fixtures/recipes/monitorpricechange.json +11 -0
- package/fixtures/recipes/monitorschedule.json +12 -0
- package/fixtures/recipes/scrapedynamicprices.json +13 -0
- package/fixtures/recipes/scrapeimagegallery.json +12 -0
- package/fixtures/recipes/scrapeinfinitefeed.json +13 -0
- package/fixtures/recipes/scrapenestedlists.json +12 -0
- package/fixtures/recipes/scrapeproductgrid.json +12 -0
- package/fixtures/recipes/scrapereviews.json +12 -0
- package/fixtures/recipes/scrapesearchresults.json +12 -0
- package/fixtures/recipes/scrapetablepagination.json +12 -0
- package/fixtures/recipes/testaccessibility.json +34 -0
- package/fixtures/recipes/testconsoleerrors.json +12 -0
- package/fixtures/recipes/testdeeplinks.json +12 -0
- package/fixtures/recipes/testformvalidation.json +13 -0
- package/fixtures/recipes/testlayoutshift.json +12 -0
- package/fixtures/recipes/testlinkcheck.json +12 -0
- package/fixtures/recipes/testloadtiming.json +12 -0
- package/fixtures/recipes/testvisualdiff.json +12 -0
- package/fixtures/workflows/changelog-digest-workflow.json +13 -0
- package/fixtures/workflows/form-survey-workflow.json +13 -0
- package/gallery.json +706 -0
- package/hardening.d.ts.map +1 -0
- package/hardening.js +188 -0
- package/headless.d.ts.map +1 -0
- package/headless.js +11522 -0
- package/http.d.ts.map +1 -0
- package/http.js +2165 -0
- package/index.cjs +54682 -0
- package/index.d.ts.map +1 -0
- package/index.js +52310 -0
- package/index.neutral.js +46343 -0
- package/{web/manifest.json → manifest.json} +1 -1
- package/mcp.d.ts.map +1 -0
- package/mcp.js +20515 -0
- package/memory.d.ts.map +1 -0
- package/{memory.ts → memory.js} +2310 -3834
- package/nativehost.template.json +10 -0
- package/node.cjs +54686 -0
- package/node.d.ts.map +1 -0
- package/pack.d.ts.map +1 -0
- package/pack.js +805 -0
- package/package.json +83 -176
- package/policy.d.ts.map +1 -0
- package/{policy.ts → policy.js} +4679 -5073
- package/progress.d.ts.map +1 -0
- package/progress.js +645 -0
- package/protocol.d.ts.map +1 -0
- package/protocol.js +8334 -0
- package/schemas/audit.schema.json +226 -0
- package/schemas/capability.schema.json +113 -0
- package/schemas/envelope.schema.json +162 -0
- package/schemas/memory.schema.json +51 -0
- package/schemas/observation.schema.json +113 -0
- package/schemas/plan.schema.json +208 -0
- package/schemas/progress.schema.json +126 -0
- package/schemas/proposal.schema.json +68 -0
- package/schemas/session.schema.json +82 -0
- package/schemas/tool.schema.json +94 -0
- package/server.d.ts.map +1 -0
- package/server.js +28877 -0
- package/umd-example.html +18 -0
- package/umd.d.ts.map +1 -0
- package/accounts.ts +0 -2087
- package/agent.ts +0 -2331
- package/antigravity.ts +0 -2139
- package/apifreeze.ts +0 -4146
- package/auth.ts +0 -642
- package/background.ts +0 -16837
- package/bridge.ts +0 -2080
- package/build.ts +0 -54
- package/bun.ts +0 -26
- package/capture.ts +0 -1614
- package/checksecrets.ts +0 -72
- package/cjs.ts +0 -9
- package/cli.ts +0 -3500
- package/commands.ts +0 -1101
- package/companion.ts +0 -450
- package/compatibility.ts +0 -37
- package/config.ts +0 -3137
- package/constants.ts +0 -943
- package/core.ts +0 -1473
- package/crossbrowser.ts +0 -1359
- package/dashdone.ts +0 -605
- package/data.ts +0 -943
- package/database.ts +0 -133
- package/debug.ts +0 -850
- package/deno.ts +0 -27
- package/devthink.ts +0 -707
- package/dist/accounts.d.ts +0 -409
- package/dist/agent.d.ts +0 -837
- package/dist/antigravity.d.ts +0 -380
- package/dist/apifreeze.d.ts +0 -113
- package/dist/auth.d.ts +0 -224
- package/dist/capture.d.ts +0 -595
- package/dist/cjs.d.ts +0 -6
- package/dist/commands.d.ts +0 -310
- package/dist/compatibility.d.ts +0 -17
- package/dist/config.d.ts +0 -1853
- package/dist/constants.d.ts +0 -637
- package/dist/core.d.ts +0 -361
- package/dist/data.d.ts +0 -330
- package/dist/database.d.ts +0 -24
- package/dist/debug.d.ts +0 -270
- package/dist/engine.d.ts +0 -74
- package/dist/environments.d.ts +0 -244
- package/dist/evidence.d.ts +0 -277
- package/dist/export.d.ts +0 -311
- package/dist/fingerprint.d.ts +0 -594
- package/dist/flow.d.ts +0 -300
- package/dist/gates.d.ts +0 -103
- package/dist/identity.d.ts +0 -51
- package/dist/ids.d.ts +0 -7
- package/dist/llm.d.ts +0 -652
- package/dist/models.d.ts +0 -1807
- package/dist/net.d.ts +0 -325
- package/dist/neutral.d.ts +0 -41
- package/dist/oauth.d.ts +0 -703
- package/dist/page.d.ts +0 -1166
- package/dist/perf.d.ts +0 -481
- package/dist/plan.d.ts +0 -134
- package/dist/project.d.ts +0 -395
- package/dist/providers.d.ts +0 -37
- package/dist/quota.d.ts +0 -453
- package/dist/recovery.d.ts +0 -621
- package/dist/request.d.ts +0 -1492
- package/dist/run.d.ts +0 -779
- package/dist/runtime.d.ts +0 -212
- package/dist/search.d.ts +0 -375
- package/dist/security.d.ts +0 -534
- package/dist/serve.d.ts +0 -136
- package/dist/session.d.ts +0 -296
- package/dist/storage.d.ts +0 -53
- package/dist/streaming.d.ts +0 -1119
- package/dist/swarm.d.ts +0 -328
- package/dist/tools.d.ts +0 -170
- package/dist/types.d.ts +0 -8357
- package/dist/utils.d.ts +0 -82
- package/dist/version.d.ts +0 -7
- package/dist/versionregistry.d.ts +0 -406
- package/dist/views.d.ts +0 -579
- package/dist/workbenchsession.d.ts +0 -69
- package/dist/workflow.d.ts +0 -649
- package/docs/readme.md +0 -92
- package/docs/schemas/antigravity.json +0 -192
- package/engine.ts +0 -1524
- package/environments.ts +0 -1005
- package/evidence.ts +0 -643
- package/export.ts +0 -889
- package/fingerprint.ts +0 -1458
- package/flow.ts +0 -1190
- package/gates.ts +0 -307
- package/gateway.ts +0 -34
- package/hardening.ts +0 -191
- package/headless.ts +0 -369
- package/http.ts +0 -2110
- package/identity.ts +0 -246
- package/ids.ts +0 -26
- package/index.ts +0 -369
- package/llm.ts +0 -2682
- package/mcp.ts +0 -1835
- package/models.ts +0 -3805
- package/modes.ts +0 -43
- package/net.ts +0 -1214
- package/neutral.ts +0 -362
- package/node.ts +0 -26
- package/oauth.ts +0 -2216
- package/offscreen.ts +0 -170
- package/pack.ts +0 -956
- package/page.ts +0 -7824
- package/pagebridge.ts +0 -1116
- package/perf.ts +0 -957
- package/plan.ts +0 -672
- package/plugin.ts +0 -76
- package/prisma.config.ts +0 -27
- package/progress.ts +0 -1308
- package/project.ts +0 -1291
- package/protocol.ts +0 -4187
- package/providers.ts +0 -246
- package/quota.ts +0 -1887
- package/recovery.ts +0 -2433
- package/request.ts +0 -4482
- package/run.ts +0 -2135
- package/runtime.ts +0 -526
- package/search.ts +0 -1760
- package/security.ts +0 -1673
- package/serve.ts +0 -419
- package/server.ts +0 -5538
- package/session.ts +0 -1162
- package/storage.ts +0 -182
- package/streaming.ts +0 -4101
- package/swarm.ts +0 -884
- package/sync.ts +0 -56
- package/tests/agentcert.test.ts +0 -128
- package/tests/agentfleet.test.ts +0 -214
- package/tests/agentreview.test.ts +0 -241
- package/tests/agentstream.test.ts +0 -335
- package/tests/agentwork.test.ts +0 -356
- package/tests/apifreeze.test.ts +0 -290
- package/tests/apimap.test.ts +0 -112
- package/tests/approvalgate.test.ts +0 -175
- package/tests/artifactmanifest.test.ts +0 -204
- package/tests/attentionfeed.test.ts +0 -163
- package/tests/backgroundruns.test.ts +0 -100
- package/tests/batchscheduling.test.ts +0 -131
- package/tests/blackboard.test.ts +0 -238
- package/tests/bridge.test.ts +0 -1088
- package/tests/browsercoverage.test.ts +0 -134
- package/tests/browserpolyfills.test.ts +0 -124
- package/tests/build.mjs +0 -1260
- package/tests/clientauth.test.ts +0 -223
- package/tests/clitools.test.ts +0 -578
- package/tests/confirmgates.test.ts +0 -190
- package/tests/containerpack.test.ts +0 -143
- package/tests/controlflow.test.ts +0 -2120
- package/tests/coordination.test.ts +0 -345
- package/tests/copyscreen.test.ts +0 -139
- package/tests/core.test.ts +0 -417
- package/tests/costcert.test.ts +0 -95
- package/tests/crossbrowser.test.ts +0 -115
- package/tests/cspaudit.test.ts +0 -79
- package/tests/dashdone.test.ts +0 -615
- package/tests/datagrid.test.ts +0 -137
- package/tests/doccheck.test.ts +0 -107
- package/tests/dombatch.test.ts +0 -109
- package/tests/emulation.test.ts +0 -282
- package/tests/environments.test.ts +0 -259
- package/tests/evidenceviews.test.ts +0 -88
- package/tests/exporttools.test.ts +0 -185
- package/tests/firefoxprep.test.ts +0 -134
- package/tests/flowlibrary.test.ts +0 -242
- package/tests/flowrun.test.ts +0 -303
- package/tests/forensics.test.ts +0 -439
- package/tests/gateway.test.ts +0 -939
- package/tests/headlesslib.test.ts +0 -171
- package/tests/httpstream.test.ts +0 -277
- package/tests/immutablelog.test.ts +0 -157
- package/tests/inboundguard.test.ts +0 -177
- package/tests/lazyload.test.ts +0 -72
- package/tests/librarymodes.test.ts +0 -623
- package/tests/llm.test.ts +0 -696
- package/tests/manifest.test.ts +0 -226
- package/tests/maskinputs.test.ts +0 -150
- package/tests/matrixverify.test.ts +0 -111
- package/tests/mavenpack.test.ts +0 -75
- package/tests/mcpserver.test.ts +0 -704
- package/tests/memory.test.ts +0 -4155
- package/tests/memorycare.test.ts +0 -230
- package/tests/migrateplan.test.ts +0 -349
- package/tests/minimization.test.ts +0 -414
- package/tests/modelroute.test.ts +0 -112
- package/tests/multiagent.test.ts +0 -440
- package/tests/nativebridge.test.ts +0 -807
- package/tests/navigation.test.ts +0 -284
- package/tests/nugetpack.test.ts +0 -83
- package/tests/orchestration.test.ts +0 -449
- package/tests/originpolicy.test.ts +0 -405
- package/tests/outputcompare.test.ts +0 -97
- package/tests/package.test.ts +0 -91
- package/tests/pagebridge.test.ts +0 -5909
- package/tests/pentest.test.ts +0 -75
- package/tests/perfrecords.test.ts +0 -257
- package/tests/permdiff.test.ts +0 -85
- package/tests/phishguard.test.ts +0 -128
- package/tests/pickerviews.test.ts +0 -155
- package/tests/pipelines.test.ts +0 -381
- package/tests/planlint.test.ts +0 -240
- package/tests/planreview.test.ts +0 -383
- package/tests/platformtargets.test.ts +0 -56
- package/tests/policy.test.ts +0 -8284
- package/tests/portability.test.ts +0 -96
- package/tests/progress.test.ts +0 -1036
- package/tests/promptlibrary.test.ts +0 -116
- package/tests/protocol.test.ts +0 -4793
- package/tests/publishingpipeline.test.ts +0 -314
- package/tests/quickactions.test.ts +0 -164
- package/tests/readiness.test.ts +0 -78
- package/tests/recipes.test.ts +0 -163
- package/tests/redactshots.test.ts +0 -216
- package/tests/registernvidiakeys.ts +0 -51
- package/tests/relayserve.test.ts +0 -304
- package/tests/releasenotes.test.ts +0 -276
- package/tests/resilience.test.ts +0 -467
- package/tests/resourceaware.test.ts +0 -187
- package/tests/runbudget.test.ts +0 -125
- package/tests/runhistory.test.ts +0 -299
- package/tests/runreplay.test.ts +0 -113
- package/tests/runresume.test.ts +0 -184
- package/tests/runstate.test.ts +0 -288
- package/tests/runtimeadapters.test.ts +0 -251
- package/tests/safariskeleton.test.ts +0 -115
- package/tests/sandboxframe.test.ts +0 -196
- package/tests/sbom.test.ts +0 -105
- package/tests/secretvault.test.ts +0 -188
- package/tests/selcache.test.ts +0 -111
- package/tests/sessioninterface.test.ts +0 -791
- package/tests/sessions.test.ts +0 -591
- package/tests/siteprefs.test.ts +0 -228
- package/tests/snapshotdelta.test.ts +0 -165
- package/tests/statusviews.test.ts +0 -237
- package/tests/stepmeter.test.ts +0 -200
- package/tests/streamparse.test.ts +0 -163
- package/tests/stylepruning.test.ts +0 -90
- package/tests/surfaces.test.ts +0 -282
- package/tests/sweep.test.ts +0 -78
- package/tests/syncbridge.test.ts +0 -164
- package/tests/taskqueue.test.ts +0 -206
- package/tests/toolcalls.test.ts +0 -336
- package/tests/toolcatalog.test.ts +0 -201
- package/tests/torture-agent.test.ts +0 -706
- package/tests/torture-auth.test.ts +0 -461
- package/tests/torture-commands.test.ts +0 -895
- package/tests/torture-data.test.ts +0 -923
- package/tests/torture-environments.test.ts +0 -285
- package/tests/torture-export.test.ts +0 -263
- package/tests/torture-http.test.ts +0 -1379
- package/tests/torture-llm.test.ts +0 -808
- package/tests/torture-memory.test.ts +0 -1084
- package/tests/torture-plan.test.ts +0 -829
- package/tests/torture-run.test.ts +0 -626
- package/tests/torture-session.test.ts +0 -928
- package/tests/torture-swarm.test.ts +0 -1245
- package/tests/torture-tools.test.ts +0 -964
- package/tests/torture-workflow.test.ts +0 -2354
- package/tests/tourviews.test.ts +0 -52
- package/tests/transparency.test.ts +0 -147
- package/tests/trigger.test.ts +0 -941
- package/tests/v1sunset.test.ts +0 -428
- package/tests/virtlist.test.ts +0 -94
- package/tests/vision.test.ts +0 -540
- package/tests/vsixpack.test.ts +0 -145
- package/tests/webapi.test.ts +0 -523
- package/tests/workflow.test.ts +0 -1785
- package/tests/workfloweditor.test.ts +0 -759
- package/tests/xpipack.test.ts +0 -128
- package/tools.ts +0 -734
- package/types.ts +0 -9908
- package/umd.ts +0 -9
- package/utils.ts +0 -249
- package/version.ts +0 -8
- package/versionregistry.ts +0 -1310
- package/views.ts +0 -2153
- package/vitest.config.ts +0 -12
- package/web/App.tsx +0 -78
- package/web/README.md +0 -47
- package/web/capacitor.config.ts +0 -46
- package/web/const.ts +0 -19
- package/web/control.shell.tsx +0 -66
- package/web/dashboardpage.ts +0 -554
- package/web/db.ts +0 -493
- package/web/design.html +0 -541
- package/web/gatewayview/Gateway.tsx +0 -345
- package/web/gatewayview/config.ts +0 -1042
- package/web/gatewayview/definition.ts +0 -174
- package/web/icons.ts +0 -15
- package/web/optionspage.ts +0 -691
- package/web/popup.ts +0 -1651
- package/web/schema.prisma +0 -176
- package/web/sidepanel.ts +0 -7941
- package/web/sitemanifest.json +0 -13
- package/web/terminal-ui.tsx +0 -622
- package/web/transparencypage.ts +0 -541
- package/web/vite.config.ts +0 -39
- package/web/workspace.ts +0 -23
- package/workbenchmemory.ts +0 -104
- package/workbenchsession.ts +0 -304
- package/workflow.ts +0 -4495
- /package/{dist/bun.d.ts → bun.d.ts} +0 -0
- /package/{dist/cli.d.ts → cli.d.ts} +0 -0
- /package/{dist/companion.d.ts → companion.d.ts} +0 -0
- /package/{dist/crossbrowser.d.ts → crossbrowser.d.ts} +0 -0
- /package/{dist/dashdone.d.ts → dashdone.d.ts} +0 -0
- /package/{dist/deno.d.ts → deno.d.ts} +0 -0
- /package/{dist/hardening.d.ts → hardening.d.ts} +0 -0
- /package/{dist/headless.d.ts → headless.d.ts} +0 -0
- /package/{dist/http.d.ts → http.d.ts} +0 -0
- /package/{dist/index.d.ts → index.d.ts} +0 -0
- /package/{dist/mcp.d.ts → mcp.d.ts} +0 -0
- /package/{dist/memory.d.ts → memory.d.ts} +0 -0
- /package/{dist/node.d.ts → node.d.ts} +0 -0
- /package/{dist/pack.d.ts → pack.d.ts} +0 -0
- /package/{dist/policy.d.ts → policy.d.ts} +0 -0
- /package/{dist/progress.d.ts → progress.d.ts} +0 -0
- /package/{dist/protocol.d.ts → protocol.d.ts} +0 -0
- /package/{dist/server.d.ts → server.d.ts} +0 -0
- /package/{dist/umd.d.ts → umd.d.ts} +0 -0
package/devthink.ts
DELETED
|
@@ -1,707 +0,0 @@
|
|
|
1
|
-
#!/usr/bin/env bun
|
|
2
|
-
|
|
3
|
-
import { readFileSync } from "node:fs";
|
|
4
|
-
import { createInterface } from "node:readline/promises";
|
|
5
|
-
import { stdin, stdout } from "node:process";
|
|
6
|
-
import {
|
|
7
|
-
clearAuthCredential,
|
|
8
|
-
ensurePaths,
|
|
9
|
-
getConfigValue,
|
|
10
|
-
migrateLegacyCredentials,
|
|
11
|
-
parseConfigValue,
|
|
12
|
-
readAuth,
|
|
13
|
-
readConfig,
|
|
14
|
-
redactAuth,
|
|
15
|
-
redactConfig,
|
|
16
|
-
resolvePaths,
|
|
17
|
-
saveConfig,
|
|
18
|
-
setAuthCredential,
|
|
19
|
-
setConfigValue,
|
|
20
|
-
type DevThinkConfig,
|
|
21
|
-
} from "./config.js";
|
|
22
|
-
import { createMemoryStore, memorySummary } from "./workbenchmemory.js";
|
|
23
|
-
import { listModes, modePrompt, resolveMode } from "./modes.js";
|
|
24
|
-
import { listModels, listProviders, streamChat } from "./providers.js";
|
|
25
|
-
import {
|
|
26
|
-
appendMessage,
|
|
27
|
-
createSession,
|
|
28
|
-
exportSession,
|
|
29
|
-
listSessions,
|
|
30
|
-
loadSession,
|
|
31
|
-
type Session,
|
|
32
|
-
} from "./workbenchsession.js";
|
|
33
|
-
import {
|
|
34
|
-
createPairing,
|
|
35
|
-
createPairingLink,
|
|
36
|
-
getIdentity,
|
|
37
|
-
pairingStatus,
|
|
38
|
-
revokeBrowserSessions,
|
|
39
|
-
setIdentityUserId,
|
|
40
|
-
} from "./identity.js";
|
|
41
|
-
import { readPreferences, savePreference } from "./storage.js";
|
|
42
|
-
import type { ChatEvent } from "./streaming.js";
|
|
43
|
-
import { banner, box, colors, formatConfig, formatEvent, statusBar } from "./web/terminal-ui.js";
|
|
44
|
-
import { startServer } from "./server.js";
|
|
45
|
-
import { exportLocalSnapshot, remoteSyncStatus } from "./sync.js";
|
|
46
|
-
|
|
47
|
-
export type ParsedArgs = { flags: Record<string, string | boolean>; positional: string[] };
|
|
48
|
-
|
|
49
|
-
function version(): string {
|
|
50
|
-
const embedded = process.env.DEVTHINK_VERSION?.trim();
|
|
51
|
-
if (embedded) return embedded;
|
|
52
|
-
try {
|
|
53
|
-
const file = new URL("./package.json", import.meta.url);
|
|
54
|
-
return String((JSON.parse(readFileSync(file, "utf8")) as { version?: string }).version || "0.0.0");
|
|
55
|
-
} catch {
|
|
56
|
-
return "0.0.0";
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
|
|
60
|
-
function parseArgs(args: string[]): ParsedArgs {
|
|
61
|
-
const flags: Record<string, string | boolean> = {};
|
|
62
|
-
const positional: string[] = [];
|
|
63
|
-
for (let index = 0; index < args.length; index += 1) {
|
|
64
|
-
const value = args[index];
|
|
65
|
-
if (!value.startsWith("-")) {
|
|
66
|
-
positional.push(value);
|
|
67
|
-
continue;
|
|
68
|
-
}
|
|
69
|
-
const key = value.replace(/^-+/, "");
|
|
70
|
-
const next = args[index + 1];
|
|
71
|
-
if (next && !next.startsWith("-")) {
|
|
72
|
-
flags[key] = next;
|
|
73
|
-
index += 1;
|
|
74
|
-
} else flags[key] = true;
|
|
75
|
-
}
|
|
76
|
-
return { flags, positional };
|
|
77
|
-
}
|
|
78
|
-
|
|
79
|
-
function stringFlag(parsed: ParsedArgs, key: string): string | undefined {
|
|
80
|
-
const value = parsed.flags[key];
|
|
81
|
-
return typeof value === "string" ? value : undefined;
|
|
82
|
-
}
|
|
83
|
-
|
|
84
|
-
function boolFlag(parsed: ParsedArgs, key: string): boolean {
|
|
85
|
-
return parsed.flags[key] === true;
|
|
86
|
-
}
|
|
87
|
-
|
|
88
|
-
function printHelp(): void {
|
|
89
|
-
console.log(
|
|
90
|
-
[
|
|
91
|
-
`${colors.cyan}${colors.bold}DevThink CLI${colors.reset} v${version()}`,
|
|
92
|
-
"",
|
|
93
|
-
"Usage: devthink <command> [options]",
|
|
94
|
-
"",
|
|
95
|
-
"Commands:",
|
|
96
|
-
" chat [message] Stream a model response",
|
|
97
|
-
" providers List supported provider transports",
|
|
98
|
-
" models --provider <id> List provider models",
|
|
99
|
-
" modes List the 20 operational modes",
|
|
100
|
-
" config [key] [value] Read or write local configuration",
|
|
101
|
-
" config preferences Show shared workbench preferences",
|
|
102
|
-
" config settings Show shared identity, pairing, provider and database summary",
|
|
103
|
-
" config set <key> <value> Set theme, railMode, or interfaceZoom",
|
|
104
|
-
" auth login <provider> Save a user-provided official credential",
|
|
105
|
-
" auth status Show redacted configured credential sources",
|
|
106
|
-
" auth clear <provider> Remove a stored provider credential",
|
|
107
|
-
" auth migrate Move legacy config credentials into auth.json",
|
|
108
|
-
" identity [--id <value>] Show or set the local public user identifier",
|
|
109
|
-
" pair create Create an automatic one-time link for the web workbench",
|
|
110
|
-
" pair revoke Revoke current paired browser sessions",
|
|
111
|
-
" sync status Show local snapshot and remote adapter readiness",
|
|
112
|
-
" sync export Print a credential-free local sync snapshot",
|
|
113
|
-
" gateway status Show the embedded provider gateway state",
|
|
114
|
-
" sessions list List saved sessions",
|
|
115
|
-
" sessions export <id> Print a session as Markdown or JSON",
|
|
116
|
-
" projects List local workspaces shared with the web",
|
|
117
|
-
" usage Show local workspace, session, tab and message counts",
|
|
118
|
-
" routes List browser and gateway routes",
|
|
119
|
-
" serve [--port <n>] Start the local loopback API",
|
|
120
|
-
" init Create local DevThink directories",
|
|
121
|
-
" interactive Start the terminal chat loop",
|
|
122
|
-
"",
|
|
123
|
-
"Grand-merge families (one binary, one router):",
|
|
124
|
-
" ext <command> The DevThink extension surface: manifest, describe,",
|
|
125
|
-
" planlint, migrateplan, recipes, flowrun, runworkflow,",
|
|
126
|
-
" exportdata, headless, serve (mcp), native, doctor, init",
|
|
127
|
-
" provider <command> The provider account surface: login, logout, accounts,",
|
|
128
|
-
" quota, config, models, status, doctor, menu",
|
|
129
|
-
" gateway <command> The embedded gateway surface: init, add, list, show,",
|
|
130
|
-
" validate, keys, models, serve, export",
|
|
131
|
-
"",
|
|
132
|
-
"Chat options:",
|
|
133
|
-
" --provider <id> openai, zai, anthropic, google, openrouter, qwen, deepseek, groq, mistral, xai, ollama, mimo",
|
|
134
|
-
" --model <id> Provider model identifier",
|
|
135
|
-
" --mode <id> One of the 20 registered modes",
|
|
136
|
-
" --prompt <text> Explicit prompt, useful in scripts",
|
|
137
|
-
" --format json Emit one machine-readable result",
|
|
138
|
-
" --no-save Do not persist the session",
|
|
139
|
-
"",
|
|
140
|
-
"Credentials are read from ~/.config/devthink/auth.json or environment variables. Browser-cookie capture and anti-bot bypass are not supported.",
|
|
141
|
-
].join("\n"),
|
|
142
|
-
);
|
|
143
|
-
}
|
|
144
|
-
|
|
145
|
-
function loadRuntime(): {
|
|
146
|
-
config: DevThinkConfig;
|
|
147
|
-
paths: ReturnType<typeof resolvePaths>;
|
|
148
|
-
memory: ReturnType<typeof createMemoryStore>;
|
|
149
|
-
} {
|
|
150
|
-
const paths = ensurePaths(resolvePaths());
|
|
151
|
-
const config = readConfig(paths);
|
|
152
|
-
return { config, paths, memory: createMemoryStore(paths) };
|
|
153
|
-
}
|
|
154
|
-
|
|
155
|
-
function printEvents(events: ChatEvent[], json: boolean): void {
|
|
156
|
-
if (json) {
|
|
157
|
-
console.log(JSON.stringify(events));
|
|
158
|
-
return;
|
|
159
|
-
}
|
|
160
|
-
for (const event of events) {
|
|
161
|
-
const rendered = formatEvent(event);
|
|
162
|
-
if (rendered) process.stdout.write(rendered);
|
|
163
|
-
}
|
|
164
|
-
process.stdout.write("\n");
|
|
165
|
-
}
|
|
166
|
-
|
|
167
|
-
async function runChat(
|
|
168
|
-
prompt: string,
|
|
169
|
-
parsed: ParsedArgs,
|
|
170
|
-
runtime: ReturnType<typeof loadRuntime>,
|
|
171
|
-
current?: Session,
|
|
172
|
-
render?: { onEvent?: (event: ChatEvent) => void; silent?: boolean },
|
|
173
|
-
): Promise<Session | undefined> {
|
|
174
|
-
const provider = stringFlag(parsed, "provider") || runtime.config.activeProvider || runtime.config.provider;
|
|
175
|
-
const model = stringFlag(parsed, "model") || runtime.config.activeModel || runtime.config.model;
|
|
176
|
-
const mode = stringFlag(parsed, "mode") || "chat";
|
|
177
|
-
if (!provider || !model) throw new Error("Set provider and model with --provider/--model or devthink config.");
|
|
178
|
-
const modeDefinition = resolveMode(mode);
|
|
179
|
-
const requestedSession = stringFlag(parsed, "session");
|
|
180
|
-
const session =
|
|
181
|
-
current ||
|
|
182
|
-
(requestedSession ? loadSession(runtime.paths, requestedSession) : undefined) ||
|
|
183
|
-
createSession(runtime.paths, {
|
|
184
|
-
mode: modeDefinition.id,
|
|
185
|
-
model,
|
|
186
|
-
provider,
|
|
187
|
-
workspaceId: stringFlag(parsed, "workspace"),
|
|
188
|
-
tabId: stringFlag(parsed, "tab"),
|
|
189
|
-
});
|
|
190
|
-
const storedMemory = runtime.memory.resolve({ text: prompt, sessionId: session.id });
|
|
191
|
-
const system = [
|
|
192
|
-
modePrompt(modeDefinition),
|
|
193
|
-
storedMemory ? `Relevant local memory: ${storedMemory.content}` : memorySummary(runtime.memory),
|
|
194
|
-
]
|
|
195
|
-
.filter(Boolean)
|
|
196
|
-
.join("\n\n");
|
|
197
|
-
const userMessage = { role: "user" as const, content: prompt };
|
|
198
|
-
const nextSession = appendMessage(runtime.paths, session, userMessage);
|
|
199
|
-
const events: ChatEvent[] = [];
|
|
200
|
-
let text = "";
|
|
201
|
-
let reasoning = "";
|
|
202
|
-
const json = stringFlag(parsed, "format") === "json";
|
|
203
|
-
const stream = await streamChat(
|
|
204
|
-
{
|
|
205
|
-
provider,
|
|
206
|
-
model,
|
|
207
|
-
messages: [
|
|
208
|
-
{ role: "system", content: system },
|
|
209
|
-
...nextSession.messages.map(({ role, content }) => ({ role, content })),
|
|
210
|
-
],
|
|
211
|
-
temperature: runtime.config.temperature,
|
|
212
|
-
maxTokens: runtime.config.maxTokens,
|
|
213
|
-
},
|
|
214
|
-
runtime.config,
|
|
215
|
-
runtime.paths,
|
|
216
|
-
);
|
|
217
|
-
for await (const event of stream) {
|
|
218
|
-
events.push(event);
|
|
219
|
-
if (event.type === "text") text += event.text;
|
|
220
|
-
if (event.type === "reasoning") reasoning += event.text;
|
|
221
|
-
render?.onEvent?.(event);
|
|
222
|
-
if (!json && !render?.silent) {
|
|
223
|
-
const rendered = formatEvent(event);
|
|
224
|
-
if (rendered) process.stdout.write(rendered);
|
|
225
|
-
}
|
|
226
|
-
}
|
|
227
|
-
const withAssistant = appendMessage(runtime.paths, nextSession, { role: "assistant", content: text });
|
|
228
|
-
runtime.memory.remember({ layer: "session", key: withAssistant.id, content: text.slice(0, 2000) });
|
|
229
|
-
if (json)
|
|
230
|
-
console.log(
|
|
231
|
-
JSON.stringify({
|
|
232
|
-
workspaceId: withAssistant.workspaceId,
|
|
233
|
-
sessionId: withAssistant.id,
|
|
234
|
-
tabId: withAssistant.activeTabId,
|
|
235
|
-
messageId: withAssistant.messages.at(-1)?.id,
|
|
236
|
-
provider,
|
|
237
|
-
model,
|
|
238
|
-
mode: modeDefinition.id,
|
|
239
|
-
text,
|
|
240
|
-
reasoning,
|
|
241
|
-
}),
|
|
242
|
-
);
|
|
243
|
-
else if (!render?.silent) process.stdout.write("\n");
|
|
244
|
-
return withAssistant;
|
|
245
|
-
}
|
|
246
|
-
|
|
247
|
-
async function handleConfig(parsed: ParsedArgs, runtime: ReturnType<typeof loadRuntime>): Promise<void> {
|
|
248
|
-
const action = parsed.positional[1];
|
|
249
|
-
if (action === "settings") {
|
|
250
|
-
const identity = getIdentity(runtime.paths);
|
|
251
|
-
const sessions = listSessions(runtime.paths);
|
|
252
|
-
return console.log(
|
|
253
|
-
JSON.stringify(
|
|
254
|
-
{
|
|
255
|
-
identity,
|
|
256
|
-
pairing: pairingStatus(runtime.paths),
|
|
257
|
-
preferences: Object.fromEntries(
|
|
258
|
-
Object.entries(readPreferences(runtime.paths)).map(([key, preference]) => [key, preference.value]),
|
|
259
|
-
),
|
|
260
|
-
provider: {
|
|
261
|
-
activeProvider: runtime.config.activeProvider || runtime.config.provider || undefined,
|
|
262
|
-
activeModel: runtime.config.activeModel || runtime.config.model || undefined,
|
|
263
|
-
},
|
|
264
|
-
database: {
|
|
265
|
-
ownerUserId: identity.userId,
|
|
266
|
-
local: true,
|
|
267
|
-
persistence: "cli-owned-sqlite",
|
|
268
|
-
workspaces: new Set(sessions.map((session) => session.workspaceId)).size,
|
|
269
|
-
sessions: sessions.length,
|
|
270
|
-
},
|
|
271
|
-
},
|
|
272
|
-
null,
|
|
273
|
-
2,
|
|
274
|
-
),
|
|
275
|
-
);
|
|
276
|
-
}
|
|
277
|
-
if (action === "preferences")
|
|
278
|
-
return console.log(
|
|
279
|
-
JSON.stringify(
|
|
280
|
-
Object.fromEntries(
|
|
281
|
-
Object.entries(readPreferences(runtime.paths)).map(([key, preference]) => [key, preference.value]),
|
|
282
|
-
),
|
|
283
|
-
null,
|
|
284
|
-
2,
|
|
285
|
-
),
|
|
286
|
-
);
|
|
287
|
-
if (action === "set") {
|
|
288
|
-
const key = parsed.positional[2];
|
|
289
|
-
const value = parsed.positional[3];
|
|
290
|
-
if (!key || !value) throw new Error("Usage: devthink config set <theme|railMode|interfaceZoom> <value>");
|
|
291
|
-
const valid =
|
|
292
|
-
(key === "theme" && ["dark", "light"].includes(value)) ||
|
|
293
|
-
(key === "railMode" && ["always", "auto", "off"].includes(value)) ||
|
|
294
|
-
(key === "interfaceZoom" && /^(?:[8-9][0-9]|1[0-4][0-9]|150)$/.test(value));
|
|
295
|
-
if (!valid) throw new Error("Supported values: theme dark|light; railMode always|auto|off; interfaceZoom 80-150.");
|
|
296
|
-
savePreference(runtime.paths, key, value);
|
|
297
|
-
return console.log(`${key} updated.`);
|
|
298
|
-
}
|
|
299
|
-
const key = action;
|
|
300
|
-
const raw = parsed.positional[2];
|
|
301
|
-
if (!key) return console.log(formatConfig(redactConfig(runtime.config)));
|
|
302
|
-
if (raw === undefined) return console.log(`${key} = ${JSON.stringify(getConfigValue(runtime.config, key))}`);
|
|
303
|
-
saveConfig(setConfigValue(runtime.config, key, parseConfigValue(raw)), runtime.paths);
|
|
304
|
-
console.log(`${key} updated.`);
|
|
305
|
-
}
|
|
306
|
-
|
|
307
|
-
async function handleAuth(parsed: ParsedArgs, runtime: ReturnType<typeof loadRuntime>): Promise<void> {
|
|
308
|
-
const action = parsed.positional[1] || "status";
|
|
309
|
-
if (action === "status")
|
|
310
|
-
return console.log(
|
|
311
|
-
JSON.stringify(
|
|
312
|
-
{
|
|
313
|
-
config: redactConfig(runtime.config),
|
|
314
|
-
auth: redactAuth(readAuth(runtime.paths)),
|
|
315
|
-
authPath: runtime.paths.auth,
|
|
316
|
-
},
|
|
317
|
-
null,
|
|
318
|
-
2,
|
|
319
|
-
),
|
|
320
|
-
);
|
|
321
|
-
if (action === "login") {
|
|
322
|
-
const provider = parsed.positional[2];
|
|
323
|
-
const token = stringFlag(parsed, "token") || stringFlag(parsed, "api-key");
|
|
324
|
-
const kind = stringFlag(parsed, "kind") || "api-key";
|
|
325
|
-
if (!provider || !token)
|
|
326
|
-
throw new Error(
|
|
327
|
-
"Usage: devthink auth login <provider> --token <user-provided-credential> [--kind api-key|bearer|oauth]",
|
|
328
|
-
);
|
|
329
|
-
if (!(["api-key", "bearer", "oauth"] as string[]).includes(kind))
|
|
330
|
-
throw new Error("--kind must be api-key, bearer or oauth.");
|
|
331
|
-
const expiresAt = stringFlag(parsed, "expires-at");
|
|
332
|
-
const refreshToken = stringFlag(parsed, "refresh-token");
|
|
333
|
-
const resourceUrl = stringFlag(parsed, "resource-url");
|
|
334
|
-
const credential =
|
|
335
|
-
kind === "oauth"
|
|
336
|
-
? {
|
|
337
|
-
kind: "oauth" as const,
|
|
338
|
-
accessToken: token,
|
|
339
|
-
...(refreshToken ? { refreshToken } : {}),
|
|
340
|
-
...(expiresAt ? { expiresAt: Number(expiresAt) } : {}),
|
|
341
|
-
...(resourceUrl ? { resourceUrl } : {}),
|
|
342
|
-
}
|
|
343
|
-
: { kind: kind as "api-key" | "bearer", value: token };
|
|
344
|
-
setAuthCredential(provider, credential, runtime.paths);
|
|
345
|
-
saveConfig({ ...runtime.config, activeProvider: runtime.config.activeProvider || provider }, runtime.paths);
|
|
346
|
-
return console.log(`${provider} credential saved to ${runtime.paths.auth}.`);
|
|
347
|
-
}
|
|
348
|
-
if (action === "clear") {
|
|
349
|
-
const provider = parsed.positional[2];
|
|
350
|
-
if (!provider) throw new Error("Usage: devthink auth clear <provider>");
|
|
351
|
-
clearAuthCredential(provider, runtime.paths);
|
|
352
|
-
const next = { ...runtime.config };
|
|
353
|
-
const providers = { ...(next.providers || {}) };
|
|
354
|
-
if (providers[provider]) {
|
|
355
|
-
const { auth: _auth, apiKey: _apiKey, ...remaining } = providers[provider];
|
|
356
|
-
providers[provider] = remaining;
|
|
357
|
-
}
|
|
358
|
-
next.providers = providers;
|
|
359
|
-
delete (next as Record<string, unknown>)[`${provider}ApiKey`];
|
|
360
|
-
saveConfig(next, runtime.paths);
|
|
361
|
-
return console.log(
|
|
362
|
-
`${provider} credential cleared from ${runtime.paths.auth}; legacy config fields were removed if present.`,
|
|
363
|
-
);
|
|
364
|
-
}
|
|
365
|
-
if (action === "migrate") {
|
|
366
|
-
const result = migrateLegacyCredentials(runtime.config, runtime.paths);
|
|
367
|
-
return console.log(
|
|
368
|
-
result.migrated.length
|
|
369
|
-
? `Migrated ${result.migrated.join(", ")} to ${runtime.paths.auth}.`
|
|
370
|
-
: "No legacy credentials needed migration.",
|
|
371
|
-
);
|
|
372
|
-
}
|
|
373
|
-
throw new Error("Supported auth actions: login, status, clear, migrate.");
|
|
374
|
-
}
|
|
375
|
-
|
|
376
|
-
function handleIdentity(parsed: ParsedArgs, runtime: ReturnType<typeof loadRuntime>): void {
|
|
377
|
-
const requestedUserId = stringFlag(parsed, "id");
|
|
378
|
-
const identity = requestedUserId ? setIdentityUserId(runtime.paths, requestedUserId) : getIdentity(runtime.paths);
|
|
379
|
-
console.log(JSON.stringify({ identity, pairing: pairingStatus(runtime.paths) }, null, 2));
|
|
380
|
-
}
|
|
381
|
-
|
|
382
|
-
function handlePairing(parsed: ParsedArgs, runtime: ReturnType<typeof loadRuntime>): void {
|
|
383
|
-
const action = parsed.positional[1] || "create";
|
|
384
|
-
if (action === "status") return handleIdentity(parsed, runtime);
|
|
385
|
-
if (action === "revoke")
|
|
386
|
-
return console.log(`Revoked ${revokeBrowserSessions(runtime.paths)} paired browser session(s).`);
|
|
387
|
-
if (action !== "create") throw new Error("Supported pair actions: create, status, revoke.");
|
|
388
|
-
const pairing = createPairing(runtime.paths);
|
|
389
|
-
const pagesUrl = stringFlag(parsed, "web-url") || runtime.config.web?.pagesUrl;
|
|
390
|
-
const gatewayUrl = stringFlag(parsed, "gateway") || runtime.config.web?.gatewayUrl;
|
|
391
|
-
const openUrl = createPairingLink(pagesUrl, gatewayUrl, pairing.pairingId, pairing.code);
|
|
392
|
-
console.log(
|
|
393
|
-
JSON.stringify(
|
|
394
|
-
{
|
|
395
|
-
userId: pairing.identity.userId,
|
|
396
|
-
pairingId: pairing.pairingId,
|
|
397
|
-
code: pairing.code,
|
|
398
|
-
expiresAt: pairing.expiresAt,
|
|
399
|
-
...(pagesUrl ? { pagesUrl } : {}),
|
|
400
|
-
...(gatewayUrl ? { gatewayUrl } : {}),
|
|
401
|
-
...(openUrl ? { openUrl } : {}),
|
|
402
|
-
message: openUrl
|
|
403
|
-
? "Open openUrl to prefill and consume this one-time local invitation automatically."
|
|
404
|
-
: "Set web.pagesUrl and web.gatewayUrl, or pass --web-url and --gateway, to generate an automatic invitation link.",
|
|
405
|
-
},
|
|
406
|
-
null,
|
|
407
|
-
2,
|
|
408
|
-
),
|
|
409
|
-
);
|
|
410
|
-
}
|
|
411
|
-
|
|
412
|
-
function handleSync(parsed: ParsedArgs, runtime: ReturnType<typeof loadRuntime>): void {
|
|
413
|
-
const action = parsed.positional[1] || "status";
|
|
414
|
-
const snapshot = exportLocalSnapshot(runtime.paths);
|
|
415
|
-
if (action === "export") return console.log(JSON.stringify(snapshot, null, 2));
|
|
416
|
-
if (action === "status")
|
|
417
|
-
return console.log(
|
|
418
|
-
JSON.stringify(
|
|
419
|
-
{
|
|
420
|
-
userId: snapshot.userId,
|
|
421
|
-
deviceId: snapshot.deviceId,
|
|
422
|
-
workspaces: snapshot.workspaces.length,
|
|
423
|
-
sessions: snapshot.sessions.length,
|
|
424
|
-
remote: remoteSyncStatus(runtime.config),
|
|
425
|
-
},
|
|
426
|
-
null,
|
|
427
|
-
2,
|
|
428
|
-
),
|
|
429
|
-
);
|
|
430
|
-
throw new Error("Supported sync actions: status, export.");
|
|
431
|
-
}
|
|
432
|
-
|
|
433
|
-
function handleGateway(runtime: ReturnType<typeof loadRuntime>): void {
|
|
434
|
-
const activeProvider = runtime.config.activeProvider || runtime.config.provider || "not configured";
|
|
435
|
-
const endpoint =
|
|
436
|
-
activeProvider === "not configured"
|
|
437
|
-
? undefined
|
|
438
|
-
: runtime.config.providers?.[activeProvider]?.baseUrl || runtime.config.baseUrl;
|
|
439
|
-
console.log(
|
|
440
|
-
formatConfig({
|
|
441
|
-
mode: runtime.config.gateway?.mode || "embedded",
|
|
442
|
-
streaming: runtime.config.gateway?.stream ?? true,
|
|
443
|
-
activeProvider,
|
|
444
|
-
endpoint: endpoint || "provider default",
|
|
445
|
-
webEnabled: runtime.config.web?.enabled ?? true,
|
|
446
|
-
config: runtime.paths.config,
|
|
447
|
-
auth: runtime.paths.auth,
|
|
448
|
-
}),
|
|
449
|
-
);
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
async function handleSessions(parsed: ParsedArgs, runtime: ReturnType<typeof loadRuntime>): Promise<void> {
|
|
453
|
-
const action = parsed.positional[1] || "list";
|
|
454
|
-
if (action === "list")
|
|
455
|
-
return console.log(
|
|
456
|
-
listSessions(runtime.paths)
|
|
457
|
-
.map((session) => `${session.id} ${session.title}`)
|
|
458
|
-
.join("\n") || "No sessions.",
|
|
459
|
-
);
|
|
460
|
-
if (action === "export") {
|
|
461
|
-
const id = parsed.positional[2];
|
|
462
|
-
if (!id) throw new Error("Usage: devthink sessions export <id>");
|
|
463
|
-
console.log(exportSession(runtime.paths, id, stringFlag(parsed, "format") === "json" ? "json" : "markdown"));
|
|
464
|
-
return;
|
|
465
|
-
}
|
|
466
|
-
throw new Error("Supported session actions: list, export.");
|
|
467
|
-
}
|
|
468
|
-
|
|
469
|
-
function handleProjects(runtime: ReturnType<typeof loadRuntime>): void {
|
|
470
|
-
const projects = new Map<string, { title: string; sessions: number; updatedAt: string }>();
|
|
471
|
-
for (const session of listSessions(runtime.paths)) {
|
|
472
|
-
const current = projects.get(session.workspaceId);
|
|
473
|
-
projects.set(session.workspaceId, {
|
|
474
|
-
title: current?.title || session.title.replace(/^Untitled session$/, "Untitled workspace"),
|
|
475
|
-
sessions: (current?.sessions || 0) + 1,
|
|
476
|
-
updatedAt: current?.updatedAt && current.updatedAt > session.updatedAt ? current.updatedAt : session.updatedAt,
|
|
477
|
-
});
|
|
478
|
-
}
|
|
479
|
-
const output = [...projects.entries()]
|
|
480
|
-
.sort((left, right) => right[1].updatedAt.localeCompare(left[1].updatedAt))
|
|
481
|
-
.map(([id, project]) => `${id} ${project.sessions} session${project.sessions === 1 ? "" : "s"} ${project.title}`);
|
|
482
|
-
console.log(output.join("\n") || "No projects.");
|
|
483
|
-
}
|
|
484
|
-
|
|
485
|
-
function handleUsage(runtime: ReturnType<typeof loadRuntime>): void {
|
|
486
|
-
const sessions = listSessions(runtime.paths);
|
|
487
|
-
console.log(
|
|
488
|
-
JSON.stringify(
|
|
489
|
-
{
|
|
490
|
-
workspaces: new Set(sessions.map((session) => session.workspaceId)).size,
|
|
491
|
-
sessions: sessions.length,
|
|
492
|
-
tabs: sessions.reduce((total, session) => total + session.tabs.length, 0),
|
|
493
|
-
messages: sessions.reduce((total, session) => total + session.messages.length, 0),
|
|
494
|
-
providers: listProviders().length,
|
|
495
|
-
},
|
|
496
|
-
null,
|
|
497
|
-
2,
|
|
498
|
-
),
|
|
499
|
-
);
|
|
500
|
-
}
|
|
501
|
-
|
|
502
|
-
function handleRoutes(): void {
|
|
503
|
-
console.log(
|
|
504
|
-
[
|
|
505
|
-
"web: /",
|
|
506
|
-
"web: /providers",
|
|
507
|
-
"web: /projects",
|
|
508
|
-
"web: /routes",
|
|
509
|
-
"web: /usage",
|
|
510
|
-
"web: /settings",
|
|
511
|
-
"web: /w/:workspaceId/s/:sessionId/t/:tabId/:sectionId",
|
|
512
|
-
"gateway: GET /health",
|
|
513
|
-
"gateway: GET /identity",
|
|
514
|
-
"gateway: PUT /identity",
|
|
515
|
-
"gateway: GET /settings",
|
|
516
|
-
"gateway: GET /providers",
|
|
517
|
-
"gateway: GET /workspaces",
|
|
518
|
-
"gateway: GET /usage",
|
|
519
|
-
"gateway: GET /preferences",
|
|
520
|
-
"gateway: PATCH /preferences",
|
|
521
|
-
"gateway: POST /sessions",
|
|
522
|
-
"gateway: POST /chat",
|
|
523
|
-
].join("\n"),
|
|
524
|
-
);
|
|
525
|
-
}
|
|
526
|
-
|
|
527
|
-
async function interactive(runtime: ReturnType<typeof loadRuntime>): Promise<void> {
|
|
528
|
-
if (process.stdin.isTTY && process.stdout.isTTY && process.env.DEVTHINK_PLAIN !== "1") {
|
|
529
|
-
try {
|
|
530
|
-
const { startTerminalWorkspace } = await import("./web/terminal-ui.js");
|
|
531
|
-
return await startTerminalWorkspace(runtime, version(), (prompt, current, onEvent) =>
|
|
532
|
-
runChat(prompt, { flags: { mode: runtime.config.mode || "chat" }, positional: [] }, runtime, current, {
|
|
533
|
-
onEvent,
|
|
534
|
-
silent: true,
|
|
535
|
-
}),
|
|
536
|
-
);
|
|
537
|
-
} catch (error) {
|
|
538
|
-
process.stderr.write(
|
|
539
|
-
`${colors.yellow}Terminal workspace fallback: ${error instanceof Error ? error.message : "renderer unavailable"}${colors.reset}\n`,
|
|
540
|
-
);
|
|
541
|
-
}
|
|
542
|
-
}
|
|
543
|
-
const input = createInterface({ input: stdin, output: stdout, terminal: true });
|
|
544
|
-
let session: Session | undefined;
|
|
545
|
-
let mode = runtime.config.mode || "chat";
|
|
546
|
-
console.log(banner(version()));
|
|
547
|
-
console.log(
|
|
548
|
-
box(
|
|
549
|
-
"status",
|
|
550
|
-
statusBar(
|
|
551
|
-
runtime.config.activeProvider || runtime.config.provider || "not configured",
|
|
552
|
-
runtime.config.activeModel || runtime.config.model || "not configured",
|
|
553
|
-
mode,
|
|
554
|
-
),
|
|
555
|
-
),
|
|
556
|
-
);
|
|
557
|
-
console.log("Type a message or /help. Use /exit to leave.");
|
|
558
|
-
try {
|
|
559
|
-
while (true) {
|
|
560
|
-
const value = (await input.question("> ")).trim();
|
|
561
|
-
if (!value) continue;
|
|
562
|
-
if (value === "/exit" || value === "/quit") break;
|
|
563
|
-
if (value === "/help") {
|
|
564
|
-
console.log("/models /modes /new /sessions /mode <id> /clear /exit");
|
|
565
|
-
continue;
|
|
566
|
-
}
|
|
567
|
-
if (value === "/clear") {
|
|
568
|
-
console.clear();
|
|
569
|
-
continue;
|
|
570
|
-
}
|
|
571
|
-
if (value === "/new") {
|
|
572
|
-
session = undefined;
|
|
573
|
-
console.log("New session ready.");
|
|
574
|
-
continue;
|
|
575
|
-
}
|
|
576
|
-
if (value.startsWith("/mode ")) {
|
|
577
|
-
mode = resolveMode(value.slice(6).trim()).id;
|
|
578
|
-
console.log(`Mode: ${mode}`);
|
|
579
|
-
continue;
|
|
580
|
-
}
|
|
581
|
-
if (value === "/modes") {
|
|
582
|
-
console.log(
|
|
583
|
-
listModes()
|
|
584
|
-
.map((item) => `${item.id} ${item.purpose}`)
|
|
585
|
-
.join("\n"),
|
|
586
|
-
);
|
|
587
|
-
continue;
|
|
588
|
-
}
|
|
589
|
-
if (value === "/sessions") {
|
|
590
|
-
console.log(
|
|
591
|
-
listSessions(runtime.paths)
|
|
592
|
-
.map((item) => `${item.id} ${item.title}`)
|
|
593
|
-
.join("\n") || "No sessions.",
|
|
594
|
-
);
|
|
595
|
-
continue;
|
|
596
|
-
}
|
|
597
|
-
if (value === "/models") {
|
|
598
|
-
const provider = runtime.config.activeProvider || runtime.config.provider;
|
|
599
|
-
if (!provider) console.log("Configure a provider first.");
|
|
600
|
-
else console.log((await listModels(provider, runtime.config)).map((item) => item.id).join("\n"));
|
|
601
|
-
continue;
|
|
602
|
-
}
|
|
603
|
-
session = await runChat(value, { flags: { mode }, positional: [] }, runtime, session);
|
|
604
|
-
}
|
|
605
|
-
} finally {
|
|
606
|
-
input.close();
|
|
607
|
-
}
|
|
608
|
-
}
|
|
609
|
-
|
|
610
|
-
export async function main(argv = process.argv.slice(2)): Promise<void> {
|
|
611
|
-
const parsed = parseArgs(argv);
|
|
612
|
-
const command = parsed.positional[0] || (process.stdin.isTTY ? "interactive" : "help");
|
|
613
|
-
/* the explicit version flag answers before the implicit help fallback: a
|
|
614
|
-
non tty caller (the desktop lane's version gate, piped scripts, the
|
|
615
|
-
container health probe) passes --version with no positional command, so
|
|
616
|
-
the empty positional falls back to help and the old order printed the
|
|
617
|
-
usage banner instead of the version the gate compares. */
|
|
618
|
-
if (boolFlag(parsed, "version") || command === "version") return console.log(version());
|
|
619
|
-
if (boolFlag(parsed, "help") || command === "help") return printHelp();
|
|
620
|
-
/* the grand-merge families: the extension, provider and gateway command
|
|
621
|
-
surfaces ride as family namespaces of the single devthink binary —
|
|
622
|
-
one bin, one router, zero duplicated parsers (the saddle standard). */
|
|
623
|
-
if (command === "ext") {
|
|
624
|
-
const family = argv.slice(argv.indexOf("ext") + 1);
|
|
625
|
-
const cli = await import("./cli.js");
|
|
626
|
-
return void (await cli.runclifamily(family));
|
|
627
|
-
}
|
|
628
|
-
if (command === "provider") {
|
|
629
|
-
const family = argv.slice(argv.indexOf("provider") + 1);
|
|
630
|
-
if (family.length === 0) return printHelp();
|
|
631
|
-
const consolemodule = await import("./server.js");
|
|
632
|
-
return void (await consolemodule.runproviderfamily(family));
|
|
633
|
-
}
|
|
634
|
-
if (
|
|
635
|
-
command === "gateway" &&
|
|
636
|
-
(parsed.positional[1] === "init" ||
|
|
637
|
-
parsed.positional[1] === "add" ||
|
|
638
|
-
parsed.positional[1] === "list" ||
|
|
639
|
-
parsed.positional[1] === "show" ||
|
|
640
|
-
parsed.positional[1] === "validate" ||
|
|
641
|
-
parsed.positional[1] === "keys" ||
|
|
642
|
-
parsed.positional[1] === "serve" ||
|
|
643
|
-
parsed.positional[1] === "export" ||
|
|
644
|
-
parsed.positional[1] === "models")
|
|
645
|
-
) {
|
|
646
|
-
const family = argv.slice(argv.indexOf("gateway") + 1);
|
|
647
|
-
const consolemodule = await import("./server.js");
|
|
648
|
-
return void (await consolemodule.runclifamily(family));
|
|
649
|
-
}
|
|
650
|
-
const runtime = loadRuntime();
|
|
651
|
-
if (command === "init") return console.log(`Initialized ${runtime.paths.home}\nConfig: ${runtime.paths.config}`);
|
|
652
|
-
if (command === "providers")
|
|
653
|
-
return console.log(
|
|
654
|
-
listProviders()
|
|
655
|
-
.map((provider) => `${provider.id} ${provider.protocol} ${provider.env}`)
|
|
656
|
-
.join("\n"),
|
|
657
|
-
);
|
|
658
|
-
if (command === "modes")
|
|
659
|
-
return console.log(
|
|
660
|
-
listModes()
|
|
661
|
-
.map((mode) => `${mode.id} ${mode.purpose}`)
|
|
662
|
-
.join("\n"),
|
|
663
|
-
);
|
|
664
|
-
if (command === "config") return handleConfig(parsed, runtime);
|
|
665
|
-
if (command === "auth") return handleAuth(parsed, runtime);
|
|
666
|
-
if (command === "identity") return handleIdentity(parsed, runtime);
|
|
667
|
-
if (command === "pair") return handlePairing(parsed, runtime);
|
|
668
|
-
if (command === "sync") return handleSync(parsed, runtime);
|
|
669
|
-
if (command === "gateway") return handleGateway(runtime);
|
|
670
|
-
if (command === "sessions") return handleSessions(parsed, runtime);
|
|
671
|
-
if (command === "projects") return handleProjects(runtime);
|
|
672
|
-
if (command === "usage") return handleUsage(runtime);
|
|
673
|
-
if (command === "routes") return handleRoutes();
|
|
674
|
-
if (command === "models") {
|
|
675
|
-
const provider = stringFlag(parsed, "provider") || runtime.config.activeProvider || runtime.config.provider;
|
|
676
|
-
if (!provider) throw new Error("Use --provider or configure provider.");
|
|
677
|
-
return console.log(
|
|
678
|
-
(await listModels(provider, runtime.config, runtime.paths))
|
|
679
|
-
.map((model) => `${model.id} ${model.provider}`)
|
|
680
|
-
.join("\n"),
|
|
681
|
-
);
|
|
682
|
-
}
|
|
683
|
-
if (command === "serve") {
|
|
684
|
-
const server = await startServer({
|
|
685
|
-
port: stringFlag(parsed, "port") ? Number(stringFlag(parsed, "port")) : undefined,
|
|
686
|
-
config: runtime.config,
|
|
687
|
-
paths: runtime.paths,
|
|
688
|
-
});
|
|
689
|
-
console.log(`DevThink API listening at ${server.address}`);
|
|
690
|
-
return;
|
|
691
|
-
}
|
|
692
|
-
if (command === "interactive") return interactive(runtime);
|
|
693
|
-
if (command === "chat") {
|
|
694
|
-
const prompt = stringFlag(parsed, "prompt") || parsed.positional.slice(1).join(" ");
|
|
695
|
-
if (!prompt) throw new Error('Usage: devthink chat --prompt "your message"');
|
|
696
|
-
return void (await runChat(prompt, parsed, runtime));
|
|
697
|
-
}
|
|
698
|
-
throw new Error(`Unknown command: ${command}`);
|
|
699
|
-
}
|
|
700
|
-
|
|
701
|
-
const directEntry = process.argv[1]?.endsWith("devthink.ts") || process.argv[1]?.endsWith("devthink");
|
|
702
|
-
const bunEntry = (import.meta as ImportMeta & { main?: boolean }).main === true;
|
|
703
|
-
if (directEntry || bunEntry)
|
|
704
|
-
main().catch((error: unknown) => {
|
|
705
|
-
console.error(`${colors.red}Error:${colors.reset} ${error instanceof Error ? error.message : "Command failed."}`);
|
|
706
|
-
process.exitCode = 1;
|
|
707
|
-
});
|