dsh-one-click-polish 1.2.1 → 1.2.3
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/client.js +93 -5
- package/index.js +78 -1
- package/package.json +1 -1
package/client.js
CHANGED
|
@@ -41,6 +41,7 @@ window.__ModuleLoader__.load({
|
|
|
41
41
|
const PROGRESS = ENDPOINT.replace(/\/polish$/, '/progress')
|
|
42
42
|
const PILOT = ENDPOINT.replace(/\/polish$/, '/autopilot')
|
|
43
43
|
const RUNS = ENDPOINT.replace(/\/polish$/, '/runs')
|
|
44
|
+
const VERSION = ENDPOINT.replace(/\/polish$/, '/version')
|
|
44
45
|
|
|
45
46
|
/** The in-flight request, so the panel can cancel it. */
|
|
46
47
|
let activeAbort = null
|
|
@@ -253,8 +254,8 @@ window.__ModuleLoader__.load({
|
|
|
253
254
|
'auto.warn.body': '启动后 AI 会自动往这个会话里发送消息:读对话 → 写下一步提示词 → 发给助手,一轮接一轮。它会消耗模型额度,也可能做出你没想到的改动。随时可以中断或结束循环。',
|
|
254
255
|
'auto.warn.cancel': '再想想',
|
|
255
256
|
'auto.warn.confirm': '确认启动',
|
|
256
|
-
'auto.interrupt': '跳过这一轮',
|
|
257
|
-
'auto.interrupt.hint': '取消助手正在做的这一轮,循环继续,它会重新判断下一步。',
|
|
257
|
+
'auto.interrupt': '跳过这一轮',
|
|
258
|
+
'auto.interrupt.hint': '取消助手正在做的这一轮,循环继续,它会重新判断下一步。',
|
|
258
259
|
'auto.stop.hint': '整个自动驾驶停下。之后可以从这里继续。',
|
|
259
260
|
'auto.stop': '停止自动',
|
|
260
261
|
'auto.running': '运行中',
|
|
@@ -281,6 +282,14 @@ window.__ModuleLoader__.load({
|
|
|
281
282
|
'settings.idleWait': '等待助手完成上一轮的上限',
|
|
282
283
|
'settings.idleWait.hint': '自动驾驶要发下一条时,如果助手还在处理,它会等。超过这个上限就先停下,点「继续」可以接着来。长会话需要更长的时间。',
|
|
283
284
|
'settings.idleWait.unit': '分钟',
|
|
285
|
+
'version.current': '当前版本',
|
|
286
|
+
'version.latest': '已是最新',
|
|
287
|
+
'version.newest': 'npm 上有',
|
|
288
|
+
'version.checking': '检查更新中…',
|
|
289
|
+
'version.unknown': '查不到最新版本',
|
|
290
|
+
'version.how': '怎么更新',
|
|
291
|
+
'version.recheck': '重新检查',
|
|
292
|
+
'version.updateHint': '卸载后按包名重装即可更新(dsh 不为第三方插件提供更新按钮)',
|
|
284
293
|
'settings.explore': '检索预算',
|
|
285
294
|
'settings.explore.hint': '标准/深度润色时会先查资料。这是查资料总共能用多久、最多查几轮。查完后再改写,两者互不占用。',
|
|
286
295
|
'settings.explore.unit': '秒',
|
|
@@ -412,8 +421,8 @@ window.__ModuleLoader__.load({
|
|
|
412
421
|
'auto.warn.body': 'The AI will send messages into this conversation by itself: read the history, write the next prompt, send it, round after round. It spends model quota and may change things you did not expect. You can interrupt or end the loop at any time.',
|
|
413
422
|
'auto.warn.cancel': 'Not now',
|
|
414
423
|
'auto.warn.confirm': 'Start',
|
|
415
|
-
'auto.interrupt': 'Skip this round',
|
|
416
|
-
'auto.interrupt.hint': 'Cancel the turn the assistant is running. The loop stays alive and re-plans the next step.',
|
|
424
|
+
'auto.interrupt': 'Skip this round',
|
|
425
|
+
'auto.interrupt.hint': 'Cancel the turn the assistant is running. The loop stays alive and re-plans the next step.',
|
|
417
426
|
'auto.stop.hint': 'End the autopilot. You can continue from here afterwards.',
|
|
418
427
|
'auto.stop': 'Stop autopilot',
|
|
419
428
|
'auto.running': 'Running',
|
|
@@ -440,6 +449,14 @@ window.__ModuleLoader__.load({
|
|
|
440
449
|
'settings.idleWait': 'How long to wait for the assistant',
|
|
441
450
|
'settings.idleWait.hint': 'When the loop is ready to send but the assistant is still working, it waits. Past this limit it parks, and Continue picks it up again. Long conversations need more time.',
|
|
442
451
|
'settings.idleWait.unit': 'minutes',
|
|
452
|
+
'version.current': 'Version',
|
|
453
|
+
'version.latest': 'Up to date',
|
|
454
|
+
'version.newest': 'npm has',
|
|
455
|
+
'version.checking': 'Checking for updates…',
|
|
456
|
+
'version.unknown': 'Cannot reach npm',
|
|
457
|
+
'version.how': 'How to update',
|
|
458
|
+
'version.recheck': 'Check again',
|
|
459
|
+
'version.updateHint': 'Uninstall and install by package name to update (dsh offers no update button for third-party plugins)',
|
|
443
460
|
'settings.explore': 'Lookup budget',
|
|
444
461
|
'settings.explore.hint': 'A standard or deep polish looks things up first. This is how long that may take in total, and how many rounds it may spend. The rewrite runs separately with its own budget.',
|
|
445
462
|
'settings.explore.unit': 's',
|
|
@@ -564,6 +581,25 @@ window.__ModuleLoader__.load({
|
|
|
564
581
|
.dsh-op-head{margin-bottom:18px}
|
|
565
582
|
.dsh-op-h2{margin:0 0 4px;font-size:17px;font-weight:600;line-height:26px;letter-spacing:-.01em}
|
|
566
583
|
.dsh-op-sub{margin:0;color:var(--dsw-alias-label-secondary);font-size:12.5px;line-height:20px}
|
|
584
|
+
/* Version line: this plugin's own update affordance. dsh's plugin page only
|
|
585
|
+
computes installTarget for bundles in its official catalogue, so a third-party
|
|
586
|
+
plugin has no update button there. */
|
|
587
|
+
.dsh-op-version{display:flex;flex-wrap:wrap;align-items:center;gap:8px;margin-top:9px;
|
|
588
|
+
font-size:11.5px;line-height:17px;color:var(--dsw-alias-label-secondary)}
|
|
589
|
+
.dsh-op-versionNow{font-variant-numeric:tabular-nums;
|
|
590
|
+
font-family:ui-monospace,SFMono-Regular,Menlo,monospace;font-size:11px;
|
|
591
|
+
background:var(--dsw-alias-bg-base);border-radius:999px;padding:1px 8px;
|
|
592
|
+
color:var(--dsw-alias-label-primary)}
|
|
593
|
+
.dsh-op-versionNew{display:flex;flex-wrap:wrap;align-items:center;gap:8px;
|
|
594
|
+
font-size:11.5px;color:var(--dsw-alias-state-warn-primary)}
|
|
595
|
+
.dsh-op-versionBad{color:var(--dsw-alias-label-tertiary,var(--dsw-alias-label-secondary));opacity:.8}
|
|
596
|
+
/* The manual update instruction: present when a newer version exists, quiet enough
|
|
597
|
+
not to compete with the version numbers themselves. */
|
|
598
|
+
.dsh-op-versionHint{flex:1 1 100%;font-size:11px;line-height:16px;
|
|
599
|
+
color:var(--dsw-alias-label-secondary);opacity:.85}
|
|
600
|
+
/* The busy-wait line: a live counter, so it is monospaced and does not reflow as
|
|
601
|
+
the seconds tick, and it holds a fixed height so the panel does not jump. */
|
|
602
|
+
.dsh-op-waiting{font-variant-numeric:tabular-nums;min-height:17px}
|
|
567
603
|
.dsh-op-card{display:flex;flex-direction:column;gap:2px;padding:2px 16px;
|
|
568
604
|
background:var(--dsw-alias-bg-layer-1);border:1px solid var(--dsw-alias-border-l1);
|
|
569
605
|
border-radius:14px}
|
|
@@ -2266,6 +2302,8 @@ window.__ModuleLoader__.load({
|
|
|
2266
2302
|
const [form, setForm] = useState(null) // what the user is editing
|
|
2267
2303
|
const [efforts, setEfforts] = useState({ state: 'idle', list: [], defaultEffort: null })
|
|
2268
2304
|
const [saveState, setSaveState] = useState({ state: 'idle', message: '' })
|
|
2305
|
+
// null while the first lookup is in flight; afterwards { current, latest, error }
|
|
2306
|
+
const [version, setVersion] = useState(null)
|
|
2269
2307
|
const [runs, setRuns] = useState([])
|
|
2270
2308
|
const [runsPick, setRunsPick] = useState(null)
|
|
2271
2309
|
const [runEntries, setRunEntries] = useState([])
|
|
@@ -2317,6 +2355,24 @@ window.__ModuleLoader__.load({
|
|
|
2317
2355
|
|
|
2318
2356
|
useEffect(() => { load() }, [load])
|
|
2319
2357
|
|
|
2358
|
+
/** Read this plugin's version against npm. Cached on the Host for 10 minutes. */
|
|
2359
|
+
const checkVersion = useCallback(async (force) => {
|
|
2360
|
+
try {
|
|
2361
|
+
const response = await fetch(force === true ? `${VERSION}?refresh=1` : VERSION)
|
|
2362
|
+
const payload = await response.json()
|
|
2363
|
+
if (payload?.ok !== true) throw new Error(payload?.error ?? 'HTTP error')
|
|
2364
|
+
setVersion({
|
|
2365
|
+
current: typeof payload.current === 'string' ? payload.current : '',
|
|
2366
|
+
latest: typeof payload.latest === 'string' ? payload.latest : null,
|
|
2367
|
+
error: typeof payload.error === 'string' ? payload.error : null,
|
|
2368
|
+
})
|
|
2369
|
+
} catch (failure) {
|
|
2370
|
+
setVersion({ current: '', latest: null, error: String(failure?.message ?? failure) })
|
|
2371
|
+
}
|
|
2372
|
+
}, [])
|
|
2373
|
+
|
|
2374
|
+
useEffect(() => { void checkVersion(false) }, [checkVersion])
|
|
2375
|
+
|
|
2320
2376
|
/** Sessions that have an archived run, newest first. */
|
|
2321
2377
|
const loadRuns = useCallback(async () => {
|
|
2322
2378
|
try {
|
|
@@ -2462,7 +2518,39 @@ window.__ModuleLoader__.load({
|
|
|
2462
2518
|
const pageBody = h('div', { className: 'dsh-op-page' },
|
|
2463
2519
|
h('div', { className: 'dsh-op-head' },
|
|
2464
2520
|
h('h2', { className: 'dsh-op-h2' }, t('settings.title')),
|
|
2465
|
-
h('p', { className: 'dsh-op-sub' }, t('settings.sub'))
|
|
2521
|
+
h('p', { className: 'dsh-op-sub' }, t('settings.sub')),
|
|
2522
|
+
// dsh's own plugin page can only offer 更新 for bundles in its official
|
|
2523
|
+
// catalogue, so a third-party plugin gets no update affordance there.
|
|
2524
|
+
// The version line puts that question here instead.
|
|
2525
|
+
h('div', { className: 'dsh-op-version' },
|
|
2526
|
+
h('span', { className: 'dsh-op-versionNow' },
|
|
2527
|
+
`${t('version.current')} ${version.current === '' ? '?' : version.current}`),
|
|
2528
|
+
version === null
|
|
2529
|
+
? h('span', { className: 'dsh-op-hint dsh-op-hint--inline' }, t('version.checking'))
|
|
2530
|
+
: version.error !== null && version.error !== ''
|
|
2531
|
+
? h('span', { className: 'dsh-op-versionBad' },
|
|
2532
|
+
`${t('version.unknown')} · ${version.error}`)
|
|
2533
|
+
: version.latest === null
|
|
2534
|
+
? h('span', { className: 'dsh-op-hint dsh-op-hint--inline' }, t('version.unknown'))
|
|
2535
|
+
: version.latest !== version.current
|
|
2536
|
+
? h('div', { className: 'dsh-op-versionNew' },
|
|
2537
|
+
h('span', null, `${t('version.newest')} ${version.latest}`),
|
|
2538
|
+
h('a', {
|
|
2539
|
+
className: 'dsh-op-link',
|
|
2540
|
+
href: 'https://www.npmjs.com/package/dsh-one-click-polish',
|
|
2541
|
+
target: '_blank',
|
|
2542
|
+
rel: 'noreferrer',
|
|
2543
|
+
}, t('version.how')),
|
|
2544
|
+
h('button', {
|
|
2545
|
+
type: 'button',
|
|
2546
|
+
className: 'dsh-op-link',
|
|
2547
|
+
onClick: () => { void checkVersion(true) },
|
|
2548
|
+
}, t('version.recheck')),
|
|
2549
|
+
// dsh derives installTarget only from its official catalogue, so a
|
|
2550
|
+
// third-party plugin has no update button. State the manual step
|
|
2551
|
+
// rather than leaving the user to wonder where one is.
|
|
2552
|
+
h('span', { className: 'dsh-op-versionHint' }, t('version.updateHint')))
|
|
2553
|
+
: h('span', { className: 'dsh-op-hint dsh-op-hint--inline' }, t('version.latest')))),
|
|
2466
2554
|
h('div', { className: 'dsh-op-card' },
|
|
2467
2555
|
h('div', { className: 'dsh-op-cardTitle' }, t('settings.group.model')),
|
|
2468
2556
|
h('div', { className: 'dsh-op-field' },
|
package/index.js
CHANGED
|
@@ -23,7 +23,8 @@ export const name = 'one-click-polish'
|
|
|
23
23
|
export const inject = ['llm', 'agents', 'webServer']
|
|
24
24
|
|
|
25
25
|
import { existsSync, readFileSync, writeFileSync } from 'node:fs'
|
|
26
|
-
import { join } from 'node:path'
|
|
26
|
+
import { dirname, join } from 'node:path'
|
|
27
|
+
import { fileURLToPath } from 'node:url'
|
|
27
28
|
|
|
28
29
|
const PREFIX = '/plugins/dsh-one-click-polish'
|
|
29
30
|
const DEFAULT_MAX_INPUT_CHARS = 12000
|
|
@@ -466,6 +467,61 @@ async function produceRewrite(ctx, settings, mode, strength, research, input, ag
|
|
|
466
467
|
return text
|
|
467
468
|
}
|
|
468
469
|
|
|
470
|
+
/**
|
|
471
|
+
* This plugin's own version, and the newest one on npm.
|
|
472
|
+
*
|
|
473
|
+
* dsh's plugin page only offers an update button for bundles in its official
|
|
474
|
+
* catalogue, because `installTarget` is computed from that catalogue. A third-party
|
|
475
|
+
* plugin therefore has no update affordance there at all, so the question "is there
|
|
476
|
+
* a newer version?" is answered here instead, on the plugin's own settings page.
|
|
477
|
+
*/
|
|
478
|
+
const VERSION_TTL_MS = 10 * 60 * 1000
|
|
479
|
+
let versionCache = { at: 0, latest: null, error: null }
|
|
480
|
+
|
|
481
|
+
async function versionInfo() {
|
|
482
|
+
let current = ''
|
|
483
|
+
try {
|
|
484
|
+
// Resolve from this module rather than the process cwd: the Host may run with
|
|
485
|
+
// any working directory, and this file sits next to its own manifest.
|
|
486
|
+
const here = dirname(fileURLToPath(import.meta.url))
|
|
487
|
+
const manifest = JSON.parse(readFileSync(join(here, 'package.json'), 'utf8'))
|
|
488
|
+
current = typeof manifest.version === 'string' ? manifest.version : ''
|
|
489
|
+
} catch { /* a missing manifest just means no version to report */ }
|
|
490
|
+
|
|
491
|
+
if (versionCache.latest !== null && Date.now() - versionCache.at < VERSION_TTL_MS) {
|
|
492
|
+
return { current, latest: versionCache.latest, error: null, checked: versionCache.at }
|
|
493
|
+
}
|
|
494
|
+
|
|
495
|
+
// The registry is the only source of truth for "what is published"; a failed
|
|
496
|
+
// lookup must not look like "you are up to date".
|
|
497
|
+
let latest = null
|
|
498
|
+
let error = null
|
|
499
|
+
try {
|
|
500
|
+
const controller = new AbortController()
|
|
501
|
+
const timer = setTimeout(() => controller.abort(), 8000)
|
|
502
|
+
const response = await fetch('https://registry.npmjs.org/dsh-one-click-polish/latest', {
|
|
503
|
+
signal: controller.signal,
|
|
504
|
+
headers: { accept: 'application/json' },
|
|
505
|
+
})
|
|
506
|
+
clearTimeout(timer)
|
|
507
|
+
if (!response.ok) throw new Error(`HTTP ${response.status}`)
|
|
508
|
+
const payload = await response.json()
|
|
509
|
+
latest = typeof payload?.version === 'string' ? payload.version : null
|
|
510
|
+
} catch (failure) {
|
|
511
|
+
error = textOf(failure)
|
|
512
|
+
}
|
|
513
|
+
versionCache = { at: Date.now(), latest, error }
|
|
514
|
+
return { current, latest, error, checked: Date.now() }
|
|
515
|
+
}
|
|
516
|
+
|
|
517
|
+
async function versionRoute(req, res) {
|
|
518
|
+
// `refresh=1` drops the TTL cache: the panel offers a recheck, and a button that
|
|
519
|
+
// silently answers from cache would look broken.
|
|
520
|
+
const url = new URL(req.url ?? '/', 'http://localhost')
|
|
521
|
+
if (url.searchParams.get('refresh') === '1') versionCache.at = 0
|
|
522
|
+
sendJson(res, 200, { ok: true, ...(await versionInfo()) })
|
|
523
|
+
}
|
|
524
|
+
|
|
469
525
|
async function statusRoute(ctx, req, res) {
|
|
470
526
|
const url = new URL(req.url ?? '/', 'http://localhost')
|
|
471
527
|
const sessionId = url.searchParams.get('sessionId') ?? undefined
|
|
@@ -553,6 +609,20 @@ function allowedRoots(ctx, agent) {
|
|
|
553
609
|
function profileDir() {
|
|
554
610
|
const fromEnv = process.env.DSH_PROFILE_DIR
|
|
555
611
|
if (typeof fromEnv === 'string' && fromEnv !== '') return fromEnv
|
|
612
|
+
|
|
613
|
+
// Resolve from where this module actually lives: <profile>/node_modules/<pkg>/.
|
|
614
|
+
// That anchor stays correct whatever working directory the Host was launched with,
|
|
615
|
+
// and it is what keeps the run log and the resume checkpoint discoverable after an
|
|
616
|
+
// uninstall-and-reinstall: those files live in the profile rather than in the
|
|
617
|
+
// package, so they survive the uninstall and must still be found afterwards.
|
|
618
|
+
try {
|
|
619
|
+
const here = dirname(fileURLToPath(import.meta.url))
|
|
620
|
+
const profile = join(here, '..', '..')
|
|
621
|
+
if (existsSync(join(profile, 'package.json')) && existsSync(join(profile, 'cordis.patch.yml'))) {
|
|
622
|
+
return profile
|
|
623
|
+
}
|
|
624
|
+
} catch { /* fall through to the working-directory guess */ }
|
|
625
|
+
|
|
556
626
|
try {
|
|
557
627
|
const cwd = process.cwd()
|
|
558
628
|
if (!existsSync(join(cwd, 'cordis.patch.yml'))) return null
|
|
@@ -2466,6 +2536,13 @@ export function apply(ctx, config) {
|
|
|
2466
2536
|
})
|
|
2467
2537
|
|
|
2468
2538
|
|
|
2539
|
+
ctx.effect(() => server.register({
|
|
2540
|
+
kind: 'exact',
|
|
2541
|
+
path: `${PREFIX}/version`,
|
|
2542
|
+
handler: (req, res) => versionRoute(req, res)
|
|
2543
|
+
.catch(error => sendJson(res, 500, { ok: false, error: textOf(error) })),
|
|
2544
|
+
}), 'one-click-polish: version route')
|
|
2545
|
+
|
|
2469
2546
|
ctx.effect(() => server.register({
|
|
2470
2547
|
kind: 'exact',
|
|
2471
2548
|
path: `${PREFIX}/status`,
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "dsh-one-click-polish",
|
|
3
|
-
"version": "1.2.
|
|
3
|
+
"version": "1.2.3",
|
|
4
4
|
"description": "One-click polish, expand and autopilot for the DeepSeek Harness composer: rewrite the draft with the model the session is switched to, expand a one-line wish into a task brief, or let an AI drive a goal round after round.",
|
|
5
5
|
"keywords": [
|
|
6
6
|
"dsh",
|