@danypops/tickets 0.5.2 → 0.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/package.json +2 -2
- package/src/application/service.ts +5 -0
- package/src/cli/index.ts +2 -1
- package/src/daemon/ledger.ts +8 -2
- package/src/daemon/ops.ts +2 -2
- package/src/daemon/server.ts +2 -2
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@danypops/tickets",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.6.0",
|
|
4
4
|
"description": "Unified CLI, daemon, and TypeScript library for issue tracking across GitHub, GitLab, and Jira.",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"license": "MIT",
|
|
@@ -25,7 +25,7 @@
|
|
|
25
25
|
},
|
|
26
26
|
"dependencies": {
|
|
27
27
|
"@danypops/vehicle-core": "^0.1.1",
|
|
28
|
-
"@danypops/vehicle-server": "^0.
|
|
28
|
+
"@danypops/vehicle-server": "^0.2.1",
|
|
29
29
|
"@danypops/vehicle-client": "^0.1.1",
|
|
30
30
|
"@danypops/enigma-client": "^0.3.0",
|
|
31
31
|
"@gitbeaker/rest": "^43.8.0",
|
|
@@ -39,6 +39,11 @@ export class TicketService {
|
|
|
39
39
|
return Object.keys(this.repos);
|
|
40
40
|
}
|
|
41
41
|
|
|
42
|
+
/** Every configured backend's name plus which optional capabilities its own repository actually implements -- lets a driving adapter (the CLI, pi-tickets) branch on real capability instead of a hardcoded backend name. */
|
|
43
|
+
backendCapabilities(): { name: string; supportsRawQuery: boolean }[] {
|
|
44
|
+
return Object.values(this.repos).map((repo) => ({ name: repo.name, supportsRawQuery: hasRawQuery(repo) }));
|
|
45
|
+
}
|
|
46
|
+
|
|
42
47
|
/**
|
|
43
48
|
* Swaps the live backend set atomically. A backend newly configured in
|
|
44
49
|
* Enigma (or removed) becomes usable on the next call without
|
package/src/cli/index.ts
CHANGED
|
@@ -144,8 +144,9 @@ ledger
|
|
|
144
144
|
.command("search <query>")
|
|
145
145
|
.description("search the local ledger (works even if the backend is currently unreachable)")
|
|
146
146
|
.option("--limit <n>", "max results", (v) => Number.parseInt(v, 10))
|
|
147
|
+
.option("--backend <name>", "scope the search to one configured backend")
|
|
147
148
|
.action(async (query: string, opts) => {
|
|
148
|
-
await withClient((client) => client.call("ledger.search", { query, limit: opts.limit }));
|
|
149
|
+
await withClient((client) => client.call("ledger.search", { query, limit: opts.limit, backend: opts.backend }));
|
|
149
150
|
});
|
|
150
151
|
|
|
151
152
|
ledger
|
package/src/daemon/ledger.ts
CHANGED
|
@@ -98,9 +98,15 @@ export class Ledger {
|
|
|
98
98
|
return row ? rowToIssue(row) : undefined;
|
|
99
99
|
}
|
|
100
100
|
|
|
101
|
-
/** Bounded LIKE search over title, newest-synced first. Explicit limit, capped hard. */
|
|
102
|
-
search(query: string, limit = DEFAULT_SEARCH_LIMIT): Issue[] {
|
|
101
|
+
/** Bounded LIKE search over title, newest-synced first, optionally scoped to one backend. Explicit limit, capped hard. */
|
|
102
|
+
search(query: string, limit = DEFAULT_SEARCH_LIMIT, backend?: string): Issue[] {
|
|
103
103
|
const bounded = Math.min(Math.max(limit, 1), MAX_SEARCH_LIMIT);
|
|
104
|
+
if (backend) {
|
|
105
|
+
const rows = this.db
|
|
106
|
+
.query("SELECT * FROM issues WHERE title LIKE ? AND backend = ? ORDER BY synced_at DESC LIMIT ?")
|
|
107
|
+
.all(`%${query}%`, backend, bounded) as IssueRow[];
|
|
108
|
+
return rows.map(rowToIssue);
|
|
109
|
+
}
|
|
104
110
|
const rows = this.db
|
|
105
111
|
.query("SELECT * FROM issues WHERE title LIKE ? ORDER BY synced_at DESC LIMIT ?")
|
|
106
112
|
.all(`%${query}%`, bounded) as IssueRow[];
|
package/src/daemon/ops.ts
CHANGED
|
@@ -47,7 +47,7 @@ export interface TicketOpInputs extends Record<TicketOperation, unknown> {
|
|
|
47
47
|
"issue.children": { ref: string };
|
|
48
48
|
"issue.comments": { ref: string };
|
|
49
49
|
"issue.comment_add": { ref: string; body: string };
|
|
50
|
-
"ledger.search": { query: string; limit?: number };
|
|
50
|
+
"ledger.search": { query: string; limit?: number; backend?: string };
|
|
51
51
|
"ledger.stats": Record<string, never>;
|
|
52
52
|
"focus.set": { ref: string };
|
|
53
53
|
"focus.get": Record<string, never>;
|
|
@@ -67,7 +67,7 @@ export interface TicketOpInputs extends Record<TicketOperation, unknown> {
|
|
|
67
67
|
}
|
|
68
68
|
|
|
69
69
|
export interface TicketOpOutputs extends Record<TicketOperation, unknown> {
|
|
70
|
-
"backends.list": { backends: string[] };
|
|
70
|
+
"backends.list": { backends: { name: string; supportsRawQuery: boolean }[] };
|
|
71
71
|
"issue.list": { issues: Issue[] };
|
|
72
72
|
"issue.get": { issue: Issue };
|
|
73
73
|
"issue.create": { issue: Issue };
|
package/src/daemon/server.ts
CHANGED
|
@@ -59,7 +59,7 @@ export type Handler<Op extends TicketOperation> = (
|
|
|
59
59
|
* newer surface.
|
|
60
60
|
*/
|
|
61
61
|
export const TICKET_OP_HANDLERS: { [Op in TicketOperation]: Handler<Op> } = {
|
|
62
|
-
"backends.list": async (deps) => ({ backends: deps.service.
|
|
62
|
+
"backends.list": async (deps) => ({ backends: deps.service.backendCapabilities() }),
|
|
63
63
|
"issue.list": async (deps, input) => ({ issues: await deps.service.list(input.backend, input.filter) }),
|
|
64
64
|
"issue.get": async (deps, input) => ({ issue: await deps.service.get(input.ref) }),
|
|
65
65
|
"issue.create": async (deps, input) => ({ issue: await deps.service.create(input.backend, input.input) }),
|
|
@@ -68,7 +68,7 @@ export const TICKET_OP_HANDLERS: { [Op in TicketOperation]: Handler<Op> } = {
|
|
|
68
68
|
"issue.children": async (deps, input) => ({ issues: await deps.service.children(input.ref) }),
|
|
69
69
|
"issue.comments": async (deps, input) => ({ comments: await deps.service.comments(input.ref) }),
|
|
70
70
|
"issue.comment_add": async (deps, input) => ({ comment: await deps.service.addComment(input.ref, input.body) }),
|
|
71
|
-
"ledger.search": async (deps, input) => ({ issues: deps.ledger.search(input.query, input.limit) }),
|
|
71
|
+
"ledger.search": async (deps, input) => ({ issues: deps.ledger.search(input.query, input.limit, input.backend) }),
|
|
72
72
|
"ledger.stats": async (deps) => ({ backends: deps.ledger.stats() }),
|
|
73
73
|
"focus.set": async (deps, input) => {
|
|
74
74
|
// Ledger-first: focusing a ticket already pooled locally needs no live
|