threadwell 0.0.1 → 0.0.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/CHANGELOG.md +3 -0
- package/README.md +402 -668
- package/dist/core/settings-manager.d.ts.map +1 -1
- package/dist/core/settings-manager.js +1 -1
- package/dist/core/settings-manager.js.map +1 -1
- package/dist/core/slash-commands.d.ts.map +1 -1
- package/dist/core/slash-commands.js +1 -0
- package/dist/core/slash-commands.js.map +1 -1
- package/dist/modes/interactive/interactive-mode.d.ts +6 -0
- package/dist/modes/interactive/interactive-mode.d.ts.map +1 -1
- package/dist/modes/interactive/interactive-mode.js +75 -15
- package/dist/modes/interactive/interactive-mode.js.map +1 -1
- package/dist/utils/version-check.d.ts +3 -1
- package/dist/utils/version-check.d.ts.map +1 -1
- package/dist/utils/version-check.js +9 -5
- package/dist/utils/version-check.js.map +1 -1
- package/docs/settings.md +1 -1
- package/docs/usage.md +1 -1
- package/package.json +4 -4
|
@@ -138,6 +138,8 @@ export class InteractiveMode {
|
|
|
138
138
|
lastSigintTime = 0;
|
|
139
139
|
lastEscapeTime = 0;
|
|
140
140
|
changelogMarkdown = undefined;
|
|
141
|
+
startupUpdateVersion = undefined;
|
|
142
|
+
shownUpdateVersion = undefined;
|
|
141
143
|
startupNoticesShown = false;
|
|
142
144
|
anthropicSubscriptionWarningShown = false;
|
|
143
145
|
// Status line tracking (for mutating immediately-sequential status updates)
|
|
@@ -356,6 +358,41 @@ export class InteractiveMode {
|
|
|
356
358
|
this.editor.setAutocompleteProvider?.(provider);
|
|
357
359
|
}
|
|
358
360
|
}
|
|
361
|
+
async getStartupUpdateVersion() {
|
|
362
|
+
if (process.env.THREADWELL_OFFLINE || process.env.THREADWELL_SKIP_VERSION_CHECK)
|
|
363
|
+
return undefined;
|
|
364
|
+
return await checkForNewThreadwellVersion(this.version, { timeoutMs: 1500 });
|
|
365
|
+
}
|
|
366
|
+
getStartupWhatsNewLines() {
|
|
367
|
+
const whatsNewLines = ["• context usage bar", "• startup interface toggles", "• cleaner visual cards"];
|
|
368
|
+
if (!this.changelogMarkdown)
|
|
369
|
+
return [theme.fg("muted", `v${this.version}`), ...whatsNewLines];
|
|
370
|
+
const versionMatch = this.changelogMarkdown.match(/##\s+\[?(\d+\.\d+\.\d+)\]?/);
|
|
371
|
+
const versionLine = theme.fg("muted", `changelog v${versionMatch?.[1] ?? this.version}`);
|
|
372
|
+
const changelogBullets = this.changelogMarkdown
|
|
373
|
+
.split("\n")
|
|
374
|
+
.map((line) => line.trim())
|
|
375
|
+
.filter((line) => /^[-*•]\s+/.test(line))
|
|
376
|
+
.map((line) => line.replace(/^[-*•]\s+/, "• "))
|
|
377
|
+
.slice(0, 2);
|
|
378
|
+
return [
|
|
379
|
+
...whatsNewLines,
|
|
380
|
+
"",
|
|
381
|
+
versionLine,
|
|
382
|
+
...changelogBullets,
|
|
383
|
+
`${theme.fg("accent", "/changelog")} full details`,
|
|
384
|
+
];
|
|
385
|
+
}
|
|
386
|
+
getStartupUpdateLines() {
|
|
387
|
+
if (!this.startupUpdateVersion)
|
|
388
|
+
return [""];
|
|
389
|
+
return [
|
|
390
|
+
`${theme.fg("warning", "update")} ${theme.fg("warning", `v${this.startupUpdateVersion} available`)}`,
|
|
391
|
+
`${theme.fg("dim", "run")} ${theme.fg("accent", `${APP_NAME} update`)}`,
|
|
392
|
+
`${theme.fg("dim", "inside")} ${theme.fg("accent", "/update")} for details`,
|
|
393
|
+
"",
|
|
394
|
+
];
|
|
395
|
+
}
|
|
359
396
|
showStartupNoticesIfNeeded() {
|
|
360
397
|
if (this.startupNoticesShown) {
|
|
361
398
|
return;
|
|
@@ -388,6 +425,10 @@ export class InteractiveMode {
|
|
|
388
425
|
this.registerSignalHandlers();
|
|
389
426
|
// Load changelog (only show new entries, skip for resumed sessions)
|
|
390
427
|
this.changelogMarkdown = this.getChangelogForDisplay();
|
|
428
|
+
const interfaceSettings = this.settingsManager.getInterfaceSettings();
|
|
429
|
+
if (interfaceSettings.showUpdateNotifications) {
|
|
430
|
+
this.startupUpdateVersion = await this.getStartupUpdateVersion();
|
|
431
|
+
}
|
|
391
432
|
// Ensure fd and rg are available (downloads if missing, adds to PATH via getBinDir)
|
|
392
433
|
// Both are needed: fd for autocomplete, rg for grep tool and bash commands
|
|
393
434
|
const [fdPath] = await Promise.all([ensureTool("fd"), ensureTool("rg")]);
|
|
@@ -443,7 +484,6 @@ export class InteractiveMode {
|
|
|
443
484
|
].join(theme.fg("muted", " · "));
|
|
444
485
|
const compactOnboarding = theme.fg("dim", `Press ${keyText("app.tools.expand")} to show full startup help and loaded resources.`);
|
|
445
486
|
const onboarding = theme.fg("dim", `${DISTRO_IDENTITY.name} keeps project continuity in context. Ask it what remains or where you left off.`);
|
|
446
|
-
const interfaceSettings = this.settingsManager.getInterfaceSettings();
|
|
447
487
|
this.builtInHeader = interfaceSettings.showStartupCard
|
|
448
488
|
? new SplitInfoCard({
|
|
449
489
|
leftTitle: `${DISTRO_IDENTITY.name} ${this.version}`,
|
|
@@ -453,16 +493,9 @@ export class InteractiveMode {
|
|
|
453
493
|
`${theme.fg("dim", "cwd")} ${cwd}`,
|
|
454
494
|
`${theme.fg("dim", "model")} ${modelText}`,
|
|
455
495
|
`${theme.fg("dim", "continuity")} ${continuityText}`,
|
|
456
|
-
|
|
457
|
-
],
|
|
458
|
-
rightLines: [
|
|
459
|
-
theme.fg("muted", `v${this.version}`),
|
|
460
|
-
"• context usage bar",
|
|
461
|
-
"• startup interface toggles",
|
|
462
|
-
"• cleaner visual cards",
|
|
463
|
-
"",
|
|
464
|
-
`${theme.fg("accent", "/changelog")} full details`,
|
|
496
|
+
...this.getStartupUpdateLines(),
|
|
465
497
|
],
|
|
498
|
+
rightLines: this.getStartupWhatsNewLines(),
|
|
466
499
|
footerLines: [
|
|
467
500
|
compactInstructions,
|
|
468
501
|
`${theme.fg("accent", "/settings")} ${theme.fg("muted", "interface + memory")}`,
|
|
@@ -2085,6 +2118,11 @@ export class InteractiveMode {
|
|
|
2085
2118
|
this.editor.setText("");
|
|
2086
2119
|
return;
|
|
2087
2120
|
}
|
|
2121
|
+
if (text === "/update") {
|
|
2122
|
+
await this.handleUpdateCommand();
|
|
2123
|
+
this.editor.setText("");
|
|
2124
|
+
return;
|
|
2125
|
+
}
|
|
2088
2126
|
if (text === "/hotkeys") {
|
|
2089
2127
|
this.handleHotkeysCommand();
|
|
2090
2128
|
this.editor.setText("");
|
|
@@ -3155,20 +3193,42 @@ export class InteractiveMode {
|
|
|
3155
3193
|
this.showWarning("Usage: /memory status | enable | disable | recent [limit] | search <query> | why [memory:<id>...|id] | doctor | export | forget <id> --confirm | purge --confirm");
|
|
3156
3194
|
}
|
|
3157
3195
|
showNewVersionNotification(newVersion) {
|
|
3196
|
+
if (this.shownUpdateVersion === newVersion)
|
|
3197
|
+
return;
|
|
3198
|
+
this.shownUpdateVersion = newVersion;
|
|
3158
3199
|
const action = theme.fg("accent", `${APP_NAME} update`);
|
|
3159
3200
|
const updateInstruction = theme.fg("muted", `New version ${newVersion} is available. Run `) + action;
|
|
3160
|
-
const
|
|
3161
|
-
const changelogLine = theme.fg("muted", "
|
|
3201
|
+
const alternateCommand = theme.fg("muted", "Also available: ") + theme.fg("accent", "threadwell update");
|
|
3202
|
+
const changelogLine = theme.fg("muted", "What's new: ") + theme.fg("accent", "/changelog");
|
|
3203
|
+
this.chatContainer.addChild(new Spacer(1));
|
|
3204
|
+
this.chatContainer.addChild(new DynamicFrame(`${updateInstruction}\n${alternateCommand}\n${changelogLine}`, (text) => theme.fg("warning", text), false, (text) => text, theme.bold(theme.fg("warning", "Update Available"))));
|
|
3205
|
+
this.ui.requestRender();
|
|
3206
|
+
}
|
|
3207
|
+
async handleUpdateCommand() {
|
|
3208
|
+
const latestVersion = this.startupUpdateVersion ?? (await checkForNewThreadwellVersion(this.version));
|
|
3209
|
+
const versionLine = latestVersion
|
|
3210
|
+
? `${theme.fg("warning", `Threadwell v${latestVersion} is available.`)} ${theme.fg("muted", `Current: v${this.version}`)}`
|
|
3211
|
+
: theme.fg("muted", `Threadwell v${this.version}. Run the update command to check/install the latest npm release.`);
|
|
3212
|
+
const lines = [
|
|
3213
|
+
versionLine,
|
|
3214
|
+
"",
|
|
3215
|
+
`${theme.fg("dim", "Outside Threadwell:")} ${theme.fg("accent", `${APP_NAME} update`)}`,
|
|
3216
|
+
`${theme.fg("dim", "Alias:")} ${theme.fg("accent", "threadwell update")}`,
|
|
3217
|
+
"",
|
|
3218
|
+
theme.fg("muted", "Threadwell does not self-update from inside the live TUI. Exit and run the command above."),
|
|
3219
|
+
theme.fg("muted", `Use ${theme.fg("accent", "/changelog")} to view what's new.`),
|
|
3220
|
+
];
|
|
3162
3221
|
this.chatContainer.addChild(new Spacer(1));
|
|
3163
|
-
this.chatContainer.addChild(new DynamicFrame(
|
|
3222
|
+
this.chatContainer.addChild(new DynamicFrame(lines.join("\n"), (text) => theme.fg("warning", text), false, (text) => text, theme.bold(theme.fg("warning", "Threadwell Update"))));
|
|
3164
3223
|
this.ui.requestRender();
|
|
3165
3224
|
}
|
|
3166
3225
|
showPackageUpdateNotification(packages) {
|
|
3167
3226
|
const action = theme.fg("accent", `${APP_NAME} update`);
|
|
3168
|
-
const updateInstruction = theme.fg("muted", "
|
|
3227
|
+
const updateInstruction = theme.fg("muted", "Updates are available. Run ") + action;
|
|
3228
|
+
const alternateCommand = theme.fg("muted", "Alias: ") + theme.fg("accent", "threadwell update");
|
|
3169
3229
|
const packageLines = packages.map((pkg) => `- ${pkg}`).join("\n");
|
|
3170
3230
|
this.chatContainer.addChild(new Spacer(1));
|
|
3171
|
-
this.chatContainer.addChild(new DynamicFrame(`${updateInstruction}\n${theme.fg("muted", "Packages:")}\n${packageLines}`, (text) => theme.fg("warning", text), false, (text) => text, theme.bold(theme.fg("warning", "
|
|
3231
|
+
this.chatContainer.addChild(new DynamicFrame(`${updateInstruction}\n${alternateCommand}\n${theme.fg("muted", "Packages:")}\n${packageLines}`, (text) => theme.fg("warning", text), false, (text) => text, theme.bold(theme.fg("warning", "Update Available"))));
|
|
3172
3232
|
this.ui.requestRender();
|
|
3173
3233
|
}
|
|
3174
3234
|
/**
|