@duckmind/dm-darwin-x64 0.35.9 → 0.36.0
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/dm
CHANGED
|
Binary file
|
|
@@ -87,7 +87,7 @@ describe("registerCommands", () => {
|
|
|
87
87
|
);
|
|
88
88
|
});
|
|
89
89
|
|
|
90
|
-
it("returns
|
|
90
|
+
it("returns restored autocomplete while hiding repair-only account identifiers", () => {
|
|
91
91
|
const registerCommand = vi.fn();
|
|
92
92
|
registerCommands(
|
|
93
93
|
{ registerCommand } as never,
|
|
@@ -102,21 +102,29 @@ describe("registerCommands", () => {
|
|
|
102
102
|
};
|
|
103
103
|
|
|
104
104
|
const subcommands = commandOptions.getArgumentCompletions("");
|
|
105
|
-
expect(subcommands?.map((item) => item.value)).toEqual([
|
|
105
|
+
expect(subcommands?.map((item) => item.value)).toEqual([
|
|
106
|
+
"sync",
|
|
107
|
+
"use",
|
|
108
|
+
"show",
|
|
109
|
+
"rotation",
|
|
110
|
+
"verify",
|
|
111
|
+
"path",
|
|
112
|
+
"reset",
|
|
113
|
+
"help",
|
|
114
|
+
]);
|
|
106
115
|
expect(subcommands?.map((item) => item.value)).not.toContain("accounts");
|
|
107
|
-
expect(subcommands?.map((item) => item.value)).not.toContain("show");
|
|
108
|
-
expect(subcommands?.map((item) => item.value)).not.toContain("use");
|
|
109
116
|
expect(subcommands?.map((item) => item.value)).not.toContain("refresh");
|
|
110
|
-
expect(subcommands?.map((item) => item.value)).not.toContain("rotation");
|
|
111
117
|
expect(subcommands?.map((item) => item.value)).not.toContain("reauth");
|
|
112
118
|
expect(subcommands?.map((item) => item.value)).not.toContain("footer");
|
|
113
|
-
expect(subcommands?.map((item) => item.value)).not.toContain("verify");
|
|
114
|
-
expect(subcommands?.map((item) => item.value)).not.toContain("path");
|
|
115
|
-
expect(subcommands?.map((item) => item.value)).not.toContain("reset");
|
|
116
|
-
expect(subcommands?.map((item) => item.value)).not.toContain("help");
|
|
117
119
|
|
|
118
120
|
const useAccounts = commandOptions.getArgumentCompletions("use a");
|
|
119
|
-
expect(useAccounts).
|
|
121
|
+
expect(useAccounts).toEqual([
|
|
122
|
+
{ value: "use alpha@example.com", label: "alpha@example.com" },
|
|
123
|
+
]);
|
|
124
|
+
|
|
125
|
+
expect(commandOptions.getArgumentCompletions("reset m")).toEqual([
|
|
126
|
+
{ value: "reset manual", label: "manual" },
|
|
127
|
+
]);
|
|
120
128
|
|
|
121
129
|
const refreshAccounts = commandOptions.getArgumentCompletions("refresh a");
|
|
122
130
|
expect(refreshAccounts).toBeNull();
|
|
@@ -140,12 +148,12 @@ describe("registerCommands", () => {
|
|
|
140
148
|
});
|
|
141
149
|
|
|
142
150
|
expect(notify).toHaveBeenCalledWith(
|
|
143
|
-
"/ultradex requires a subcommand in non-interactive mode. Use /ultradex
|
|
151
|
+
"/ultradex requires a subcommand in non-interactive mode. Use /ultradex help.",
|
|
144
152
|
"warning",
|
|
145
153
|
);
|
|
146
154
|
});
|
|
147
155
|
|
|
148
|
-
it("hides
|
|
156
|
+
it("hides repair-only subcommands even when typed directly", async () => {
|
|
149
157
|
const registerCommand = vi.fn();
|
|
150
158
|
registerCommands(
|
|
151
159
|
{ registerCommand } as never,
|
|
@@ -162,7 +170,57 @@ describe("registerCommands", () => {
|
|
|
162
170
|
ui: { notify },
|
|
163
171
|
});
|
|
164
172
|
|
|
165
|
-
expect(notify).toHaveBeenCalledWith(
|
|
173
|
+
expect(notify).toHaveBeenCalledWith(
|
|
174
|
+
expect.stringContaining(
|
|
175
|
+
"use: select, activate, or remove managed account",
|
|
176
|
+
),
|
|
177
|
+
"info",
|
|
178
|
+
);
|
|
179
|
+
const helpText = String(notify.mock.calls.at(-1)?.[0] ?? "");
|
|
180
|
+
for (const label of [
|
|
181
|
+
"sync: download and decrypt DuckMind managed accounts",
|
|
182
|
+
"use: select, activate, or remove managed account",
|
|
183
|
+
"show: managed account and usage summary",
|
|
184
|
+
"rotation: current rotation behavior",
|
|
185
|
+
"verify: runtime health checks",
|
|
186
|
+
"path: storage and settings locations",
|
|
187
|
+
"reset: clear manual or quota state",
|
|
188
|
+
"help: command usage",
|
|
189
|
+
]) {
|
|
190
|
+
expect(helpText).toContain(label);
|
|
191
|
+
}
|
|
192
|
+
});
|
|
193
|
+
|
|
194
|
+
it("runs restored state subcommands instead of falling back to sync-only help", async () => {
|
|
195
|
+
const registerCommand = vi.fn();
|
|
196
|
+
const accountManager = {
|
|
197
|
+
getAccounts: () => [],
|
|
198
|
+
hasManualAccount: vi.fn(() => true),
|
|
199
|
+
clearManualAccount: vi.fn(),
|
|
200
|
+
clearAllQuotaExhaustion: vi.fn(() => 0),
|
|
201
|
+
} as unknown as AccountManager;
|
|
202
|
+
const statusController = createStatusControllerMock();
|
|
203
|
+
registerCommands(
|
|
204
|
+
{ registerCommand } as never,
|
|
205
|
+
accountManager,
|
|
206
|
+
statusController,
|
|
207
|
+
);
|
|
208
|
+
|
|
209
|
+
const commandOptions = registerCommand.mock.calls[0]?.[1] as {
|
|
210
|
+
handler: (args: string, ctx: unknown) => Promise<void>;
|
|
211
|
+
};
|
|
212
|
+
const notify = vi.fn();
|
|
213
|
+
await commandOptions.handler("reset manual", {
|
|
214
|
+
hasUI: false,
|
|
215
|
+
ui: { notify },
|
|
216
|
+
});
|
|
217
|
+
|
|
218
|
+
expect(accountManager.clearManualAccount).toHaveBeenCalledOnce();
|
|
219
|
+
expect(mocks.syncManagedAccountsFromDuckMind).not.toHaveBeenCalled();
|
|
220
|
+
expect(notify).toHaveBeenCalledWith(
|
|
221
|
+
expect.stringContaining("reset: target=manual"),
|
|
222
|
+
"info",
|
|
223
|
+
);
|
|
166
224
|
});
|
|
167
225
|
|
|
168
226
|
it("uses the explicit sync secret without remembering it after a successful sync", async () => {
|
|
@@ -33,8 +33,17 @@ import { formatResetAt, isUsageUntouched } from "./usage";
|
|
|
33
33
|
const SETTINGS_FILE = getAgentSettingsPath();
|
|
34
34
|
const NO_ACCOUNTS_MESSAGE =
|
|
35
35
|
"No managed accounts found. Run /ultradex sync <secret> to import DuckMind managed accounts.";
|
|
36
|
-
const HELP_TEXT =
|
|
37
|
-
"Usage: /ultradex sync [secret]"
|
|
36
|
+
const HELP_TEXT = [
|
|
37
|
+
"Usage: /ultradex [sync [secret]|use [identifier]|show|rotation|verify|path|reset [manual|quota|all]|help]",
|
|
38
|
+
"sync: download and decrypt DuckMind managed accounts",
|
|
39
|
+
"use: select, activate, or remove managed account",
|
|
40
|
+
"show: managed account and usage summary",
|
|
41
|
+
"rotation: current rotation behavior",
|
|
42
|
+
"verify: runtime health checks",
|
|
43
|
+
"path: storage and settings locations",
|
|
44
|
+
"reset: clear manual or quota state",
|
|
45
|
+
"help: command usage",
|
|
46
|
+
].join("\n");
|
|
38
47
|
const SUBCOMMANDS = [
|
|
39
48
|
"accounts",
|
|
40
49
|
"use",
|
|
@@ -52,6 +61,13 @@ const SUBCOMMANDS = [
|
|
|
52
61
|
const RESET_TARGETS = ["manual", "quota", "all"] as const;
|
|
53
62
|
const VISIBLE_SUBCOMMANDS = [
|
|
54
63
|
"sync",
|
|
64
|
+
"use",
|
|
65
|
+
"show",
|
|
66
|
+
"rotation",
|
|
67
|
+
"verify",
|
|
68
|
+
"path",
|
|
69
|
+
"reset",
|
|
70
|
+
"help",
|
|
55
71
|
] as const;
|
|
56
72
|
|
|
57
73
|
type Subcommand = (typeof SUBCOMMANDS)[number];
|
|
@@ -156,6 +172,10 @@ function getSubcommandCompletions(prefix: string): AutocompleteItem[] | null {
|
|
|
156
172
|
return matches.length > 0 ? toAutocompleteItems(matches) : null;
|
|
157
173
|
}
|
|
158
174
|
|
|
175
|
+
function isVisibleSubcommand(value: Subcommand): boolean {
|
|
176
|
+
return VISIBLE_SUBCOMMANDS.some((subcommand) => subcommand === value);
|
|
177
|
+
}
|
|
178
|
+
|
|
159
179
|
function getAccountCompletions(
|
|
160
180
|
subcommand: "accounts" | "use" | "reauth",
|
|
161
181
|
prefix: string,
|
|
@@ -208,6 +228,16 @@ function getCommandCompletions(
|
|
|
208
228
|
return getSubcommandCompletions(trimmedStart.toLowerCase());
|
|
209
229
|
}
|
|
210
230
|
|
|
231
|
+
const subcommand = trimmedStart.slice(0, firstSpaceIndex).toLowerCase();
|
|
232
|
+
const rest = trimmedStart.slice(firstSpaceIndex + 1).trimStart();
|
|
233
|
+
|
|
234
|
+
if (subcommand === "use") {
|
|
235
|
+
return getAccountCompletions("use", rest, accountManager);
|
|
236
|
+
}
|
|
237
|
+
if (subcommand === "reset") {
|
|
238
|
+
return getResetCompletions(rest);
|
|
239
|
+
}
|
|
240
|
+
|
|
211
241
|
return null;
|
|
212
242
|
}
|
|
213
243
|
|
|
@@ -1016,6 +1046,13 @@ async function openMainPanel(
|
|
|
1016
1046
|
): Promise<void> {
|
|
1017
1047
|
const actions = [
|
|
1018
1048
|
"sync: download and decrypt DuckMind managed accounts",
|
|
1049
|
+
"use: select, activate, or remove managed account",
|
|
1050
|
+
"show: managed account and usage summary",
|
|
1051
|
+
"rotation: current rotation behavior",
|
|
1052
|
+
"verify: runtime health checks",
|
|
1053
|
+
"path: storage and settings locations",
|
|
1054
|
+
"reset: clear manual or quota state",
|
|
1055
|
+
"help: command usage",
|
|
1019
1056
|
];
|
|
1020
1057
|
|
|
1021
1058
|
const selected = await ctx.ui.select("Ultradex", actions);
|
|
@@ -1043,7 +1080,7 @@ export function registerCommands(
|
|
|
1043
1080
|
): void {
|
|
1044
1081
|
pi.registerCommand("ultradex", {
|
|
1045
1082
|
description:
|
|
1046
|
-
"
|
|
1083
|
+
"Manage Ultradex sync, account selection, status, rotation, and health",
|
|
1047
1084
|
getArgumentCompletions: (argumentPrefix: string) =>
|
|
1048
1085
|
getCommandCompletions(argumentPrefix, accountManager),
|
|
1049
1086
|
handler: async (
|
|
@@ -1054,7 +1091,7 @@ export function registerCommands(
|
|
|
1054
1091
|
if (!parsed.subcommand) {
|
|
1055
1092
|
if (!ctx.hasUI) {
|
|
1056
1093
|
ctx.ui.notify(
|
|
1057
|
-
"/ultradex requires a subcommand in non-interactive mode. Use /ultradex
|
|
1094
|
+
"/ultradex requires a subcommand in non-interactive mode. Use /ultradex help.",
|
|
1058
1095
|
"warning",
|
|
1059
1096
|
);
|
|
1060
1097
|
return;
|
|
@@ -1063,17 +1100,17 @@ export function registerCommands(
|
|
|
1063
1100
|
return;
|
|
1064
1101
|
}
|
|
1065
1102
|
|
|
1066
|
-
|
|
1067
|
-
|
|
1068
|
-
|
|
1069
|
-
|
|
1070
|
-
|
|
1071
|
-
|
|
1072
|
-
|
|
1073
|
-
|
|
1074
|
-
|
|
1103
|
+
if (!isSubcommand(parsed.subcommand)) {
|
|
1104
|
+
ctx.ui.notify(`Unknown subcommand: ${parsed.subcommand}`, "warning");
|
|
1105
|
+
runHelpSubcommand(ctx);
|
|
1106
|
+
return;
|
|
1107
|
+
}
|
|
1108
|
+
if (!isVisibleSubcommand(parsed.subcommand)) {
|
|
1109
|
+
runHelpSubcommand(ctx);
|
|
1110
|
+
return;
|
|
1111
|
+
}
|
|
1075
1112
|
|
|
1076
|
-
|
|
1113
|
+
await runSubcommand(
|
|
1077
1114
|
parsed.subcommand,
|
|
1078
1115
|
parsed.rest,
|
|
1079
1116
|
pi,
|
|
@@ -3605,9 +3605,9 @@
|
|
|
3605
3605
|
"license": "MIT"
|
|
3606
3606
|
},
|
|
3607
3607
|
"node_modules/cosmiconfig": {
|
|
3608
|
-
"version": "9.0.
|
|
3609
|
-
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.
|
|
3610
|
-
"integrity": "sha512-
|
|
3608
|
+
"version": "9.0.2",
|
|
3609
|
+
"resolved": "https://registry.npmjs.org/cosmiconfig/-/cosmiconfig-9.0.2.tgz",
|
|
3610
|
+
"integrity": "sha512-gtTZxTDau1wL7Y7zifc2dd8jHSK/k6BTx/2Xp/BpdlAdnlYWFVt7qhJqgwi7637yRwRQ3qL4ZidbB4I8tA5VOg==",
|
|
3611
3611
|
"dev": true,
|
|
3612
3612
|
"license": "MIT",
|
|
3613
3613
|
"dependencies": {
|