@wirecat/cli-core 0.399.0 → 0.401.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/CHANGELOG.md +111 -0
- package/README.md +1 -1
- package/dist/analysis/consents.d.ts +11 -6
- package/dist/analysis/consents.js +5 -2
- package/dist/cli/bot/mcp.js +2 -1
- package/dist/cli/bot/store.js +1 -1
- package/dist/cli/config-command.js +20 -1
- package/dist/cli/context.d.ts +2 -0
- package/dist/cli/context.js +1 -1
- package/dist/cli/effects.d.ts +4 -1
- package/dist/cli/effects.js +10 -2
- package/dist/cli/index.d.ts +3 -2
- package/dist/cli/index.js +3 -2
- package/dist/cli/json-fields.js +12 -1
- package/dist/cli/meeting-evidence-answer.d.ts +46 -0
- package/dist/cli/meeting-evidence-answer.js +22 -0
- package/dist/cli/meeting-preparation-answer.js +1 -13
- package/dist/cli/messenger/account-command.js +15 -6
- package/dist/cli/messenger/account-profile-query.d.ts +2 -0
- package/dist/cli/messenger/account-profile-query.js +13 -0
- package/dist/cli/messenger/account-sessions-command.js +1 -2
- package/dist/cli/messenger/admin-commands.js +12 -12
- package/dist/cli/messenger/admin-contacts-command.js +6 -3
- package/dist/cli/messenger/admin-folders-command.js +5 -5
- package/dist/cli/messenger/admin-moderation-command.js +4 -4
- package/dist/cli/messenger/admin-statistics-command.js +6 -14
- package/dist/cli/messenger/analysis-consents-query.d.ts +5 -0
- package/dist/cli/messenger/analysis-consents-query.js +20 -0
- package/dist/cli/messenger/archive-commands.js +3 -3
- package/dist/cli/messenger/attachments-command.js +3 -0
- package/dist/cli/messenger/backfill-command.js +5 -4
- package/dist/cli/messenger/chat-queries.d.ts +1 -0
- package/dist/cli/messenger/chat-queries.js +12 -2
- package/dist/cli/messenger/chats-command.js +2 -2
- package/dist/cli/messenger/chats-documents-command.js +7 -5
- package/dist/cli/messenger/chats-members-command.js +7 -3
- package/dist/cli/messenger/chats-read-command.js +1 -1
- package/dist/cli/messenger/chats-tracking-command.js +14 -6
- package/dist/cli/messenger/contacts-command.js +9 -5
- package/dist/cli/messenger/conversations-command.js +20 -16
- package/dist/cli/messenger/doctor-command.js +4 -1
- package/dist/cli/messenger/document-links-query.d.ts +2 -0
- package/dist/cli/messenger/document-links-query.js +9 -0
- package/dist/cli/messenger/download-command.js +1 -0
- package/dist/cli/messenger/flood-command.d.ts +2 -2
- package/dist/cli/messenger/flood-command.js +3 -3
- package/dist/cli/messenger/gaps-command.js +2 -2
- package/dist/cli/messenger/guard-commands.js +35 -13
- package/dist/cli/messenger/images-command.js +1 -0
- package/dist/cli/messenger/media-archive-command.js +2 -0
- package/dist/cli/messenger/media-archive-move-command.js +1 -0
- package/dist/cli/messenger/media-archive-timer-command.js +1 -1
- package/dist/cli/messenger/mentions-command.js +15 -2
- package/dist/cli/messenger/message-writes.d.ts +192 -2
- package/dist/cli/messenger/message-writes.js +6 -2
- package/dist/cli/messenger/messages-command.js +2 -0
- package/dist/cli/messenger/messages-delete-command.js +1 -0
- package/dist/cli/messenger/messages-edit-command.js +1 -0
- package/dist/cli/messenger/messages-evidence-command.js +3 -1
- package/dist/cli/messenger/messages-forward-command.js +1 -0
- package/dist/cli/messenger/messages-pin-command.js +3 -0
- package/dist/cli/messenger/messages-send-command.js +10 -6
- package/dist/cli/messenger/metadata-command.js +6 -1
- package/dist/cli/messenger/models-command.js +10 -5
- package/dist/cli/messenger/polls-command.js +4 -0
- package/dist/cli/messenger/private-people-command.js +3 -3
- package/dist/cli/messenger/rankings-command.js +6 -11
- package/dist/cli/messenger/reactions-command.js +2 -0
- package/dist/cli/messenger/recipients-query.d.ts +5 -0
- package/dist/cli/messenger/recipients-query.js +18 -0
- package/dist/cli/messenger/records-command.js +13 -8
- package/dist/cli/messenger/review.js +1 -1
- package/dist/cli/messenger/schedule-command.js +2 -2
- package/dist/cli/messenger/search-answers.js +2 -0
- package/dist/cli/messenger/search-command.js +3 -1
- package/dist/cli/messenger/searches-command.js +5 -1
- package/dist/cli/messenger/sends-query.d.ts +5 -0
- package/dist/cli/messenger/sends-query.js +33 -0
- package/dist/cli/messenger/serve-command.js +1 -0
- package/dist/cli/messenger/server-command.js +0 -3
- package/dist/cli/messenger/statistics-query.d.ts +14 -0
- package/dist/cli/messenger/statistics-query.js +143 -0
- package/dist/cli/messenger/stats-command.js +5 -5
- package/dist/cli/messenger/store-maintenance-command.js +10 -10
- package/dist/cli/messenger/stored.js +4 -1
- package/dist/cli/messenger/tags-command.js +7 -1
- package/dist/cli/messenger/tasks-command.js +57 -14
- package/dist/cli/messenger/transcribe-command.js +1 -0
- package/dist/cli/messenger/watch-answers.d.ts +6 -0
- package/dist/cli/messenger/watch-answers.js +69 -0
- package/dist/cli/messenger/watch-command.d.ts +1 -1
- package/dist/cli/messenger/watch-command.js +56 -7
- package/dist/cli/program.js +5 -1
- package/dist/cli/runs/command.js +25 -38
- package/dist/cli/runs/query.d.ts +5 -0
- package/dist/cli/runs/query.js +32 -0
- package/dist/cli/runs/search-command.d.ts +4 -0
- package/dist/cli/runs/search-command.js +27 -0
- package/dist/cli/runs/search-query.d.ts +4 -0
- package/dist/cli/runs/search-query.js +50 -0
- package/dist/cli/runs/search.d.ts +2 -1
- package/dist/cli/runs/search.js +6 -6
- package/dist/documents/index.d.ts +1 -0
- package/dist/documents/index.js +1 -0
- package/dist/domain/attachments.js +9 -1
- package/dist/domain/rankings-options.js +3 -3
- package/dist/entities/account-change.d.ts +89 -0
- package/dist/entities/account-change.js +20 -0
- package/dist/entities/account-profile.d.ts +7 -0
- package/dist/entities/account-profile.js +8 -0
- package/dist/entities/analysis-consent.d.ts +9 -0
- package/dist/entities/analysis-consent.js +4 -0
- package/dist/entities/attachment-results.d.ts +96 -0
- package/dist/entities/attachment-results.js +31 -0
- package/dist/entities/batch-result.d.ts +27 -0
- package/dist/entities/batch-result.js +18 -0
- package/dist/entities/chat-admin.d.ts +234 -0
- package/dist/entities/chat-admin.js +84 -0
- package/dist/entities/chat-change.d.ts +25 -0
- package/dist/entities/chat-change.js +11 -0
- package/dist/entities/chat-metadata.d.ts +34 -0
- package/dist/entities/chat-metadata.js +15 -0
- package/dist/entities/chat-moderation.d.ts +44 -0
- package/dist/entities/chat-moderation.js +37 -0
- package/dist/entities/chat-tracking.d.ts +26 -0
- package/dist/entities/chat-tracking.js +23 -0
- package/dist/entities/contact-activity.d.ts +52 -0
- package/dist/entities/contact-activity.js +42 -0
- package/dist/entities/contact-context.d.ts +1568 -0
- package/dist/entities/contact-context.js +191 -0
- package/dist/entities/contact-write.d.ts +22 -0
- package/dist/entities/contact-write.js +6 -0
- package/dist/entities/conversation-preparation.d.ts +63 -0
- package/dist/entities/conversation-preparation.js +23 -0
- package/dist/entities/conversation-results.d.ts +567 -0
- package/dist/entities/conversation-results.js +94 -0
- package/dist/entities/document-link.d.ts +13 -0
- package/dist/entities/document-link.js +11 -0
- package/dist/entities/extraction-report.d.ts +95 -0
- package/dist/entities/extraction-report.js +34 -0
- package/dist/entities/hit.d.ts +4 -0
- package/dist/entities/hit.js +4 -0
- package/dist/entities/image-embedding.d.ts +9 -0
- package/dist/entities/image-embedding.js +10 -0
- package/dist/entities/index.d.ts +8284 -1921
- package/dist/entities/index.js +178 -3
- package/dist/entities/listener.d.ts +2150 -0
- package/dist/entities/listener.js +46 -0
- package/dist/entities/media-archive.d.ts +43 -0
- package/dist/entities/media-archive.js +32 -0
- package/dist/entities/meeting-evidence.d.ts +86 -0
- package/dist/entities/meeting-evidence.js +25 -0
- package/dist/entities/meeting-preparation-parts.d.ts +14 -0
- package/dist/entities/meeting-preparation-parts.js +15 -13
- package/dist/entities/meeting-task-proposal.d.ts +14 -0
- package/dist/entities/meeting-task-proposal.js +19 -0
- package/dist/entities/meeting.d.ts +1 -1
- package/dist/entities/meeting.js +1 -1
- package/dist/entities/mention.d.ts +63 -0
- package/dist/entities/mention.js +44 -0
- package/dist/entities/message-change.d.ts +19 -0
- package/dist/entities/message-change.js +6 -0
- package/dist/entities/message-context.d.ts +617 -0
- package/dist/entities/message-context.js +20 -0
- package/dist/entities/message-read.d.ts +73 -0
- package/dist/entities/message-read.js +58 -0
- package/dist/entities/message-transfer.d.ts +379 -0
- package/dist/entities/message-transfer.js +83 -0
- package/dist/entities/message-write.d.ts +378 -0
- package/dist/entities/message-write.js +10 -0
- package/dist/entities/model-key.d.ts +14 -0
- package/dist/entities/model-key.js +10 -0
- package/dist/entities/poll.d.ts +40 -0
- package/dist/entities/poll.js +16 -0
- package/dist/entities/private-contact.d.ts +10 -0
- package/dist/entities/private-contact.js +4 -0
- package/dist/entities/reaction-change.d.ts +7 -0
- package/dist/entities/reaction-change.js +8 -0
- package/dist/entities/recipient.d.ts +29 -0
- package/dist/entities/recipient.js +11 -0
- package/dist/entities/recorded-run.d.ts +103 -0
- package/dist/entities/recorded-run.js +44 -0
- package/dist/entities/saved-search.d.ts +4 -0
- package/dist/entities/saved-search.js +2 -0
- package/dist/entities/send-attempt.d.ts +31 -0
- package/dist/entities/send-attempt.js +29 -0
- package/dist/entities/store-maintenance.d.ts +319 -0
- package/dist/entities/store-maintenance.js +145 -0
- package/dist/entities/store-records.d.ts +442 -0
- package/dist/entities/store-records.js +99 -0
- package/dist/entities/tag-change.d.ts +74 -0
- package/dist/entities/tag-change.js +31 -0
- package/dist/entities/task-pair.d.ts +31 -0
- package/dist/entities/task-pair.js +23 -0
- package/dist/entities/task-results.d.ts +524 -0
- package/dist/entities/task-results.js +142 -0
- package/dist/errors/reasons.js +3 -0
- package/dist/mcp/agent.d.ts +3 -1
- package/dist/mcp/agent.js +17 -10
- package/dist/mcp/bot/server.d.ts +2 -0
- package/dist/mcp/bot/server.js +1 -0
- package/dist/mcp/server.js +3 -1
- package/dist/mcp/tools/attachments.js +1 -0
- package/dist/meetings/cli/index.js +4 -2
- package/dist/meetings/cli/passage.js +1 -0
- package/dist/meetings/index.d.ts +2 -1
- package/dist/meetings/index.js +1 -0
- package/dist/meetings/links.d.ts +16 -0
- package/dist/meetings/read-answers.d.ts +185 -0
- package/dist/meetings/read-answers.js +213 -0
- package/dist/ports/messenger.d.ts +10 -1
- package/dist/runs/run.d.ts +10 -2
- package/dist/runs/run.js +11 -3
- package/dist/sends/guard.d.ts +1 -1
- package/dist/sends/guard.js +9 -5
- package/dist/sends/journal.d.ts +9 -2
- package/dist/sends/journal.js +9 -2
- package/dist/sends/permissions.d.ts +5 -1
- package/dist/sends/permissions.js +42 -2
- package/dist/sends/recipients.d.ts +8 -0
- package/dist/sends/recipients.js +9 -0
- package/dist/sends/upload.d.ts +4 -4
- package/dist/sends/upload.js +24 -20
- package/dist/services/admin-statistics.js +3 -3
- package/dist/services/chat-documents.d.ts +1 -0
- package/dist/services/chat-documents.js +9 -3
- package/dist/services/chats.d.ts +1 -1
- package/dist/services/chats.js +5 -2
- package/dist/services/documents/mirrors.d.ts +98 -0
- package/dist/services/documents/mirrors.js +144 -0
- package/dist/services/meeting-links.d.ts +2 -17
- package/dist/services/messages.js +1 -0
- package/dist/services/search-all-meetings.js +21 -8
- package/dist/services/task-rules.d.ts +1 -1
- package/dist/services/tasks.d.ts +2 -2
- package/dist/services/tasks.js +1 -1
- package/dist/store/exports.d.ts +1 -1
- package/dist/store/exports.js +1 -1
- package/dist/store/messages.d.ts +3 -1
- package/dist/store/messages.js +2 -2
- package/dist/store/roster.d.ts +4 -1
- package/dist/store/roster.js +2 -2
- package/dist/store/sqlite/chats.d.ts +12 -0
- package/dist/store/sqlite/chats.js +1 -0
- package/dist/store/sqlite/document-links.d.ts +1 -1
- package/dist/store/sqlite/document-links.js +5 -5
- package/dist/store/sqlite/drizzle/bun.js +3 -3
- package/dist/store/sqlite/drizzle/bun.js.map +1 -1
- package/dist/store/sqlite/drizzle/core.js +2 -2
- package/dist/store/sqlite/drizzle/core.js.map +1 -1
- package/dist/store/sqlite/drizzle/node.js +3 -3
- package/dist/store/sqlite/drizzle/node.js.map +1 -1
- package/dist/store/sqlite/drizzle/{shared-O7CTKP45.js → shared-HKXF6HKX.js} +57 -57
- package/dist/store/sqlite/drizzle/{shared-O7CTKP45.js.map → shared-HKXF6HKX.js.map} +1 -1
- package/dist/store/sqlite/involvements.js +2 -1
- package/dist/store/sqlite/roster.d.ts +2 -1
- package/dist/store/sqlite/roster.js +3 -2
- package/package.json +2 -2
- package/parity.json +14 -69
|
@@ -29,7 +29,7 @@ const line = ({ id, key, state, kind, group, createdAt, message, note }) => [
|
|
|
29
29
|
: "(not in the store)",
|
|
30
30
|
].join(" ");
|
|
31
31
|
const when = (at) => (at === null ? "—" : at.slice(0, 16).replace("T", " "));
|
|
32
|
-
const toReview = (count) => count ? `; ${count} possible duplicate pair(s) went to tasks duplicates` : "";
|
|
32
|
+
const toReview = (count) => count ? `; ${count} possible duplicate pair(s) went to tasks duplicates list` : "";
|
|
33
33
|
const suggestionLine = ({ as, by, certainty, reason }) => `close suggested: ${as} by ${by} at certainty ${certainty}${reason === null ? "" : ` — ${reason}`}; waits on the owner`;
|
|
34
34
|
const card = (task) => [
|
|
35
35
|
`${task.key} ${task.status} ${task.type} ${task.category ?? "—"} ${task.title}`,
|
|
@@ -44,7 +44,7 @@ const card = (task) => [
|
|
|
44
44
|
].join("\n");
|
|
45
45
|
const applyText = (pass, yes, tool) => yes
|
|
46
46
|
? `${pass.chat}: ${pass.messages} messages read; ${pass.added} opened, ${pass.closed} closed` +
|
|
47
|
-
(pass.review ? `; ${pass.review} may be the same job as another — ${tool} tasks duplicates` : "")
|
|
47
|
+
(pass.review ? `; ${pass.review} may be the same job as another — ${tool} tasks duplicates list` : "")
|
|
48
48
|
: [
|
|
49
49
|
`${pass.chat}: ${pass.messages} messages read; would open ${pass.tasks.length}, close ${pass.closed}`,
|
|
50
50
|
...pass.tasks.map((task) => ` ${task.kind.padEnd(8)} ${(task.category ?? "—").padEnd(13)} ${task.source}`),
|
|
@@ -152,6 +152,7 @@ export const tasksCommand = (messenger) => {
|
|
|
152
152
|
context.renderer.note("no tasks — review, inbox and messages sync add them as questions arrive");
|
|
153
153
|
});
|
|
154
154
|
planOptions(destroysNothing(annotate(tasks.command("add"), {
|
|
155
|
+
output: { entity: "task_created" },
|
|
155
156
|
effects: LOCAL_WRITE,
|
|
156
157
|
examples: [`${tool} personal tasks add note:101 --type promise --category documents --title "Review draft"`],
|
|
157
158
|
}))
|
|
@@ -185,6 +186,7 @@ export const tasksCommand = (messenger) => {
|
|
|
185
186
|
context.renderer.note(`${task.key ?? task.id} follows up ${followUpOf.key} (${followUpOf.status}), which stays closed: linked follow-up-of`);
|
|
186
187
|
});
|
|
187
188
|
planOptions(destroysNothing(annotate(tasks.command("plan"), {
|
|
189
|
+
output: { entity: "task_card" },
|
|
188
190
|
effects: LOCAL_WRITE,
|
|
189
191
|
examples: [`${tool} personal tasks plan DOC-12 --title "Review draft"`],
|
|
190
192
|
}))
|
|
@@ -201,6 +203,7 @@ export const tasksCommand = (messenger) => {
|
|
|
201
203
|
renderAnswer(this, context, itemOf(snakeKeys(planned)), () => `${card(planned)}\n`);
|
|
202
204
|
});
|
|
203
205
|
destroysNothing(annotate(tasks.command("link"), {
|
|
206
|
+
output: { entity: "task_links" },
|
|
204
207
|
effects: LOCAL_WRITE,
|
|
205
208
|
examples: [`${tool} personal tasks link DOC-12 https://example.com/draft`],
|
|
206
209
|
}))
|
|
@@ -221,9 +224,13 @@ export const tasksCommand = (messenger) => {
|
|
|
221
224
|
? `${linked.relations.map((one) => `${one.from} ${one.kind} ${one.to}`).join("\n")}\n`
|
|
222
225
|
: `${card(linked)}\n`);
|
|
223
226
|
if (!("relations" in linked) && linked.review && context.format === "pretty")
|
|
224
|
-
context.renderer.note(`${linked.review} possible duplicate pair(s) went to tasks duplicates`);
|
|
227
|
+
context.renderer.note(`${linked.review} possible duplicate pair(s) went to tasks duplicates list`);
|
|
225
228
|
});
|
|
226
|
-
annotate(tasks.command("show"), {
|
|
229
|
+
annotate(tasks.command("show"), {
|
|
230
|
+
output: { entity: "task_card" },
|
|
231
|
+
effects: LOCAL_READ,
|
|
232
|
+
examples: [`${tool} personal tasks show DOC-12`],
|
|
233
|
+
})
|
|
227
234
|
.description("one task: its plan and everything linked to it")
|
|
228
235
|
.argument("<task>", "the task's id or key, as tasks list shows it")
|
|
229
236
|
.action(async function (id) {
|
|
@@ -231,7 +238,11 @@ export const tasksCommand = (messenger) => {
|
|
|
231
238
|
const shown = await context.withServices((services) => services.tasks.show(id));
|
|
232
239
|
renderAnswer(this, context, itemOf(snakeKeys(shown)), () => `${card(shown)}\n`);
|
|
233
240
|
});
|
|
234
|
-
annotate(tasks.command("related"), {
|
|
241
|
+
annotate(tasks.command("related"), {
|
|
242
|
+
output: { entity: "task_similar" },
|
|
243
|
+
effects: LOCAL_READ,
|
|
244
|
+
examples: [`${tool} tasks related PR-12`],
|
|
245
|
+
})
|
|
235
246
|
.summary("tasks that may be the same job as this one, best first; merges nothing")
|
|
236
247
|
.description("tasks that may be the same job as this one, best first, each with a band — likely, maybe, different — and the " +
|
|
237
248
|
"reasons; merges nothing")
|
|
@@ -255,7 +266,11 @@ export const tasksCommand = (messenger) => {
|
|
|
255
266
|
if (found.length === 0 && context.format === "pretty")
|
|
256
267
|
context.renderer.note("no open or recent task looks alike");
|
|
257
268
|
});
|
|
258
|
-
const duplicates =
|
|
269
|
+
const duplicates = tasks.command("duplicates").description("pairs of tasks that may be one job");
|
|
270
|
+
withQuery(annotate(duplicates.command("list"), {
|
|
271
|
+
effects: LOCAL_READ,
|
|
272
|
+
examples: [`${tool} tasks duplicates list --limit 10`, `${tool} tasks duplicates list decision:unsure`],
|
|
273
|
+
})
|
|
259
274
|
.summary("pairs of tasks a rule opened that may be one job, newest first")
|
|
260
275
|
.description("pairs of tasks a rule opened that may be one job, newest first, with score and reasons: merge, reject or " +
|
|
261
276
|
"defer each; decision:unsure lists the ones deferred to the owner"), TASK_PAIR_QUERY)
|
|
@@ -263,10 +278,10 @@ export const tasksCommand = (messenger) => {
|
|
|
263
278
|
.action(async function (words) {
|
|
264
279
|
const context = messengerContext(this, messenger);
|
|
265
280
|
const { limit, offset } = pageOf(context.settings);
|
|
266
|
-
const decision = queryTerms(words, TASK_PAIR_QUERY, "tasks duplicates").get("decision");
|
|
281
|
+
const decision = queryTerms(words, TASK_PAIR_QUERY, "tasks duplicates list").get("decision");
|
|
267
282
|
const rows = await context.withServices((services) => services.tasks.duplicates({ decision, limit: limit + 1, offset }));
|
|
268
283
|
const shown = rows.slice(0, limit);
|
|
269
|
-
renderAnswer(this, context, pagedList("tasks duplicates", context.settings, {
|
|
284
|
+
renderAnswer(this, context, pagedList("tasks duplicates list", context.settings, {
|
|
270
285
|
items: shown.map(snakeKeys),
|
|
271
286
|
has_more: rows.length > limit,
|
|
272
287
|
}), () => (shown.length === 0 ? "" : `${shown.map(pairLine).join("\n")}\n`));
|
|
@@ -280,6 +295,7 @@ export const tasksCommand = (messenger) => {
|
|
|
280
295
|
renderAnswer(this, context, itemOf(snakeKeys(pair)), () => `${pair.decision} ${pairLine(pair)}\n`);
|
|
281
296
|
};
|
|
282
297
|
destroysNothing(annotate(duplicates.command("reject"), {
|
|
298
|
+
output: { entity: "task_pair" },
|
|
283
299
|
effects: LOCAL_WRITE,
|
|
284
300
|
examples: [`${tool} tasks duplicates reject PR-14 PR-12`],
|
|
285
301
|
}))
|
|
@@ -289,6 +305,7 @@ export const tasksCommand = (messenger) => {
|
|
|
289
305
|
.argument("<other-task>", "the task it was paired with")
|
|
290
306
|
.action(decided("rejected", "tasks.duplicates.reject"));
|
|
291
307
|
destroysNothing(annotate(duplicates.command("defer"), {
|
|
308
|
+
output: { entity: "task_pair" },
|
|
292
309
|
effects: LOCAL_WRITE,
|
|
293
310
|
examples: [`${tool} tasks duplicates defer PR-14 PR-12`],
|
|
294
311
|
}))
|
|
@@ -297,7 +314,11 @@ export const tasksCommand = (messenger) => {
|
|
|
297
314
|
.argument("<task>", "the task listed as the duplicate, by its id or key")
|
|
298
315
|
.argument("<other-task>", "the task it was paired with")
|
|
299
316
|
.action(decided("unsure", "tasks.duplicates.defer"));
|
|
300
|
-
destroysNothing(annotate(tasks.command("merge"), {
|
|
317
|
+
destroysNothing(annotate(tasks.command("merge"), {
|
|
318
|
+
output: { entity: "task_merge" },
|
|
319
|
+
effects: LOCAL_WRITE,
|
|
320
|
+
examples: [`${tool} tasks merge PR-14 --into PR-12`],
|
|
321
|
+
}))
|
|
301
322
|
.summary("one job seen twice: fold the duplicate into the task that stays")
|
|
302
323
|
.description("one job seen twice: link every message of the duplicate to the task and close the duplicate dismissed, " +
|
|
303
324
|
"duplicate-of the task; nothing is deleted, and tasks unmerge undoes it")
|
|
@@ -311,7 +332,11 @@ export const tasksCommand = (messenger) => {
|
|
|
311
332
|
renderAnswer(this, context, itemOf(snakeKeys(merged)), () => `${dup} merged into ${merged.task.key}; ${merged.linked} message(s) linked${toReview(merged.review)}\n` +
|
|
312
333
|
`${card(merged.task)}\n`);
|
|
313
334
|
});
|
|
314
|
-
destroysNothing(annotate(tasks.command("unmerge"), {
|
|
335
|
+
destroysNothing(annotate(tasks.command("unmerge"), {
|
|
336
|
+
output: { entity: "task_unmerge" },
|
|
337
|
+
effects: LOCAL_WRITE,
|
|
338
|
+
examples: [`${tool} tasks unmerge PR-14`],
|
|
339
|
+
}))
|
|
315
340
|
.summary("undo a merge: reopen the task and remove its duplicate-of relation")
|
|
316
341
|
.description("undo a merge: reopen the task and remove its duplicate-of relation; messages the merge linked stay linked")
|
|
317
342
|
.argument("<task>", "the merged task, by its id or key")
|
|
@@ -344,7 +369,11 @@ export const tasksCommand = (messenger) => {
|
|
|
344
369
|
}));
|
|
345
370
|
renderAnswer(this, context, itemOf(agendaItem(agenda)), () => `${agendaText(agenda)}\n`);
|
|
346
371
|
});
|
|
347
|
-
annotate(tasks.command("categories"), {
|
|
372
|
+
annotate(tasks.command("categories"), {
|
|
373
|
+
output: { entity: "task_categories" },
|
|
374
|
+
effects: LOCAL_READ,
|
|
375
|
+
examples: [`${tool} tasks categories`],
|
|
376
|
+
})
|
|
348
377
|
.summary("the categories a task takes, with what each means")
|
|
349
378
|
.description("the categories a task takes, with what each means and the words a rule picks it by")
|
|
350
379
|
.action(async function () {
|
|
@@ -365,6 +394,7 @@ export const tasksCommand = (messenger) => {
|
|
|
365
394
|
].join("\n"));
|
|
366
395
|
});
|
|
367
396
|
destroysNothing(annotate(tasks.command("scan"), {
|
|
397
|
+
output: { entity: "task_scan" },
|
|
368
398
|
effects: LOCAL_WRITE,
|
|
369
399
|
examples: [`${tool} tasks scan <chat>`, `${tool} tasks scan <chat> --last 300 --yes`],
|
|
370
400
|
}))
|
|
@@ -389,7 +419,11 @@ export const tasksCommand = (messenger) => {
|
|
|
389
419
|
}, { name: "tasks scan" });
|
|
390
420
|
renderAnswer(this, context, listOf("tasks scan", { items: passes.map(snakeKeys), limit: passes.length, has_more: false }), () => `${passes.map((pass) => applyText(pass, yes, tool)).join("\n")}\n`);
|
|
391
421
|
});
|
|
392
|
-
destroysNothing(annotate(tasks.command("claim"), {
|
|
422
|
+
destroysNothing(annotate(tasks.command("claim"), {
|
|
423
|
+
output: { entity: "task_card" },
|
|
424
|
+
effects: LOCAL_WRITE,
|
|
425
|
+
examples: [`${tool} tasks claim PR-12 --lease 2h`],
|
|
426
|
+
}))
|
|
393
427
|
.description("take an open task so no other agent works it at once; the claim lapses by itself")
|
|
394
428
|
.argument("<task>", "the task's id or key, as tasks list shows it")
|
|
395
429
|
.option("--lease <duration>", "how long the claim lasts: 30m, 2h (default 30m); claiming again extends it", durationOf("--lease"))
|
|
@@ -401,7 +435,11 @@ export const tasksCommand = (messenger) => {
|
|
|
401
435
|
const claimed = await context.withServices((services) => services.tasks.claim(id, holderOf(this), lease));
|
|
402
436
|
renderAnswer(this, context, itemOf(snakeKeys(claimed)), () => `${card(claimed)}\n`);
|
|
403
437
|
});
|
|
404
|
-
destroysNothing(annotate(tasks.command("release"), {
|
|
438
|
+
destroysNothing(annotate(tasks.command("release"), {
|
|
439
|
+
output: { entity: "task_card" },
|
|
440
|
+
effects: LOCAL_WRITE,
|
|
441
|
+
examples: [`${tool} tasks release PR-12`],
|
|
442
|
+
}))
|
|
405
443
|
.description("give back a task you claimed, before the claim lapses; the owner may release any")
|
|
406
444
|
.argument("<task>", "the task's id or key, as tasks list shows it")
|
|
407
445
|
.option("--holder <name>", HOLDER_HELP)
|
|
@@ -412,6 +450,7 @@ export const tasksCommand = (messenger) => {
|
|
|
412
450
|
renderAnswer(this, context, itemOf(snakeKeys(released)), () => `${card(released)}\n`);
|
|
413
451
|
});
|
|
414
452
|
destroysNothing(annotate(tasks.command("close"), {
|
|
453
|
+
output: { entity: "task_closed" },
|
|
415
454
|
effects: LOCAL_WRITE,
|
|
416
455
|
examples: [
|
|
417
456
|
`${tool} tasks close Q-15 --as done --certainty 0.9 --reason answered-in-chat`,
|
|
@@ -452,7 +491,11 @@ export const tasksCommand = (messenger) => {
|
|
|
452
491
|
context.renderer.note(`${closed.key ?? id} stays open: the close waits on the owner — ${tool} tasks close ${closed.key ?? id} ` +
|
|
453
492
|
`confirms it, ${tool} tasks reject ${closed.key ?? id} refuses it`);
|
|
454
493
|
});
|
|
455
|
-
annotate(tasks.command("reject"), {
|
|
494
|
+
annotate(tasks.command("reject"), {
|
|
495
|
+
output: { entity: "task_card" },
|
|
496
|
+
effects: LOCAL_WRITE,
|
|
497
|
+
examples: [`${tool} tasks reject Q-15`],
|
|
498
|
+
})
|
|
456
499
|
.summary("refuse an agent's close of a task: it stays open and the suggestion goes")
|
|
457
500
|
.description("refuse the close an agent suggested: the task stays open and leaves close:suggested; the agent may close it again")
|
|
458
501
|
.argument("<task>", "the task's id or key, as tasks list shows it")
|
|
@@ -9,6 +9,7 @@ import { heardAnswer } from "./message-answers.js";
|
|
|
9
9
|
import { keepRefreshedRefs } from "./refreshed-refs.js";
|
|
10
10
|
/** `messages transcribe`: a voice message as text, by the messenger or by a model on this machine. */
|
|
11
11
|
export const transcribeSubcommand = (messages, messenger) => annotate(messages.command("transcribe"), {
|
|
12
|
+
output: { entity: "message_transcript" },
|
|
12
13
|
examples: [`${messenger.app.command} personal messages transcribe "Book club" 101`],
|
|
13
14
|
effects: REMOTE_READ,
|
|
14
15
|
})
|
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type * as v from "valibot";
|
|
2
|
+
import type { MessageEvent, MessageHit } from "../../domain/models.js";
|
|
3
|
+
import type { messageEvent, watchedMessage } from "../../entities/listener.js";
|
|
4
|
+
import type { AccountKey } from "../../store/store.js";
|
|
5
|
+
export declare const watchedMessageItem: (value: MessageHit, account: AccountKey) => v.InferOutput<typeof watchedMessage>;
|
|
6
|
+
export declare const watchEventItem: (value: MessageEvent, account: AccountKey) => v.InferOutput<typeof messageEvent>;
|
|
@@ -0,0 +1,69 @@
|
|
|
1
|
+
import { chatEventAnswer, memberAnswer, pollVoteAnswer } from "./chat-answers.js";
|
|
2
|
+
import { messageItem } from "./message-items.js";
|
|
3
|
+
const observed = (value) => ({
|
|
4
|
+
value: value.value,
|
|
5
|
+
observed_at: value.observedAt,
|
|
6
|
+
source: value.source,
|
|
7
|
+
...(value.reactions === undefined ? {} : { reactions: value.reactions }),
|
|
8
|
+
});
|
|
9
|
+
export const watchedMessageItem = (value, account) => {
|
|
10
|
+
const counters = value.counterObservations;
|
|
11
|
+
return {
|
|
12
|
+
...messageItem(value, account),
|
|
13
|
+
...(value.starred === undefined ? {} : { starred: value.starred }),
|
|
14
|
+
...(counters === undefined
|
|
15
|
+
? {}
|
|
16
|
+
: {
|
|
17
|
+
counter_observations: {
|
|
18
|
+
...(counters.views === undefined ? {} : { views: observed(counters.views) }),
|
|
19
|
+
...(counters.reactions === undefined ? {} : { reactions: observed(counters.reactions) }),
|
|
20
|
+
...(counters.comments === undefined ? {} : { comments: observed(counters.comments) }),
|
|
21
|
+
},
|
|
22
|
+
}),
|
|
23
|
+
};
|
|
24
|
+
};
|
|
25
|
+
const affected = (value) => ({
|
|
26
|
+
chat_id: value.chatId,
|
|
27
|
+
chat_title: value.chatTitle,
|
|
28
|
+
message_id: value.messageId,
|
|
29
|
+
});
|
|
30
|
+
export const watchEventItem = (value, account) => {
|
|
31
|
+
switch (value.event) {
|
|
32
|
+
case "message":
|
|
33
|
+
case "edit":
|
|
34
|
+
return { event: value.event, message: watchedMessageItem(value.message, account) };
|
|
35
|
+
case "delete":
|
|
36
|
+
return { event: value.event, chat_id: value.chatId, chat_title: value.chatTitle, message_id: value.messageId };
|
|
37
|
+
case "reaction":
|
|
38
|
+
return {
|
|
39
|
+
event: value.event,
|
|
40
|
+
...affected(value),
|
|
41
|
+
reactions: value.reactions,
|
|
42
|
+
...(value.counterObservation === undefined ? {} : { counter_observation: observed(value.counterObservation) }),
|
|
43
|
+
};
|
|
44
|
+
case "vote":
|
|
45
|
+
return { event: value.event, ...affected(value), vote: pollVoteAnswer(value.vote) };
|
|
46
|
+
case "person_reaction":
|
|
47
|
+
return {
|
|
48
|
+
event: value.event,
|
|
49
|
+
...affected(value),
|
|
50
|
+
reaction: {
|
|
51
|
+
person: memberAnswer(value.reaction.person),
|
|
52
|
+
own: value.reaction.own,
|
|
53
|
+
reaction: value.reaction.reaction,
|
|
54
|
+
reacted_at: value.reaction.reactedAt,
|
|
55
|
+
},
|
|
56
|
+
};
|
|
57
|
+
case "star":
|
|
58
|
+
return { event: value.event, ...affected(value), starred: value.starred };
|
|
59
|
+
case "delivery":
|
|
60
|
+
return { event: value.event, ...affected(value), delivery: value.delivery, at: value.at };
|
|
61
|
+
case "chat_event":
|
|
62
|
+
return {
|
|
63
|
+
event: value.event,
|
|
64
|
+
chat_id: value.chatId,
|
|
65
|
+
chat_title: value.chatTitle,
|
|
66
|
+
change: chatEventAnswer(value.chatId, value.change),
|
|
67
|
+
};
|
|
68
|
+
}
|
|
69
|
+
};
|
|
@@ -4,7 +4,7 @@ import type { MessengerAdapter } from "../../ports/messenger.js";
|
|
|
4
4
|
import { type Messenger, type MessengerContext } from "./context.js";
|
|
5
5
|
/**
|
|
6
6
|
* New messages as they arrive, until Ctrl-C or `--timeout` — both a normal end, exit 0: listening
|
|
7
|
-
* for a minute is a complete answer.
|
|
7
|
+
* for a minute is a complete answer. Canonical item records and one end record with `--jsonl`; `--json` is refused,
|
|
8
8
|
* because a stream is not one value. Nothing is marked read.
|
|
9
9
|
*/
|
|
10
10
|
export declare const watchCommand: (messenger: Messenger) => Command;
|
|
@@ -4,21 +4,25 @@ import { Command } from "commander";
|
|
|
4
4
|
import { renderMessages } from "../../render/messages.js";
|
|
5
5
|
import { environmentOf } from "../context.js";
|
|
6
6
|
import { REMOTE_READ } from "../effects.js";
|
|
7
|
+
import { jsonlRecords, listOf } from "../envelope.js";
|
|
7
8
|
import { withoutProviderRefs } from "../provider-refs.js";
|
|
8
9
|
import { messengerContext } from "./context.js";
|
|
10
|
+
import { selfOf } from "./message-items.js";
|
|
11
|
+
import { watchEventItem, watchedMessageItem } from "./watch-answers.js";
|
|
9
12
|
/**
|
|
10
13
|
* New messages as they arrive, until Ctrl-C or `--timeout` — both a normal end, exit 0: listening
|
|
11
|
-
* for a minute is a complete answer.
|
|
14
|
+
* for a minute is a complete answer. Canonical item records and one end record with `--jsonl`; `--json` is refused,
|
|
12
15
|
* because a stream is not one value. Nothing is marked read.
|
|
13
16
|
*/
|
|
14
17
|
export const watchCommand = (messenger) => annotate(new Command("watch"), {
|
|
18
|
+
output: { entity: "watch_item" },
|
|
15
19
|
effects: REMOTE_READ,
|
|
16
20
|
lifetime: "persistent",
|
|
17
21
|
examples: [`${messenger.app.command} personal watch --jsonl --timeout 30s`],
|
|
18
22
|
})
|
|
19
23
|
.summary("stream new messages until interrupted or timed out")
|
|
20
24
|
.description("print new messages as they arrive, until Ctrl-C or --timeout (either ends it normally)")
|
|
21
|
-
.option("--events", "
|
|
25
|
+
.option("--events", "include changes and receipts; each item names its event")
|
|
22
26
|
.action(async function () {
|
|
23
27
|
const events = this.opts().events === true;
|
|
24
28
|
const context = messengerContext(this, messenger);
|
|
@@ -35,19 +39,59 @@ export const watchCommand = (messenger) => annotate(new Command("watch"), {
|
|
|
35
39
|
provider: messenger.provider,
|
|
36
40
|
locale: messenger.app.locale,
|
|
37
41
|
})}`;
|
|
38
|
-
//
|
|
39
|
-
// a line of another shape.
|
|
42
|
+
// Event-tagged payloads are opt-in; ordinary items remain message values.
|
|
40
43
|
const stop = new AbortController();
|
|
44
|
+
let connection;
|
|
45
|
+
let printed = 0;
|
|
46
|
+
const account = () => {
|
|
47
|
+
if (!connection)
|
|
48
|
+
throw new Error("watch has no connected account");
|
|
49
|
+
return selfOf(messenger, connection);
|
|
50
|
+
};
|
|
41
51
|
const print = (event) => {
|
|
42
52
|
if (stop.signal.aborted || (!events && event.event !== "message"))
|
|
43
53
|
return;
|
|
44
54
|
if (context.format === "jsonl") {
|
|
45
|
-
|
|
55
|
+
const data = events
|
|
56
|
+
? watchEventItem(event, account())
|
|
57
|
+
: event.event === "message"
|
|
58
|
+
? watchedMessageItem(event.message, account())
|
|
59
|
+
: undefined;
|
|
60
|
+
if (data === undefined)
|
|
61
|
+
return;
|
|
62
|
+
context.streams.data(JSON.stringify({ type: "item", data: withoutProviderRefs(data) }));
|
|
63
|
+
printed++;
|
|
46
64
|
}
|
|
47
65
|
else
|
|
48
66
|
context.streams.data(describe(event, render));
|
|
49
67
|
};
|
|
50
|
-
|
|
68
|
+
const finish = (complete, error) => {
|
|
69
|
+
if (context.format !== "jsonl" || environmentOf(this).commandSignal?.aborted)
|
|
70
|
+
return;
|
|
71
|
+
const issues = !complete && error instanceof CliError ? [{ code: error.code, source: "watch" }] : undefined;
|
|
72
|
+
for (const record of jsonlRecords(listOf("watch", {
|
|
73
|
+
items: [],
|
|
74
|
+
limit: Math.max(1, printed),
|
|
75
|
+
has_more: false,
|
|
76
|
+
paging: "cursor",
|
|
77
|
+
meta: { complete, ...(issues ? { issues } : {}) },
|
|
78
|
+
})))
|
|
79
|
+
context.streams.data(JSON.stringify(record));
|
|
80
|
+
};
|
|
81
|
+
try {
|
|
82
|
+
await listenUntilStopped(this, context, messenger, print, {
|
|
83
|
+
stop,
|
|
84
|
+
pipe: true,
|
|
85
|
+
connected: (open) => {
|
|
86
|
+
connection = open;
|
|
87
|
+
},
|
|
88
|
+
});
|
|
89
|
+
}
|
|
90
|
+
catch (error) {
|
|
91
|
+
finish(false, error);
|
|
92
|
+
throw error;
|
|
93
|
+
}
|
|
94
|
+
finish(true);
|
|
51
95
|
});
|
|
52
96
|
/**
|
|
53
97
|
* Listens until Ctrl-C, SIGTERM, `--timeout` or — with `pipe` — a reader that has gone away.
|
|
@@ -55,7 +99,11 @@ export const watchCommand = (messenger) => annotate(new Command("watch"), {
|
|
|
55
99
|
* `feed` runs it beside `watch`, so what the messenger pushes reaches the store (`stored`).
|
|
56
100
|
*/
|
|
57
101
|
export const listenUntilStopped = async (command, context, messenger, onEvent, { stop, pipe = false, catchUp = false, onReady = () => context.renderer.note("listening — Ctrl-C to stop"), connected, }) => {
|
|
58
|
-
const
|
|
102
|
+
const environment = environmentOf(command);
|
|
103
|
+
const phase = environment.untilStopped?.();
|
|
104
|
+
const given = phase
|
|
105
|
+
? AbortSignal.any([phase, ...[environment.signal].filter((one) => one !== undefined)])
|
|
106
|
+
: environment.signal;
|
|
59
107
|
const end = () => stop.abort();
|
|
60
108
|
given?.addEventListener("abort", end, { once: true });
|
|
61
109
|
const signals = given ? [] : ["SIGINT", "SIGTERM"];
|
|
@@ -96,6 +144,7 @@ export const listenUntilStopped = async (command, context, messenger, onEvent, {
|
|
|
96
144
|
if (pipe && !given)
|
|
97
145
|
process.stdout.off("error", closed);
|
|
98
146
|
given?.removeEventListener("abort", end);
|
|
147
|
+
environment.endUntilStopped?.();
|
|
99
148
|
}
|
|
100
149
|
};
|
|
101
150
|
const describe = (event, render) => {
|
package/dist/cli/program.js
CHANGED
|
@@ -11,7 +11,7 @@ import { failureContext } from "../errors/reasons.js";
|
|
|
11
11
|
import { envName, readOnlyLockOf, readOnlyRefusal } from "../ports/app.js";
|
|
12
12
|
import { recorded, wasSettled } from "../runs/recording.js";
|
|
13
13
|
import { processRun, useAsProcessRun } from "../runs/scope.js";
|
|
14
|
-
import { keyForCommand } from "../sends/permissions.js";
|
|
14
|
+
import { AUTHORITY_KEY, keyForCommand } from "../sends/permissions.js";
|
|
15
15
|
import { logParsedArgv, logVersion } from "./argv-log.js";
|
|
16
16
|
import { commandPathOf } from "./command-contract.js";
|
|
17
17
|
import { outputFor, provide } from "./context.js";
|
|
@@ -254,6 +254,10 @@ const runOnce = async (argv, definition, options) => {
|
|
|
254
254
|
if (lock && changesAuthorityNow(action) && !flags.dryRun)
|
|
255
255
|
throw new CliError("permission_error", `this process is read-only (${lock}) — \`${command} ${path.join(" ")}\` changes what a later run may do; ` +
|
|
256
256
|
`run it without ${lock}`);
|
|
257
|
+
if (options.agent && options.agent.authority !== true && changesAuthorityNow(action))
|
|
258
|
+
throw new CliError("permission_error", `\`${command} ${path.join(" ")}\` changes what a later run may do, and this profile keeps that from agents ` +
|
|
259
|
+
`(${AUTHORITY_KEY}) — the owner turns it on in a terminal: ` +
|
|
260
|
+
`\`${command} <profile> config set${path[0] === "bot" ? " --bot" : ""} permissions.${AUTHORITY_KEY} allow\``, { permission: AUTHORITY_KEY, sent: false });
|
|
257
261
|
const { lifetime, cooperative: stopsAtItsPace } = metaOf(action);
|
|
258
262
|
const persistent = lifetime === "persistent";
|
|
259
263
|
listens = persistent;
|
package/dist/cli/runs/command.js
CHANGED
|
@@ -1,13 +1,14 @@
|
|
|
1
1
|
import { CliError } from "@wirecat/cli-base";
|
|
2
2
|
import { annotate } from "@wirecat/cli-base/commands";
|
|
3
|
-
import { Command
|
|
3
|
+
import { Command } from "commander";
|
|
4
4
|
import { findRun, listRuns, readEvents, runsDirFor } from "../../runs/run.js";
|
|
5
5
|
import { environmentOf, outputFor } from "../context.js";
|
|
6
6
|
import { LOCAL_READ, NO_EFFECTS } from "../effects.js";
|
|
7
7
|
import { itemOf, listOf, renderAnswer, snakeKeys } from "../envelope.js";
|
|
8
|
+
import { typedQuery, withQuery } from "../list-query.js";
|
|
8
9
|
import { positiveCount } from "../paging.js";
|
|
9
10
|
import { lineOf } from "../steps.js";
|
|
10
|
-
import {
|
|
11
|
+
import { RUNS_QUERY, runListFilter } from "./query.js";
|
|
11
12
|
/** Reading the log is not itself worth recording, so **nothing here starts a run**. */
|
|
12
13
|
export const runsCommand = (app) => {
|
|
13
14
|
const command = new Command("runs").description("recorded runs — what this tool did, and when");
|
|
@@ -18,24 +19,35 @@ export const runsCommand = (app) => {
|
|
|
18
19
|
throw new CliError("not_found", `no recorded run "${id}" — \`${lineOf(from, "runs list")}\` shows them`);
|
|
19
20
|
return found;
|
|
20
21
|
};
|
|
21
|
-
annotate(command.command("list"), {
|
|
22
|
-
effects: LOCAL_READ,
|
|
22
|
+
withQuery(annotate(command.command("list"), {
|
|
23
23
|
examples: [`${app.command} runs list --limit 10`],
|
|
24
|
-
|
|
24
|
+
effects: LOCAL_READ,
|
|
25
|
+
}), RUNS_QUERY)
|
|
25
26
|
.description("recorded runs, newest first")
|
|
26
27
|
.option("--limit <n>", "how many to show", positiveCount("--limit"), 20)
|
|
27
28
|
.option("--page <n>", "which page, starting at 1", positiveCount("--page"), 1)
|
|
28
|
-
.action(function () {
|
|
29
|
+
.action(function (words) {
|
|
30
|
+
const filter = runListFilter(words);
|
|
29
31
|
const { limit, page } = this.opts();
|
|
30
32
|
const output = outputFor(this);
|
|
31
33
|
const { renderer } = output;
|
|
32
|
-
const runs = listRuns(dir(this), { atLeast: page * limit + 1 });
|
|
34
|
+
const runs = listRuns(dir(this), { atLeast: page * limit + 1, filter });
|
|
33
35
|
const shown = runs.slice((page - 1) * limit, page * limit);
|
|
34
|
-
renderAnswer(this, output, listOf("runs list", {
|
|
36
|
+
renderAnswer(this, output, listOf("runs list", {
|
|
37
|
+
items: shown.map(snakeKeys),
|
|
38
|
+
limit,
|
|
39
|
+
page,
|
|
40
|
+
has_more: runs.length > page * limit,
|
|
41
|
+
args: words.length ? { query: typedQuery(words) } : {},
|
|
42
|
+
}));
|
|
35
43
|
if (runs.length === 0)
|
|
36
44
|
renderer.note("nothing recorded — a run is kept with `--record`, or when it fails");
|
|
37
45
|
});
|
|
38
|
-
annotate(command.command("show"), {
|
|
46
|
+
annotate(command.command("show"), {
|
|
47
|
+
examples: [`${app.command} runs show run-101`],
|
|
48
|
+
effects: LOCAL_READ,
|
|
49
|
+
output: { entity: "run", view: "details" },
|
|
50
|
+
})
|
|
39
51
|
.argument("<run-id>", `an id from \`${app.command} runs list\``)
|
|
40
52
|
.description("one run: what it was, how it ended, and every event it logged")
|
|
41
53
|
.option("--problems", "only failed responses, warnings and crashes")
|
|
@@ -56,36 +68,11 @@ export const runsCommand = (app) => {
|
|
|
56
68
|
if (shown.length < events.length)
|
|
57
69
|
renderer.note(`${events.length - shown.length} other events — \`${lineOf(this, `runs show ${id}`)}\` shows them all`);
|
|
58
70
|
});
|
|
59
|
-
annotate(command.command("
|
|
60
|
-
|
|
61
|
-
|
|
71
|
+
annotate(command.command("path"), {
|
|
72
|
+
examples: [`${app.command} runs path run-101`],
|
|
73
|
+
effects: NO_EFFECTS,
|
|
74
|
+
output: { entity: "run_location" },
|
|
62
75
|
})
|
|
63
|
-
.description("search recorded diagnostic metadata and events; no message contents")
|
|
64
|
-
.argument("[query]", "case-insensitive literal diagnostic text")
|
|
65
|
-
.addOption(new Option("--status <status>", "run outcome").choices(["success", "failed", "partial", "running"]))
|
|
66
|
-
.option("--error-code <code>", "one stable error code")
|
|
67
|
-
.option("--operation <name>", "one operation, such as messages.download")
|
|
68
|
-
.option("--profile <name>", "one recorded profile")
|
|
69
|
-
.option("--since-time <time>", "runs starting on or after an ISO time or 2h / 1d ago")
|
|
70
|
-
.option("--limit <n>", "matches per page, at most 100", positiveCount("--limit"), 20)
|
|
71
|
-
.option("--page <n>", "result page", positiveCount("--page"), 1)
|
|
72
|
-
.action(function (query) {
|
|
73
|
-
const options = this.opts();
|
|
74
|
-
const found = searchRuns(dir(this), {
|
|
75
|
-
...options,
|
|
76
|
-
since: options.sinceTime,
|
|
77
|
-
...(query === undefined ? {} : { query }),
|
|
78
|
-
});
|
|
79
|
-
renderAnswer(this, outputFor(this), runsFound(found, {
|
|
80
|
-
query,
|
|
81
|
-
status: options.status,
|
|
82
|
-
error_code: options.errorCode,
|
|
83
|
-
operation: options.operation,
|
|
84
|
-
profile: options.profile,
|
|
85
|
-
since_time: options.sinceTime,
|
|
86
|
-
}));
|
|
87
|
-
});
|
|
88
|
-
annotate(command.command("path"), { effects: NO_EFFECTS, examples: [`${app.command} runs path run-101`] })
|
|
89
76
|
.argument("<run-id>", `an id from \`${app.command} runs list\``)
|
|
90
77
|
.description("the directory holding one run")
|
|
91
78
|
.action(function (id) {
|
|
@@ -0,0 +1,5 @@
|
|
|
1
|
+
import { type QueryRegistry } from "@wirecat/cli-base/query";
|
|
2
|
+
import type { RunListFilter } from "../../runs/run.js";
|
|
3
|
+
import { type QueryWords } from "../list-query.js";
|
|
4
|
+
export declare const RUNS_QUERY: QueryRegistry;
|
|
5
|
+
export declare const runListFilter: (words: QueryWords) => RunListFilter;
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
import { queryFieldsOf } from "@wirecat/cli-base/query";
|
|
2
|
+
import { recordedRun } from "../../entities/index.js";
|
|
3
|
+
import { queryTerms } from "../list-query.js";
|
|
4
|
+
export const RUNS_QUERY = {
|
|
5
|
+
entity: "run",
|
|
6
|
+
backend: "native",
|
|
7
|
+
fields: queryFieldsOf(recordedRun, {
|
|
8
|
+
native: ["run_id", "command", "profile", "status", "error_code"],
|
|
9
|
+
examples: {
|
|
10
|
+
command: 'command:"messages send"',
|
|
11
|
+
profile: "profile:work",
|
|
12
|
+
status: "status:failed",
|
|
13
|
+
error_code: "error_code:timeout",
|
|
14
|
+
},
|
|
15
|
+
}).map((field) => field.native
|
|
16
|
+
? {
|
|
17
|
+
...field,
|
|
18
|
+
operators: field.operators.filter((operator) => operator === "term" || operator === "phrase"),
|
|
19
|
+
}
|
|
20
|
+
: field),
|
|
21
|
+
};
|
|
22
|
+
export const runListFilter = (words) => {
|
|
23
|
+
const terms = queryTerms(words, RUNS_QUERY, "runs list");
|
|
24
|
+
const status = recordedRun.entries.status.options.find((value) => value === terms.get("status"));
|
|
25
|
+
return {
|
|
26
|
+
...(terms.has("run_id") ? { runId: terms.get("run_id") } : {}),
|
|
27
|
+
...(terms.has("command") ? { command: terms.get("command") } : {}),
|
|
28
|
+
...(terms.has("profile") ? { profile: terms.get("profile") } : {}),
|
|
29
|
+
...(status === undefined ? {} : { status }),
|
|
30
|
+
...(terms.has("error_code") ? { errorCode: terms.get("error_code") } : {}),
|
|
31
|
+
};
|
|
32
|
+
};
|
|
@@ -0,0 +1,27 @@
|
|
|
1
|
+
import { annotate } from "@wirecat/cli-base/commands";
|
|
2
|
+
import { Command } from "commander";
|
|
3
|
+
import { runsDirFor } from "../../runs/run.js";
|
|
4
|
+
import { environmentOf, outputFor } from "../context.js";
|
|
5
|
+
import { LOCAL_READ } from "../effects.js";
|
|
6
|
+
import { renderAnswer } from "../envelope.js";
|
|
7
|
+
import { typedQuery, withQuery } from "../list-query.js";
|
|
8
|
+
import { positiveCount } from "../paging.js";
|
|
9
|
+
import { runsFound, searchRuns } from "./search.js";
|
|
10
|
+
import { RUN_SEARCH_QUERY, runSearchFilter } from "./search-query.js";
|
|
11
|
+
/** Diagnostic files are independent of linked accounts and never start a recorded run themselves. */
|
|
12
|
+
export const runsSearchCommand = (app) => annotate(withQuery(new Command("runs")
|
|
13
|
+
.summary("search recorded diagnostic metadata and events")
|
|
14
|
+
.description("search recorded diagnostic metadata and events; literal words and field:value terms joined by AND; no message contents")
|
|
15
|
+
.option("--since-time <time>", "runs starting on or after an ISO time or 2h / 1d ago")
|
|
16
|
+
.option("--limit <n>", "matches per page, at most 100", positiveCount("--limit"), 20)
|
|
17
|
+
.option("--page <n>", "result page", positiveCount("--page"), 1), RUN_SEARCH_QUERY), {
|
|
18
|
+
effects: LOCAL_READ,
|
|
19
|
+
output: { entity: "run", view: "hit" },
|
|
20
|
+
examples: [`${app.command} search runs timeout status:failed --limit 10`],
|
|
21
|
+
}).action(function (words) {
|
|
22
|
+
const filter = runSearchFilter(words);
|
|
23
|
+
const options = this.opts();
|
|
24
|
+
const dir = runsDirFor(app, environmentOf(this).env ?? process.env);
|
|
25
|
+
const found = searchRuns(dir, { ...filter, ...options, since: options.sinceTime });
|
|
26
|
+
renderAnswer(this, outputFor(this), runsFound(found, { query: typedQuery(words), since_time: options.sinceTime }));
|
|
27
|
+
});
|
|
@@ -0,0 +1,4 @@
|
|
|
1
|
+
import { type QueryWords } from "../list-query.js";
|
|
2
|
+
import type { RunSearch } from "./search.js";
|
|
3
|
+
export declare const RUN_SEARCH_QUERY: import("@wirecat/cli-base/query").QueryRegistry;
|
|
4
|
+
export declare const runSearchFilter: (words: QueryWords) => Pick<RunSearch, "terms" | "status" | "errorCode" | "operation" | "profile">;
|