@yankeguo/dsh-command-devlead 0.0.0-stage → 0.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/LICENSE +21 -0
- package/lib/index.js +352 -0
- package/package.json +32 -3
- package/README.md +0 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
MIT License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 Y.-K. Guo
|
|
4
|
+
|
|
5
|
+
Permission is hereby granted, free of charge, to any person obtaining a copy
|
|
6
|
+
of this software and associated documentation files (the "Software"), to deal
|
|
7
|
+
in the Software without restriction, including without limitation the rights
|
|
8
|
+
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
|
|
9
|
+
copies of the Software, and to permit persons to whom the Software is
|
|
10
|
+
furnished to do so, subject to the following conditions:
|
|
11
|
+
|
|
12
|
+
The above copyright notice and this permission notice shall be included in all
|
|
13
|
+
copies or substantial portions of the Software.
|
|
14
|
+
|
|
15
|
+
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
|
|
16
|
+
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
|
|
17
|
+
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
|
|
18
|
+
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
|
|
19
|
+
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
|
|
20
|
+
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
|
|
21
|
+
SOFTWARE.
|
package/lib/index.js
ADDED
|
@@ -0,0 +1,352 @@
|
|
|
1
|
+
// Built by dsh-devlead. Do not edit.
|
|
2
|
+
|
|
3
|
+
// packages/command/src/index.ts
|
|
4
|
+
import { CommandDefinitionId } from "@deepseek-ai/dsh-commands/brand";
|
|
5
|
+
import { isDevLeadError } from "@yankeguo/dsh-devlead";
|
|
6
|
+
import { DEVLEAD_COMMAND_NAME as DEVLEAD_COMMAND_NAME2 } from "@yankeguo/dsh-devlead-protocol";
|
|
7
|
+
|
|
8
|
+
// packages/command/src/parse.ts
|
|
9
|
+
import { DEVLEAD_COMMAND_NAME } from "@yankeguo/dsh-devlead-protocol";
|
|
10
|
+
var COMMAND_GRAMMAR = "[status|on|off|watch <session>|unwatch <session>]";
|
|
11
|
+
var USAGE = `Usage: /${DEVLEAD_COMMAND_NAME} ${COMMAND_GRAMMAR}`;
|
|
12
|
+
function invalid(message) {
|
|
13
|
+
return { kind: "invalid", message };
|
|
14
|
+
}
|
|
15
|
+
function splitHead(input) {
|
|
16
|
+
const match = /^(\S+)(?:\s+([\s\S]*))?$/u.exec(input);
|
|
17
|
+
if (match === null) return { head: input.toLowerCase(), rest: "" };
|
|
18
|
+
return { head: match[1].toLowerCase(), rest: (match[2] ?? "").trim() };
|
|
19
|
+
}
|
|
20
|
+
function unquote(text) {
|
|
21
|
+
const trimmed = text.trim();
|
|
22
|
+
if (trimmed.length < 2) return trimmed;
|
|
23
|
+
const first = trimmed[0];
|
|
24
|
+
const last = trimmed[trimmed.length - 1];
|
|
25
|
+
const pair = first === '"' && last === '"' || first === "'" && last === "'";
|
|
26
|
+
return pair ? trimmed.slice(1, -1).trim() : trimmed;
|
|
27
|
+
}
|
|
28
|
+
function unexpectedArgument(subcommand) {
|
|
29
|
+
return invalid(`The /devlead ${subcommand} subcommand does not take an argument.`);
|
|
30
|
+
}
|
|
31
|
+
function parseSessionArgument(subcommand, text) {
|
|
32
|
+
const session = unquote(text);
|
|
33
|
+
if (session.length === 0) {
|
|
34
|
+
return invalid(
|
|
35
|
+
`/devlead ${subcommand} requires a Session id or a unique id prefix. Run /devlead to inspect the current watch set.`
|
|
36
|
+
);
|
|
37
|
+
}
|
|
38
|
+
if (/\s/u.test(session)) {
|
|
39
|
+
return invalid(
|
|
40
|
+
`"/devlead ${subcommand}" takes one Session reference without spaces; pass the full Session id or a unique id prefix.`
|
|
41
|
+
);
|
|
42
|
+
}
|
|
43
|
+
return { kind: subcommand, session };
|
|
44
|
+
}
|
|
45
|
+
function parseDevLeadCommand(rawInput) {
|
|
46
|
+
const trimmed = rawInput.trim();
|
|
47
|
+
const complete = /^\/devlead[/\s]*/iu.exec(trimmed);
|
|
48
|
+
const input = (complete === null ? trimmed : trimmed.slice(complete[0].length)).trim();
|
|
49
|
+
if (input.length === 0) return { kind: "status" };
|
|
50
|
+
switch (input.toLowerCase()) {
|
|
51
|
+
case "status":
|
|
52
|
+
return { kind: "status" };
|
|
53
|
+
case "on":
|
|
54
|
+
return { kind: "on" };
|
|
55
|
+
case "off":
|
|
56
|
+
return { kind: "off" };
|
|
57
|
+
default:
|
|
58
|
+
break;
|
|
59
|
+
}
|
|
60
|
+
const { head, rest } = splitHead(input);
|
|
61
|
+
switch (head) {
|
|
62
|
+
case "watch":
|
|
63
|
+
return parseSessionArgument("watch", rest);
|
|
64
|
+
case "unwatch":
|
|
65
|
+
return parseSessionArgument("unwatch", rest);
|
|
66
|
+
// A no-argument subcommand followed by stray text is a typo, not a
|
|
67
|
+
// Session reference; name the offending subcommand instead of guessing.
|
|
68
|
+
case "status":
|
|
69
|
+
case "on":
|
|
70
|
+
case "off":
|
|
71
|
+
return unexpectedArgument(head);
|
|
72
|
+
default:
|
|
73
|
+
return invalid(`Unknown /devlead subcommand "${head}".`);
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
|
|
77
|
+
// packages/command/src/render.ts
|
|
78
|
+
import {
|
|
79
|
+
formatInstant,
|
|
80
|
+
notificationLine,
|
|
81
|
+
transitionLabel
|
|
82
|
+
} from "@yankeguo/dsh-devlead-protocol";
|
|
83
|
+
var RECENT_NOTIFICATION_LIMIT = 5;
|
|
84
|
+
var HELP_LINE = "Help: /devlead on | /devlead off | /devlead watch <session> | /devlead unwatch <session>";
|
|
85
|
+
function modeLabel(enabled) {
|
|
86
|
+
return enabled ? "on" : "off";
|
|
87
|
+
}
|
|
88
|
+
function sessionLabel(view) {
|
|
89
|
+
const title = view.title?.trim() ?? "";
|
|
90
|
+
return title.length === 0 ? view.sessionId : `${title} (${view.sessionId})`;
|
|
91
|
+
}
|
|
92
|
+
function sessionStateLabel(view) {
|
|
93
|
+
const state = view.archived ? "archived" : view.running ? "running" : view.live ? "idle" : "cold";
|
|
94
|
+
const parts = [state];
|
|
95
|
+
if (view.running && (view.pendingInputs ?? 0) > 0) parts.push(`${view.pendingInputs} queued`);
|
|
96
|
+
if (view.lastTurn !== void 0) {
|
|
97
|
+
const outcome = view.lastTransition === void 0 ? "" : ` ${transitionLabel(view.lastTransition)}`;
|
|
98
|
+
parts.push(`last turn ${view.lastTurn}${outcome}`);
|
|
99
|
+
}
|
|
100
|
+
const base = parts.join(" \xB7 ");
|
|
101
|
+
return view.lastError === void 0 ? base : `${base}: ${view.lastError}`;
|
|
102
|
+
}
|
|
103
|
+
function watchedLines(snapshot) {
|
|
104
|
+
const total = snapshot.watched.length + snapshot.missingWatched.length;
|
|
105
|
+
if (total === 0) return ["Watched sessions: none"];
|
|
106
|
+
const running = snapshot.watched.filter((view) => view.running).length;
|
|
107
|
+
const summary = running === 0 ? `Watched sessions: ${total}` : `Watched sessions: ${total} (${running} running)`;
|
|
108
|
+
const lines = [summary];
|
|
109
|
+
for (const view of snapshot.watched) lines.push(` - ${sessionLabel(view)} \u2014 ${sessionStateLabel(view)}`);
|
|
110
|
+
for (const sessionId of snapshot.missingWatched) lines.push(` - ${sessionId} \u2014 not found`);
|
|
111
|
+
return lines;
|
|
112
|
+
}
|
|
113
|
+
function notificationLines(snapshot) {
|
|
114
|
+
if (snapshot.notifications.length === 0) return ["Recent notifications: none"];
|
|
115
|
+
const lines = ["Recent notifications:"];
|
|
116
|
+
for (const notification of snapshot.notifications) {
|
|
117
|
+
lines.push(` - ${formatInstant(notification.at)} ${notificationLine(notification)}`);
|
|
118
|
+
}
|
|
119
|
+
return lines;
|
|
120
|
+
}
|
|
121
|
+
function statusLines(snapshot) {
|
|
122
|
+
const lines = [
|
|
123
|
+
`DevLead mode: ${modeLabel(snapshot.enabled)}`,
|
|
124
|
+
...watchedLines(snapshot),
|
|
125
|
+
...notificationLines(snapshot)
|
|
126
|
+
];
|
|
127
|
+
if (!snapshot.enabled) {
|
|
128
|
+
lines.push(
|
|
129
|
+
"DevLead mode is off: no notification wakes this Session until it is turned on again.",
|
|
130
|
+
"Turn DevLead mode on with: /devlead on"
|
|
131
|
+
);
|
|
132
|
+
}
|
|
133
|
+
lines.push(HELP_LINE);
|
|
134
|
+
return lines;
|
|
135
|
+
}
|
|
136
|
+
function renderStatus(snapshot, title) {
|
|
137
|
+
const lines = title === void 0 ? [] : [title, ""];
|
|
138
|
+
return { kind: "success", text: [...lines, ...statusLines(snapshot)].join("\n") };
|
|
139
|
+
}
|
|
140
|
+
function errorResult(text) {
|
|
141
|
+
return { kind: "error", text };
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
// packages/command/src/resolve.ts
|
|
145
|
+
function candidateOf(view) {
|
|
146
|
+
return view.title === void 0 ? { sessionId: view.sessionId } : { sessionId: view.sessionId, title: view.title };
|
|
147
|
+
}
|
|
148
|
+
function mergeCandidates(listed, watchedSessionIds) {
|
|
149
|
+
const candidates = /* @__PURE__ */ new Map();
|
|
150
|
+
for (const view of listed) candidates.set(view.sessionId, candidateOf(view));
|
|
151
|
+
for (const sessionId of watchedSessionIds) {
|
|
152
|
+
if (!candidates.has(sessionId)) candidates.set(sessionId, { sessionId });
|
|
153
|
+
}
|
|
154
|
+
return [...candidates.values()];
|
|
155
|
+
}
|
|
156
|
+
function resolveSessionReference(query, candidates) {
|
|
157
|
+
const reference = query.trim();
|
|
158
|
+
if (reference.length === 0) return { kind: "missing" };
|
|
159
|
+
for (const candidate of candidates) {
|
|
160
|
+
if (candidate.sessionId !== reference) continue;
|
|
161
|
+
return candidate.title === void 0 ? { kind: "resolved", sessionId: candidate.sessionId } : { kind: "resolved", sessionId: candidate.sessionId, title: candidate.title };
|
|
162
|
+
}
|
|
163
|
+
const matches = candidates.filter((candidate) => candidate.sessionId.startsWith(reference));
|
|
164
|
+
const first = matches[0];
|
|
165
|
+
if (first === void 0) return { kind: "missing" };
|
|
166
|
+
if (matches.length === 1) {
|
|
167
|
+
return first.title === void 0 ? { kind: "resolved", sessionId: first.sessionId } : { kind: "resolved", sessionId: first.sessionId, title: first.title };
|
|
168
|
+
}
|
|
169
|
+
return { kind: "ambiguous", candidates: matches };
|
|
170
|
+
}
|
|
171
|
+
var MAX_RENDERED_CANDIDATES = 10;
|
|
172
|
+
function candidateLabel(candidate) {
|
|
173
|
+
return candidate.title === void 0 ? candidate.sessionId : `${candidate.title} (${candidate.sessionId})`;
|
|
174
|
+
}
|
|
175
|
+
function formatCandidates(candidates) {
|
|
176
|
+
const shown = candidates.slice(0, MAX_RENDERED_CANDIDATES);
|
|
177
|
+
const lines = shown.map((candidate) => ` - ${candidateLabel(candidate)}`);
|
|
178
|
+
const hidden = candidates.length - shown.length;
|
|
179
|
+
if (hidden > 0) lines.push(` \u2026 and ${hidden} more`);
|
|
180
|
+
return lines;
|
|
181
|
+
}
|
|
182
|
+
|
|
183
|
+
// packages/command/src/index.ts
|
|
184
|
+
var name = "command-devlead";
|
|
185
|
+
var inject = ["commands", "devLead"];
|
|
186
|
+
var DESCRIPTION = "Turn DevLead mode on or off for this Session, watch or unwatch another Session, and inspect the DevLead mode, watch set, and recent notification digest.";
|
|
187
|
+
var NOT_ENABLED_MESSAGE = "DevLead mode is off for this Session, so its watch set cannot change. Turn it on with /devlead on first.";
|
|
188
|
+
async function collectStatus(ctx, invocation) {
|
|
189
|
+
const view = ctx.devLead.view(invocation.agent);
|
|
190
|
+
const watched = [];
|
|
191
|
+
const missingWatched = [];
|
|
192
|
+
if (view.sessions.length > 0) {
|
|
193
|
+
const sessions = await ctx.devLead.listSessions(
|
|
194
|
+
invocation.agent,
|
|
195
|
+
{ watchedOnly: true },
|
|
196
|
+
invocation.signal
|
|
197
|
+
);
|
|
198
|
+
const byId = new Map(sessions.map((session) => [session.sessionId, session]));
|
|
199
|
+
for (const sessionId of view.sessions) {
|
|
200
|
+
const session = byId.get(sessionId);
|
|
201
|
+
if (session === void 0) missingWatched.push(sessionId);
|
|
202
|
+
else watched.push(session);
|
|
203
|
+
}
|
|
204
|
+
}
|
|
205
|
+
return {
|
|
206
|
+
enabled: view.enabled,
|
|
207
|
+
watched,
|
|
208
|
+
missingWatched,
|
|
209
|
+
notifications: ctx.devLead.notifications(invocation.agent, { limit: RECENT_NOTIFICATION_LIMIT })
|
|
210
|
+
};
|
|
211
|
+
}
|
|
212
|
+
async function collectCandidates(ctx, invocation, watchedSessionIds) {
|
|
213
|
+
const sessions = await ctx.devLead.listSessions(invocation.agent, {}, invocation.signal);
|
|
214
|
+
return mergeCandidates(sessions, watchedSessionIds);
|
|
215
|
+
}
|
|
216
|
+
function ambiguousResult(query, candidates) {
|
|
217
|
+
return errorResult([
|
|
218
|
+
`Session reference "${query}" is ambiguous; it matches ${candidates.length} Sessions:`,
|
|
219
|
+
...formatCandidates(candidates),
|
|
220
|
+
"Use a longer prefix or the full Session id."
|
|
221
|
+
].join("\n"));
|
|
222
|
+
}
|
|
223
|
+
function missingSessionResult(query) {
|
|
224
|
+
return errorResult(
|
|
225
|
+
`No Session matches "${query}". Check the Session id, or run /devlead to inspect the watched Sessions.`
|
|
226
|
+
);
|
|
227
|
+
}
|
|
228
|
+
function referenceLabel(sessionId, title) {
|
|
229
|
+
return title === void 0 ? sessionId : `${title} (${sessionId})`;
|
|
230
|
+
}
|
|
231
|
+
async function resolveBeyondListing(ctx, invocation, reference) {
|
|
232
|
+
try {
|
|
233
|
+
const view = await ctx.devLead.getSession(invocation.agent, reference, invocation.signal);
|
|
234
|
+
return view.title === void 0 ? { kind: "resolved", sessionId: view.sessionId } : { kind: "resolved", sessionId: view.sessionId, title: view.title };
|
|
235
|
+
} catch (error) {
|
|
236
|
+
if (!isDevLeadError(error)) throw error;
|
|
237
|
+
if (error.code === "DEVLEAD_INVALID_INPUT") return { kind: "ambiguous", message: error.message };
|
|
238
|
+
if (error.code === "DEVLEAD_SESSION_NOT_FOUND") return { kind: "missing" };
|
|
239
|
+
throw error;
|
|
240
|
+
}
|
|
241
|
+
}
|
|
242
|
+
async function resolveWatchTarget(ctx, invocation, reference, watchedSessionIds) {
|
|
243
|
+
const candidates = await collectCandidates(ctx, invocation, watchedSessionIds);
|
|
244
|
+
const resolution = resolveSessionReference(reference, candidates);
|
|
245
|
+
if (resolution.kind === "resolved") return resolution;
|
|
246
|
+
if (resolution.kind === "ambiguous") {
|
|
247
|
+
return { kind: "failure", result: ambiguousResult(reference, resolution.candidates) };
|
|
248
|
+
}
|
|
249
|
+
const fallback = await resolveBeyondListing(ctx, invocation, reference);
|
|
250
|
+
if (fallback.kind === "resolved") return fallback;
|
|
251
|
+
if (fallback.kind === "ambiguous") {
|
|
252
|
+
return {
|
|
253
|
+
kind: "failure",
|
|
254
|
+
result: errorResult(`${fallback.message}
|
|
255
|
+
Use a longer prefix or the full Session id.`)
|
|
256
|
+
};
|
|
257
|
+
}
|
|
258
|
+
return { kind: "failure", result: missingSessionResult(reference) };
|
|
259
|
+
}
|
|
260
|
+
async function executeMode(ctx, invocation, enabled) {
|
|
261
|
+
if (ctx.devLead.view(invocation.agent).enabled === enabled) {
|
|
262
|
+
const title2 = enabled ? "DevLead mode is already on." : "DevLead mode is already off.";
|
|
263
|
+
return renderStatus(await collectStatus(ctx, invocation), title2);
|
|
264
|
+
}
|
|
265
|
+
await ctx.devLead.setEnabled(invocation.agent, enabled, invocation.signal);
|
|
266
|
+
const title = enabled ? "DevLead mode enabled." : "DevLead mode disabled.";
|
|
267
|
+
return renderStatus(await collectStatus(ctx, invocation), title);
|
|
268
|
+
}
|
|
269
|
+
async function executeWatch(ctx, invocation, command) {
|
|
270
|
+
const view = ctx.devLead.view(invocation.agent);
|
|
271
|
+
if (!view.enabled) return errorResult(NOT_ENABLED_MESSAGE);
|
|
272
|
+
const target = await resolveWatchTarget(ctx, invocation, command.session, view.sessions);
|
|
273
|
+
if (target.kind === "failure") return target.result;
|
|
274
|
+
const { sessionId } = target;
|
|
275
|
+
const label = referenceLabel(sessionId, target.title);
|
|
276
|
+
const watching = view.sessions.includes(sessionId);
|
|
277
|
+
if (command.kind === "watch") {
|
|
278
|
+
const title2 = watching ? `Already watching ${label}.` : `Now watching ${label}.`;
|
|
279
|
+
if (!watching) await ctx.devLead.watchSession(invocation.agent, sessionId, true);
|
|
280
|
+
return renderStatus(await collectStatus(ctx, invocation), title2);
|
|
281
|
+
}
|
|
282
|
+
const title = watching ? `Stopped watching ${label}.` : `Not watching ${label}.`;
|
|
283
|
+
if (watching) await ctx.devLead.watchSession(invocation.agent, sessionId, false);
|
|
284
|
+
return renderStatus(await collectStatus(ctx, invocation), title);
|
|
285
|
+
}
|
|
286
|
+
function friendlyDevLeadError(error) {
|
|
287
|
+
switch (error.code) {
|
|
288
|
+
case "DEVLEAD_NOT_ENABLED":
|
|
289
|
+
return NOT_ENABLED_MESSAGE;
|
|
290
|
+
case "DEVLEAD_AGENT_NOT_LIVE":
|
|
291
|
+
return "This Session is no longer live, so DevLead mode cannot be changed. Open it again from the sidebar and retry.";
|
|
292
|
+
case "DEVLEAD_INVALID_INPUT":
|
|
293
|
+
return `The /devlead request is not usable: ${error.message}`;
|
|
294
|
+
case "DEVLEAD_SESSION_NOT_FOUND":
|
|
295
|
+
return `The host could not find that Session: ${error.message}`;
|
|
296
|
+
case "DEVLEAD_SESSION_ARCHIVED":
|
|
297
|
+
return "That Session is archived; unarchive it in DSH before watching or steering it.";
|
|
298
|
+
case "DEVLEAD_SESSION_UNAVAILABLE":
|
|
299
|
+
return `That Session cannot be resumed right now: ${error.message}`;
|
|
300
|
+
case "DEVLEAD_WATCH_LIMIT":
|
|
301
|
+
return "The maximum number of watched Sessions has been reached. Stop watching one with /devlead unwatch <session> first.";
|
|
302
|
+
case "DEVLEAD_SELF_WATCH":
|
|
303
|
+
return "A DevLead Session cannot watch itself.";
|
|
304
|
+
case "DEVLEAD_PROJECTION_INVALID":
|
|
305
|
+
return `This Session's DevLead records are damaged: ${error.message}. Inspect the Session log for the offending plugin:devlead record.`;
|
|
306
|
+
case "DEVLEAD_WORKSPACE_NOT_FOUND":
|
|
307
|
+
return `The Workspace could not be resolved: ${error.message}`;
|
|
308
|
+
case "DEVLEAD_DIRECTORY_MISSING":
|
|
309
|
+
return `The target directory is missing: ${error.message}`;
|
|
310
|
+
default:
|
|
311
|
+
return `The DevLead request failed: ${error.message}`;
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
async function executeDevLeadCommand(ctx, invocation) {
|
|
315
|
+
const command = parseDevLeadCommand(invocation.rawInput);
|
|
316
|
+
if (invocation.attachments.length > 0) {
|
|
317
|
+
return errorResult(
|
|
318
|
+
"The /devlead command does not accept attachments; use the plain command text instead."
|
|
319
|
+
);
|
|
320
|
+
}
|
|
321
|
+
if (command.kind === "invalid") return errorResult(`${command.message}
|
|
322
|
+
${USAGE}`);
|
|
323
|
+
try {
|
|
324
|
+
switch (command.kind) {
|
|
325
|
+
case "status":
|
|
326
|
+
return renderStatus(await collectStatus(ctx, invocation));
|
|
327
|
+
case "on":
|
|
328
|
+
case "off":
|
|
329
|
+
return await executeMode(ctx, invocation, command.kind === "on");
|
|
330
|
+
case "watch":
|
|
331
|
+
case "unwatch":
|
|
332
|
+
return await executeWatch(ctx, invocation, command);
|
|
333
|
+
}
|
|
334
|
+
} catch (error) {
|
|
335
|
+
if (isDevLeadError(error)) return errorResult(friendlyDevLeadError(error));
|
|
336
|
+
throw error;
|
|
337
|
+
}
|
|
338
|
+
}
|
|
339
|
+
function apply(ctx) {
|
|
340
|
+
ctx.commands.register({
|
|
341
|
+
definitionId: CommandDefinitionId("@yankeguo/dsh-command-devlead"),
|
|
342
|
+
name: DEVLEAD_COMMAND_NAME2,
|
|
343
|
+
description: DESCRIPTION,
|
|
344
|
+
input: { hint: COMMAND_GRAMMAR },
|
|
345
|
+
handler: (invocation) => executeDevLeadCommand(ctx, invocation)
|
|
346
|
+
});
|
|
347
|
+
}
|
|
348
|
+
export {
|
|
349
|
+
apply,
|
|
350
|
+
inject,
|
|
351
|
+
name
|
|
352
|
+
};
|
package/package.json
CHANGED
|
@@ -1,6 +1,35 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@yankeguo/dsh-command-devlead",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "Human-facing /devlead command: enable or disable DevLead mode for the current session and inspect the lead's managed workspaces, sessions, and notifications.",
|
|
5
|
+
"license": "MIT",
|
|
6
|
+
"type": "module",
|
|
7
|
+
"main": "lib/index.js",
|
|
8
|
+
"exports": {
|
|
9
|
+
".": "./lib/index.js",
|
|
10
|
+
"./package.json": "./package.json"
|
|
11
|
+
},
|
|
12
|
+
"files": [
|
|
13
|
+
"lib"
|
|
14
|
+
],
|
|
15
|
+
"peerDependencies": {
|
|
16
|
+
"@deepseek-ai/cordis": "~4.1.0",
|
|
17
|
+
"@deepseek-ai/dsh-commands": "0.2.2-rc.1"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"@yankeguo/dsh-devlead": "0.1.0",
|
|
21
|
+
"@yankeguo/dsh-devlead-protocol": "0.1.0"
|
|
22
|
+
},
|
|
23
|
+
"engines": {
|
|
24
|
+
"dsh": ">=0.2.2-rc.1 <0.3.0"
|
|
25
|
+
},
|
|
26
|
+
"publishConfig": {
|
|
27
|
+
"access": "public"
|
|
28
|
+
},
|
|
29
|
+
"repository": {
|
|
30
|
+
"type": "git",
|
|
31
|
+
"url": "git+https://github.com/yankeguo/dsh-devlead.git",
|
|
32
|
+
"directory": "packages/command"
|
|
33
|
+
},
|
|
34
|
+
"homepage": "https://github.com/yankeguo/dsh-devlead#readme"
|
|
6
35
|
}
|
package/README.md
DELETED