dgxay-code-cli 1.0.0 → 1.1.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/README-zh.md +50 -8
- package/README.md +50 -9
- package/package.json +1 -1
- package/src/cli/ansi.js +38 -8
- package/src/cli/approval.js +11 -11
- package/src/cli/editor.js +456 -202
- package/src/cli/i18n.js +276 -0
- package/src/cli/index.js +34 -34
- package/src/cli/print.js +5 -5
- package/src/cli/render.js +147 -76
- package/src/cli/repl.js +205 -141
- package/src/cli/slash.js +29 -28
- package/src/cli/ui.js +8 -8
- package/src/commands/chat.js +45 -45
- package/src/commands/config.js +81 -81
- package/src/commands/context.js +5 -5
- package/src/commands/doctor.js +34 -34
- package/src/commands/export.js +13 -13
- package/src/commands/mcp.js +51 -51
- package/src/commands/model.js +38 -38
- package/src/commands/oauth.js +61 -61
- package/src/commands/permission.js +19 -19
- package/src/commands/provider.js +70 -70
- package/src/commands/run.js +20 -20
- package/src/commands/skill.js +15 -15
- package/src/commands/workspace.js +18 -18
- package/src/core/agent.js +19 -18
- package/src/core/llm.js +10 -10
- package/src/core/mcp.js +5 -5
- package/src/core/oauth.js +36 -36
- package/src/core/prompt.js +46 -46
- package/src/core/sessions.js +7 -7
- package/src/core/tools.js +24 -24
- package/src/services/input.js +1 -1
- package/src/services/settings.js +28 -28
- package/src/services/skills.js +1 -1
- package/src/services/terminal.js +3 -3
package/src/commands/provider.js
CHANGED
|
@@ -21,15 +21,15 @@ const oauth = require('../core/oauth');
|
|
|
21
21
|
const { ask, askSecret, confirm } = require('../services/input');
|
|
22
22
|
|
|
23
23
|
const options = [
|
|
24
|
-
{ name: 'name', type: 'string', valueName: 'text', desc: '
|
|
24
|
+
{ name: 'name', type: 'string', valueName: 'text', desc: 'Provider name' },
|
|
25
25
|
{ name: 'protocol', type: 'string', valueName: 'p', desc: 'openai / anthropic / responses' },
|
|
26
|
-
{ name: 'base-url', type: 'string', valueName: 'url', desc: '
|
|
26
|
+
{ name: 'base-url', type: 'string', valueName: 'url', desc: 'Base URL' },
|
|
27
27
|
{ name: 'api-key', type: 'string', valueName: 'key', desc: 'API Key' },
|
|
28
|
-
{ name: 'model', type: 'list', valueName: 'id', desc: '
|
|
29
|
-
{ name: 'oauth-provider', type: 'string', valueName: 'id', desc: '
|
|
30
|
-
{ name: 'review-model', type: 'string', valueName: 'id', desc: '
|
|
31
|
-
{ name: 'context-window', type: 'number', valueName: 'n', desc: '
|
|
32
|
-
{ name: 'yes', alias: 'y', type: 'boolean', desc: '
|
|
28
|
+
{ name: 'model', type: 'list', valueName: 'id', desc: 'Model ID (repeatable or comma-separated)' },
|
|
29
|
+
{ name: 'oauth-provider', type: 'string', valueName: 'id', desc: 'Use a connected OAuth account' },
|
|
30
|
+
{ name: 'review-model', type: 'string', valueName: 'id', desc: 'Auto review model ID' },
|
|
31
|
+
{ name: 'context-window', type: 'number', valueName: 'n', desc: 'Context window (optional)' },
|
|
32
|
+
{ name: 'yes', alias: 'y', type: 'boolean', desc: 'Skip confirmation' }
|
|
33
33
|
];
|
|
34
34
|
|
|
35
35
|
function list() {
|
|
@@ -37,15 +37,15 @@ function list() {
|
|
|
37
37
|
const providers = config.providers || [];
|
|
38
38
|
print.blank();
|
|
39
39
|
if (!providers.length) {
|
|
40
|
-
print.hint('
|
|
40
|
+
print.hint('No providers yet. Run dgxay provider add or dgxay config init');
|
|
41
41
|
print.blank();
|
|
42
42
|
return 0;
|
|
43
43
|
}
|
|
44
|
-
print.heading(
|
|
44
|
+
print.heading(`Providers (${providers.length})`);
|
|
45
45
|
const rows = providers.map((provider, index) => [
|
|
46
46
|
String(index + 1),
|
|
47
|
-
index === 0 ? COLORS.accent('
|
|
48
|
-
provider.id === config.activeProviderId ? COLORS.green('
|
|
47
|
+
index === 0 ? COLORS.accent('default') : '',
|
|
48
|
+
provider.id === config.activeProviderId ? COLORS.green('active') : '',
|
|
49
49
|
provider.name,
|
|
50
50
|
settings.PROTOCOL_META[provider.protocol || 'openai'].short,
|
|
51
51
|
provider.baseUrl,
|
|
@@ -58,17 +58,17 @@ function list() {
|
|
|
58
58
|
{ title: '#', max: 3 },
|
|
59
59
|
{ title: '', max: 4 },
|
|
60
60
|
{ title: '', max: 4 },
|
|
61
|
-
{ title: '
|
|
62
|
-
{ title: '
|
|
61
|
+
{ title: 'Name', max: 16 },
|
|
62
|
+
{ title: 'Protocol', max: 16 },
|
|
63
63
|
{ title: 'Base URL', max: 40 },
|
|
64
|
-
{ title: '
|
|
65
|
-
{ title: '
|
|
66
|
-
{ title: '
|
|
64
|
+
{ title: 'Models', max: 30 },
|
|
65
|
+
{ title: 'Review model', max: 18 },
|
|
66
|
+
{ title: 'Auth', max: 16 }
|
|
67
67
|
],
|
|
68
68
|
rows
|
|
69
69
|
);
|
|
70
70
|
print.blank();
|
|
71
|
-
print.hint('
|
|
71
|
+
print.hint('Provider order matters: the first one is the default provider and the fallback source when no review model is configured');
|
|
72
72
|
print.blank();
|
|
73
73
|
return 0;
|
|
74
74
|
}
|
|
@@ -84,7 +84,7 @@ async function add(opts) {
|
|
|
84
84
|
|
|
85
85
|
if (interactive) {
|
|
86
86
|
if (!opts.protocol) {
|
|
87
|
-
const answer = await ask('
|
|
87
|
+
const answer = await ask('Protocol [1] OpenAI ChatCompletions [2] Anthropic Messages [3] OpenAI Responses : ');
|
|
88
88
|
const index = Number(String(answer || '').trim()) || 1;
|
|
89
89
|
protocol = ['openai', 'anthropic', 'responses'][index - 1] || 'openai';
|
|
90
90
|
}
|
|
@@ -93,15 +93,15 @@ async function add(opts) {
|
|
|
93
93
|
baseUrl = String(answer || '').trim() || settings.PROTOCOL_META[protocol].basePlaceholder;
|
|
94
94
|
}
|
|
95
95
|
if (!name) {
|
|
96
|
-
const answer = await ask('
|
|
96
|
+
const answer = await ask('Provider name: ');
|
|
97
97
|
name = String(answer || '').trim();
|
|
98
98
|
}
|
|
99
99
|
if (!oauthProvider && apiKey === undefined) {
|
|
100
|
-
const secret = await askSecret('API Key
|
|
100
|
+
const secret = await askSecret('API Key (may be empty for local models): ');
|
|
101
101
|
apiKey = secret === null ? undefined : secret;
|
|
102
102
|
}
|
|
103
103
|
if (!models.length) {
|
|
104
|
-
const answer = await ask('
|
|
104
|
+
const answer = await ask('Model ID (separate multiple with commas): ');
|
|
105
105
|
models = String(answer || '')
|
|
106
106
|
.split(/[,,\s]+/)
|
|
107
107
|
.filter(Boolean);
|
|
@@ -118,14 +118,14 @@ async function add(opts) {
|
|
|
118
118
|
oauthProvider,
|
|
119
119
|
reviewModelId: opts.reviewModelId
|
|
120
120
|
});
|
|
121
|
-
print.ok(
|
|
121
|
+
print.ok(`Provider added: ${result.provider.name} (${result.provider.id})`);
|
|
122
122
|
return 0;
|
|
123
123
|
}
|
|
124
124
|
|
|
125
125
|
function edit(ref, opts) {
|
|
126
126
|
const provider = settings.findProvider(ref);
|
|
127
127
|
if (!provider) {
|
|
128
|
-
print.fail(
|
|
128
|
+
print.fail(`Provider not found: ${ref}`);
|
|
129
129
|
return 1;
|
|
130
130
|
}
|
|
131
131
|
const result = settings.upsertProvider({
|
|
@@ -139,28 +139,28 @@ function edit(ref, opts) {
|
|
|
139
139
|
oauthProvider: opts.oauthProvider,
|
|
140
140
|
reviewModelId: opts.reviewModelId
|
|
141
141
|
});
|
|
142
|
-
print.ok(
|
|
142
|
+
print.ok(`Provider updated: ${result.provider.name}`);
|
|
143
143
|
return 0;
|
|
144
144
|
}
|
|
145
145
|
|
|
146
146
|
async function remove(ref, opts) {
|
|
147
147
|
const provider = settings.findProvider(ref);
|
|
148
148
|
if (!provider) {
|
|
149
|
-
print.fail(
|
|
149
|
+
print.fail(`Provider not found: ${ref}`);
|
|
150
150
|
return 1;
|
|
151
151
|
}
|
|
152
152
|
if (!opts.yes && process.stdin.isTTY) {
|
|
153
|
-
const ok = await confirm(
|
|
153
|
+
const ok = await confirm(`Delete provider "${provider.name}" and its API key?`, false);
|
|
154
154
|
if (!ok) {
|
|
155
|
-
print.hint('
|
|
155
|
+
print.hint('Cancelled');
|
|
156
156
|
return 1;
|
|
157
157
|
}
|
|
158
158
|
}
|
|
159
159
|
const config = settings.removeProvider(provider.id);
|
|
160
|
-
print.ok(
|
|
161
|
-
if (!config.providers?.length) print.hint('
|
|
160
|
+
print.ok(`Deleted "${provider.name}"`);
|
|
161
|
+
if (!config.providers?.length) print.hint('No providers left; run dgxay config init to reconfigure');
|
|
162
162
|
else if (config.activeProviderId !== settings.readConfig().activeProviderId) {
|
|
163
|
-
print.hint(
|
|
163
|
+
print.hint(`Active provider switched to "${(config.providers || []).find((p) => p.id === config.activeProviderId)?.name || 'unknown'}"`);
|
|
164
164
|
}
|
|
165
165
|
return 0;
|
|
166
166
|
}
|
|
@@ -168,36 +168,36 @@ async function remove(ref, opts) {
|
|
|
168
168
|
function use(ref) {
|
|
169
169
|
const provider = settings.findProvider(ref);
|
|
170
170
|
if (!provider) {
|
|
171
|
-
print.fail(
|
|
171
|
+
print.fail(`Provider not found: ${ref}`);
|
|
172
172
|
return 1;
|
|
173
173
|
}
|
|
174
174
|
const model = provider.models?.[0];
|
|
175
175
|
if (!model) {
|
|
176
|
-
print.fail(
|
|
176
|
+
print.fail(`Provider ${provider.name} has no models`);
|
|
177
177
|
return 1;
|
|
178
178
|
}
|
|
179
179
|
settings.saveConfig({ activeProviderId: provider.id, activeModelId: model.id });
|
|
180
|
-
print.ok(
|
|
180
|
+
print.ok(`Active provider: ${provider.name} / ${model.name || model.id}`);
|
|
181
181
|
return 0;
|
|
182
182
|
}
|
|
183
183
|
|
|
184
184
|
function review(ref, opts) {
|
|
185
185
|
const provider = settings.findProvider(ref);
|
|
186
186
|
if (!provider) {
|
|
187
|
-
print.fail(
|
|
187
|
+
print.fail(`Provider not found: ${ref}`);
|
|
188
188
|
return 1;
|
|
189
189
|
}
|
|
190
190
|
if (opts.reviewModel === undefined) {
|
|
191
191
|
const model = (provider.models || []).find((m) => m.id === provider.reviewModelId);
|
|
192
|
-
if (model) print.write(
|
|
193
|
-
else print.write(`${provider.name}
|
|
192
|
+
if (model) print.write(`Review model for ${provider.name}: ${model.name || model.id} (${model.id})`);
|
|
193
|
+
else print.write(`${provider.name} has no review model configured; auto review falls back to the default provider`);
|
|
194
194
|
return 0;
|
|
195
195
|
}
|
|
196
196
|
const models = provider.models || [];
|
|
197
197
|
const target = models.find((m) => m.id === opts.reviewModel);
|
|
198
198
|
if (opts.reviewModel && !target) {
|
|
199
|
-
print.fail(
|
|
200
|
-
print.hint(
|
|
199
|
+
print.fail(`Provider ${provider.name} has no model ${opts.reviewModel}`);
|
|
200
|
+
print.hint(`Available: ${models.map((m) => m.id).join(', ')}`);
|
|
201
201
|
return 1;
|
|
202
202
|
}
|
|
203
203
|
const next = (settings.readConfig().providers || []).map((p) =>
|
|
@@ -205,10 +205,10 @@ function review(ref, opts) {
|
|
|
205
205
|
);
|
|
206
206
|
settings.saveConfig({ providers: next });
|
|
207
207
|
if (target) {
|
|
208
|
-
print.ok(
|
|
209
|
-
print.hint('
|
|
208
|
+
print.ok(`Auto review model for ${provider.name}: ${target.name || target.id}`);
|
|
209
|
+
print.hint('You can now select "Auto review" in /permission');
|
|
210
210
|
} else {
|
|
211
|
-
print.ok(
|
|
211
|
+
print.ok(`Cleared the review model for ${provider.name}`);
|
|
212
212
|
}
|
|
213
213
|
return 0;
|
|
214
214
|
}
|
|
@@ -216,37 +216,37 @@ function review(ref, opts) {
|
|
|
216
216
|
function move(ref, direction) {
|
|
217
217
|
const dir = direction === 'up' || direction === 'u' || direction === '-1' ? -1 : 1;
|
|
218
218
|
settings.moveProvider(ref, dir);
|
|
219
|
-
print.ok(
|
|
219
|
+
print.ok(`${dir < 0 ? 'Moved up' : 'Moved down'} "${settings.findProvider(ref)?.name || ref}"`);
|
|
220
220
|
return list();
|
|
221
221
|
}
|
|
222
222
|
|
|
223
223
|
function oauthAccounts() {
|
|
224
224
|
const list = oauth.listProviders();
|
|
225
225
|
print.blank();
|
|
226
|
-
print.heading('OAuth
|
|
226
|
+
print.heading('OAuth accounts');
|
|
227
227
|
const rows = list.map((item) => [
|
|
228
228
|
item.name,
|
|
229
229
|
item.subtitle,
|
|
230
230
|
item.connection && !item.connection.expired
|
|
231
|
-
? COLORS.green('
|
|
231
|
+
? COLORS.green('connected')
|
|
232
232
|
: item.connection?.expired
|
|
233
|
-
? COLORS.yellow('
|
|
234
|
-
: '
|
|
233
|
+
? COLORS.yellow('expired')
|
|
234
|
+
: 'not connected',
|
|
235
235
|
item.connection?.account || '',
|
|
236
|
-
item.redirectMode === 'manual' ? '
|
|
236
|
+
item.redirectMode === 'manual' ? 'manual auth code' : 'system browser'
|
|
237
237
|
]);
|
|
238
238
|
print.table(
|
|
239
239
|
[
|
|
240
|
-
{ title: '
|
|
241
|
-
{ title: '
|
|
242
|
-
{ title: '
|
|
243
|
-
{ title: '
|
|
244
|
-
{ title: '
|
|
240
|
+
{ title: 'Platform', max: 12 },
|
|
241
|
+
{ title: 'Account type', max: 24 },
|
|
242
|
+
{ title: 'Status', max: 8 },
|
|
243
|
+
{ title: 'Account', max: 30 },
|
|
244
|
+
{ title: 'Auth method', max: 12 }
|
|
245
245
|
],
|
|
246
246
|
rows
|
|
247
247
|
);
|
|
248
248
|
print.blank();
|
|
249
|
-
print.hint('dgxay oauth connect
|
|
249
|
+
print.hint('dgxay oauth connect <platform> to connect an account; then use dgxay provider add --oauth-provider <platform>');
|
|
250
250
|
print.blank();
|
|
251
251
|
return 0;
|
|
252
252
|
}
|
|
@@ -263,33 +263,33 @@ async function run({ argv }) {
|
|
|
263
263
|
return add(opts);
|
|
264
264
|
case 'edit':
|
|
265
265
|
case 'set': {
|
|
266
|
-
if (!rest[0]) throw Object.assign(new Error('
|
|
266
|
+
if (!rest[0]) throw Object.assign(new Error('Usage: dgxay provider edit <name> [options]'), { userError: true });
|
|
267
267
|
return edit(rest[0], opts);
|
|
268
268
|
}
|
|
269
269
|
case 'rm':
|
|
270
270
|
case 'remove':
|
|
271
271
|
case 'delete': {
|
|
272
|
-
if (!rest[0]) throw Object.assign(new Error('
|
|
272
|
+
if (!rest[0]) throw Object.assign(new Error('Usage: dgxay provider rm <name>'), { userError: true });
|
|
273
273
|
return remove(rest[0], opts);
|
|
274
274
|
}
|
|
275
275
|
case 'use': {
|
|
276
|
-
if (!rest[0]) throw Object.assign(new Error('
|
|
276
|
+
if (!rest[0]) throw Object.assign(new Error('Usage: dgxay provider use <name>'), { userError: true });
|
|
277
277
|
return use(rest[0]);
|
|
278
278
|
}
|
|
279
279
|
case 'mv':
|
|
280
280
|
case 'move': {
|
|
281
|
-
if (!rest[0]) throw Object.assign(new Error('
|
|
281
|
+
if (!rest[0]) throw Object.assign(new Error('Usage: dgxay provider mv <name> up|down'), { userError: true });
|
|
282
282
|
return move(rest[0], rest[1] || 'down');
|
|
283
283
|
}
|
|
284
284
|
case 'review': {
|
|
285
285
|
if (!rest[0]) {
|
|
286
286
|
const config = settings.readConfig();
|
|
287
|
-
const rows = (config.providers || []).map((p) => [p.name, p.reviewModelId || '
|
|
287
|
+
const rows = (config.providers || []).map((p) => [p.name, p.reviewModelId || '(not configured)']);
|
|
288
288
|
print.blank();
|
|
289
289
|
print.table(
|
|
290
290
|
[
|
|
291
|
-
{ title: '
|
|
292
|
-
{ title: '
|
|
291
|
+
{ title: 'Provider', max: 20 },
|
|
292
|
+
{ title: 'Review model', max: 30 }
|
|
293
293
|
],
|
|
294
294
|
rows
|
|
295
295
|
);
|
|
@@ -301,8 +301,8 @@ async function run({ argv }) {
|
|
|
301
301
|
case 'oauth':
|
|
302
302
|
return oauthAccounts();
|
|
303
303
|
default:
|
|
304
|
-
print.fail(
|
|
305
|
-
print.hint('
|
|
304
|
+
print.fail(`Unknown subcommand: ${action}`);
|
|
305
|
+
print.hint('Available: list / add / edit / rm / use / mv / review / oauth');
|
|
306
306
|
return 1;
|
|
307
307
|
}
|
|
308
308
|
}
|
|
@@ -310,17 +310,17 @@ async function run({ argv }) {
|
|
|
310
310
|
module.exports = {
|
|
311
311
|
name: 'provider',
|
|
312
312
|
aliases: ['prov'],
|
|
313
|
-
summary: '
|
|
313
|
+
summary: 'Provider and review model management',
|
|
314
314
|
usage: 'dgxay provider <list|add|edit|rm|use|mv|review>',
|
|
315
315
|
options,
|
|
316
316
|
subcommands: [
|
|
317
|
-
['list', '
|
|
318
|
-
['add', '
|
|
319
|
-
['edit
|
|
320
|
-
['rm
|
|
321
|
-
['use
|
|
322
|
-
['mv
|
|
323
|
-
['review [
|
|
317
|
+
['list', 'List all providers'],
|
|
318
|
+
['add', 'Add a provider'],
|
|
319
|
+
['edit <name>', 'Edit a provider'],
|
|
320
|
+
['rm <name>', 'Delete a provider'],
|
|
321
|
+
['use <name>', 'Set as the active provider'],
|
|
322
|
+
['mv <name> up|down', 'Reorder providers'],
|
|
323
|
+
['review [name] [--model id]', 'View / set the auto review model']
|
|
324
324
|
],
|
|
325
325
|
examples: [
|
|
326
326
|
'dgxay provider list',
|
package/src/commands/run.js
CHANGED
|
@@ -19,30 +19,30 @@ const { StreamRenderer } = require('../cli/render');
|
|
|
19
19
|
const { resolveChatArg } = require('./_shared');
|
|
20
20
|
|
|
21
21
|
const options = [
|
|
22
|
-
{ name: 'prompt', alias: 'p', type: 'string', valueName: 'text', desc: '
|
|
23
|
-
{ name: 'mode', alias: 'm', type: 'string', valueName: 'mode', desc: 'chat / work
|
|
22
|
+
{ name: 'prompt', alias: 'p', type: 'string', valueName: 'text', desc: 'Prompt' },
|
|
23
|
+
{ name: 'mode', alias: 'm', type: 'string', valueName: 'mode', desc: 'chat / work (default chat)' },
|
|
24
24
|
{ name: 'permission', type: 'string', valueName: 'level', desc: 'none / normal / auto / full' },
|
|
25
|
-
{ name: 'workspace', alias: 'C', type: 'string', valueName: 'dir', desc: '
|
|
26
|
-
{ name: 'provider', type: 'string', valueName: 'name', desc: '
|
|
27
|
-
{ name: 'model', type: 'string', valueName: 'id', desc: '
|
|
28
|
-
{ name: 'skill', type: 'string', valueName: 'name', desc: '
|
|
29
|
-
{ name: 'resume', alias: 'r', type: 'string', valueName: 'id|index', desc: '
|
|
30
|
-
{ name: 'continue', alias: 'c', type: 'boolean', desc: '
|
|
31
|
-
{ name: 'output', alias: 'o', type: 'string', valueName: 'text|json', desc: '
|
|
32
|
-
{ name: 'yes', alias: 'y', type: 'boolean', desc: '
|
|
33
|
-
{ name: 'quiet', alias: 'q', type: 'boolean', desc: '
|
|
25
|
+
{ name: 'workspace', alias: 'C', type: 'string', valueName: 'dir', desc: 'Workspace directory' },
|
|
26
|
+
{ name: 'provider', type: 'string', valueName: 'name', desc: 'Provider id or name' },
|
|
27
|
+
{ name: 'model', type: 'string', valueName: 'id', desc: 'Model id' },
|
|
28
|
+
{ name: 'skill', type: 'string', valueName: 'name', desc: 'Skill to enable' },
|
|
29
|
+
{ name: 'resume', alias: 'r', type: 'string', valueName: 'id|index', desc: 'Continue a conversation by index or id' },
|
|
30
|
+
{ name: 'continue', alias: 'c', type: 'boolean', desc: 'Continue the most recent conversation' },
|
|
31
|
+
{ name: 'output', alias: 'o', type: 'string', valueName: 'text|json', desc: 'Output format, default text' },
|
|
32
|
+
{ name: 'yes', alias: 'y', type: 'boolean', desc: 'Auto-approve permission requests (dangerous)' },
|
|
33
|
+
{ name: 'quiet', alias: 'q', type: 'boolean', desc: 'Only print the reply text' }
|
|
34
34
|
];
|
|
35
35
|
|
|
36
36
|
async function run({ argv, globalOptions, runtime }) {
|
|
37
37
|
const { options: opts, positionals } = parseArgs(argv, options);
|
|
38
38
|
const prompt = String(opts.prompt || positionals.join(' ') || runtime.prompt || '').trim();
|
|
39
39
|
if (!prompt) {
|
|
40
|
-
throw Object.assign(new Error('
|
|
40
|
+
throw Object.assign(new Error('Missing prompt: use -p "..." or pass the question directly'), { userError: true });
|
|
41
41
|
}
|
|
42
42
|
|
|
43
43
|
const config = settings.readConfig();
|
|
44
44
|
if (!config.providers?.length) {
|
|
45
|
-
throw Object.assign(new Error('
|
|
45
|
+
throw Object.assign(new Error('No provider configured. Run dgxay config init first'), { userError: true });
|
|
46
46
|
}
|
|
47
47
|
|
|
48
48
|
const mode = String(opts.mode || runtime.mode || 'chat') === 'work' ? 'work' : 'chat';
|
|
@@ -148,11 +148,11 @@ function persistChat({ chat, prompt, mode, permission, result, history }) {
|
|
|
148
148
|
files: result.files,
|
|
149
149
|
usage: result.usage || null
|
|
150
150
|
});
|
|
151
|
-
if (!target.title || target.title === '
|
|
151
|
+
if (!target.title || target.title === 'New conversation') target.title = sessions.titleFrom(prompt);
|
|
152
152
|
sessions.saveChat(target);
|
|
153
153
|
return target;
|
|
154
154
|
} catch (err) {
|
|
155
|
-
if (process.env.DGXAY_DEBUG === '1') process.stderr.write(`[session]
|
|
155
|
+
if (process.env.DGXAY_DEBUG === '1') process.stderr.write(`[session] save failed: ${err.message}\n`);
|
|
156
156
|
return null;
|
|
157
157
|
}
|
|
158
158
|
}
|
|
@@ -160,13 +160,13 @@ function persistChat({ chat, prompt, mode, permission, result, history }) {
|
|
|
160
160
|
module.exports = {
|
|
161
161
|
name: 'run',
|
|
162
162
|
aliases: [],
|
|
163
|
-
summary: '
|
|
164
|
-
usage: 'dgxay run -p "
|
|
163
|
+
summary: 'One-shot: send a prompt and print the reply',
|
|
164
|
+
usage: 'dgxay run -p "prompt" [-C dir] [-m work] [--permission auto]',
|
|
165
165
|
options,
|
|
166
166
|
examples: [
|
|
167
|
-
'dgxay run -p "
|
|
168
|
-
'dgxay run -p "
|
|
169
|
-
'dgxay run -p "
|
|
167
|
+
'dgxay run -p "explain the structure of this repo" -C .',
|
|
168
|
+
'dgxay run -p "add install notes to the README" -m work -C ./project',
|
|
169
|
+
'dgxay run -p "write a quicksort function" -o json'
|
|
170
170
|
],
|
|
171
171
|
run
|
|
172
172
|
};
|
package/src/commands/skill.js
CHANGED
|
@@ -16,7 +16,7 @@ const skills = require('../services/skills');
|
|
|
16
16
|
const cfg = require('../services/config');
|
|
17
17
|
const settings = require('../services/settings');
|
|
18
18
|
|
|
19
|
-
const options = [{ name: 'json', type: 'boolean', desc: '
|
|
19
|
+
const options = [{ name: 'json', type: 'boolean', desc: 'Output JSON' }];
|
|
20
20
|
|
|
21
21
|
async function run({ argv }) {
|
|
22
22
|
const { action: rawAction, rest, options: opts } = actionFirst(argv, options);
|
|
@@ -34,9 +34,9 @@ async function run({ argv }) {
|
|
|
34
34
|
return 0;
|
|
35
35
|
}
|
|
36
36
|
print.blank();
|
|
37
|
-
print.heading(
|
|
37
|
+
print.heading(`Skills (${settings.homeRelative(cfg.SKILLS_DIR)})`);
|
|
38
38
|
if (!list.length) {
|
|
39
|
-
print.hint('
|
|
39
|
+
print.hint(' No skills yet. Drop a name.md or <dir>/SKILL.md into the skills directory.');
|
|
40
40
|
print.blank();
|
|
41
41
|
return 0;
|
|
42
42
|
}
|
|
@@ -44,24 +44,24 @@ async function run({ argv }) {
|
|
|
44
44
|
print.table(
|
|
45
45
|
[
|
|
46
46
|
{ title: '#', max: 3 },
|
|
47
|
-
{ title: '
|
|
48
|
-
{ title: '
|
|
49
|
-
{ title: '
|
|
47
|
+
{ title: 'Name', max: 24 },
|
|
48
|
+
{ title: 'Description', max: 60 },
|
|
49
|
+
{ title: 'File', max: 24 }
|
|
50
50
|
],
|
|
51
51
|
rows
|
|
52
52
|
);
|
|
53
53
|
print.blank();
|
|
54
|
-
print.hint('
|
|
54
|
+
print.hint('Enable with /skill <name> in a conversation; for a single run add --skill <name>');
|
|
55
55
|
print.blank();
|
|
56
56
|
return 0;
|
|
57
57
|
}
|
|
58
58
|
|
|
59
59
|
if (action === 'show' || action === 'cat') {
|
|
60
60
|
const name = rest[0];
|
|
61
|
-
if (!name) throw Object.assign(new Error('
|
|
61
|
+
if (!name) throw Object.assign(new Error('Usage: dgxay skill show <name>'), { userError: true });
|
|
62
62
|
const skill = skills.readSkill(name);
|
|
63
63
|
if (!skill) {
|
|
64
|
-
print.fail(
|
|
64
|
+
print.fail(`Skill not found: ${name}`);
|
|
65
65
|
return 1;
|
|
66
66
|
}
|
|
67
67
|
print.blank();
|
|
@@ -73,21 +73,21 @@ async function run({ argv }) {
|
|
|
73
73
|
return 0;
|
|
74
74
|
}
|
|
75
75
|
|
|
76
|
-
print.fail(
|
|
77
|
-
print.hint('
|
|
76
|
+
print.fail(`Unknown command: ${action}`);
|
|
77
|
+
print.hint('Available: list / show / path');
|
|
78
78
|
return 1;
|
|
79
79
|
}
|
|
80
80
|
|
|
81
81
|
module.exports = {
|
|
82
82
|
name: 'skill',
|
|
83
83
|
aliases: ['skills'],
|
|
84
|
-
summary: '
|
|
84
|
+
summary: 'List and view skills',
|
|
85
85
|
usage: 'dgxay skill <list|show|path>',
|
|
86
86
|
options,
|
|
87
87
|
subcommands: [
|
|
88
|
-
['list', '
|
|
89
|
-
['show
|
|
90
|
-
['path', '
|
|
88
|
+
['list', 'List skills'],
|
|
89
|
+
['show <name>', 'View skill content'],
|
|
90
|
+
['path', 'Show the skills directory']
|
|
91
91
|
],
|
|
92
92
|
examples: ['dgxay skill list', 'dgxay skill show review', 'dgxay skill path'],
|
|
93
93
|
run
|
|
@@ -16,7 +16,7 @@ const { parseArgs, actionFirst } = require('../cli/args');
|
|
|
16
16
|
const { COLORS } = require('../cli/ansi');
|
|
17
17
|
const settings = require('../services/settings');
|
|
18
18
|
|
|
19
|
-
const options = [{ name: 'both', alias: 'b', type: 'boolean', desc: '
|
|
19
|
+
const options = [{ name: 'both', alias: 'b', type: 'boolean', desc: 'Also persist to config (default only sets the current process)' }];
|
|
20
20
|
|
|
21
21
|
async function run({ argv }) {
|
|
22
22
|
const { action, rest, options: opts } = actionFirst(argv, options);
|
|
@@ -26,12 +26,12 @@ async function run({ argv }) {
|
|
|
26
26
|
const workspace = config.work?.workspace || process.cwd();
|
|
27
27
|
print.blank();
|
|
28
28
|
print.keyValue([
|
|
29
|
-
{ label: '
|
|
30
|
-
{ label: '
|
|
31
|
-
{ label: '
|
|
29
|
+
{ label: 'Current workspace', value: workspace },
|
|
30
|
+
{ label: 'Process directory', value: process.cwd() },
|
|
31
|
+
{ label: 'Recent', value: (config.work?.recentWorkspaces || []).slice(0, 5).join('\n') || '(none)', multiline: true }
|
|
32
32
|
]);
|
|
33
33
|
print.blank();
|
|
34
|
-
print.hint('dgxay workspace set
|
|
34
|
+
print.hint('Set it with dgxay workspace set <dir>; inside a conversation use /cd');
|
|
35
35
|
print.blank();
|
|
36
36
|
return 0;
|
|
37
37
|
}
|
|
@@ -40,11 +40,11 @@ async function run({ argv }) {
|
|
|
40
40
|
const recents = config.work?.recentWorkspaces || [];
|
|
41
41
|
print.blank();
|
|
42
42
|
if (!recents.length) {
|
|
43
|
-
print.hint('
|
|
43
|
+
print.hint('No workspace has been set yet');
|
|
44
44
|
print.blank();
|
|
45
45
|
return 0;
|
|
46
46
|
}
|
|
47
|
-
print.heading('
|
|
47
|
+
print.heading('Recent workspaces');
|
|
48
48
|
recents.forEach((item, index) => {
|
|
49
49
|
const exists = fs.existsSync(item) ? COLORS.green('✓') : COLORS.red('✗');
|
|
50
50
|
print.write(` ${status(index + 1)} ${exists} ${item}`);
|
|
@@ -55,23 +55,23 @@ async function run({ argv }) {
|
|
|
55
55
|
|
|
56
56
|
if (action === 'set' || action === 'use' || action === 'cd') {
|
|
57
57
|
const target = rest[0] || '';
|
|
58
|
-
if (!target) throw Object.assign(new Error('
|
|
58
|
+
if (!target) throw Object.assign(new Error('Usage: dgxay workspace set <dir>'), { userError: true });
|
|
59
59
|
const resolved = path.resolve(target);
|
|
60
60
|
try {
|
|
61
|
-
if (!fs.statSync(resolved).isDirectory()) throw new Error('
|
|
61
|
+
if (!fs.statSync(resolved).isDirectory()) throw new Error('Not a directory');
|
|
62
62
|
} catch {
|
|
63
|
-
print.fail(
|
|
63
|
+
print.fail(`Directory not found: ${resolved}`);
|
|
64
64
|
return 1;
|
|
65
65
|
}
|
|
66
66
|
settings.setWorkspace(resolved);
|
|
67
|
-
print.ok(
|
|
67
|
+
print.ok(`Workspace: ${resolved}`);
|
|
68
68
|
void opts;
|
|
69
69
|
return 0;
|
|
70
70
|
}
|
|
71
71
|
|
|
72
72
|
if (action === 'clear' || action === 'unset') {
|
|
73
73
|
settings.setWorkspace('');
|
|
74
|
-
print.ok('
|
|
74
|
+
print.ok('Workspace cleared');
|
|
75
75
|
return 0;
|
|
76
76
|
}
|
|
77
77
|
|
|
@@ -86,14 +86,14 @@ function status(index) {
|
|
|
86
86
|
module.exports = {
|
|
87
87
|
name: 'workspace',
|
|
88
88
|
aliases: ['ws'],
|
|
89
|
-
summary: '
|
|
90
|
-
usage: 'dgxay workspace [set|list|clear] [
|
|
89
|
+
summary: 'Workspace management',
|
|
90
|
+
usage: 'dgxay workspace [set|list|clear] [dir]',
|
|
91
91
|
options,
|
|
92
92
|
subcommands: [
|
|
93
|
-
['show', '
|
|
94
|
-
['set
|
|
95
|
-
['list', '
|
|
96
|
-
['clear', '
|
|
93
|
+
['show', 'Show current workspace'],
|
|
94
|
+
['set <dir>', 'Set the workspace'],
|
|
95
|
+
['list', 'Show recent workspaces'],
|
|
96
|
+
['clear', 'Clear']
|
|
97
97
|
],
|
|
98
98
|
examples: ['dgxay workspace set ./project', 'dgxay workspace list'],
|
|
99
99
|
run
|