dsh-tabbit 0.2.3 → 0.3.2

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.
Files changed (39) hide show
  1. package/CHANGELOG.md +133 -0
  2. package/LICENSE +21 -0
  3. package/README.en.md +141 -0
  4. package/README.md +70 -76
  5. package/client/client.js +390 -0
  6. package/cordis.patch.yml +76 -5
  7. package/lib/core/index.js +756 -0
  8. package/lib/installer/detect.js +374 -0
  9. package/lib/installer/download.js +247 -0
  10. package/lib/installer/index.js +254 -0
  11. package/lib/mentions/index.js +595 -0
  12. package/lib/permissions/index.js +136 -0
  13. package/lib/runtime/cli.js +229 -0
  14. package/lib/runtime/client.js +454 -0
  15. package/lib/runtime/codec.js +126 -0
  16. package/lib/runtime/endpoint.js +248 -0
  17. package/lib/runtime/errors.js +126 -0
  18. package/lib/runtime/instances.js +287 -0
  19. package/lib/runtime/net.js +143 -0
  20. package/lib/runtime/peer.js +132 -0
  21. package/lib/tool-browser/index.js +476 -0
  22. package/lib/update-check.js +343 -0
  23. package/lib/web-fetch/index.js +219 -0
  24. package/package.json +55 -16
  25. package/skills/tabbit/SKILL.md +66 -0
  26. package/skills/tabbit/references/interaction-helpers.md +150 -0
  27. package/skills/tabbit/references/platform-invocation.md +174 -0
  28. package/skills/{tabbit-browser → tabbit}/references/playwright-recipes.md +11 -3
  29. package/skills/tabbit/references/runtime-recovery.md +104 -0
  30. package/README.zh-CN.md +0 -114
  31. package/index.js +0 -352
  32. package/installer.js +0 -568
  33. package/skills/tabbit-browser/SKILL.md +0 -274
  34. package/skills/tabbit-browser/agents/openai.yaml +0 -4
  35. package/skills/tabbit-browser/references/interaction-helpers.md +0 -103
  36. package/skills/tabbit-browser/references/platform-invocation.md +0 -45
  37. package/skills/tabbit-browser/references/runtime-recovery.md +0 -95
  38. package/update-check.js +0 -177
  39. /package/skills/{tabbit-browser → tabbit}/references/information-extraction.md +0 -0
package/update-check.js DELETED
@@ -1,177 +0,0 @@
1
- import { mkdir, readFile, writeFile } from 'node:fs/promises'
2
- import { homedir } from 'node:os'
3
- import { dirname, join } from 'node:path'
4
-
5
- const DAY_MS = 24 * 60 * 60 * 1000
6
- const FETCH_TIMEOUT_MS = 1500
7
- const CHANGELOG_MAX_CHARS = 500
8
- // The raw CDN carries no GitHub API rate limit, which unauthenticated checks
9
- // from shared egress IPs would otherwise exhaust within the hour.
10
- const DEFAULT_CHANGELOG_URL = 'https://raw.githubusercontent.com/Tabbit-Browser/dsh-tabbit/main/CHANGELOG.md'
11
- const PACKAGE_URL = new URL('./package.json', import.meta.url)
12
-
13
- let cachedLocalVersion
14
-
15
- function numericVersion(version) {
16
- const match = String(version ?? '').trim().match(/^v?(\d+(?:\.\d+)*)/i)
17
- return match ? match[1].split('.').map(Number) : undefined
18
- }
19
-
20
- export function compareVersions(left, right) {
21
- const leftParts = numericVersion(left)
22
- const rightParts = numericVersion(right)
23
- if (!leftParts || !rightParts) return undefined
24
- const length = Math.max(leftParts.length, rightParts.length)
25
- for (let index = 0; index < length; index += 1) {
26
- const a = leftParts[index] ?? 0
27
- const b = rightParts[index] ?? 0
28
- if (a !== b) return a > b ? 1 : -1
29
- }
30
- return 0
31
- }
32
-
33
- export function flattenChangelog(text) {
34
- return String(text ?? '').replace(/\s+/g, ' ').trim()
35
- }
36
-
37
- export function truncateChangelog(text) {
38
- const value = flattenChangelog(text)
39
- if (value.length <= CHANGELOG_MAX_CHARS) return value
40
- return `${value.slice(0, CHANGELOG_MAX_CHARS - 1).trimEnd()}…`
41
- }
42
-
43
- export function parseLatestChangelog(markdown) {
44
- const match = String(markdown ?? '').match(/^## +(v?\d+(?:\.\d+)+).*$/m)
45
- if (!match) throw new Error('Latest changelog has no version heading.')
46
- const version = numericVersion(match[1])?.join('.')
47
- if (!version) throw new Error('Latest changelog heading has no usable version.')
48
- const sectionStart = match.index + match[0].length
49
- const nextSection = String(markdown).slice(sectionStart).search(/^## +/m)
50
- const section = nextSection === -1
51
- ? String(markdown).slice(sectionStart)
52
- : String(markdown).slice(sectionStart, sectionStart + nextSection)
53
- return { version, changelog: truncateChangelog(section) }
54
- }
55
-
56
- export function defaultCacheFile(env = process.env, platform = process.platform) {
57
- const base = env.XDG_CACHE_HOME
58
- || (platform === 'win32'
59
- ? env.LOCALAPPDATA || join(homedir(), 'AppData', 'Local')
60
- : undefined)
61
- || join(homedir(), '.cache')
62
- return join(base, 'tabbit-dsh', 'update-check.json')
63
- }
64
-
65
- export async function readLocalVersion() {
66
- if (cachedLocalVersion !== undefined) return cachedLocalVersion ?? undefined
67
- try {
68
- const parsed = JSON.parse(await readFile(PACKAGE_URL, 'utf8'))
69
- cachedLocalVersion = typeof parsed.version === 'string' ? parsed.version : null
70
- } catch {
71
- cachedLocalVersion = null
72
- }
73
- return cachedLocalVersion ?? undefined
74
- }
75
-
76
- export async function readCachedCheck(cacheFile) {
77
- try {
78
- const parsed = JSON.parse(await readFile(cacheFile, 'utf8'))
79
- return parsed && typeof parsed === 'object' ? parsed : {}
80
- } catch {
81
- return {}
82
- }
83
- }
84
-
85
- async function writeCachedCheck(cacheFile, state) {
86
- await mkdir(dirname(cacheFile), { recursive: true })
87
- await writeFile(cacheFile, `${JSON.stringify(state, null, 2)}\n`, 'utf8')
88
- }
89
-
90
- export async function fetchLatestChangelog({
91
- url = process.env.TABBIT_PLUGIN_UPDATE_URL || DEFAULT_CHANGELOG_URL,
92
- timeoutMs = FETCH_TIMEOUT_MS,
93
- fetchImpl = fetch,
94
- } = {}) {
95
- const controller = new AbortController()
96
- const timer = setTimeout(() => controller.abort(), timeoutMs)
97
- try {
98
- const response = await fetchImpl(url, { signal: controller.signal })
99
- if (!response.ok) throw new Error(`Update check failed with HTTP ${response.status}.`)
100
- return parseLatestChangelog(await response.text())
101
- } finally {
102
- clearTimeout(timer)
103
- }
104
- }
105
-
106
- function isRecent(timestamp, now) {
107
- return typeof timestamp === 'number' && now - timestamp < DAY_MS
108
- }
109
-
110
- export function summarizeUpdate({
111
- currentVersion,
112
- latestVersion,
113
- changelog,
114
- dismissedVersion,
115
- }) {
116
- if (!currentVersion || !latestVersion) return { status: 'unknown', currentVersion }
117
- if (compareVersions(latestVersion, currentVersion) !== 1 || latestVersion === dismissedVersion) {
118
- return { status: 'current', currentVersion, latestVersion }
119
- }
120
- return { status: 'update-available', currentVersion, latestVersion, changelog }
121
- }
122
-
123
- function summaryFromCache(currentVersion, cached) {
124
- return summarizeUpdate({
125
- currentVersion,
126
- latestVersion: cached.latestVersion,
127
- changelog: cached.changelog,
128
- dismissedVersion: cached.dismissedVersion,
129
- })
130
- }
131
-
132
- async function fetchAndCacheRelease({ currentVersion, cached, cacheFile, now, fetchRelease }) {
133
- const state = { ...cached, lastAttemptAt: now }
134
- try {
135
- const release = await fetchRelease()
136
- state.checkedAt = now
137
- state.latestVersion = release.version
138
- state.changelog = release.changelog
139
- } catch {
140
- // Keep lastAttemptAt so the failure stays silent for a day before retrying.
141
- }
142
- try {
143
- await writeCachedCheck(cacheFile, state)
144
- } catch {
145
- // A read-only cache must not break the check itself.
146
- }
147
- return summaryFromCache(currentVersion, state)
148
- }
149
-
150
- export async function checkPluginUpdate({
151
- now = Date.now(),
152
- cacheFile = defaultCacheFile(),
153
- fetchRelease = fetchLatestChangelog,
154
- readVersion = readLocalVersion,
155
- force = false,
156
- } = {}) {
157
- const currentVersion = await readVersion()
158
- const cached = await readCachedCheck(cacheFile)
159
- if (!force) {
160
- if (isRecent(cached.checkedAt, now) && cached.latestVersion) {
161
- return summaryFromCache(currentVersion, cached)
162
- }
163
- if (isRecent(cached.lastAttemptAt, now)) {
164
- return { status: 'unknown', currentVersion }
165
- }
166
- }
167
- return fetchAndCacheRelease({ currentVersion, cached, cacheFile, now, fetchRelease })
168
- }
169
-
170
- export async function dismissUpdate(version, {
171
- cacheFile = defaultCacheFile(),
172
- } = {}) {
173
- const cached = await readCachedCheck(cacheFile)
174
- const state = { ...cached, dismissedVersion: String(version ?? '').trim() }
175
- await writeCachedCheck(cacheFile, state)
176
- return state
177
- }