@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
|
@@ -6,14 +6,18 @@ const config_1 = require("../lib/config");
|
|
|
6
6
|
const api_1 = require("../lib/api");
|
|
7
7
|
const resolve_doc_id_1 = require("../lib/resolve-doc-id");
|
|
8
8
|
const resolve_member_1 = require("../lib/resolve-member");
|
|
9
|
+
const sanitize_1 = require("../lib/sanitize");
|
|
9
10
|
function formatShareListRows(rows) {
|
|
10
11
|
if (rows.length === 0)
|
|
11
12
|
return [];
|
|
12
|
-
|
|
13
|
-
|
|
14
|
-
|
|
15
|
-
|
|
16
|
-
|
|
13
|
+
// Sanitize first, then measure/pad off the sanitized string so the
|
|
14
|
+
// column width matches the printed cell (control chars stripped).
|
|
15
|
+
const sanitized = rows.map(r => ({
|
|
16
|
+
name: (0, sanitize_1.sanitizeField)(r.displayName),
|
|
17
|
+
role: r.role,
|
|
18
|
+
}));
|
|
19
|
+
const nameWidth = Math.max(...sanitized.map(r => r.name.length));
|
|
20
|
+
return sanitized.map(r => `${r.name.padEnd(nameWidth, ' ')} ${r.role}`);
|
|
17
21
|
}
|
|
18
22
|
async function docShareList(docRef) {
|
|
19
23
|
if (!docRef) {
|
|
@@ -25,8 +29,7 @@ async function docShareList(docRef) {
|
|
|
25
29
|
console.error('Error: not logged in. Run `lumo auth login` first.');
|
|
26
30
|
return 1;
|
|
27
31
|
}
|
|
28
|
-
const
|
|
29
|
-
const apiUrl = envUrl && envUrl.length > 0 ? envUrl : creds.apiUrl;
|
|
32
|
+
const apiUrl = (0, api_1.resolveAuthedApiUrl)(creds.apiUrl);
|
|
30
33
|
const docId = await (0, resolve_doc_id_1.lookupDocId)(apiUrl, creds.token, docRef);
|
|
31
34
|
if (!docId) {
|
|
32
35
|
console.error(`Error: Document not found: ${docRef}`);
|
|
@@ -43,7 +46,7 @@ async function docShareList(docRef) {
|
|
|
43
46
|
]);
|
|
44
47
|
if (!sharesRes.ok) {
|
|
45
48
|
const text = await sharesRes.text();
|
|
46
|
-
console.error(`Error: ${sharesRes.status} ${sharesRes.statusText}: ${text}`);
|
|
49
|
+
console.error(`Error: ${sharesRes.status} ${sharesRes.statusText}: ${(0, sanitize_1.sanitizeField)(text)}`);
|
|
47
50
|
return 1;
|
|
48
51
|
}
|
|
49
52
|
const { shares } = (await sharesRes.json());
|
|
@@ -6,6 +6,7 @@ const config_1 = require("../lib/config");
|
|
|
6
6
|
const api_1 = require("../lib/api");
|
|
7
7
|
const resolve_doc_id_1 = require("../lib/resolve-doc-id");
|
|
8
8
|
const resolve_member_1 = require("../lib/resolve-member");
|
|
9
|
+
const sanitize_1 = require("../lib/sanitize");
|
|
9
10
|
const ALLOWED_ROLES = ['VIEWER', 'EDITOR', 'MANAGER'];
|
|
10
11
|
function normalizeRole(value) {
|
|
11
12
|
if (!value)
|
|
@@ -34,8 +35,7 @@ async function docShare(docRef, memberRef, opts) {
|
|
|
34
35
|
console.error('Error: not logged in. Run `lumo auth login` first.');
|
|
35
36
|
return 1;
|
|
36
37
|
}
|
|
37
|
-
const
|
|
38
|
-
const apiUrl = envUrl && envUrl.length > 0 ? envUrl : creds.apiUrl;
|
|
38
|
+
const apiUrl = (0, api_1.resolveAuthedApiUrl)(creds.apiUrl);
|
|
39
39
|
const docId = await (0, resolve_doc_id_1.lookupDocId)(apiUrl, creds.token, docRef);
|
|
40
40
|
if (!docId) {
|
|
41
41
|
console.error(`Error: Document not found: ${docRef}`);
|
|
@@ -55,7 +55,9 @@ async function docShare(docRef, memberRef, opts) {
|
|
|
55
55
|
return 1;
|
|
56
56
|
}
|
|
57
57
|
if (result.kind === 'ambiguous') {
|
|
58
|
-
const list = result.candidates
|
|
58
|
+
const list = result.candidates
|
|
59
|
+
.map(c => (0, sanitize_1.sanitizeField)(c.email ?? c.displayName))
|
|
60
|
+
.join(', ');
|
|
59
61
|
console.error(`Error: multiple members match "${result.query}": ${list}`);
|
|
60
62
|
return 1;
|
|
61
63
|
}
|
|
@@ -70,8 +72,8 @@ async function docShare(docRef, memberRef, opts) {
|
|
|
70
72
|
});
|
|
71
73
|
if (!res.ok) {
|
|
72
74
|
const text = await res.text();
|
|
73
|
-
console.error(`Error: ${res.status} ${res.statusText}: ${text}`);
|
|
75
|
+
console.error(`Error: ${res.status} ${res.statusText}: ${(0, sanitize_1.sanitizeField)(text)}`);
|
|
74
76
|
return 1;
|
|
75
77
|
}
|
|
76
|
-
console.log(`Shared ${docId} ↔ ${result.member.displayName} (${role})`);
|
|
78
|
+
console.log(`Shared ${docId} ↔ ${(0, sanitize_1.sanitizeField)(result.member.displayName)} (${role})`);
|
|
77
79
|
}
|
|
@@ -6,6 +6,7 @@ const config_1 = require("../lib/config");
|
|
|
6
6
|
const api_1 = require("../lib/api");
|
|
7
7
|
const markdown_tiptap_1 = require("../lib/markdown-tiptap");
|
|
8
8
|
const resolve_doc_id_1 = require("../lib/resolve-doc-id");
|
|
9
|
+
const sanitize_1 = require("../lib/sanitize");
|
|
9
10
|
function scopeLabel(s) {
|
|
10
11
|
if (s === 'PRIVATE')
|
|
11
12
|
return 'personal';
|
|
@@ -16,15 +17,15 @@ function scopeLabel(s) {
|
|
|
16
17
|
function formatShowOutput(vm) {
|
|
17
18
|
const lines = [
|
|
18
19
|
`ID: ${vm.id}`,
|
|
19
|
-
`Title: ${vm.title}`,
|
|
20
|
+
`Title: ${(0, sanitize_1.sanitizeField)(vm.title)}`,
|
|
20
21
|
`Scope: ${scopeLabel(vm.scope)}`,
|
|
21
|
-
`Project: ${vm.projectName
|
|
22
|
+
`Project: ${vm.projectName ? (0, sanitize_1.sanitizeField)(vm.projectName) : '-'}`,
|
|
22
23
|
`Created: ${vm.createdAt}`,
|
|
23
24
|
`Updated: ${vm.updatedAt}`,
|
|
24
25
|
`Mentioned tasks: ${vm.mentionedTasks.length ? vm.mentionedTasks.join(', ') : '-'}`,
|
|
25
26
|
];
|
|
26
27
|
const header = lines.join('\n');
|
|
27
|
-
return vm.bodyMarkdown ? `${header}\n\n${vm.bodyMarkdown}` : header;
|
|
28
|
+
return vm.bodyMarkdown ? `${header}\n\n${(0, sanitize_1.sanitizeField)(vm.bodyMarkdown)}` : header;
|
|
28
29
|
}
|
|
29
30
|
async function docShow(reference) {
|
|
30
31
|
if (!reference) {
|
|
@@ -36,8 +37,7 @@ async function docShow(reference) {
|
|
|
36
37
|
console.error('Error: not logged in. Run `lumo auth login` first.');
|
|
37
38
|
return 1;
|
|
38
39
|
}
|
|
39
|
-
const
|
|
40
|
-
const apiUrl = envUrl && envUrl.length > 0 ? envUrl : creds.apiUrl;
|
|
40
|
+
const apiUrl = (0, api_1.resolveAuthedApiUrl)(creds.apiUrl);
|
|
41
41
|
const id = await (0, resolve_doc_id_1.lookupDocId)(apiUrl, creds.token, reference);
|
|
42
42
|
if (!id) {
|
|
43
43
|
console.error(`Error: Document not found: ${reference}`);
|
|
@@ -48,7 +48,7 @@ async function docShow(reference) {
|
|
|
48
48
|
});
|
|
49
49
|
if (!res.ok) {
|
|
50
50
|
const text = await res.text();
|
|
51
|
-
console.error(`Error: ${res.status} ${res.statusText}: ${text}`);
|
|
51
|
+
console.error(`Error: ${res.status} ${res.statusText}: ${(0, sanitize_1.sanitizeField)(text)}`);
|
|
52
52
|
return 1;
|
|
53
53
|
}
|
|
54
54
|
// The exact shape of the GET response is not guaranteed; defensively unwrap.
|
|
@@ -0,0 +1,44 @@
|
|
|
1
|
+
"use strict";
|
|
2
|
+
Object.defineProperty(exports, "__esModule", { value: true });
|
|
3
|
+
exports.formatSyncedLine = formatSyncedLine;
|
|
4
|
+
exports.docSync = docSync;
|
|
5
|
+
const config_1 = require("../lib/config");
|
|
6
|
+
const api_1 = require("../lib/api");
|
|
7
|
+
const resolve_doc_id_1 = require("../lib/resolve-doc-id");
|
|
8
|
+
const sanitize_1 = require("../lib/sanitize");
|
|
9
|
+
function formatSyncedLine(doc) {
|
|
10
|
+
const escaped = (0, sanitize_1.sanitizeField)(doc.title).replace(/"/g, '\\"');
|
|
11
|
+
return `Synced ${doc.id} "${escaped}" from Google`;
|
|
12
|
+
}
|
|
13
|
+
async function docSync(reference) {
|
|
14
|
+
const creds = (0, config_1.readCredentials)();
|
|
15
|
+
if (!creds) {
|
|
16
|
+
console.error('Error: not logged in. Run `lumo auth login` first.');
|
|
17
|
+
return 1;
|
|
18
|
+
}
|
|
19
|
+
const apiUrl = (0, api_1.resolveAuthedApiUrl)(creds.apiUrl);
|
|
20
|
+
const base = (0, api_1.trimTrailingSlash)(apiUrl);
|
|
21
|
+
const docId = await (0, resolve_doc_id_1.lookupDocId)(apiUrl, creds.token, reference);
|
|
22
|
+
if (!docId) {
|
|
23
|
+
console.error(`Error: doc not found: ${reference}`);
|
|
24
|
+
return 1;
|
|
25
|
+
}
|
|
26
|
+
let res;
|
|
27
|
+
try {
|
|
28
|
+
res = await fetch(`${base}/api/documents/${docId}/sync-google`, {
|
|
29
|
+
method: 'POST',
|
|
30
|
+
headers: { Authorization: `Bearer ${creds.token}` },
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
catch (err) {
|
|
34
|
+
console.error(`Error: network failure: ${err.message}`);
|
|
35
|
+
return 1;
|
|
36
|
+
}
|
|
37
|
+
if (!res.ok) {
|
|
38
|
+
const text = await res.text();
|
|
39
|
+
console.error(`Error: ${res.status} ${res.statusText}: ${(0, sanitize_1.sanitizeField)(text)}`);
|
|
40
|
+
return 1;
|
|
41
|
+
}
|
|
42
|
+
const { document } = (await res.json());
|
|
43
|
+
console.log(formatSyncedLine(document));
|
|
44
|
+
}
|
|
@@ -4,6 +4,7 @@ exports.docUnbind = docUnbind;
|
|
|
4
4
|
const config_1 = require("../lib/config");
|
|
5
5
|
const api_1 = require("../lib/api");
|
|
6
6
|
const resolve_doc_id_1 = require("../lib/resolve-doc-id");
|
|
7
|
+
const sanitize_1 = require("../lib/sanitize");
|
|
7
8
|
async function docUnbind(docRef, task) {
|
|
8
9
|
if (!docRef || !task) {
|
|
9
10
|
console.error('Error: usage: lumo doc unbind <doc> <task>');
|
|
@@ -14,8 +15,7 @@ async function docUnbind(docRef, task) {
|
|
|
14
15
|
console.error('Error: not logged in. Run `lumo auth login` first.');
|
|
15
16
|
return 1;
|
|
16
17
|
}
|
|
17
|
-
const
|
|
18
|
-
const apiUrl = envUrl && envUrl.length > 0 ? envUrl : creds.apiUrl;
|
|
18
|
+
const apiUrl = (0, api_1.resolveAuthedApiUrl)(creds.apiUrl);
|
|
19
19
|
const docId = await (0, resolve_doc_id_1.lookupDocId)(apiUrl, creds.token, docRef);
|
|
20
20
|
if (!docId) {
|
|
21
21
|
console.error(`Error: Document not found: ${docRef}`);
|
|
@@ -29,12 +29,12 @@ async function docUnbind(docRef, task) {
|
|
|
29
29
|
});
|
|
30
30
|
if (res.status === 409) {
|
|
31
31
|
const { error } = (await res.json());
|
|
32
|
-
console.error(`Error: ${error}`);
|
|
32
|
+
console.error(`Error: ${(0, sanitize_1.sanitizeField)(error)}`);
|
|
33
33
|
return 1;
|
|
34
34
|
}
|
|
35
35
|
if (!res.ok) {
|
|
36
36
|
const text = await res.text();
|
|
37
|
-
console.error(`Error: ${res.status} ${res.statusText}: ${text}`);
|
|
37
|
+
console.error(`Error: ${res.status} ${res.statusText}: ${(0, sanitize_1.sanitizeField)(text)}`);
|
|
38
38
|
return 1;
|
|
39
39
|
}
|
|
40
40
|
const data = (await res.json());
|
|
@@ -5,6 +5,7 @@ const config_1 = require("../lib/config");
|
|
|
5
5
|
const api_1 = require("../lib/api");
|
|
6
6
|
const resolve_doc_id_1 = require("../lib/resolve-doc-id");
|
|
7
7
|
const resolve_member_1 = require("../lib/resolve-member");
|
|
8
|
+
const sanitize_1 = require("../lib/sanitize");
|
|
8
9
|
async function docUnshare(docRef, memberRef) {
|
|
9
10
|
if (!docRef || !memberRef) {
|
|
10
11
|
console.error('Error: usage: lumo doc unshare <doc> <member>');
|
|
@@ -15,8 +16,7 @@ async function docUnshare(docRef, memberRef) {
|
|
|
15
16
|
console.error('Error: not logged in. Run `lumo auth login` first.');
|
|
16
17
|
return 1;
|
|
17
18
|
}
|
|
18
|
-
const
|
|
19
|
-
const apiUrl = envUrl && envUrl.length > 0 ? envUrl : creds.apiUrl;
|
|
19
|
+
const apiUrl = (0, api_1.resolveAuthedApiUrl)(creds.apiUrl);
|
|
20
20
|
const docId = await (0, resolve_doc_id_1.lookupDocId)(apiUrl, creds.token, docRef);
|
|
21
21
|
if (!docId) {
|
|
22
22
|
console.error(`Error: Document not found: ${docRef}`);
|
|
@@ -36,7 +36,9 @@ async function docUnshare(docRef, memberRef) {
|
|
|
36
36
|
return 1;
|
|
37
37
|
}
|
|
38
38
|
if (result.kind === 'ambiguous') {
|
|
39
|
-
const list = result.candidates
|
|
39
|
+
const list = result.candidates
|
|
40
|
+
.map(c => (0, sanitize_1.sanitizeField)(c.email ?? c.displayName))
|
|
41
|
+
.join(', ');
|
|
40
42
|
console.error(`Error: multiple members match "${result.query}": ${list}`);
|
|
41
43
|
return 1;
|
|
42
44
|
}
|
|
@@ -48,13 +50,13 @@ async function docUnshare(docRef, memberRef) {
|
|
|
48
50
|
});
|
|
49
51
|
if (!listRes.ok) {
|
|
50
52
|
const text = await listRes.text();
|
|
51
|
-
console.error(`Error: ${listRes.status} ${listRes.statusText}: ${text}`);
|
|
53
|
+
console.error(`Error: ${listRes.status} ${listRes.statusText}: ${(0, sanitize_1.sanitizeField)(text)}`);
|
|
52
54
|
return 1;
|
|
53
55
|
}
|
|
54
56
|
const { shares } = (await listRes.json());
|
|
55
57
|
const row = shares.find(s => s.member.id === result.member.memberId);
|
|
56
58
|
if (!row) {
|
|
57
|
-
console.log(`Not shared with ${result.member.displayName}`);
|
|
59
|
+
console.log(`Not shared with ${(0, sanitize_1.sanitizeField)(result.member.displayName)}`);
|
|
58
60
|
return;
|
|
59
61
|
}
|
|
60
62
|
const delUrl = `${(0, api_1.trimTrailingSlash)(apiUrl)}/api/documents/${docId}/shares/${row.id}`;
|
|
@@ -64,8 +66,8 @@ async function docUnshare(docRef, memberRef) {
|
|
|
64
66
|
});
|
|
65
67
|
if (!delRes.ok) {
|
|
66
68
|
const text = await delRes.text();
|
|
67
|
-
console.error(`Error: ${delRes.status} ${delRes.statusText}: ${text}`);
|
|
69
|
+
console.error(`Error: ${delRes.status} ${delRes.statusText}: ${(0, sanitize_1.sanitizeField)(text)}`);
|
|
68
70
|
return 1;
|
|
69
71
|
}
|
|
70
|
-
console.log(`Unshared ${docId} ↔ ${result.member.displayName}`);
|
|
72
|
+
console.log(`Unshared ${docId} ↔ ${(0, sanitize_1.sanitizeField)(result.member.displayName)}`);
|
|
71
73
|
}
|
|
@@ -8,11 +8,12 @@ const doc_input_1 = require("../lib/doc-input");
|
|
|
8
8
|
const doc_create_1 = require("./doc-create");
|
|
9
9
|
const resolve_doc_id_1 = require("../lib/resolve-doc-id");
|
|
10
10
|
const tag_resolver_1 = require("../lib/tag-resolver");
|
|
11
|
+
const sanitize_1 = require("../lib/sanitize");
|
|
11
12
|
function formatUpdatedDocLine(doc) {
|
|
12
|
-
const escaped = doc.title.replace(/"/g, '\\"');
|
|
13
|
+
const escaped = (0, sanitize_1.sanitizeField)(doc.title).replace(/"/g, '\\"');
|
|
13
14
|
const head = `Updated ${doc.id} "${escaped}" ${doc.url}`;
|
|
14
15
|
if (doc.tags && doc.tags.length > 0) {
|
|
15
|
-
return `${head}\nTags: ${doc.tags.join(', ')}`;
|
|
16
|
+
return `${head}\nTags: ${doc.tags.map(sanitize_1.sanitizeField).join(', ')}`;
|
|
16
17
|
}
|
|
17
18
|
return head;
|
|
18
19
|
}
|
|
@@ -26,8 +27,7 @@ async function docUpdate(reference, opts) {
|
|
|
26
27
|
console.error('Error: not logged in. Run `lumo auth login` first.');
|
|
27
28
|
return 1;
|
|
28
29
|
}
|
|
29
|
-
const
|
|
30
|
-
const apiUrl = envUrl && envUrl.length > 0 ? envUrl : creds.apiUrl;
|
|
30
|
+
const apiUrl = (0, api_1.resolveAuthedApiUrl)(creds.apiUrl);
|
|
31
31
|
// CLI-side mutex check: --tag/--tag-id (bulk replace) vs --add-tag/--add-tag-id/--remove-tag/--remove-tag-id (incremental)
|
|
32
32
|
const hasBulk = (opts.tag && opts.tag.length > 0) || (opts.tagId && opts.tagId.length > 0);
|
|
33
33
|
const hasIncremental = (opts.addTag && opts.addTag.length > 0) ||
|
|
@@ -122,7 +122,7 @@ async function docUpdate(reference, opts) {
|
|
|
122
122
|
});
|
|
123
123
|
if (!res.ok) {
|
|
124
124
|
const text = await res.text();
|
|
125
|
-
console.error(`Error: ${res.status} ${res.statusText}: ${text}`);
|
|
125
|
+
console.error(`Error: ${res.status} ${res.statusText}: ${(0, sanitize_1.sanitizeField)(text)}`);
|
|
126
126
|
return 1;
|
|
127
127
|
}
|
|
128
128
|
const { document } = (await res.json());
|
|
@@ -11,9 +11,9 @@ const hook_log_1 = require("../lib/hook-log");
|
|
|
11
11
|
* if `runHook` someday throws (it currently never does), Claude Code is
|
|
12
12
|
* not disrupted.
|
|
13
13
|
*/
|
|
14
|
-
async function hookCommand(path) {
|
|
14
|
+
async function hookCommand(path, agentToken) {
|
|
15
15
|
try {
|
|
16
|
-
await (0, hook_runner_1.runHook)(path);
|
|
16
|
+
await (0, hook_runner_1.runHook)(path, agentToken);
|
|
17
17
|
}
|
|
18
18
|
catch (err) {
|
|
19
19
|
(0, hook_log_1.logHookError)(`[${path}] dispatcher`, err);
|
|
@@ -3,10 +3,12 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.memoryProjectAdd = memoryProjectAdd;
|
|
4
4
|
const config_1 = require("../lib/config");
|
|
5
5
|
const api_1 = require("../lib/api");
|
|
6
|
+
const sanitize_1 = require("../lib/sanitize");
|
|
6
7
|
const memory_content_1 = require("../lib/memory-content");
|
|
7
8
|
const resolve_1 = require("../lib/resolve");
|
|
8
9
|
const resolve_bound_task_1 = require("../lib/resolve-bound-task");
|
|
9
10
|
const resolve_project_1 = require("../lib/resolve-project");
|
|
11
|
+
const agent_1 = require("../lib/agent");
|
|
10
12
|
async function memoryProjectAdd(refArg, options) {
|
|
11
13
|
if (!options.category) {
|
|
12
14
|
console.error('Error: --category <trap|decision|convention|procedural> is required.');
|
|
@@ -17,13 +19,22 @@ async function memoryProjectAdd(refArg, options) {
|
|
|
17
19
|
console.error(`Error: ${built.error}`);
|
|
18
20
|
return 1;
|
|
19
21
|
}
|
|
22
|
+
let agent;
|
|
23
|
+
const agentRaw = options.agent?.trim();
|
|
24
|
+
if (agentRaw) {
|
|
25
|
+
const normalized = (0, agent_1.normalizeAgent)(agentRaw);
|
|
26
|
+
if (!normalized) {
|
|
27
|
+
console.error(`Error: invalid --agent "${agentRaw}". Valid values: ${agent_1.VALID_AGENT_TOKENS.join(', ')}.`);
|
|
28
|
+
return 1;
|
|
29
|
+
}
|
|
30
|
+
agent = normalized;
|
|
31
|
+
}
|
|
20
32
|
const creds = (0, config_1.readCredentials)();
|
|
21
33
|
if (!creds) {
|
|
22
34
|
console.error('Error: not logged in. Run `lumo auth login` first.');
|
|
23
35
|
return 1;
|
|
24
36
|
}
|
|
25
|
-
const
|
|
26
|
-
const apiUrl = envUrl && envUrl.length > 0 ? envUrl : creds.apiUrl;
|
|
37
|
+
const apiUrl = (0, api_1.resolveAuthedApiUrl)(creds.apiUrl);
|
|
27
38
|
const base = (0, api_1.trimTrailingSlash)(apiUrl);
|
|
28
39
|
let projectId;
|
|
29
40
|
let echoSuffix = '';
|
|
@@ -49,7 +60,11 @@ async function memoryProjectAdd(refArg, options) {
|
|
|
49
60
|
res = await fetch(`${base}/api/projects/${encodeURIComponent(projectId)}/memories`, {
|
|
50
61
|
method: 'POST',
|
|
51
62
|
headers: { Authorization: `Bearer ${creds.token}`, 'Content-Type': 'application/json' },
|
|
52
|
-
body: JSON.stringify({
|
|
63
|
+
body: JSON.stringify({
|
|
64
|
+
category: built.category,
|
|
65
|
+
content: built.content,
|
|
66
|
+
...(agent ? { agent } : {}),
|
|
67
|
+
}),
|
|
53
68
|
});
|
|
54
69
|
}
|
|
55
70
|
catch (err) {
|
|
@@ -64,7 +79,7 @@ async function memoryProjectAdd(refArg, options) {
|
|
|
64
79
|
m = b.error;
|
|
65
80
|
}
|
|
66
81
|
catch { /* */ }
|
|
67
|
-
console.error(m ? `Error: ${m}` : `Error: memory add failed (HTTP ${res.status})`);
|
|
82
|
+
console.error(m ? `Error: ${(0, sanitize_1.sanitizeField)(m)}` : `Error: memory add failed (HTTP ${res.status})`);
|
|
68
83
|
return 1;
|
|
69
84
|
}
|
|
70
85
|
process.stdout.write(`Added ${built.category} PROJECT memory${echoSuffix}\n`);
|
|
@@ -18,8 +18,7 @@ async function memoryProjectList(refArg, options) {
|
|
|
18
18
|
console.error('Error: not logged in. Run `lumo auth login` first.');
|
|
19
19
|
return 1;
|
|
20
20
|
}
|
|
21
|
-
const
|
|
22
|
-
const apiUrl = envUrl && envUrl.length > 0 ? envUrl : creds.apiUrl;
|
|
21
|
+
const apiUrl = (0, api_1.resolveAuthedApiUrl)(creds.apiUrl);
|
|
23
22
|
const base = (0, api_1.trimTrailingSlash)(apiUrl);
|
|
24
23
|
let projectId;
|
|
25
24
|
if (refArg) {
|
|
@@ -3,6 +3,7 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.memoryPromote = memoryPromote;
|
|
4
4
|
const config_1 = require("../lib/config");
|
|
5
5
|
const api_1 = require("../lib/api");
|
|
6
|
+
const sanitize_1 = require("../lib/sanitize");
|
|
6
7
|
async function memoryPromote(memoryId) {
|
|
7
8
|
if (!memoryId) {
|
|
8
9
|
console.error('Error: missing <memoryId>. Usage: lumo memory promote <memoryId>');
|
|
@@ -13,8 +14,7 @@ async function memoryPromote(memoryId) {
|
|
|
13
14
|
console.error('Error: not logged in. Run `lumo auth login` first.');
|
|
14
15
|
return 1;
|
|
15
16
|
}
|
|
16
|
-
const
|
|
17
|
-
const apiUrl = envUrl && envUrl.length > 0 ? envUrl : creds.apiUrl;
|
|
17
|
+
const apiUrl = (0, api_1.resolveAuthedApiUrl)(creds.apiUrl);
|
|
18
18
|
const base = (0, api_1.trimTrailingSlash)(apiUrl);
|
|
19
19
|
let res;
|
|
20
20
|
try {
|
|
@@ -44,7 +44,7 @@ async function memoryPromote(memoryId) {
|
|
|
44
44
|
m = b.error;
|
|
45
45
|
}
|
|
46
46
|
catch { /* */ }
|
|
47
|
-
console.error(m ? `Error: ${m}` : `Error: promote failed (HTTP ${res.status})`);
|
|
47
|
+
console.error(m ? `Error: ${(0, sanitize_1.sanitizeField)(m)}` : `Error: promote failed (HTTP ${res.status})`);
|
|
48
48
|
return 1;
|
|
49
49
|
}
|
|
50
50
|
process.stdout.write(`Promoted ${memoryId} to PROJECT — every agent on this project now sees it.\n` +
|
|
@@ -17,8 +17,7 @@ async function memoryRm(memoryId, options) {
|
|
|
17
17
|
console.error('Error: not logged in. Run `lumo auth login` first.');
|
|
18
18
|
return 1;
|
|
19
19
|
}
|
|
20
|
-
const
|
|
21
|
-
const apiUrl = envUrl && envUrl.length > 0 ? envUrl : creds.apiUrl;
|
|
20
|
+
const apiUrl = (0, api_1.resolveAuthedApiUrl)(creds.apiUrl);
|
|
22
21
|
const base = (0, api_1.trimTrailingSlash)(apiUrl);
|
|
23
22
|
let res;
|
|
24
23
|
try {
|
|
@@ -3,8 +3,10 @@ Object.defineProperty(exports, "__esModule", { value: true });
|
|
|
3
3
|
exports.memoryTaskAdd = memoryTaskAdd;
|
|
4
4
|
const config_1 = require("../lib/config");
|
|
5
5
|
const api_1 = require("../lib/api");
|
|
6
|
+
const sanitize_1 = require("../lib/sanitize");
|
|
6
7
|
const memory_content_1 = require("../lib/memory-content");
|
|
7
8
|
const resolve_bound_task_1 = require("../lib/resolve-bound-task");
|
|
9
|
+
const agent_1 = require("../lib/agent");
|
|
8
10
|
async function memoryTaskAdd(identifierArg, options) {
|
|
9
11
|
if (!options.category) {
|
|
10
12
|
console.error('Error: --category <trap|decision|convention|procedural> is required.');
|
|
@@ -15,13 +17,22 @@ async function memoryTaskAdd(identifierArg, options) {
|
|
|
15
17
|
console.error(`Error: ${built.error}`);
|
|
16
18
|
return 1;
|
|
17
19
|
}
|
|
20
|
+
let agent;
|
|
21
|
+
const agentRaw = options.agent?.trim();
|
|
22
|
+
if (agentRaw) {
|
|
23
|
+
const normalized = (0, agent_1.normalizeAgent)(agentRaw);
|
|
24
|
+
if (!normalized) {
|
|
25
|
+
console.error(`Error: invalid --agent "${agentRaw}". Valid values: ${agent_1.VALID_AGENT_TOKENS.join(', ')}.`);
|
|
26
|
+
return 1;
|
|
27
|
+
}
|
|
28
|
+
agent = normalized;
|
|
29
|
+
}
|
|
18
30
|
const creds = (0, config_1.readCredentials)();
|
|
19
31
|
if (!creds) {
|
|
20
32
|
console.error('Error: not logged in. Run `lumo auth login` first.');
|
|
21
33
|
return 1;
|
|
22
34
|
}
|
|
23
|
-
const
|
|
24
|
-
const apiUrl = envUrl && envUrl.length > 0 ? envUrl : creds.apiUrl;
|
|
35
|
+
const apiUrl = (0, api_1.resolveAuthedApiUrl)(creds.apiUrl);
|
|
25
36
|
const base = (0, api_1.trimTrailingSlash)(apiUrl);
|
|
26
37
|
// Resolve the target: explicit arg > session-bound task.
|
|
27
38
|
const identifier = identifierArg ?? (await (0, resolve_bound_task_1.resolveBoundTaskIdentifier)(apiUrl, creds.token));
|
|
@@ -60,7 +71,11 @@ async function memoryTaskAdd(identifierArg, options) {
|
|
|
60
71
|
res = await fetch(`${base}/api/tasks/${encodeURIComponent(taskId)}/memories`, {
|
|
61
72
|
method: 'POST',
|
|
62
73
|
headers: { Authorization: `Bearer ${creds.token}`, 'Content-Type': 'application/json' },
|
|
63
|
-
body: JSON.stringify({
|
|
74
|
+
body: JSON.stringify({
|
|
75
|
+
category: built.category,
|
|
76
|
+
content: built.content,
|
|
77
|
+
...(agent ? { agent } : {}),
|
|
78
|
+
}),
|
|
64
79
|
});
|
|
65
80
|
}
|
|
66
81
|
catch (err) {
|
|
@@ -75,7 +90,7 @@ async function memoryTaskAdd(identifierArg, options) {
|
|
|
75
90
|
m = b.error;
|
|
76
91
|
}
|
|
77
92
|
catch { /* */ }
|
|
78
|
-
console.error(m ? `Error: ${m}` : `Error: memory add failed (HTTP ${res.status})`);
|
|
93
|
+
console.error(m ? `Error: ${(0, sanitize_1.sanitizeField)(m)}` : `Error: memory add failed (HTTP ${res.status})`);
|
|
79
94
|
return 1;
|
|
80
95
|
}
|
|
81
96
|
process.stdout.write(`Added ${built.category} memory to ${identifier}` +
|
|
@@ -16,8 +16,7 @@ async function memoryTaskList(identifierArg, options) {
|
|
|
16
16
|
console.error('Error: not logged in. Run `lumo auth login` first.');
|
|
17
17
|
return 1;
|
|
18
18
|
}
|
|
19
|
-
const
|
|
20
|
-
const apiUrl = envUrl && envUrl.length > 0 ? envUrl : creds.apiUrl;
|
|
19
|
+
const apiUrl = (0, api_1.resolveAuthedApiUrl)(creds.apiUrl);
|
|
21
20
|
const base = (0, api_1.trimTrailingSlash)(apiUrl);
|
|
22
21
|
const identifier = identifierArg ?? (await (0, resolve_bound_task_1.resolveBoundTaskIdentifier)(apiUrl, creds.token));
|
|
23
22
|
if (!identifier) {
|
|
@@ -5,6 +5,7 @@ exports.formatCreatedMilestoneLine = formatCreatedMilestoneLine;
|
|
|
5
5
|
exports.milestoneCreate = milestoneCreate;
|
|
6
6
|
const config_1 = require("../lib/config");
|
|
7
7
|
const api_1 = require("../lib/api");
|
|
8
|
+
const sanitize_1 = require("../lib/sanitize");
|
|
8
9
|
const resolve_1 = require("../lib/resolve");
|
|
9
10
|
function buildCreatePayload(name, opts) {
|
|
10
11
|
const payload = { name };
|
|
@@ -17,7 +18,7 @@ function buildCreatePayload(name, opts) {
|
|
|
17
18
|
return payload;
|
|
18
19
|
}
|
|
19
20
|
function formatCreatedMilestoneLine(milestone) {
|
|
20
|
-
return `Created milestone "${milestone.name}" ${milestone.id}`;
|
|
21
|
+
return `Created milestone "${(0, sanitize_1.sanitizeField)(milestone.name)}" ${milestone.id}`;
|
|
21
22
|
}
|
|
22
23
|
async function milestoneCreate(name, opts) {
|
|
23
24
|
if (!name || !name.trim()) {
|
|
@@ -29,8 +30,7 @@ async function milestoneCreate(name, opts) {
|
|
|
29
30
|
console.error('Error: not logged in. Run `lumo auth login` first.');
|
|
30
31
|
return 1;
|
|
31
32
|
}
|
|
32
|
-
const
|
|
33
|
-
const apiUrl = envUrl && envUrl.length > 0 ? envUrl : creds.apiUrl;
|
|
33
|
+
const apiUrl = (0, api_1.resolveAuthedApiUrl)(creds.apiUrl);
|
|
34
34
|
const base = (0, api_1.trimTrailingSlash)(apiUrl);
|
|
35
35
|
let projectId;
|
|
36
36
|
try {
|
|
@@ -72,7 +72,7 @@ async function milestoneCreate(name, opts) {
|
|
|
72
72
|
// Body wasn't JSON; fall through to status-only message
|
|
73
73
|
}
|
|
74
74
|
if (serverMsg) {
|
|
75
|
-
console.error(`Error: ${serverMsg}`);
|
|
75
|
+
console.error(`Error: ${(0, sanitize_1.sanitizeField)(serverMsg)}`);
|
|
76
76
|
}
|
|
77
77
|
else {
|
|
78
78
|
console.error(`Error: milestone create failed (HTTP ${res.status})`);
|
|
@@ -5,8 +5,9 @@ exports.milestoneDelete = milestoneDelete;
|
|
|
5
5
|
const config_1 = require("../lib/config");
|
|
6
6
|
const api_1 = require("../lib/api");
|
|
7
7
|
const resolve_1 = require("../lib/resolve");
|
|
8
|
+
const sanitize_1 = require("../lib/sanitize");
|
|
8
9
|
function formatDeleteRefusal(name, taskCount) {
|
|
9
|
-
const head = `Refusing to delete milestone "${name}" without --yes.`;
|
|
10
|
+
const head = `Refusing to delete milestone "${(0, sanitize_1.sanitizeField)(name)}" without --yes.`;
|
|
10
11
|
const tail = `Re-run with --yes to confirm.`;
|
|
11
12
|
if (taskCount === 0)
|
|
12
13
|
return `${head}\n${tail}`;
|
|
@@ -21,8 +22,7 @@ async function milestoneDelete(identifier, opts) {
|
|
|
21
22
|
console.error('Error: not logged in. Run `lumo auth login` first.');
|
|
22
23
|
return 1;
|
|
23
24
|
}
|
|
24
|
-
const
|
|
25
|
-
const apiUrl = envUrl && envUrl.length > 0 ? envUrl : creds.apiUrl;
|
|
25
|
+
const apiUrl = (0, api_1.resolveAuthedApiUrl)(creds.apiUrl);
|
|
26
26
|
const base = (0, api_1.trimTrailingSlash)(apiUrl);
|
|
27
27
|
let milestoneId;
|
|
28
28
|
let resolvedName;
|
|
@@ -89,8 +89,8 @@ async function milestoneDelete(identifier, opts) {
|
|
|
89
89
|
catch {
|
|
90
90
|
// body wasn't JSON
|
|
91
91
|
}
|
|
92
|
-
console.error(`Error: ${errMsg}`);
|
|
92
|
+
console.error(`Error: ${(0, sanitize_1.sanitizeField)(errMsg)}`);
|
|
93
93
|
return 1;
|
|
94
94
|
}
|
|
95
|
-
process.stdout.write(`Deleted milestone "${name}"\n`);
|
|
95
|
+
process.stdout.write(`Deleted milestone "${(0, sanitize_1.sanitizeField)(name)}"\n`);
|
|
96
96
|
}
|
|
@@ -5,6 +5,7 @@ exports.milestoneList = milestoneList;
|
|
|
5
5
|
const config_1 = require("../lib/config");
|
|
6
6
|
const api_1 = require("../lib/api");
|
|
7
7
|
const resolve_1 = require("../lib/resolve");
|
|
8
|
+
const sanitize_1 = require("../lib/sanitize");
|
|
8
9
|
function formatDate(iso) {
|
|
9
10
|
if (!iso)
|
|
10
11
|
return '-';
|
|
@@ -22,7 +23,7 @@ function formatMilestoneList(rows) {
|
|
|
22
23
|
const statusW = Math.max(...rows.map(r => r.status.length));
|
|
23
24
|
const dateW = Math.max(...rows.map(r => formatDate(r.targetDate).length));
|
|
24
25
|
return rows
|
|
25
|
-
.map(r => `${r.status.padEnd(statusW)} ${formatDate(r.targetDate).padEnd(dateW)} ${r.name}`)
|
|
26
|
+
.map(r => `${r.status.padEnd(statusW)} ${formatDate(r.targetDate).padEnd(dateW)} ${(0, sanitize_1.sanitizeField)(r.name)}`)
|
|
26
27
|
.join('\n');
|
|
27
28
|
}
|
|
28
29
|
async function milestoneList(options) {
|
|
@@ -31,8 +32,7 @@ async function milestoneList(options) {
|
|
|
31
32
|
console.error('Error: not logged in. Run `lumo auth login` first.');
|
|
32
33
|
return 1;
|
|
33
34
|
}
|
|
34
|
-
const
|
|
35
|
-
const apiUrl = envUrl && envUrl.length > 0 ? envUrl : creds.apiUrl;
|
|
35
|
+
const apiUrl = (0, api_1.resolveAuthedApiUrl)(creds.apiUrl);
|
|
36
36
|
const base = (0, api_1.trimTrailingSlash)(apiUrl);
|
|
37
37
|
let projectId;
|
|
38
38
|
try {
|
|
@@ -6,6 +6,7 @@ const config_1 = require("../lib/config");
|
|
|
6
6
|
const api_1 = require("../lib/api");
|
|
7
7
|
const resolve_1 = require("../lib/resolve");
|
|
8
8
|
const format_1 = require("../lib/format");
|
|
9
|
+
const sanitize_1 = require("../lib/sanitize");
|
|
9
10
|
function fmtDate(iso) {
|
|
10
11
|
return iso ? iso.slice(0, 10) : '-';
|
|
11
12
|
}
|
|
@@ -15,13 +16,13 @@ function formatMilestoneShow(m, tasks) {
|
|
|
15
16
|
m.taskCounts.IN_REVIEW +
|
|
16
17
|
m.taskCounts.DONE;
|
|
17
18
|
const lines = [
|
|
18
|
-
`Milestone: ${m.name}`,
|
|
19
|
+
`Milestone: ${(0, sanitize_1.sanitizeField)(m.name)}`,
|
|
19
20
|
`Status: ${m.status}`,
|
|
20
21
|
`Start: ${fmtDate(m.startDate)}`,
|
|
21
22
|
`Target: ${fmtDate(m.targetDate)}`,
|
|
22
|
-
`Project: ${m.projectName}`,
|
|
23
|
+
`Project: ${(0, sanitize_1.sanitizeField)(m.projectName)}`,
|
|
23
24
|
`Description:`,
|
|
24
|
-
` ${m.description && m.description.length > 0 ? m.description : '-'}`,
|
|
25
|
+
` ${m.description && m.description.length > 0 ? (0, sanitize_1.sanitizeField)(m.description) : '-'}`,
|
|
25
26
|
``,
|
|
26
27
|
`Tasks: ${total} total (TODO ${m.taskCounts.TODO} / IN_PROGRESS ${m.taskCounts.IN_PROGRESS} / IN_REVIEW ${m.taskCounts.IN_REVIEW} / DONE ${m.taskCounts.DONE})`,
|
|
27
28
|
];
|
|
@@ -36,8 +37,7 @@ async function milestoneShow(identifier, opts) {
|
|
|
36
37
|
console.error('Error: not logged in. Run `lumo auth login` first.');
|
|
37
38
|
return 1;
|
|
38
39
|
}
|
|
39
|
-
const
|
|
40
|
-
const apiUrl = envUrl && envUrl.length > 0 ? envUrl : creds.apiUrl;
|
|
40
|
+
const apiUrl = (0, api_1.resolveAuthedApiUrl)(creds.apiUrl);
|
|
41
41
|
const base = (0, api_1.trimTrailingSlash)(apiUrl);
|
|
42
42
|
let milestoneId;
|
|
43
43
|
try {
|