@lumoai/cli 1.5.0 → 1.5.1
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 +159 -15
- 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/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 +24 -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/index.js +167 -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/figma-api.js +1 -1
- package/dist/cli/src/lib/format.js +3 -2
- package/dist/cli/src/lib/hook-runner.js +26 -10
- 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/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/package.json +1 -1
|
@@ -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
|
}
|
package/dist/cli/src/index.js
CHANGED
|
@@ -66,6 +66,11 @@ const task_artifact_list_1 = require("./commands/task-artifact-list");
|
|
|
66
66
|
const task_artifact_show_1 = require("./commands/task-artifact-show");
|
|
67
67
|
const task_artifact_rm_1 = require("./commands/task-artifact-rm");
|
|
68
68
|
const task_artifact_update_1 = require("./commands/task-artifact-update");
|
|
69
|
+
const task_slack_show_1 = require("./commands/task-slack-show");
|
|
70
|
+
const task_web_show_1 = require("./commands/task-web-show");
|
|
71
|
+
const task_figma_context_1 = require("./commands/task-figma-context");
|
|
72
|
+
const task_comment_list_1 = require("./commands/task-comment-list");
|
|
73
|
+
const task_pr_show_1 = require("./commands/task-pr-show");
|
|
69
74
|
const project_list_1 = require("./commands/project-list");
|
|
70
75
|
const milestone_list_1 = require("./commands/milestone-list");
|
|
71
76
|
const milestone_create_1 = require("./commands/milestone-create");
|
|
@@ -83,6 +88,8 @@ const sprint_summary_1 = require("./commands/sprint-summary");
|
|
|
83
88
|
const sprint_add_1 = require("./commands/sprint-add");
|
|
84
89
|
const sprint_remove_1 = require("./commands/sprint-remove");
|
|
85
90
|
const doc_create_1 = require("./commands/doc-create");
|
|
91
|
+
const doc_import_gdoc_1 = require("./commands/doc-import-gdoc");
|
|
92
|
+
const doc_sync_1 = require("./commands/doc-sync");
|
|
86
93
|
const doc_update_1 = require("./commands/doc-update");
|
|
87
94
|
const doc_show_1 = require("./commands/doc-show");
|
|
88
95
|
const doc_list_1 = require("./commands/doc-list");
|
|
@@ -96,6 +103,7 @@ const doc_move_1 = require("./commands/doc-move");
|
|
|
96
103
|
const update_1 = require("./commands/update");
|
|
97
104
|
const setup_1 = require("./commands/setup");
|
|
98
105
|
const update_check_1 = require("./lib/update-check");
|
|
106
|
+
const sanitize_1 = require("./lib/sanitize");
|
|
99
107
|
// Resolve package.json relative to __dirname so this works regardless of how
|
|
100
108
|
// deep the compiled output ends up (flat dist/ or nested dist/cli/src/).
|
|
101
109
|
const pkg = require(path.resolve(__dirname, '../../..', 'package.json'));
|
|
@@ -138,7 +146,7 @@ function wrap(fn) {
|
|
|
138
146
|
}
|
|
139
147
|
catch (err) {
|
|
140
148
|
const msg = err instanceof Error ? err.message : String(err);
|
|
141
|
-
console.error(`Error: ${msg}`);
|
|
149
|
+
console.error(`Error: ${(0, sanitize_1.sanitizeField)(msg)}`);
|
|
142
150
|
process.exit(1);
|
|
143
151
|
}
|
|
144
152
|
};
|
|
@@ -170,6 +178,7 @@ program
|
|
|
170
178
|
.option('--user', 'Install into ~/.claude (applies across all projects for this user)')
|
|
171
179
|
.option('--project', 'Install into ./.claude (applies to the current project only)')
|
|
172
180
|
.option('--force', 'Overwrite an existing SKILL.md when its contents differ from the bundled version')
|
|
181
|
+
.option('--agent <token>', 'Coding agent these hooks run under (claude-code, codex, cursor, gemini-cli, github-copilot, windsurf). Baked into every hook command. Defaults to claude-code.')
|
|
173
182
|
.action(wrap(options => (0, setup_1.setup)(options)));
|
|
174
183
|
const session = program
|
|
175
184
|
.command('session')
|
|
@@ -243,6 +252,38 @@ taskFigma
|
|
|
243
252
|
.command('refresh <task>')
|
|
244
253
|
.description('Re-fetch Figma metadata + thumbnail for every link on this task. Per-link failures isolated.')
|
|
245
254
|
.action(wrap((taskId) => (0, task_figma_refresh_1.taskFigmaRefresh)({ identifier: taskId })));
|
|
255
|
+
// Tier-2 retrieval commands (LUM-122). `task context` prints the matching
|
|
256
|
+
// command at the end of each cheap inline card; the agent runs it to pull the
|
|
257
|
+
// full content on demand.
|
|
258
|
+
const taskSlack = task.command('slack').description('Inspect Slack context');
|
|
259
|
+
taskSlack
|
|
260
|
+
.command('show <identifier> <contextId>')
|
|
261
|
+
.description('Show the full stored Slack thread snapshot')
|
|
262
|
+
.action(wrap((id, ctx) => (0, task_slack_show_1.taskSlackShow)(id, ctx)));
|
|
263
|
+
const taskWeb = task.command('web').description('Inspect web link content');
|
|
264
|
+
taskWeb
|
|
265
|
+
.command('show <identifier> <linkId>')
|
|
266
|
+
.description('Show the fetched web link body as plain text')
|
|
267
|
+
.action(wrap((id, link) => (0, task_web_show_1.taskWebShow)(id, link)));
|
|
268
|
+
// taskFigma already exists above → attach the context leaf to it.
|
|
269
|
+
taskFigma
|
|
270
|
+
.command('context <identifier> <linkId>')
|
|
271
|
+
.description('Show the cached Figma design context (metadata)')
|
|
272
|
+
.action(wrap((id, link) => (0, task_figma_context_1.taskFigmaContext)(id, link)));
|
|
273
|
+
// Plural `comments` parent: `task comment <id> <body>` already exists for
|
|
274
|
+
// adding a comment, and commander disallows a duplicate name.
|
|
275
|
+
const taskComments = task
|
|
276
|
+
.command('comments')
|
|
277
|
+
.description('Inspect the full task comment thread');
|
|
278
|
+
taskComments
|
|
279
|
+
.command('list <identifier>')
|
|
280
|
+
.description('List the full task comment thread')
|
|
281
|
+
.action(wrap(id => (0, task_comment_list_1.taskCommentList)(id)));
|
|
282
|
+
const taskPr = task.command('pr').description('Inspect linked PRs');
|
|
283
|
+
taskPr
|
|
284
|
+
.command('show <identifier> <number>')
|
|
285
|
+
.description('Show the synced PR record (diff/review comments when available)')
|
|
286
|
+
.action(wrap((id, num) => (0, task_pr_show_1.taskPrShow)(id, num)));
|
|
246
287
|
const taskMemory = task
|
|
247
288
|
.command('memory')
|
|
248
289
|
.description('View and record memories scoped to a task');
|
|
@@ -269,6 +310,7 @@ taskMemory
|
|
|
269
310
|
.option('--applies <text>', 'convention: where the rule applies')
|
|
270
311
|
.option('--workflow <text>', 'procedural: the workflow name')
|
|
271
312
|
.option('--step <text>', 'procedural: a step (repeatable)', collect, [])
|
|
313
|
+
.option('--agent <agent>', 'Producing agent: claude-code | codex | cursor | gemini-cli | github-copilot | windsurf (default claude-code)')
|
|
272
314
|
.action(wrap((taskArg, opts) => (0, memory_task_add_1.memoryTaskAdd)(taskArg, opts)));
|
|
273
315
|
const taskArtifact = task
|
|
274
316
|
.command('artifact')
|
|
@@ -334,6 +376,7 @@ projectMemory
|
|
|
334
376
|
.option('--applies <text>', 'convention: where it applies')
|
|
335
377
|
.option('--workflow <text>', 'procedural workflow')
|
|
336
378
|
.option('--step <text>', 'procedural step (repeatable)', collect, [])
|
|
379
|
+
.option('--agent <agent>', 'Producing agent: claude-code | codex | cursor | gemini-cli | github-copilot | windsurf (default claude-code)')
|
|
337
380
|
.action(wrap((p, opts) => (0, memory_project_add_1.memoryProjectAdd)(p, opts)));
|
|
338
381
|
const memoryCmd = program
|
|
339
382
|
.command('memory')
|
|
@@ -463,6 +506,16 @@ doc
|
|
|
463
506
|
.option('--tag <name>', 'Attach tag by name (repeatable)', collect, [])
|
|
464
507
|
.option('--tag-id <cuid>', 'Attach tag by id (repeatable)', collect, [])
|
|
465
508
|
.action(wrap((title, opts) => (0, doc_create_1.docCreate)(title, opts)));
|
|
509
|
+
doc
|
|
510
|
+
.command('import-gdoc <url>')
|
|
511
|
+
.description('Import a Google Doc as a Lumo doc (one-way Google → Lumo)')
|
|
512
|
+
.option('--scope <scope>', 'personal | workspace (default: personal)')
|
|
513
|
+
.option('--task <LUM-N>', 'Bind the imported doc to this task')
|
|
514
|
+
.action(wrap((url, opts) => (0, doc_import_gdoc_1.docImportGdoc)(url, opts)));
|
|
515
|
+
doc
|
|
516
|
+
.command('sync <doc>')
|
|
517
|
+
.description('Re-sync a Google-imported doc (overwrites the Lumo body)')
|
|
518
|
+
.action(wrap(ref => (0, doc_sync_1.docSync)(ref)));
|
|
466
519
|
doc
|
|
467
520
|
.command('update <doc>')
|
|
468
521
|
.description('Update an existing document. <doc> accepts a cuid or a case-insensitive title (ambiguous titles fail with candidates). Replacement body comes from --content, --file, or piped stdin (pick one). --tag/--tag-id (bulk replace) cannot be combined with --add-tag/--add-tag-id/--remove-tag/--remove-tag-id.')
|
|
@@ -551,110 +604,122 @@ task
|
|
|
551
604
|
const hook = program
|
|
552
605
|
.command('hook')
|
|
553
606
|
.description('Claude Code hook ingestion (invoked by settings.json, not humans)');
|
|
554
|
-
hook
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
558
|
-
|
|
559
|
-
|
|
560
|
-
|
|
561
|
-
|
|
562
|
-
|
|
563
|
-
|
|
564
|
-
|
|
565
|
-
|
|
566
|
-
|
|
567
|
-
|
|
568
|
-
|
|
569
|
-
|
|
570
|
-
|
|
571
|
-
|
|
572
|
-
|
|
573
|
-
|
|
574
|
-
|
|
575
|
-
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
579
|
-
|
|
580
|
-
|
|
581
|
-
|
|
582
|
-
|
|
583
|
-
|
|
584
|
-
|
|
585
|
-
|
|
586
|
-
|
|
587
|
-
|
|
588
|
-
|
|
589
|
-
|
|
590
|
-
|
|
591
|
-
|
|
592
|
-
|
|
593
|
-
|
|
594
|
-
|
|
595
|
-
|
|
596
|
-
|
|
597
|
-
|
|
598
|
-
|
|
599
|
-
|
|
600
|
-
|
|
601
|
-
|
|
602
|
-
|
|
603
|
-
|
|
604
|
-
|
|
605
|
-
|
|
606
|
-
|
|
607
|
-
|
|
608
|
-
|
|
609
|
-
|
|
610
|
-
|
|
611
|
-
|
|
612
|
-
|
|
613
|
-
|
|
614
|
-
|
|
615
|
-
|
|
616
|
-
|
|
617
|
-
|
|
618
|
-
|
|
619
|
-
|
|
620
|
-
|
|
621
|
-
|
|
622
|
-
|
|
623
|
-
|
|
624
|
-
|
|
625
|
-
|
|
626
|
-
|
|
627
|
-
|
|
628
|
-
|
|
629
|
-
|
|
630
|
-
|
|
631
|
-
|
|
632
|
-
|
|
633
|
-
|
|
634
|
-
|
|
635
|
-
|
|
636
|
-
|
|
637
|
-
|
|
638
|
-
|
|
639
|
-
|
|
640
|
-
|
|
641
|
-
|
|
642
|
-
|
|
643
|
-
|
|
644
|
-
|
|
645
|
-
|
|
646
|
-
|
|
647
|
-
|
|
648
|
-
|
|
649
|
-
|
|
650
|
-
|
|
651
|
-
|
|
652
|
-
|
|
653
|
-
|
|
607
|
+
// Slug → help-text for every `lumo hook <slug>` subcommand. Each one accepts
|
|
608
|
+
// an optional `--agent <token>` flag (baked into settings.json by `lumo setup
|
|
609
|
+
// --agent <token>`); the value rides to the server as the X-Lumo-Agent header
|
|
610
|
+
// so auto-sedimented memories are attributed to the agent that produced them.
|
|
611
|
+
// Keep this list in sync with LUMO_HOOK_EVENTS (cli/src/lib/hooks-template.ts)
|
|
612
|
+
// and the server-side HookEventType slugs.
|
|
613
|
+
const HOOK_SUBCOMMANDS = [
|
|
614
|
+
[
|
|
615
|
+
'pre-tool-use',
|
|
616
|
+
'Forward a PreToolUse hook event to Lumo (reads JSON from stdin)',
|
|
617
|
+
],
|
|
618
|
+
[
|
|
619
|
+
'post-tool-use',
|
|
620
|
+
'Forward a PostToolUse hook event to Lumo (reads JSON from stdin)',
|
|
621
|
+
],
|
|
622
|
+
[
|
|
623
|
+
'post-tool-use-failure',
|
|
624
|
+
'Forward a PostToolUseFailure hook event to Lumo (reads JSON from stdin)',
|
|
625
|
+
],
|
|
626
|
+
[
|
|
627
|
+
'user-prompt-submit',
|
|
628
|
+
'Forward a UserPromptSubmit hook event to Lumo (reads JSON from stdin)',
|
|
629
|
+
],
|
|
630
|
+
['stop', 'Forward a Stop hook event to Lumo (reads JSON from stdin)'],
|
|
631
|
+
[
|
|
632
|
+
'stop-failure',
|
|
633
|
+
'Forward a StopFailure hook event to Lumo (reads JSON from stdin)',
|
|
634
|
+
],
|
|
635
|
+
[
|
|
636
|
+
'permission-request',
|
|
637
|
+
'Forward a PermissionRequest hook event to Lumo (reads JSON from stdin)',
|
|
638
|
+
],
|
|
639
|
+
[
|
|
640
|
+
'permission-denied',
|
|
641
|
+
'Forward a PermissionDenied hook event to Lumo (reads JSON from stdin)',
|
|
642
|
+
],
|
|
643
|
+
[
|
|
644
|
+
'session-start',
|
|
645
|
+
'Forward a SessionStart hook event to Lumo (reads JSON from stdin)',
|
|
646
|
+
],
|
|
647
|
+
[
|
|
648
|
+
'session-end',
|
|
649
|
+
'Forward a SessionEnd hook event to Lumo (reads JSON from stdin)',
|
|
650
|
+
],
|
|
651
|
+
[
|
|
652
|
+
'subagent-start',
|
|
653
|
+
'Forward a SubagentStart hook event to Lumo (reads JSON from stdin)',
|
|
654
|
+
],
|
|
655
|
+
[
|
|
656
|
+
'subagent-stop',
|
|
657
|
+
'Forward a SubagentStop hook event to Lumo (reads JSON from stdin)',
|
|
658
|
+
],
|
|
659
|
+
[
|
|
660
|
+
'worktree-create',
|
|
661
|
+
'Forward a WorktreeCreate hook event to Lumo (reads JSON from stdin)',
|
|
662
|
+
],
|
|
663
|
+
[
|
|
664
|
+
'worktree-remove',
|
|
665
|
+
'Forward a WorktreeRemove hook event to Lumo (reads JSON from stdin)',
|
|
666
|
+
],
|
|
667
|
+
[
|
|
668
|
+
'file-changed',
|
|
669
|
+
'Forward a FileChanged hook event to Lumo (reads JSON from stdin)',
|
|
670
|
+
],
|
|
671
|
+
[
|
|
672
|
+
'config-change',
|
|
673
|
+
'Forward a ConfigChange hook event to Lumo (reads JSON from stdin)',
|
|
674
|
+
],
|
|
675
|
+
[
|
|
676
|
+
'task-created',
|
|
677
|
+
'Forward a TaskCreated hook event to Lumo (reads JSON from stdin)',
|
|
678
|
+
],
|
|
679
|
+
[
|
|
680
|
+
'task-completed',
|
|
681
|
+
'Forward a TaskCompleted hook event to Lumo (reads JSON from stdin)',
|
|
682
|
+
],
|
|
683
|
+
[
|
|
684
|
+
'post-tool-batch',
|
|
685
|
+
'Forward a PostToolBatch hook event to Lumo (reads JSON from stdin)',
|
|
686
|
+
],
|
|
687
|
+
[
|
|
688
|
+
'user-prompt-expansion',
|
|
689
|
+
'Forward a UserPromptExpansion hook event to Lumo (reads JSON from stdin)',
|
|
690
|
+
],
|
|
691
|
+
[
|
|
692
|
+
'notification',
|
|
693
|
+
'Forward a Notification hook event to Lumo (reads JSON from stdin)',
|
|
694
|
+
],
|
|
695
|
+
[
|
|
696
|
+
'elicitation',
|
|
697
|
+
'Forward an Elicitation hook event to Lumo (reads JSON from stdin)',
|
|
698
|
+
],
|
|
699
|
+
[
|
|
700
|
+
'elicitation-result',
|
|
701
|
+
'Forward an ElicitationResult hook event to Lumo (reads JSON from stdin)',
|
|
702
|
+
],
|
|
703
|
+
[
|
|
704
|
+
'cwd-changed',
|
|
705
|
+
'Forward a CwdChanged hook event to Lumo (reads JSON from stdin)',
|
|
706
|
+
],
|
|
707
|
+
[
|
|
708
|
+
'instructions-loaded',
|
|
709
|
+
'Forward an InstructionsLoaded hook event to Lumo (reads JSON from stdin)',
|
|
710
|
+
],
|
|
711
|
+
];
|
|
712
|
+
for (const [slug, description] of HOOK_SUBCOMMANDS) {
|
|
713
|
+
hook
|
|
714
|
+
.command(slug)
|
|
715
|
+
.description(description)
|
|
716
|
+
.option('--agent <token>', 'Coding agent that owns this session (e.g. claude-code, codex). Baked in by `lumo setup --agent`.')
|
|
717
|
+
.action(wrap((opts) => (0, hook_1.hookCommand)(slug, opts.agent)));
|
|
718
|
+
}
|
|
654
719
|
if (!isUpdateCheckWorker) {
|
|
655
720
|
program.parseAsync(process.argv).catch(err => {
|
|
656
721
|
const msg = err instanceof Error ? err.message : String(err);
|
|
657
|
-
console.error(`Error: ${msg}`);
|
|
722
|
+
console.error(`Error: ${(0, sanitize_1.sanitizeField)(msg)}`);
|
|
658
723
|
process.exit(1);
|
|
659
724
|
});
|
|
660
725
|
}
|
|
@@ -5,7 +5,7 @@
|
|
|
5
5
|
* mirrored here. Keep in sync with prisma `enum TaskArtifactAgent`.
|
|
6
6
|
*/
|
|
7
7
|
Object.defineProperty(exports, "__esModule", { value: true });
|
|
8
|
-
exports.VALID_AGENT_TOKENS = exports.AGENT_LABELS = void 0;
|
|
8
|
+
exports.VALID_AGENT_TOKENS = exports.ENUM_TO_TOKEN = exports.AGENT_LABELS = void 0;
|
|
9
9
|
exports.normalizeAgent = normalizeAgent;
|
|
10
10
|
/** enum value → display label (matches lib/i18n en.json taskArtifact.agent.*) */
|
|
11
11
|
exports.AGENT_LABELS = {
|
|
@@ -16,6 +16,15 @@ exports.AGENT_LABELS = {
|
|
|
16
16
|
GITHUB_COPILOT: 'GitHub Copilot',
|
|
17
17
|
WINDSURF: 'Windsurf',
|
|
18
18
|
};
|
|
19
|
+
/** enum value → canonical CLI token (inverse of the non-alias TOKEN_TO_ENUM rows) */
|
|
20
|
+
exports.ENUM_TO_TOKEN = {
|
|
21
|
+
CLAUDE_CODE: 'claude-code',
|
|
22
|
+
CODEX: 'codex',
|
|
23
|
+
CURSOR: 'cursor',
|
|
24
|
+
GEMINI_CLI: 'gemini-cli',
|
|
25
|
+
GITHUB_COPILOT: 'github-copilot',
|
|
26
|
+
WINDSURF: 'windsurf',
|
|
27
|
+
};
|
|
19
28
|
/** accepted CLI token (normalized) → enum value */
|
|
20
29
|
const TOKEN_TO_ENUM = {
|
|
21
30
|
'claude-code': 'CLAUDE_CODE',
|