@lumoai/cli 1.5.0 → 1.6.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/assets/skill.md +189 -16
- package/dist/cli/src/commands/auth-login.js +4 -3
- package/dist/cli/src/commands/auth-logout.js +2 -1
- package/dist/cli/src/commands/doc-bind.js +3 -3
- package/dist/cli/src/commands/doc-create.js +5 -5
- package/dist/cli/src/commands/doc-delete.js +4 -4
- package/dist/cli/src/commands/doc-import-gdoc.js +82 -0
- package/dist/cli/src/commands/doc-list.js +7 -7
- package/dist/cli/src/commands/doc-move.js +8 -8
- package/dist/cli/src/commands/doc-share-list.js +11 -8
- package/dist/cli/src/commands/doc-share.js +7 -5
- package/dist/cli/src/commands/doc-show.js +6 -6
- package/dist/cli/src/commands/doc-sync.js +44 -0
- package/dist/cli/src/commands/doc-unbind.js +4 -4
- package/dist/cli/src/commands/doc-unshare.js +9 -7
- package/dist/cli/src/commands/doc-update.js +5 -5
- package/dist/cli/src/commands/hook.js +2 -2
- package/dist/cli/src/commands/memory-project-add.js +19 -4
- package/dist/cli/src/commands/memory-project-list.js +1 -2
- package/dist/cli/src/commands/memory-promote.js +3 -3
- package/dist/cli/src/commands/memory-rm.js +1 -2
- package/dist/cli/src/commands/memory-task-add.js +19 -4
- package/dist/cli/src/commands/memory-task-list.js +1 -2
- package/dist/cli/src/commands/milestone-create.js +4 -4
- package/dist/cli/src/commands/milestone-delete.js +5 -5
- package/dist/cli/src/commands/milestone-list.js +3 -3
- package/dist/cli/src/commands/milestone-show.js +5 -5
- package/dist/cli/src/commands/milestone-update.js +6 -5
- package/dist/cli/src/commands/project-list.js +3 -3
- package/dist/cli/src/commands/session-attach.js +5 -5
- package/dist/cli/src/commands/session-detach.js +3 -3
- package/dist/cli/src/commands/session-status.js +3 -3
- package/dist/cli/src/commands/session-wrap.js +32 -0
- package/dist/cli/src/commands/setup.js +33 -7
- package/dist/cli/src/commands/sprint-add.js +3 -3
- package/dist/cli/src/commands/sprint-close.js +5 -5
- package/dist/cli/src/commands/sprint-create.js +4 -4
- package/dist/cli/src/commands/sprint-delete.js +5 -5
- package/dist/cli/src/commands/sprint-list.js +3 -3
- package/dist/cli/src/commands/sprint-remove.js +3 -3
- package/dist/cli/src/commands/sprint-show.js +4 -4
- package/dist/cli/src/commands/sprint-start.js +4 -4
- package/dist/cli/src/commands/sprint-summary.js +7 -7
- package/dist/cli/src/commands/sprint-update.js +6 -5
- package/dist/cli/src/commands/task-artifact-add.js +17 -5
- package/dist/cli/src/commands/task-artifact-list.js +4 -4
- package/dist/cli/src/commands/task-artifact-rm.js +4 -4
- package/dist/cli/src/commands/task-artifact-show.js +8 -8
- package/dist/cli/src/commands/task-artifact-update.js +5 -5
- package/dist/cli/src/commands/task-comment-list.js +111 -0
- package/dist/cli/src/commands/task-comment.js +3 -3
- package/dist/cli/src/commands/task-context.js +29 -12
- package/dist/cli/src/commands/task-create.js +7 -7
- package/dist/cli/src/commands/task-figma-add.js +3 -2
- package/dist/cli/src/commands/task-figma-context.js +61 -0
- package/dist/cli/src/commands/task-figma-list.js +3 -2
- package/dist/cli/src/commands/task-figma-refresh.js +4 -3
- package/dist/cli/src/commands/task-figma-rm.js +3 -2
- package/dist/cli/src/commands/task-list.js +1 -2
- package/dist/cli/src/commands/task-pr-show.js +66 -0
- package/dist/cli/src/commands/task-show.js +8 -7
- package/dist/cli/src/commands/task-slack-show.js +59 -0
- package/dist/cli/src/commands/task-update.js +7 -7
- package/dist/cli/src/commands/task-web-show.js +64 -0
- package/dist/cli/src/commands/whoami.js +4 -3
- package/dist/cli/src/commands/wrap/progress-comment-section.js +81 -0
- package/dist/cli/src/index.js +174 -102
- package/dist/cli/src/lib/agent.js +10 -1
- package/dist/cli/src/lib/api.js +81 -1
- package/dist/cli/src/lib/config.js +2 -1
- package/dist/cli/src/lib/doc-input.js +12 -1
- package/dist/cli/src/lib/editor.js +66 -0
- package/dist/cli/src/lib/figma-api.js +1 -1
- package/dist/cli/src/lib/format.js +3 -2
- package/dist/cli/src/lib/hook-runner.js +64 -19
- package/dist/cli/src/lib/hooks-template.js +52 -7
- package/dist/cli/src/lib/memory-content.js +4 -3
- package/dist/cli/src/lib/path-guard.js +125 -0
- package/dist/cli/src/lib/progress-comment-api.js +47 -0
- package/dist/cli/src/lib/resolve-doc-id.js +2 -1
- package/dist/cli/src/lib/resolve-member.js +2 -1
- package/dist/cli/src/lib/sanitize.js +17 -0
- package/dist/cli/src/lib/tag-resolver.js +2 -1
- package/dist/cli/src/lib/update-check.js +2 -2
- package/dist/cli/src/lib/wrap-panel.js +15 -0
- package/package.json +1 -1
|
@@ -0,0 +1,66 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.taskPrShow = taskPrShow;
|
|
4
|
+
const config_1 = require("../lib/config");
|
|
5
|
+
const api_1 = require("../lib/api");
|
|
6
|
+
const sanitize_1 = require("../lib/sanitize");
|
|
7
|
+
/**
|
|
8
|
+
* `lumo task pr show <LUM-N> <number>`
|
|
9
|
+
*
|
|
10
|
+
* Tier-2 retrieval for the cheap inline PR card. Reads the synced PR record
|
|
11
|
+
* (title, state, ciStatus, branches, author, url) from
|
|
12
|
+
* `/api/tasks/:id/pull-requests/:number`. Live diff + review comments need a
|
|
13
|
+
* GitHub token, so the route degrades to the stored record + a `note`; we print
|
|
14
|
+
* the note when present.
|
|
15
|
+
*/
|
|
16
|
+
async function taskPrShow(identifier, prNumber) {
|
|
17
|
+
if (!identifier || !prNumber) {
|
|
18
|
+
console.error('Error: usage: lumo task pr show <LUM-42> <number>');
|
|
19
|
+
return 1;
|
|
20
|
+
}
|
|
21
|
+
const creds = (0, config_1.readCredentials)();
|
|
22
|
+
if (!creds) {
|
|
23
|
+
console.error('Error: not logged in. Run `lumo auth login` first.');
|
|
24
|
+
return 1;
|
|
25
|
+
}
|
|
26
|
+
const apiUrl = (0, api_1.resolveAuthedApiUrl)(creds.apiUrl);
|
|
27
|
+
const base = (0, api_1.trimTrailingSlash)(apiUrl);
|
|
28
|
+
let res;
|
|
29
|
+
try {
|
|
30
|
+
res = await fetch(`${base}/api/tasks/${encodeURIComponent(identifier)}/pull-requests/${encodeURIComponent(prNumber)}`, { headers: { Authorization: `Bearer ${creds.token}` } });
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
34
|
+
console.error(`Error: could not reach Lumo API at ${apiUrl} (${msg})`);
|
|
35
|
+
return 1;
|
|
36
|
+
}
|
|
37
|
+
if (res.status === 401) {
|
|
38
|
+
console.error('Error: API key invalid or revoked. Run `lumo auth login`.');
|
|
39
|
+
return 1;
|
|
40
|
+
}
|
|
41
|
+
if (res.status === 400) {
|
|
42
|
+
console.error(`Error: invalid PR number "${prNumber}"`);
|
|
43
|
+
return 1;
|
|
44
|
+
}
|
|
45
|
+
if (res.status === 404) {
|
|
46
|
+
console.error(`Error: task ${identifier} or PR #${prNumber} not found in workspace ${creds.workspaceSlug}`);
|
|
47
|
+
return 1;
|
|
48
|
+
}
|
|
49
|
+
if (!res.ok) {
|
|
50
|
+
console.error(`Error: pr show failed (HTTP ${res.status})`);
|
|
51
|
+
return 1;
|
|
52
|
+
}
|
|
53
|
+
const { pullRequest: pr, note } = (await res.json());
|
|
54
|
+
console.log(`#${pr.number}${pr.repo ? ` (${(0, sanitize_1.sanitizeField)(pr.repo)})` : ''} ${(0, sanitize_1.sanitizeField)(pr.title ?? '')}`);
|
|
55
|
+
console.log(`state: ${pr.state ?? 'unknown'}${pr.isDraft ? ' · draft' : ''}`);
|
|
56
|
+
if (pr.ciStatus)
|
|
57
|
+
console.log(`ci: ${pr.ciStatus}`);
|
|
58
|
+
if (pr.authorLogin)
|
|
59
|
+
console.log(`author: ${(0, sanitize_1.sanitizeField)(pr.authorLogin)}`);
|
|
60
|
+
if (pr.headBranch || pr.baseBranch)
|
|
61
|
+
console.log(`branch: ${pr.headBranch ?? '?'} → ${pr.baseBranch ?? '?'}`);
|
|
62
|
+
if (pr.url)
|
|
63
|
+
console.log(`url: ${pr.url}`);
|
|
64
|
+
if (note)
|
|
65
|
+
console.log(`\nnote: ${(0, sanitize_1.sanitizeField)(note)}`);
|
|
66
|
+
}
|
|
@@ -4,20 +4,22 @@ exports.formatTaskShow = formatTaskShow;
|
|
|
4
4
|
exports.taskShow = taskShow;
|
|
5
5
|
const config_1 = require("../lib/config");
|
|
6
6
|
const api_1 = require("../lib/api");
|
|
7
|
+
const sanitize_1 = require("../lib/sanitize");
|
|
7
8
|
/**
|
|
8
9
|
* Render task detail as a key:value block. Multi-line description is
|
|
9
10
|
* indented under a `Description:` label so the structure stays scannable.
|
|
10
11
|
*/
|
|
11
12
|
function formatTaskShow(task) {
|
|
12
13
|
const lines = [];
|
|
13
|
-
lines.push(`${task.identifier} ${task.title}`);
|
|
14
|
+
lines.push(`${task.identifier} ${(0, sanitize_1.sanitizeField)(task.title)}`);
|
|
14
15
|
lines.push(`Status: ${task.status}`);
|
|
15
16
|
lines.push(`Priority: ${task.priority}`);
|
|
16
|
-
lines.push(`Project: ${task.project.name}`);
|
|
17
|
+
lines.push(`Project: ${(0, sanitize_1.sanitizeField)(task.project.name)}`);
|
|
17
18
|
if (task.assignee) {
|
|
19
|
+
const label = (0, sanitize_1.sanitizeField)(task.assignee.label);
|
|
18
20
|
const detail = task.assignee.email && task.assignee.type === 'member'
|
|
19
|
-
? `${
|
|
20
|
-
:
|
|
21
|
+
? `${label} <${(0, sanitize_1.sanitizeField)(task.assignee.email)}>`
|
|
22
|
+
: label;
|
|
21
23
|
lines.push(`Assignee: ${detail}`);
|
|
22
24
|
}
|
|
23
25
|
else {
|
|
@@ -28,7 +30,7 @@ function formatTaskShow(task) {
|
|
|
28
30
|
if (body && body.trim().length > 0) {
|
|
29
31
|
lines.push('');
|
|
30
32
|
lines.push('Description:');
|
|
31
|
-
for (const line of body.split('\n')) {
|
|
33
|
+
for (const line of (0, sanitize_1.sanitizeField)(body).split('\n')) {
|
|
32
34
|
lines.push(` ${line}`);
|
|
33
35
|
}
|
|
34
36
|
}
|
|
@@ -44,8 +46,7 @@ async function taskShow(identifier) {
|
|
|
44
46
|
console.error('Error: not logged in. Run `lumo auth login` first.');
|
|
45
47
|
return 1;
|
|
46
48
|
}
|
|
47
|
-
const
|
|
48
|
-
const apiUrl = envUrl && envUrl.length > 0 ? envUrl : creds.apiUrl;
|
|
49
|
+
const apiUrl = (0, api_1.resolveAuthedApiUrl)(creds.apiUrl);
|
|
49
50
|
const url = `${(0, api_1.trimTrailingSlash)(apiUrl)}/api/tasks/by-identifier/${encodeURIComponent(identifier)}`;
|
|
50
51
|
let res;
|
|
51
52
|
try {
|
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.taskSlackShow = taskSlackShow;
|
|
4
|
+
const config_1 = require("../lib/config");
|
|
5
|
+
const api_1 = require("../lib/api");
|
|
6
|
+
const sanitize_1 = require("../lib/sanitize");
|
|
7
|
+
/**
|
|
8
|
+
* `lumo task slack show <LUM-N> <context-id>`
|
|
9
|
+
*
|
|
10
|
+
* Tier-2 retrieval for the cheap inline Slack card. Fetches the stored thread
|
|
11
|
+
* snapshot (no live Slack call) from
|
|
12
|
+
* `/api/tasks/:id/slack-contexts/:contextId/snapshot` and prints one line per
|
|
13
|
+
* message as `author: text`, falling back to `@<userId>` when the display name
|
|
14
|
+
* is missing.
|
|
15
|
+
*/
|
|
16
|
+
async function taskSlackShow(identifier, contextId) {
|
|
17
|
+
if (!identifier || !contextId) {
|
|
18
|
+
console.error('Error: usage: lumo task slack show <LUM-42> <context-id>');
|
|
19
|
+
return 1;
|
|
20
|
+
}
|
|
21
|
+
const creds = (0, config_1.readCredentials)();
|
|
22
|
+
if (!creds) {
|
|
23
|
+
console.error('Error: not logged in. Run `lumo auth login` first.');
|
|
24
|
+
return 1;
|
|
25
|
+
}
|
|
26
|
+
const apiUrl = (0, api_1.resolveAuthedApiUrl)(creds.apiUrl);
|
|
27
|
+
const base = (0, api_1.trimTrailingSlash)(apiUrl);
|
|
28
|
+
let res;
|
|
29
|
+
try {
|
|
30
|
+
res = await fetch(`${base}/api/tasks/${encodeURIComponent(identifier)}/slack-contexts/${encodeURIComponent(contextId)}/snapshot`, { headers: { Authorization: `Bearer ${creds.token}` } });
|
|
31
|
+
}
|
|
32
|
+
catch (err) {
|
|
33
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
34
|
+
console.error(`Error: could not reach Lumo API at ${apiUrl} (${msg})`);
|
|
35
|
+
return 1;
|
|
36
|
+
}
|
|
37
|
+
if (res.status === 401) {
|
|
38
|
+
console.error('Error: API key invalid or revoked. Run `lumo auth login`.');
|
|
39
|
+
return 1;
|
|
40
|
+
}
|
|
41
|
+
if (res.status === 404) {
|
|
42
|
+
console.error(`Error: task ${identifier} or slack context ${contextId} not found in workspace ${creds.workspaceSlug}`);
|
|
43
|
+
return 1;
|
|
44
|
+
}
|
|
45
|
+
if (!res.ok) {
|
|
46
|
+
console.error(`Error: slack show failed (HTTP ${res.status})`);
|
|
47
|
+
return 1;
|
|
48
|
+
}
|
|
49
|
+
const { snapshot } = (await res.json());
|
|
50
|
+
const messages = snapshot?.messages ?? [];
|
|
51
|
+
if (messages.length === 0) {
|
|
52
|
+
console.log('(no messages in stored snapshot)');
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
for (const m of messages) {
|
|
56
|
+
const author = (0, sanitize_1.sanitizeField)(m.userName ?? '@' + m.userId);
|
|
57
|
+
console.log(`${author}: ${(0, sanitize_1.sanitizeField)(m.text)}`);
|
|
58
|
+
}
|
|
59
|
+
}
|
|
@@ -10,6 +10,7 @@ const api_1 = require("../lib/api");
|
|
|
10
10
|
const task_create_1 = require("./task-create");
|
|
11
11
|
const tag_resolver_1 = require("../lib/tag-resolver");
|
|
12
12
|
const resolve_1 = require("../lib/resolve");
|
|
13
|
+
const sanitize_1 = require("../lib/sanitize");
|
|
13
14
|
const ALLOWED_STATUSES = ['TODO', 'IN_PROGRESS', 'IN_REVIEW', 'DONE'];
|
|
14
15
|
/**
|
|
15
16
|
* Pure function: given the task's current sprint binding and the resolved
|
|
@@ -87,10 +88,10 @@ function buildUpdatePayload(opts) {
|
|
|
87
88
|
* Appends a Tags line when tags are present.
|
|
88
89
|
*/
|
|
89
90
|
function formatUpdatedTaskLine(task) {
|
|
90
|
-
const escapedTitle = task.title.replace(/"/g, '\\"');
|
|
91
|
+
const escapedTitle = (0, sanitize_1.sanitizeField)(task.title).replace(/"/g, '\\"');
|
|
91
92
|
const head = `Updated ${task.identifier} "${escapedTitle}" ${task.url}`;
|
|
92
93
|
if (task.tags && task.tags.length > 0) {
|
|
93
|
-
return `${head}\nTags: ${task.tags.join(', ')}`;
|
|
94
|
+
return `${head}\nTags: ${task.tags.map(sanitize_1.sanitizeField).join(', ')}`;
|
|
94
95
|
}
|
|
95
96
|
return head;
|
|
96
97
|
}
|
|
@@ -146,8 +147,7 @@ async function taskUpdate(identifier, opts) {
|
|
|
146
147
|
console.error('Error: not logged in. Run `lumo auth login` first.');
|
|
147
148
|
return 1;
|
|
148
149
|
}
|
|
149
|
-
const
|
|
150
|
-
const apiUrl = envUrl && envUrl.length > 0 ? envUrl : creds.apiUrl;
|
|
150
|
+
const apiUrl = (0, api_1.resolveAuthedApiUrl)(creds.apiUrl);
|
|
151
151
|
// Resolve tag refs into ids
|
|
152
152
|
let tagIds;
|
|
153
153
|
let addTagIds;
|
|
@@ -235,7 +235,7 @@ async function taskUpdate(identifier, opts) {
|
|
|
235
235
|
// Body wasn't JSON; fall through to status-only message
|
|
236
236
|
}
|
|
237
237
|
if (serverMsg) {
|
|
238
|
-
console.error(`Error: ${serverMsg}`);
|
|
238
|
+
console.error(`Error: ${(0, sanitize_1.sanitizeField)(serverMsg)}`);
|
|
239
239
|
}
|
|
240
240
|
else {
|
|
241
241
|
console.error(`Error: task update failed (HTTP ${res.status})`);
|
|
@@ -365,7 +365,7 @@ async function taskUpdate(identifier, opts) {
|
|
|
365
365
|
errMsg = b.error;
|
|
366
366
|
}
|
|
367
367
|
catch { /* ignore */ }
|
|
368
|
-
console.error(`Error: ${errMsg}`);
|
|
368
|
+
console.error(`Error: ${(0, sanitize_1.sanitizeField)(errMsg)}`);
|
|
369
369
|
return 1;
|
|
370
370
|
}
|
|
371
371
|
const oldLabel = oldNumber !== null ? `#${oldNumber}` : action.oldSprintId;
|
|
@@ -397,7 +397,7 @@ async function taskUpdate(identifier, opts) {
|
|
|
397
397
|
errMsg = b.error;
|
|
398
398
|
}
|
|
399
399
|
catch { /* ignore */ }
|
|
400
|
-
console.error(`Error: ${errMsg}`);
|
|
400
|
+
console.error(`Error: ${(0, sanitize_1.sanitizeField)(errMsg)}`);
|
|
401
401
|
return 1;
|
|
402
402
|
}
|
|
403
403
|
// resolvedSprintNumber is set from the resolveSprintId call above
|
|
@@ -0,0 +1,64 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.taskWebShow = taskWebShow;
|
|
4
|
+
const config_1 = require("../lib/config");
|
|
5
|
+
const api_1 = require("../lib/api");
|
|
6
|
+
const sanitize_1 = require("../lib/sanitize");
|
|
7
|
+
/**
|
|
8
|
+
* `lumo task web show <LUM-N> <link-id>`
|
|
9
|
+
*
|
|
10
|
+
* Tier-2 retrieval for the cheap inline WebLink card. Fetches the page body
|
|
11
|
+
* (cached, or fetched behind the SSRF guard on first read) from
|
|
12
|
+
* `/api/tasks/:id/web-links/:linkId/body` and prints it as plain text.
|
|
13
|
+
*/
|
|
14
|
+
async function taskWebShow(identifier, linkId) {
|
|
15
|
+
if (!identifier || !linkId) {
|
|
16
|
+
console.error('Error: usage: lumo task web show <LUM-42> <link-id>');
|
|
17
|
+
return 1;
|
|
18
|
+
}
|
|
19
|
+
const creds = (0, config_1.readCredentials)();
|
|
20
|
+
if (!creds) {
|
|
21
|
+
console.error('Error: not logged in. Run `lumo auth login` first.');
|
|
22
|
+
return 1;
|
|
23
|
+
}
|
|
24
|
+
const apiUrl = (0, api_1.resolveAuthedApiUrl)(creds.apiUrl);
|
|
25
|
+
const base = (0, api_1.trimTrailingSlash)(apiUrl);
|
|
26
|
+
let res;
|
|
27
|
+
try {
|
|
28
|
+
res = await fetch(`${base}/api/tasks/${encodeURIComponent(identifier)}/web-links/${encodeURIComponent(linkId)}/body`, { headers: { Authorization: `Bearer ${creds.token}` } });
|
|
29
|
+
}
|
|
30
|
+
catch (err) {
|
|
31
|
+
const msg = err instanceof Error ? err.message : String(err);
|
|
32
|
+
console.error(`Error: could not reach Lumo API at ${apiUrl} (${msg})`);
|
|
33
|
+
return 1;
|
|
34
|
+
}
|
|
35
|
+
if (res.status === 401) {
|
|
36
|
+
console.error('Error: API key invalid or revoked. Run `lumo auth login`.');
|
|
37
|
+
return 1;
|
|
38
|
+
}
|
|
39
|
+
if (res.status === 404) {
|
|
40
|
+
console.error(`Error: task ${identifier} or web link ${linkId} not found in workspace ${creds.workspaceSlug}`);
|
|
41
|
+
return 1;
|
|
42
|
+
}
|
|
43
|
+
if (!res.ok) {
|
|
44
|
+
let serverMsg = null;
|
|
45
|
+
try {
|
|
46
|
+
const errBody = (await res.json());
|
|
47
|
+
if (typeof errBody.error === 'string')
|
|
48
|
+
serverMsg = errBody.error;
|
|
49
|
+
}
|
|
50
|
+
catch {
|
|
51
|
+
/* not JSON */
|
|
52
|
+
}
|
|
53
|
+
console.error(serverMsg
|
|
54
|
+
? `Error: ${(0, sanitize_1.sanitizeField)(serverMsg)}`
|
|
55
|
+
: `Error: web show failed (HTTP ${res.status})`);
|
|
56
|
+
return 1;
|
|
57
|
+
}
|
|
58
|
+
const { body } = (await res.json());
|
|
59
|
+
if (!body || body.trim().length === 0) {
|
|
60
|
+
console.log('(empty body)');
|
|
61
|
+
return;
|
|
62
|
+
}
|
|
63
|
+
console.log((0, sanitize_1.sanitizeField)(body));
|
|
64
|
+
}
|
|
@@ -2,6 +2,7 @@
|
|
|
2
2
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
3
|
exports.whoami = whoami;
|
|
4
4
|
const config_1 = require("../lib/config");
|
|
5
|
+
const sanitize_1 = require("../lib/sanitize");
|
|
5
6
|
async function whoami() {
|
|
6
7
|
const creds = (0, config_1.readCredentials)();
|
|
7
8
|
if (!creds) {
|
|
@@ -9,8 +10,8 @@ async function whoami() {
|
|
|
9
10
|
console.log('Run `lumo auth login` to log in');
|
|
10
11
|
return 1;
|
|
11
12
|
}
|
|
12
|
-
console.log(`Logged in as ${creds.email}`);
|
|
13
|
-
console.log(` Workspace: ${creds.workspaceName} (${creds.workspaceSlug})`);
|
|
14
|
-
console.log(` Key: ${creds.apiKeyName} (${creds.apiKeyPrefix})`);
|
|
13
|
+
console.log(`Logged in as ${(0, sanitize_1.sanitizeField)(creds.email)}`);
|
|
14
|
+
console.log(` Workspace: ${(0, sanitize_1.sanitizeField)(creds.workspaceName)} (${creds.workspaceSlug})`);
|
|
15
|
+
console.log(` Key: ${(0, sanitize_1.sanitizeField)(creds.apiKeyName)} (${creds.apiKeyPrefix})`);
|
|
15
16
|
console.log(` API: ${creds.apiUrl}`);
|
|
16
17
|
}
|
|
@@ -0,0 +1,81 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.ProgressCommentSection = void 0;
|
|
4
|
+
exports.formatProgressBody = formatProgressBody;
|
|
5
|
+
const sanitize_1 = require("../../lib/sanitize");
|
|
6
|
+
const line_prompt_1 = require("../../lib/line-prompt");
|
|
7
|
+
const editor_1 = require("../../lib/editor");
|
|
8
|
+
const progress_comment_api_1 = require("../../lib/progress-comment-api");
|
|
9
|
+
const HEADER = '本次会话进度';
|
|
10
|
+
/** Join turn summaries into a bulleted progress comment body under a header. */
|
|
11
|
+
function formatProgressBody(summaries) {
|
|
12
|
+
return [HEADER, ...summaries.map(s => `- ${s}`)].join('\n');
|
|
13
|
+
}
|
|
14
|
+
/**
|
|
15
|
+
* Wrap-panel section that drafts a progress comment from the session's
|
|
16
|
+
* unposted turnSummaries and posts it after y/e/s confirmation. Holds its own
|
|
17
|
+
* draft + body state between prepare() and run().
|
|
18
|
+
*/
|
|
19
|
+
class ProgressCommentSection {
|
|
20
|
+
deps;
|
|
21
|
+
title = '进度评论';
|
|
22
|
+
draft = null;
|
|
23
|
+
body = '';
|
|
24
|
+
constructor(deps) {
|
|
25
|
+
this.deps = deps;
|
|
26
|
+
}
|
|
27
|
+
async prepare() {
|
|
28
|
+
this.draft = await (0, progress_comment_api_1.fetchProgressDraft)(this.deps.creds, this.deps.sessionId);
|
|
29
|
+
if (!this.draft.taskIdentifier || this.draft.summaries.length === 0) {
|
|
30
|
+
return false;
|
|
31
|
+
}
|
|
32
|
+
this.body = formatProgressBody(this.draft.summaries.map(s => s.turnSummary));
|
|
33
|
+
return true;
|
|
34
|
+
}
|
|
35
|
+
async run(opts) {
|
|
36
|
+
const draft = this.draft;
|
|
37
|
+
if (!draft || !draft.watermark)
|
|
38
|
+
return;
|
|
39
|
+
// Preview: sanitize the server free-text before it hits the terminal.
|
|
40
|
+
process.stdout.write(`将发到 ${draft.taskIdentifier} "${(0, sanitize_1.sanitizeField)(draft.taskTitle ?? '')}":\n`);
|
|
41
|
+
process.stdout.write(`${(0, sanitize_1.sanitizeField)(this.body)}\n`);
|
|
42
|
+
if (opts.dryRun) {
|
|
43
|
+
process.stdout.write('(dry-run,未发送)\n');
|
|
44
|
+
return;
|
|
45
|
+
}
|
|
46
|
+
if (opts.yes) {
|
|
47
|
+
await this.post(draft.watermark, this.body);
|
|
48
|
+
return;
|
|
49
|
+
}
|
|
50
|
+
const choice = (await (0, line_prompt_1.promptLine)('[y] 发送 [e] 编辑 [s] 跳过 > ')).toLowerCase();
|
|
51
|
+
if (choice === 's' || choice === '') {
|
|
52
|
+
process.stdout.write('已跳过。\n');
|
|
53
|
+
return;
|
|
54
|
+
}
|
|
55
|
+
if (choice === 'e') {
|
|
56
|
+
const edited = (await (0, editor_1.editInEditor)(this.body)).trim();
|
|
57
|
+
if (edited.length === 0) {
|
|
58
|
+
process.stdout.write('正文为空,已跳过。\n');
|
|
59
|
+
return;
|
|
60
|
+
}
|
|
61
|
+
process.stdout.write(`${(0, sanitize_1.sanitizeField)(edited)}\n`);
|
|
62
|
+
const confirm = (await (0, line_prompt_1.promptLine)('[y] 发送 [s] 跳过 > ')).toLowerCase();
|
|
63
|
+
if (confirm !== 'y') {
|
|
64
|
+
process.stdout.write('已跳过。\n');
|
|
65
|
+
return;
|
|
66
|
+
}
|
|
67
|
+
await this.post(draft.watermark, edited);
|
|
68
|
+
return;
|
|
69
|
+
}
|
|
70
|
+
if (choice === 'y') {
|
|
71
|
+
await this.post(draft.watermark, this.body);
|
|
72
|
+
return;
|
|
73
|
+
}
|
|
74
|
+
process.stdout.write('无法识别的选择,已跳过。\n');
|
|
75
|
+
}
|
|
76
|
+
async post(watermark, body) {
|
|
77
|
+
const { commentId } = await (0, progress_comment_api_1.postProgressComment)(this.deps.creds, this.deps.sessionId, { body, watermark });
|
|
78
|
+
process.stdout.write(`已发送进度评论 (comment ${commentId})\n`);
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
exports.ProgressCommentSection = ProgressCommentSection;
|