@wrongstack/cli 0.306.0 → 0.306.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.
- package/dist/{auth-GVPYLJPS.js → auth-L3WGSGDX.js} +4 -4
- package/dist/{chunk-WC3DK6BI.js → chunk-HITHEXE3.js} +2 -2
- package/dist/{chunk-5JW3XCRA.js → chunk-KXN5HZDL.js} +2 -2
- package/dist/{chunk-V3XH6XBJ.js → chunk-T6YAVFXA.js} +33 -2
- package/dist/{chunk-3IC4IEZC.js → chunk-VUVOMXWP.js} +34 -3
- package/dist/{cli-main-DHNFGP3Z.js → cli-main-3PUWFKSL.js} +132 -106
- package/dist/execute-deps.d.ts +14 -0
- package/dist/{execution-TTE7R5UY.js → execution-4IG5XKOL.js} +378 -2
- package/dist/index.js +6 -6
- package/dist/provider-helpers.d.ts +1 -5
- package/dist/{providers-models-VV74TRQ2.js → providers-models-HQN3AT3K.js} +2 -2
- package/dist/services/run-git.d.ts +18 -0
- package/dist/slash-commands/git.d.ts +0 -5
- package/dist/slash-commands/theme.d.ts +32 -0
- package/dist/tui-resource-menus.d.ts +13 -0
- package/package.json +24 -24
package/dist/execute-deps.d.ts
CHANGED
|
@@ -148,6 +148,20 @@ export interface ProviderDeps {
|
|
|
148
148
|
id: string;
|
|
149
149
|
family: string;
|
|
150
150
|
models: string[];
|
|
151
|
+
modelDetails?: Record<string, {
|
|
152
|
+
name?: string | undefined;
|
|
153
|
+
description?: string | undefined;
|
|
154
|
+
tools?: boolean | undefined;
|
|
155
|
+
vision?: boolean | undefined;
|
|
156
|
+
reasoning?: boolean | undefined;
|
|
157
|
+
maxContext?: number | undefined;
|
|
158
|
+
maxOutput?: number | undefined;
|
|
159
|
+
inputCost?: number | undefined;
|
|
160
|
+
outputCost?: number | undefined;
|
|
161
|
+
cacheReadCost?: number | undefined;
|
|
162
|
+
knowledge?: string | undefined;
|
|
163
|
+
releaseDate?: string | undefined;
|
|
164
|
+
}> | undefined;
|
|
151
165
|
}>>;
|
|
152
166
|
switchProviderAndModel: (providerId: string, modelId: string) => string | null | Promise<string | null>;
|
|
153
167
|
onModelContextResolved?: ((providerId: string, modelId: string, maxContext: number) => void) | undefined;
|
|
@@ -5,9 +5,10 @@ import {
|
|
|
5
5
|
normalizeTuiThinkingWord,
|
|
6
6
|
resolveActualTarget,
|
|
7
7
|
resolvePersistPath,
|
|
8
|
+
runGit,
|
|
8
9
|
setAutoSuggestions,
|
|
9
10
|
setSuggestions
|
|
10
|
-
} from "./chunk-
|
|
11
|
+
} from "./chunk-T6YAVFXA.js";
|
|
11
12
|
import {
|
|
12
13
|
startCliHqConnection
|
|
13
14
|
} from "./chunk-FKWHSFX4.js";
|
|
@@ -5024,6 +5025,373 @@ function createTuiNextStepCallbacks(input) {
|
|
|
5024
5025
|
};
|
|
5025
5026
|
}
|
|
5026
5027
|
|
|
5028
|
+
// src/tui-resource-menus.ts
|
|
5029
|
+
import { readdir } from "node:fs/promises";
|
|
5030
|
+
import { readJsonObjectFile } from "@wrongstack/core/utils";
|
|
5031
|
+
function createTuiResourceMenuGetter(ctx) {
|
|
5032
|
+
return async (id) => {
|
|
5033
|
+
switch (id) {
|
|
5034
|
+
case "fallback":
|
|
5035
|
+
return fallbackMenu(ctx.configStore);
|
|
5036
|
+
case "profile":
|
|
5037
|
+
return profileMenu(ctx.configStore, ctx.paths);
|
|
5038
|
+
case "provider-status":
|
|
5039
|
+
return providerStatusMenu(ctx.statusTracker);
|
|
5040
|
+
case "memory":
|
|
5041
|
+
return memoryMenu(ctx.memoryStore);
|
|
5042
|
+
case "worktree":
|
|
5043
|
+
return worktreeMenu(ctx.projectRoot);
|
|
5044
|
+
case "git":
|
|
5045
|
+
return gitMenu(ctx.projectRoot);
|
|
5046
|
+
}
|
|
5047
|
+
};
|
|
5048
|
+
}
|
|
5049
|
+
function fallbackMenu(store) {
|
|
5050
|
+
const config = store.get();
|
|
5051
|
+
const chain = config.fallbackModels ?? [];
|
|
5052
|
+
const profiles = config.fallbackProfiles ?? {};
|
|
5053
|
+
const favorites = config.favoriteModels ?? [];
|
|
5054
|
+
const auto = config.fallbackAuto !== false;
|
|
5055
|
+
const items = [
|
|
5056
|
+
{
|
|
5057
|
+
id: "leader",
|
|
5058
|
+
label: "Leader",
|
|
5059
|
+
status: "good",
|
|
5060
|
+
summary: `${config.provider}/${config.model}`,
|
|
5061
|
+
details: [
|
|
5062
|
+
{ label: "provider", value: config.provider },
|
|
5063
|
+
{ label: "model", value: config.model },
|
|
5064
|
+
{ label: "bridge", value: config.fallbackBridge || "disabled" }
|
|
5065
|
+
],
|
|
5066
|
+
body: "The active session model. The bridge, when configured, is tried before the ordered fallback chain."
|
|
5067
|
+
},
|
|
5068
|
+
{
|
|
5069
|
+
id: "auto",
|
|
5070
|
+
label: "Smart fallback",
|
|
5071
|
+
status: auto ? "good" : "muted",
|
|
5072
|
+
summary: auto ? "enabled" : "disabled",
|
|
5073
|
+
details: [
|
|
5074
|
+
{ label: "mode", value: auto ? "auto-derived when chain is empty" : "explicit chain only" },
|
|
5075
|
+
{ label: "favorites only", value: config.favoriteModelsOnly ? "yes" : "no" },
|
|
5076
|
+
{ label: "favorites", value: String(favorites.length) }
|
|
5077
|
+
],
|
|
5078
|
+
actions: [
|
|
5079
|
+
{
|
|
5080
|
+
key: "t",
|
|
5081
|
+
label: auto ? "turn off" : "turn on",
|
|
5082
|
+
command: `/fallback auto ${auto ? "off" : "on"}`
|
|
5083
|
+
}
|
|
5084
|
+
]
|
|
5085
|
+
},
|
|
5086
|
+
...chain.map((ref, index) => ({
|
|
5087
|
+
id: `chain:${index}`,
|
|
5088
|
+
label: `${index + 1}. ${ref}`,
|
|
5089
|
+
status: "warn",
|
|
5090
|
+
summary: "explicit fallback",
|
|
5091
|
+
details: [
|
|
5092
|
+
{ label: "position", value: String(index + 1) },
|
|
5093
|
+
{ label: "model ref", value: ref },
|
|
5094
|
+
{ label: "after", value: index === 0 ? "leader/bridge" : chain[index - 1] ?? "leader" }
|
|
5095
|
+
],
|
|
5096
|
+
actions: [
|
|
5097
|
+
{ key: "x", label: "remove", command: `/fallback remove ${index + 1}`, confirm: true }
|
|
5098
|
+
]
|
|
5099
|
+
})),
|
|
5100
|
+
...Object.entries(profiles).sort(([a], [b]) => a.localeCompare(b)).map(([name, refs]) => ({
|
|
5101
|
+
id: `profile:${name}`,
|
|
5102
|
+
label: `Profile: ${name}`,
|
|
5103
|
+
status: refs.length > 0 ? "good" : "muted",
|
|
5104
|
+
summary: `${refs.length} model${refs.length === 1 ? "" : "s"}`,
|
|
5105
|
+
details: [
|
|
5106
|
+
{ label: "name", value: name },
|
|
5107
|
+
{ label: "length", value: String(refs.length) }
|
|
5108
|
+
],
|
|
5109
|
+
body: refs.join(" \u2192 ") || "(empty profile)",
|
|
5110
|
+
actions: [
|
|
5111
|
+
{ key: "u", label: "use", command: `/fallback profile use ${name}`, confirm: true },
|
|
5112
|
+
{ key: "x", label: "delete", command: `/fallback profile remove ${name}`, confirm: true }
|
|
5113
|
+
]
|
|
5114
|
+
})),
|
|
5115
|
+
...favorites.map((ref, index) => ({
|
|
5116
|
+
id: `favorite:${index}`,
|
|
5117
|
+
label: `\u2605 ${ref}`,
|
|
5118
|
+
status: "good",
|
|
5119
|
+
summary: "favorite model",
|
|
5120
|
+
details: [{ label: "model ref", value: ref }],
|
|
5121
|
+
actions: [
|
|
5122
|
+
{
|
|
5123
|
+
key: "x",
|
|
5124
|
+
label: "unfavorite",
|
|
5125
|
+
command: `/fallback fav remove ${index + 1}`,
|
|
5126
|
+
confirm: true
|
|
5127
|
+
}
|
|
5128
|
+
]
|
|
5129
|
+
}))
|
|
5130
|
+
];
|
|
5131
|
+
return {
|
|
5132
|
+
id: "fallback",
|
|
5133
|
+
title: "Fallback routing",
|
|
5134
|
+
subtitle: `${chain.length} explicit \xB7 ${Object.keys(profiles).length} profiles \xB7 ${favorites.length} favorites`,
|
|
5135
|
+
items
|
|
5136
|
+
};
|
|
5137
|
+
}
|
|
5138
|
+
async function profileMenu(store, paths) {
|
|
5139
|
+
const active = store.get().activeProfile ?? paths.profileName ?? "default";
|
|
5140
|
+
let names = [];
|
|
5141
|
+
try {
|
|
5142
|
+
names = (await readdir(paths.profilesDir, { withFileTypes: true })).filter((entry) => entry.isDirectory()).map((entry) => entry.name).sort();
|
|
5143
|
+
} catch {
|
|
5144
|
+
}
|
|
5145
|
+
const items = await Promise.all(
|
|
5146
|
+
names.map(async (name) => {
|
|
5147
|
+
const path14 = paths.profileConfig(name);
|
|
5148
|
+
const data = await readJsonObjectFile(path14);
|
|
5149
|
+
const provider = typeof data["provider"] === "string" ? data["provider"] : "unset";
|
|
5150
|
+
const model = typeof data["model"] === "string" ? data["model"] : "unset";
|
|
5151
|
+
const fallbackCount = Array.isArray(data["fallbackModels"]) ? data["fallbackModels"].length : 0;
|
|
5152
|
+
const profileCount = isRecord(data["fallbackProfiles"]) ? Object.keys(data["fallbackProfiles"]).length : 0;
|
|
5153
|
+
const isActive = name === active;
|
|
5154
|
+
return {
|
|
5155
|
+
id: name,
|
|
5156
|
+
label: name,
|
|
5157
|
+
status: isActive ? "good" : "muted",
|
|
5158
|
+
summary: isActive ? "active" : `${provider}/${model}`,
|
|
5159
|
+
details: [
|
|
5160
|
+
{ label: "active", value: isActive ? "yes" : "no" },
|
|
5161
|
+
{ label: "provider", value: provider },
|
|
5162
|
+
{ label: "model", value: model },
|
|
5163
|
+
{
|
|
5164
|
+
label: "theme",
|
|
5165
|
+
value: typeof data["themePreset"] === "string" ? data["themePreset"] : "default"
|
|
5166
|
+
},
|
|
5167
|
+
{ label: "fallbacks", value: String(fallbackCount) },
|
|
5168
|
+
{ label: "fallback profiles", value: String(profileCount) },
|
|
5169
|
+
{ label: "config", value: path14 }
|
|
5170
|
+
],
|
|
5171
|
+
body: isActive ? "This profile owns the current session configuration." : "Switching profiles closes this session so every service restarts with the selected configuration.",
|
|
5172
|
+
actions: isActive ? [] : [{ key: "s", label: "switch", command: `/profile switch ${name}`, confirm: true }]
|
|
5173
|
+
};
|
|
5174
|
+
})
|
|
5175
|
+
);
|
|
5176
|
+
return {
|
|
5177
|
+
id: "profile",
|
|
5178
|
+
title: "Profiles",
|
|
5179
|
+
subtitle: `active: ${active}`,
|
|
5180
|
+
emptyText: "No profiles found.",
|
|
5181
|
+
items
|
|
5182
|
+
};
|
|
5183
|
+
}
|
|
5184
|
+
function providerStatusMenu(tracker) {
|
|
5185
|
+
const snapshot = tracker?.getSnapshot();
|
|
5186
|
+
const items = snapshot?.statuses.map((status) => ({
|
|
5187
|
+
id: `${status.providerId}/${status.model}`,
|
|
5188
|
+
label: `${status.providerId}/${status.model}`,
|
|
5189
|
+
status: status.state === "healthy" ? "good" : status.state === "degraded" ? "warn" : "bad",
|
|
5190
|
+
summary: status.state,
|
|
5191
|
+
details: [
|
|
5192
|
+
{ label: "state", value: status.state },
|
|
5193
|
+
{ label: "successes", value: String(status.totalSuccesses) },
|
|
5194
|
+
{ label: "failures", value: String(status.totalFailures) },
|
|
5195
|
+
{ label: "rate limits", value: String(status.rateLimitHits) },
|
|
5196
|
+
{ label: "consecutive failures", value: String(status.consecutiveFailures) },
|
|
5197
|
+
{
|
|
5198
|
+
label: "cooldown",
|
|
5199
|
+
value: status.stateExpiresAt ? new Date(status.stateExpiresAt).toLocaleString() : "none"
|
|
5200
|
+
},
|
|
5201
|
+
{ label: "last error kind", value: status.lastErrorKind ?? "none" }
|
|
5202
|
+
],
|
|
5203
|
+
body: status.lastErrorMessage ?? "No recorded error.",
|
|
5204
|
+
actions: [
|
|
5205
|
+
...status.state !== "healthy" ? [
|
|
5206
|
+
{
|
|
5207
|
+
key: "r",
|
|
5208
|
+
label: "retry now",
|
|
5209
|
+
command: `/provider-status retry ${status.providerId} ${status.model}`
|
|
5210
|
+
}
|
|
5211
|
+
] : [],
|
|
5212
|
+
{
|
|
5213
|
+
key: "x",
|
|
5214
|
+
label: "clear history",
|
|
5215
|
+
command: `/provider-status clear ${status.providerId} ${status.model}`,
|
|
5216
|
+
confirm: true
|
|
5217
|
+
}
|
|
5218
|
+
]
|
|
5219
|
+
})) ?? [];
|
|
5220
|
+
return {
|
|
5221
|
+
id: "provider-status",
|
|
5222
|
+
title: "Provider health",
|
|
5223
|
+
subtitle: snapshot ? `${snapshot.healthy} healthy \xB7 ${snapshot.degraded} degraded \xB7 ${snapshot.blocked} blocked` : "tracker unavailable",
|
|
5224
|
+
emptyText: "No provider/model activity has been recorded.",
|
|
5225
|
+
items
|
|
5226
|
+
};
|
|
5227
|
+
}
|
|
5228
|
+
async function memoryMenu(store) {
|
|
5229
|
+
if (!store)
|
|
5230
|
+
return {
|
|
5231
|
+
id: "memory",
|
|
5232
|
+
title: "Memory",
|
|
5233
|
+
emptyText: "Memory is disabled in this host.",
|
|
5234
|
+
items: []
|
|
5235
|
+
};
|
|
5236
|
+
const [health, entries] = await Promise.all([store.health(), store.list(void 0, 100)]);
|
|
5237
|
+
return {
|
|
5238
|
+
id: "memory",
|
|
5239
|
+
title: "Memory",
|
|
5240
|
+
subtitle: `${health.status} \xB7 ${health.backend} \xB7 newest 100`,
|
|
5241
|
+
emptyText: "No memories found.",
|
|
5242
|
+
items: entries.map((entry, index) => ({
|
|
5243
|
+
id: `${entry.ts}:${index}`,
|
|
5244
|
+
label: truncate(entry.text.replace(/\s+/g, " "), 52),
|
|
5245
|
+
status: entry.priority === "critical" || entry.priority === "high" ? "warn" : "muted",
|
|
5246
|
+
summary: `${entry.scope} \xB7 ${entry.type ?? "fact"}`,
|
|
5247
|
+
details: [
|
|
5248
|
+
{ label: "scope", value: entry.scope },
|
|
5249
|
+
{ label: "type", value: entry.type ?? "fact" },
|
|
5250
|
+
{ label: "priority", value: entry.priority ?? "medium" },
|
|
5251
|
+
{
|
|
5252
|
+
label: "confidence",
|
|
5253
|
+
value: entry.confidence === void 0 ? "unspecified" : entry.confidence.toFixed(2)
|
|
5254
|
+
},
|
|
5255
|
+
{ label: "created", value: entry.ts },
|
|
5256
|
+
{ label: "last accessed", value: entry.lastAccessed ?? "never" },
|
|
5257
|
+
{ label: "tags", value: entry.tags?.join(", ") || "none" },
|
|
5258
|
+
{ label: "source", value: entry.source ?? "unknown" }
|
|
5259
|
+
],
|
|
5260
|
+
body: entry.text,
|
|
5261
|
+
actions: entry.scope === "project-memory" ? [
|
|
5262
|
+
{
|
|
5263
|
+
key: "x",
|
|
5264
|
+
label: "forget matching text",
|
|
5265
|
+
command: `/memory forget ${entry.text.replace(/\s+/g, " ").trim()} --exact`,
|
|
5266
|
+
confirm: true
|
|
5267
|
+
}
|
|
5268
|
+
] : []
|
|
5269
|
+
}))
|
|
5270
|
+
};
|
|
5271
|
+
}
|
|
5272
|
+
async function gitMenu(projectRoot) {
|
|
5273
|
+
const [branch, head, status] = await Promise.all([
|
|
5274
|
+
runGit(["branch", "--show-current"], projectRoot),
|
|
5275
|
+
runGit(["rev-parse", "--short", "HEAD"], projectRoot),
|
|
5276
|
+
runGit(["status", "--porcelain=v1"], projectRoot)
|
|
5277
|
+
]);
|
|
5278
|
+
if (status.code !== 0)
|
|
5279
|
+
return { id: "git", title: "Git", emptyText: "Not a git repository.", items: [] };
|
|
5280
|
+
const lines = status.stdout.split(/\r?\n/).filter(Boolean);
|
|
5281
|
+
const items = [
|
|
5282
|
+
{
|
|
5283
|
+
id: "repo",
|
|
5284
|
+
label: branch.stdout.trim() || "(detached)",
|
|
5285
|
+
status: lines.length === 0 ? "good" : "warn",
|
|
5286
|
+
summary: `${head.stdout.trim() || "no HEAD"} \xB7 ${lines.length === 0 ? "clean" : `${lines.length} changes`}`,
|
|
5287
|
+
details: [
|
|
5288
|
+
{ label: "branch", value: branch.stdout.trim() || "(detached)" },
|
|
5289
|
+
{ label: "HEAD", value: head.stdout.trim() || "(unborn)" },
|
|
5290
|
+
{
|
|
5291
|
+
label: "working tree",
|
|
5292
|
+
value: lines.length === 0 ? "clean" : `${lines.length} changed paths`
|
|
5293
|
+
}
|
|
5294
|
+
],
|
|
5295
|
+
actions: [{ key: "c", label: "commit workflow", command: "/commit", confirm: true }]
|
|
5296
|
+
},
|
|
5297
|
+
...lines.map((line, index) => {
|
|
5298
|
+
const code = line.slice(0, 2);
|
|
5299
|
+
const path14 = line.slice(3);
|
|
5300
|
+
const staged = code[0] !== " " && code[0] !== "?";
|
|
5301
|
+
const unstaged = code[1] !== " " || code === "??";
|
|
5302
|
+
return {
|
|
5303
|
+
id: `change:${index}:${path14}`,
|
|
5304
|
+
label: path14,
|
|
5305
|
+
status: staged ? "good" : "warn",
|
|
5306
|
+
summary: `${code} \xB7 ${staged ? "staged" : "not staged"}${unstaged ? " \xB7 working tree" : ""}`,
|
|
5307
|
+
details: [
|
|
5308
|
+
{ label: "status", value: code },
|
|
5309
|
+
{ label: "staged", value: staged ? "yes" : "no" },
|
|
5310
|
+
{ label: "unstaged", value: unstaged ? "yes" : "no" },
|
|
5311
|
+
{ label: "path", value: path14 }
|
|
5312
|
+
],
|
|
5313
|
+
actions: [
|
|
5314
|
+
{ key: "d", label: "diff summary", command: staged ? "/git diff --staged" : "/git diff" }
|
|
5315
|
+
]
|
|
5316
|
+
};
|
|
5317
|
+
})
|
|
5318
|
+
];
|
|
5319
|
+
return { id: "git", title: "Git", subtitle: projectRoot, items };
|
|
5320
|
+
}
|
|
5321
|
+
async function worktreeMenu(projectRoot) {
|
|
5322
|
+
const result = await runGit(["worktree", "list", "--porcelain"], projectRoot);
|
|
5323
|
+
if (result.code !== 0) {
|
|
5324
|
+
return {
|
|
5325
|
+
id: "worktree",
|
|
5326
|
+
title: "Worktrees",
|
|
5327
|
+
emptyText: result.stderr || "Not a git repository.",
|
|
5328
|
+
items: []
|
|
5329
|
+
};
|
|
5330
|
+
}
|
|
5331
|
+
const records = result.stdout.trim().split(/\r?\n\r?\n/).map((block) => block.split(/\r?\n/).filter(Boolean)).filter((lines) => lines.length > 0);
|
|
5332
|
+
const rows = await Promise.all(
|
|
5333
|
+
records.map(async (lines, index) => {
|
|
5334
|
+
const fields = Object.fromEntries(
|
|
5335
|
+
lines.map((line) => {
|
|
5336
|
+
const split = line.indexOf(" ");
|
|
5337
|
+
return split < 0 ? [line, "yes"] : [line.slice(0, split), line.slice(split + 1)];
|
|
5338
|
+
})
|
|
5339
|
+
);
|
|
5340
|
+
const path14 = fields["worktree"] ?? "(unknown path)";
|
|
5341
|
+
const branchRef = fields["branch"];
|
|
5342
|
+
const branch = branchRef?.replace(/^refs\/heads\//, "") ?? (fields["detached"] ? "(detached)" : "(bare)");
|
|
5343
|
+
const status = path14 === "(unknown path)" || fields["prunable"] ? null : await runGit(["status", "--porcelain=v1"], path14);
|
|
5344
|
+
const changes = status?.code === 0 ? status.stdout.split(/\r?\n/).filter(Boolean) : [];
|
|
5345
|
+
const dirty = changes.length > 0;
|
|
5346
|
+
const isMain = index === 0;
|
|
5347
|
+
return {
|
|
5348
|
+
id: path14,
|
|
5349
|
+
label: branch,
|
|
5350
|
+
status: fields["prunable"] ? "bad" : dirty ? "warn" : "good",
|
|
5351
|
+
summary: `${isMain ? "main" : "linked"} \xB7 ${dirty ? `${changes.length} changes` : "clean"}`,
|
|
5352
|
+
details: [
|
|
5353
|
+
{ label: "path", value: path14 },
|
|
5354
|
+
{ label: "branch", value: branch },
|
|
5355
|
+
{ label: "HEAD", value: fields["HEAD"]?.slice(0, 12) ?? "unknown" },
|
|
5356
|
+
{ label: "working tree", value: dirty ? `${changes.length} changed paths` : "clean" },
|
|
5357
|
+
{ label: "locked", value: fields["locked"] ?? "no" },
|
|
5358
|
+
{ label: "prunable", value: fields["prunable"] ?? "no" }
|
|
5359
|
+
],
|
|
5360
|
+
body: changes.slice(0, 30).join("\n") || (isMain ? "Primary checkout." : "Linked checkout."),
|
|
5361
|
+
actions: isMain ? [
|
|
5362
|
+
{ key: "p", label: "prune stale metadata", command: "/worktree prune" },
|
|
5363
|
+
{
|
|
5364
|
+
key: "x",
|
|
5365
|
+
label: "clean managed worktrees",
|
|
5366
|
+
command: "/worktree clean --yes",
|
|
5367
|
+
confirm: true
|
|
5368
|
+
}
|
|
5369
|
+
] : branchRef ? [
|
|
5370
|
+
{
|
|
5371
|
+
key: "m",
|
|
5372
|
+
label: "squash merge",
|
|
5373
|
+
command: `/worktree merge ${branch} --yes`,
|
|
5374
|
+
confirm: true
|
|
5375
|
+
}
|
|
5376
|
+
] : []
|
|
5377
|
+
};
|
|
5378
|
+
})
|
|
5379
|
+
);
|
|
5380
|
+
return {
|
|
5381
|
+
id: "worktree",
|
|
5382
|
+
title: "Worktrees",
|
|
5383
|
+
subtitle: `${rows.length} checkout${rows.length === 1 ? "" : "s"}`,
|
|
5384
|
+
emptyText: "No worktrees found.",
|
|
5385
|
+
items: rows
|
|
5386
|
+
};
|
|
5387
|
+
}
|
|
5388
|
+
function isRecord(value) {
|
|
5389
|
+
return Boolean(value) && typeof value === "object" && !Array.isArray(value);
|
|
5390
|
+
}
|
|
5391
|
+
function truncate(value, max) {
|
|
5392
|
+
return value.length <= max ? value : `${value.slice(0, max - 1)}\u2026`;
|
|
5393
|
+
}
|
|
5394
|
+
|
|
5027
5395
|
// src/execution.ts
|
|
5028
5396
|
async function execute(deps) {
|
|
5029
5397
|
const {
|
|
@@ -5306,6 +5674,14 @@ async function execute(deps) {
|
|
|
5306
5674
|
agent,
|
|
5307
5675
|
events,
|
|
5308
5676
|
slashRegistry,
|
|
5677
|
+
skillLoader,
|
|
5678
|
+
getResourceMenu: createTuiResourceMenuGetter({
|
|
5679
|
+
configStore,
|
|
5680
|
+
paths: wpaths,
|
|
5681
|
+
memoryStore,
|
|
5682
|
+
statusTracker,
|
|
5683
|
+
projectRoot
|
|
5684
|
+
}),
|
|
5309
5685
|
secretInputController,
|
|
5310
5686
|
attachments,
|
|
5311
5687
|
tokenCounter,
|
|
@@ -5622,4 +5998,4 @@ export {
|
|
|
5622
5998
|
execute,
|
|
5623
5999
|
resolveReviewerFallbackModels
|
|
5624
6000
|
};
|
|
5625
|
-
//# sourceMappingURL=execution-
|
|
6001
|
+
//# sourceMappingURL=execution-4IG5XKOL.js.map
|
package/dist/index.js
CHANGED
|
@@ -42,11 +42,11 @@ import {
|
|
|
42
42
|
parseArgs,
|
|
43
43
|
runPicker,
|
|
44
44
|
saveToGlobalConfig
|
|
45
|
-
} from "./chunk-
|
|
45
|
+
} from "./chunk-KXN5HZDL.js";
|
|
46
46
|
import {
|
|
47
47
|
isKeylessLocalProvider,
|
|
48
48
|
visibleModelIds
|
|
49
|
-
} from "./chunk-
|
|
49
|
+
} from "./chunk-VUVOMXWP.js";
|
|
50
50
|
import {
|
|
51
51
|
mutateConfigProviders,
|
|
52
52
|
normalizeKeys,
|
|
@@ -718,7 +718,7 @@ async function launchDesktop(args) {
|
|
|
718
718
|
var loaders = {
|
|
719
719
|
acp: async () => (await import("./acp-5ZLGFHWP.js")).acpCmd,
|
|
720
720
|
init: async () => (await import("./init-E2NDDOHI.js")).initCmd,
|
|
721
|
-
auth: async () => (await import("./auth-
|
|
721
|
+
auth: async () => (await import("./auth-L3WGSGDX.js")).authCmd,
|
|
722
722
|
update: async () => (await import("./update-VZSOZGYC.js")).updateCmd,
|
|
723
723
|
sessions: async () => (await import("./sessions-config-YX2ZPAFM.js")).sessionsCmd,
|
|
724
724
|
config: async () => (await import("./sessions-config-YX2ZPAFM.js")).configCmd,
|
|
@@ -727,8 +727,8 @@ var loaders = {
|
|
|
727
727
|
audit: async () => (await import("./audit-BBR22QH3.js")).auditCmd,
|
|
728
728
|
tools: async () => (await import("./tools-skills-UNKLOB7M.js")).toolsCmd,
|
|
729
729
|
skills: async () => (await import("./tools-skills-UNKLOB7M.js")).skillsCmd,
|
|
730
|
-
providers: async () => (await import("./providers-models-
|
|
731
|
-
models: async () => (await import("./providers-models-
|
|
730
|
+
providers: async () => (await import("./providers-models-HQN3AT3K.js")).providersCmd,
|
|
731
|
+
models: async () => (await import("./providers-models-HQN3AT3K.js")).modelsCmd,
|
|
732
732
|
mcp: async () => (await import("./mcp-MSARYOPN.js")).mcpCmd,
|
|
733
733
|
plugin: async () => (await import("./plugin-usage-PTEETL3J.js")).pluginCmd,
|
|
734
734
|
plugins: async () => (await import("./plugin-usage-PTEETL3J.js")).pluginCmd,
|
|
@@ -3302,7 +3302,7 @@ async function initializeCli(argv) {
|
|
|
3302
3302
|
async function main(argv) {
|
|
3303
3303
|
const cliCtx = await initializeCli(argv);
|
|
3304
3304
|
if (typeof cliCtx === "number") return cliCtx;
|
|
3305
|
-
const { runInteractive } = await import("./cli-main-
|
|
3305
|
+
const { runInteractive } = await import("./cli-main-3PUWFKSL.js");
|
|
3306
3306
|
return runInteractive(cliCtx);
|
|
3307
3307
|
}
|
|
3308
3308
|
|
|
@@ -49,11 +49,7 @@ export declare function hasApiKey(provider: ResolvedProvider, config?: Config):
|
|
|
49
49
|
* Models are inlined from the catalog (or from `cfg.models` for custom
|
|
50
50
|
* entries) so the picker can show a real selection.
|
|
51
51
|
*/
|
|
52
|
-
export declare function buildPickableProviders(modelsRegistry: ModelsRegistry, config: Config): Promise<Array<
|
|
53
|
-
id: string;
|
|
54
|
-
family: string;
|
|
55
|
-
models: string[];
|
|
56
|
-
}>>;
|
|
52
|
+
export declare function buildPickableProviders(modelsRegistry: ModelsRegistry, config: Config): Promise<Array<import('@wrongstack/tui').ProviderOption>>;
|
|
57
53
|
/**
|
|
58
54
|
* Resolve a provider id that may be an alias. When the user has
|
|
59
55
|
* `providers[id].type` pointing at a different catalog entry, return
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import {
|
|
2
2
|
visibleModelIds
|
|
3
|
-
} from "./chunk-
|
|
3
|
+
} from "./chunk-VUVOMXWP.js";
|
|
4
4
|
import {
|
|
5
5
|
mutateConfigProviders
|
|
6
6
|
} from "./chunk-SZ42FYPT.js";
|
|
@@ -661,4 +661,4 @@ export {
|
|
|
661
661
|
modelsCmd,
|
|
662
662
|
providersCmd
|
|
663
663
|
};
|
|
664
|
-
//# sourceMappingURL=providers-models-
|
|
664
|
+
//# sourceMappingURL=providers-models-HQN3AT3K.js.map
|
|
@@ -0,0 +1,18 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Run a `git` subcommand and capture its output.
|
|
3
|
+
*
|
|
4
|
+
* Lives in `services/` rather than beside the `/git` slash command because it
|
|
5
|
+
* is shared infrastructure, not command logic: it has no `SlashCommandContext`
|
|
6
|
+
* and no rendering. The TUI resource menus need the same child process, and a
|
|
7
|
+
* non-command module importing `slash-commands/git.ts` is exactly the boundary
|
|
8
|
+
* the architecture check rejects.
|
|
9
|
+
*
|
|
10
|
+
* Never rejects on a non-zero exit — the caller inspects `code`. It rejects
|
|
11
|
+
* only when git could not be spawned at all, or when the 30s timeout fires.
|
|
12
|
+
*/
|
|
13
|
+
export declare function runGit(args: string[], cwd: string): Promise<{
|
|
14
|
+
stdout: string;
|
|
15
|
+
stderr: string;
|
|
16
|
+
code: number;
|
|
17
|
+
}>;
|
|
18
|
+
//# sourceMappingURL=run-git.d.ts.map
|
|
@@ -1,10 +1,5 @@
|
|
|
1
1
|
import type { SlashCommand } from '@wrongstack/core/types';
|
|
2
2
|
import type { SlashCommandContext } from './command-context.js';
|
|
3
|
-
export declare function runGit(args: string[], cwd: string): Promise<{
|
|
4
|
-
stdout: string;
|
|
5
|
-
stderr: string;
|
|
6
|
-
code: number;
|
|
7
|
-
}>;
|
|
8
3
|
/**
|
|
9
4
|
* Read-only operational Git command. Mutating workflows remain on `/commit`,
|
|
10
5
|
* `/push`, and the permission-gated `git` tool.
|
|
@@ -1,5 +1,37 @@
|
|
|
1
1
|
import type { InputReader, SlashCommand } from '@wrongstack/core/types';
|
|
2
2
|
import type { SlashCommandContext } from './command-context.js';
|
|
3
|
+
/**
|
|
4
|
+
* Windowed slice of the theme list for the raw-terminal picker — mirrors the
|
|
5
|
+
* math in the TUI's `useWindowedPicker` (same centering + marker rules) so
|
|
6
|
+
* both pickers agree on how many presets fit and which rows are visible.
|
|
7
|
+
* `rows` is the raw terminal height; the picker reserves its chrome (header,
|
|
8
|
+
* hint, blanks) plus worst-case marker rows up front, so a 24-row terminal
|
|
9
|
+
* never renders all 40 presets.
|
|
10
|
+
*
|
|
11
|
+
* Exported for direct unit testing (packages/cli/tests/slash-theme.test.ts);
|
|
12
|
+
* the picker itself treats it as private.
|
|
13
|
+
*/
|
|
14
|
+
export declare function computeWindow(total: number, selected: number, rows: number): {
|
|
15
|
+
start: number;
|
|
16
|
+
end: number;
|
|
17
|
+
hasAbove: boolean;
|
|
18
|
+
hasBelow: boolean;
|
|
19
|
+
};
|
|
20
|
+
/**
|
|
21
|
+
* Truncate an option's description so the rendered row never wraps on a
|
|
22
|
+
* narrow terminal. `computeWindow` budgets ONE terminal row per option; a
|
|
23
|
+
* description that wrapped onto a second physical line would silently break
|
|
24
|
+
* that budget and re-introduce the vertical overflow this picker was fixed
|
|
25
|
+
* to avoid. The description is plain text here (color-wrapped by the caller
|
|
26
|
+
* AFTER truncation), so measuring its length is ANSI-safe.
|
|
27
|
+
*
|
|
28
|
+
* Fixed chrome per row: 2 indent + 2 cursor + 21 name + 1 gap = 26 columns,
|
|
29
|
+
* plus the ` [active]` mark (9 columns) when the option is the active preset.
|
|
30
|
+
*
|
|
31
|
+
* Exported for direct unit testing (packages/cli/tests/slash-theme.test.ts);
|
|
32
|
+
* the picker itself treats it as private.
|
|
33
|
+
*/
|
|
34
|
+
export declare function truncateDesc(desc: string, columns: number, active: boolean): string;
|
|
3
35
|
export declare function buildThemeCommand(opts: SlashCommandContext & {
|
|
4
36
|
inputReader?: InputReader | undefined;
|
|
5
37
|
}): SlashCommand;
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import type { ProviderModelStatusTracker } from '@wrongstack/core/coordination';
|
|
2
|
+
import type { ConfigStore, MemoryPort } from '@wrongstack/core/types';
|
|
3
|
+
import type { WstackPaths } from '@wrongstack/core/utils';
|
|
4
|
+
import type { ResourceMenuId, ResourceMenuSnapshot } from '@wrongstack/tui';
|
|
5
|
+
export interface TuiResourceMenuContext {
|
|
6
|
+
configStore: ConfigStore;
|
|
7
|
+
paths: WstackPaths;
|
|
8
|
+
memoryStore?: MemoryPort | undefined;
|
|
9
|
+
statusTracker?: ProviderModelStatusTracker | undefined;
|
|
10
|
+
projectRoot: string;
|
|
11
|
+
}
|
|
12
|
+
export declare function createTuiResourceMenuGetter(ctx: TuiResourceMenuContext): (id: ResourceMenuId) => Promise<ResourceMenuSnapshot>;
|
|
13
|
+
//# sourceMappingURL=tui-resource-menus.d.ts.map
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@wrongstack/cli",
|
|
3
|
-
"version": "0.306.
|
|
3
|
+
"version": "0.306.2",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"description": "WrongStack CLI — terminal AI coding agent with provider catalog from models.dev. Provides `wrongstack` and `wstack` binaries.",
|
|
6
6
|
"keywords": [
|
|
@@ -42,31 +42,31 @@
|
|
|
42
42
|
],
|
|
43
43
|
"dependencies": {
|
|
44
44
|
"ws": "^8.21.1",
|
|
45
|
-
"@wrongstack/
|
|
46
|
-
"@wrongstack/
|
|
47
|
-
"@wrongstack/
|
|
48
|
-
"@wrongstack/core": "0.306.
|
|
49
|
-
"@wrongstack/
|
|
50
|
-
"@wrongstack/
|
|
51
|
-
"@wrongstack/
|
|
52
|
-
"@wrongstack/
|
|
53
|
-
"@wrongstack/requirement-intake": "0.306.
|
|
54
|
-
"@wrongstack/
|
|
55
|
-
"@wrongstack/
|
|
56
|
-
"@wrongstack/
|
|
57
|
-
"@wrongstack/sage": "0.306.
|
|
58
|
-
"@wrongstack/
|
|
59
|
-
"@wrongstack/
|
|
60
|
-
"@wrongstack/
|
|
61
|
-
"@wrongstack/
|
|
62
|
-
"@wrongstack/
|
|
63
|
-
"@wrongstack/webui
|
|
64
|
-
"@wrongstack/
|
|
65
|
-
"@wrongstack/
|
|
66
|
-
"@wrongstack/
|
|
45
|
+
"@wrongstack/acp": "0.306.2",
|
|
46
|
+
"@wrongstack/mcp": "0.306.2",
|
|
47
|
+
"@wrongstack/kanban": "0.306.2",
|
|
48
|
+
"@wrongstack/core": "0.306.2",
|
|
49
|
+
"@wrongstack/providers": "0.306.2",
|
|
50
|
+
"@wrongstack/bench": "0.306.2",
|
|
51
|
+
"@wrongstack/plug-lsp": "0.306.2",
|
|
52
|
+
"@wrongstack/persistence": "0.306.2",
|
|
53
|
+
"@wrongstack/requirement-intake": "0.306.2",
|
|
54
|
+
"@wrongstack/plugins": "0.306.2",
|
|
55
|
+
"@wrongstack/sdd": "0.306.2",
|
|
56
|
+
"@wrongstack/security-scanner": "0.306.2",
|
|
57
|
+
"@wrongstack/sage": "0.306.2",
|
|
58
|
+
"@wrongstack/runtime": "0.306.2",
|
|
59
|
+
"@wrongstack/telegram": "0.306.2",
|
|
60
|
+
"@wrongstack/simpleui": "0.306.2",
|
|
61
|
+
"@wrongstack/techstack": "0.306.2",
|
|
62
|
+
"@wrongstack/webui-hq": "0.306.2",
|
|
63
|
+
"@wrongstack/webui": "0.306.2",
|
|
64
|
+
"@wrongstack/tui": "0.306.2",
|
|
65
|
+
"@wrongstack/webui-server": "0.306.2",
|
|
66
|
+
"@wrongstack/tools": "0.306.2"
|
|
67
67
|
},
|
|
68
68
|
"optionalDependencies": {
|
|
69
|
-
"@wrongstack/desktop": "0.306.
|
|
69
|
+
"@wrongstack/desktop": "0.306.2"
|
|
70
70
|
},
|
|
71
71
|
"devDependencies": {
|
|
72
72
|
"@types/node": "^26.1.2",
|