@danypops/tickets 0.8.1 → 0.8.3

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/README.md CHANGED
@@ -277,7 +277,7 @@ bun test # both packages
277
277
  ```
278
278
 
279
279
  Tests never hit real GitHub/GitLab/Jira/Atlassian: adapters take an
280
- injectable `fetchImpl`, and the daemon tests (`test/daemon/`) run the real
280
+ injectable `fetchImpl`, and the daemon tests (`test/rpc/`, `test/sqlite/`, `test/process/`) run the real
281
281
  `@danypops/daemon-kit` `startDaemon()`/SQLite/HTTP stack against a scratch
282
282
  XDG root with a fake `IssueRepository`.
283
283
 
package/package.json CHANGED
@@ -1,12 +1,12 @@
1
1
  {
2
2
  "name": "@danypops/tickets",
3
- "version": "0.8.1",
3
+ "version": "0.8.3",
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",
7
7
  "bin": {
8
8
  "tickets": "./src/cli/index.ts",
9
- "tickets-daemon": "./src/daemon/main.ts"
9
+ "tickets-daemon": "./src/process/main.ts"
10
10
  },
11
11
  "main": "./src/index.ts",
12
12
  "types": "./src/index.ts",
@@ -19,7 +19,7 @@
19
19
  "RESEARCH.md"
20
20
  ],
21
21
  "scripts": {
22
- "daemon": "bun run src/daemon/main.ts",
22
+ "daemon": "bun run src/process/main.ts",
23
23
  "test": "bun test",
24
24
  "typecheck": "tsc --noEmit"
25
25
  },
@@ -2,11 +2,11 @@
2
2
  * Every real ticket operation projected as its own VehicleRegistry entry,
3
3
  * one per TicketOperation, instead of pi-tickets' hand-rolled
4
4
  * `tickets(action=X)` mega-tool. Operation names are already dotted
5
- * (issue.list, focus.set, discover.fields, ...) in daemon/ops.ts -- Vehicle's
5
+ * (issue.list, focus.set, discover.fields, ...) in rpc/ops.ts -- Vehicle's
6
6
  * tool-name projection turns each into its own Pi tool (issue_list,
7
7
  * focus_set, discover_fields, ...) with zero renaming needed.
8
8
  *
9
- * Delegates every operation to daemon/server.ts's TICKET_OP_HANDLERS, the
9
+ * Delegates every operation to rpc/server.ts's TICKET_OP_HANDLERS, the
10
10
  * exact same implementation the existing /api/v1/ops dispatch calls -- this
11
11
  * is a projection/contract layer on top of the existing application logic,
12
12
  * not a second copy of it.
@@ -23,9 +23,9 @@ import {
23
23
  type VehicleEffect,
24
24
  } from "@danypops/vehicle-core";
25
25
  import { VehicleRegistry } from "@danypops/vehicle-server";
26
- import type { BackendCapabilities, TicketService } from "../application/service.js";
27
- import type { TicketOperation } from "../daemon/ops.js";
28
- import { TICKET_OP_HANDLERS, type TicketsAppDeps } from "../daemon/server.js";
26
+ import type { BackendCapabilities, TicketService } from "../issue/service.js";
27
+ import type { TicketOperation } from "../rpc/ops.js";
28
+ import { TICKET_OP_HANDLERS, type TicketsAppDeps } from "../rpc/server.js";
29
29
 
30
30
  const OWNER = "tickets";
31
31
 
@@ -11,7 +11,7 @@
11
11
  * URI/local callback server needed, ideal for a headless daemon. Jira/Atlassian
12
12
  * has no equivalent (see jira-oauth.ts, which uses Authorization Code instead).
13
13
  */
14
- import type { FetchLike } from "../adapters/http.js";
14
+ import type { FetchLike } from "../http-client.js";
15
15
 
16
16
  export const DEVICE_GRANT_TYPE = "urn:ietf:params:oauth:grant-type:device_code";
17
17
 
@@ -4,7 +4,7 @@
4
4
  * Requires a GitHub OAuth App (or GitHub App) with the device flow enabled in
5
5
  * its settings; the client ID is public (no secret needed for this flow).
6
6
  */
7
- import type { FetchLike } from "../adapters/http.js";
7
+ import type { FetchLike } from "../http-client.js";
8
8
  import { type DeviceFlowConfig, type DeviceFlowToken, type PollOptions, pollForToken, requestDeviceAuthorization } from "./device-flow.js";
9
9
 
10
10
  export const GITHUB_DEVICE_AUTHORIZATION_URL = "https://github.com/login/device/code";
@@ -5,7 +5,7 @@
5
5
  * Requires a "non-confidential" GitLab OAuth application (no client secret
6
6
  * for this flow, same shape as GitHub's device flow / RFC 8628).
7
7
  */
8
- import type { FetchLike } from "../adapters/http.js";
8
+ import type { FetchLike } from "../http-client.js";
9
9
  import { type DeviceFlowConfig, type DeviceFlowToken, type PollOptions, pollForToken, requestDeviceAuthorization } from "./device-flow.js";
10
10
  import type { DevicePrompt } from "./github-oauth.js";
11
11
 
@@ -17,7 +17,7 @@
17
17
  import { randomBytes } from "node:crypto";
18
18
  import { createServer, type Server } from "node:http";
19
19
  import type { AddressInfo } from "node:net";
20
- import type { FetchLike } from "../adapters/http.js";
20
+ import type { FetchLike } from "../http-client.js";
21
21
 
22
22
  export const ATLASSIAN_AUTHORIZE_URL = "https://auth.atlassian.com/authorize";
23
23
  export const ATLASSIAN_TOKEN_URL = "https://auth.atlassian.com/oauth/token";
package/src/cli/index.ts CHANGED
@@ -1,7 +1,7 @@
1
1
  #!/usr/bin/env bun
2
2
  /**
3
3
  * The tickets CLI is a thin client of the tickets daemon: every command maps
4
- * 1:1 to a daemon RPC op (see daemon/ops.ts and daemon/server.ts), the same
4
+ * 1:1 to a daemon RPC op (see rpc/ops.ts and rpc/server.ts), the same
5
5
  * ops the pi-tickets extension calls. Nothing here opens the daemon's SQLite
6
6
  * ledger or a backend adapter directly.
7
7
  */
@@ -13,10 +13,10 @@ import { loginWithGitLabDeviceFlow } from "../auth/gitlab-oauth.js";
13
13
  import { loginWithJiraAuthorizationCode } from "../auth/jira-oauth.js";
14
14
  import { promptMaskedSecret } from "../auth/masked-prompt.js";
15
15
  import { deleteToken, isTokenFresh, listStoredBackends, loadToken, saveToken } from "../auth/token-store.js";
16
- import { createTicketsClient, type TicketsRpcClient } from "../client/tickets-client.js";
17
- import type { CreateInput, ListFilter, Priority, Status, UpdateInput } from "../domain/issue.js";
18
- import { parseStatus } from "../domain/issue.js";
16
+ import type { CreateInput, ListFilter, Priority, Status, UpdateInput } from "../issue/issue.js";
17
+ import { parseStatus } from "../issue/issue.js";
19
18
  import { installTicketsService, systemctlTickets, systemdUnitPath } from "./systemd-service.js";
19
+ import { createTicketsClient, type TicketsRpcClient } from "./tickets-client.js";
20
20
 
21
21
  function printJson(value: unknown): void {
22
22
  process.stdout.write(`${JSON.stringify(value, null, 2)}\n`);
@@ -12,8 +12,8 @@
12
12
  import { execFileSync } from "node:child_process";
13
13
  import { mkdirSync, writeFileSync } from "node:fs";
14
14
  import { dirname, join } from "node:path";
15
- import { resolveDaemonEntryPath } from "../client/tickets-client.js";
16
- import { TICKETS_DAEMON_NAMES } from "../daemon/ops.js";
15
+ import { TICKETS_DAEMON_NAMES } from "../rpc/ops.js";
16
+ import { resolveDaemonEntryPath } from "./tickets-client.js";
17
17
 
18
18
  export interface SystemdUnitOptions {
19
19
  bunBin: string;
@@ -10,8 +10,8 @@ import { fileURLToPath } from "node:url";
10
10
  import { AuthenticatedRpcClient } from "@danypops/vehicle-client/rpc-client";
11
11
  import type { DaemonHandle } from "@danypops/vehicle-server/paths";
12
12
  import { ensureAuthToken, readDaemonHandle, resolveDaemonPaths } from "@danypops/vehicle-server/paths";
13
- import { TICKETS_DAEMON_NAMES, type TicketOperation, type TicketOpInputs, type TicketOpOutputs } from "../daemon/ops.js";
14
- import { packageRoot } from "../util/package-root.js";
13
+ import { TICKETS_DAEMON_NAMES, type TicketOperation, type TicketOpInputs, type TicketOpOutputs } from "../rpc/ops.js";
14
+ import { packageRoot } from "./package-root.js";
15
15
 
16
16
  export function ticketsPaths(env?: Record<string, string | undefined>) {
17
17
  return resolveDaemonPaths(TICKETS_DAEMON_NAMES, env ? { env } : {});
@@ -32,7 +32,7 @@ async function isAlive(handle: DaemonHandle, token: string): Promise<boolean> {
32
32
  /** Absolute path to the daemon's real entry point, resolved from this package's own root. Used both to spawn it on demand and to point a systemd unit's ExecStart at it (see cli/systemd-service.ts). */
33
33
  export function resolveDaemonEntryPath(): string {
34
34
  const root = packageRoot(dirname(fileURLToPath(import.meta.url)));
35
- return join(root, "src", "daemon", "main.ts");
35
+ return join(root, "src", "process", "main.ts");
36
36
  }
37
37
 
38
38
  function spawnDaemon(): void {
@@ -68,7 +68,7 @@ export async function ensureDaemonRunning(opts: EnsureDaemonOptions = {}): Promi
68
68
  }
69
69
 
70
70
  if (opts.autoStart === false) {
71
- throw new Error("tickets daemon is not running. Start it with `npm run daemon` (or `bun run src/daemon/main.ts`).");
71
+ throw new Error("tickets daemon is not running. Start it with `npm run daemon` (or `bun run src/process/main.ts`).");
72
72
  }
73
73
 
74
74
  spawnDaemon();
@@ -80,7 +80,7 @@ export async function ensureDaemonRunning(opts: EnsureDaemonOptions = {}): Promi
80
80
  }
81
81
 
82
82
  export interface VehicleClientTarget {
83
- /** Base URL for tickets' VehicleRegistry (see ../vehicle/tickets-vehicle.ts) -- @danypops/vehicle-client's RemoteVehicleClient mounts its own /vehicle/manifest, /vehicle/invoke, /vehicle/cancel routes under this. */
83
+ /** Base URL for tickets' VehicleRegistry (see ../agent-tools/tickets-vehicle.ts) -- @danypops/vehicle-client's RemoteVehicleClient mounts its own /vehicle/manifest, /vehicle/invoke, /vehicle/cancel routes under this. */
84
84
  baseUrl: string;
85
85
  token: string;
86
86
  }
@@ -88,7 +88,7 @@ export interface VehicleClientTarget {
88
88
  /**
89
89
  * Narrow, side-effect-free surface for a Vehicle-projected domain consumer --
90
90
  * same daemon, same handle file, same Bearer token every other tickets RPC
91
- * call already uses (see daemon/server.ts's buildApp, which mounts the
91
+ * call already uses (see rpc/server.ts's buildApp, which mounts the
92
92
  * Vehicle HTTP app at /vehicle/* on this same port). Deliberately does NOT
93
93
  * call ensureDaemonRunning: that spawns the daemon and mints a fresh auth
94
94
  * token file as a side effect, which is wrong to do just from a Pi
@@ -10,12 +10,12 @@ import { type TryEnigmaCredential, tryEnigmaCredential } from "@danypops/enigma-
10
10
  import type { MaintenanceTask } from "@danypops/vehicle-server/daemon";
11
11
  import type { Logger } from "@danypops/vehicle-server/logging";
12
12
  import { parse as parseYaml } from "yaml";
13
- import { GitHubRepository } from "../adapters/github.js";
14
- import { GitLabRepository } from "../adapters/gitlab.js";
15
- import { JiraRepository } from "../adapters/jira.js";
16
- import type { TicketService } from "../application/service.js";
17
13
  import { isTokenFresh, loadToken } from "../auth/token-store.js";
18
- import type { IssueRepository } from "../ports/repository.js";
14
+ import { GitHubRepository } from "../github/github.js";
15
+ import { GitLabRepository } from "../gitlab/gitlab.js";
16
+ import type { IssueRepository } from "../issue/repository.js";
17
+ import type { TicketService } from "../issue/service.js";
18
+ import { JiraRepository } from "../jira/jira.js";
19
19
 
20
20
  export interface BackendConfig {
21
21
  /** Adapter type: "github" | "gitlab" | "jira". Falls back to the config key when omitted. */
@@ -21,8 +21,8 @@
21
21
 
22
22
  import { RequestError } from "@octokit/request-error";
23
23
  import { Octokit } from "octokit";
24
- import type { Comment, CreateInput, Issue, ListFilter, parsePriority, Status, UpdateInput } from "../domain/issue.js";
25
- import { ApiError, AuthRequiredError, IssueNotFoundError } from "./errors.js";
24
+ import { ApiError, AuthRequiredError, IssueNotFoundError } from "../issue/errors.js";
25
+ import type { Comment, CreateInput, Issue, ListFilter, parsePriority, Status, UpdateInput } from "../issue/issue.js";
26
26
 
27
27
  const DEFAULT_TIMEOUT_MS = 30_000;
28
28
 
@@ -14,8 +14,8 @@
14
14
  import { isIP } from "node:net";
15
15
  import { GitbeakerRequestError, type RequesterType, type ResourceOptions } from "@gitbeaker/requester-utils";
16
16
  import { Gitlab } from "@gitbeaker/rest";
17
- import type { Comment, CreateInput, Issue, ListFilter, parsePriority, Status, UpdateInput } from "../domain/issue.js";
18
- import { ApiError, AuthRequiredError, InvalidUrlError, IssueNotFoundError } from "./errors.js";
17
+ import { ApiError, AuthRequiredError, InvalidUrlError, IssueNotFoundError } from "../issue/errors.js";
18
+ import type { Comment, CreateInput, Issue, ListFilter, parsePriority, Status, UpdateInput } from "../issue/issue.js";
19
19
 
20
20
  export interface GitLabOptions {
21
21
  projectId: string;
@@ -1,4 +1,4 @@
1
- import { ApiError, IssueNotFoundError } from "./errors.js";
1
+ import { ApiError, IssueNotFoundError } from "./issue/errors.js";
2
2
 
3
3
  export type FetchLike = typeof fetch;
4
4
 
@@ -14,7 +14,7 @@ export interface HttpClientOptions {
14
14
  * Thin authenticated JSON HTTP client shared by all adapters. Each adapter owns its
15
15
  * own auth header construction (Bearer, Basic, PRIVATE-TOKEN, ...) and passes it in
16
16
  * via `headers`. Accepts an injectable `fetchImpl` so adapters are testable without
17
- * a network — see test/adapters/*.test.ts.
17
+ * a network — see test/github/*.test.ts, test/gitlab/*.test.ts, test/jira/*.test.ts.
18
18
  */
19
19
  export class HttpClient {
20
20
  private readonly baseUrl: string;
package/src/index.ts CHANGED
@@ -1,8 +1,3 @@
1
- export * from "./adapters/errors.js";
2
- export { type GitHubOptions, GitHubRepository } from "./adapters/github.js";
3
- export { type GitLabOptions, GitLabRepository } from "./adapters/gitlab.js";
4
- export { type JiraOptions, JiraRepository } from "./adapters/jira.js";
5
- export { NotSupportedError, TicketService, UnknownBackendError } from "./application/service.js";
6
1
  export { openUrl } from "./auth/browser.js";
7
2
  // Delegated OAuth (device flow for GitHub/GitLab, authorization code for Jira)
8
3
  // — see RESEARCH.md for why each backend gets a different flow.
@@ -19,7 +14,7 @@ export {
19
14
  type TicketsRpcClient,
20
15
  ticketsPaths,
21
16
  type VehicleClientTarget,
22
- } from "./client/tickets-client.js";
17
+ } from "./cli/tickets-client.js";
23
18
  export {
24
19
  type BackendConfig,
25
20
  buildRepositories,
@@ -28,7 +23,12 @@ export {
28
23
  defaultConfigPath,
29
24
  loadConfig,
30
25
  } from "./config/config.js";
31
- export type { FocusStatus, TicketFocusState } from "./daemon/focus.js";
32
- export type { TicketOperation, TicketOpInputs, TicketOpOutputs } from "./daemon/ops.js";
33
- export * from "./domain/issue.js";
34
- export * from "./ports/repository.js";
26
+ export { type GitHubOptions, GitHubRepository } from "./github/github.js";
27
+ export { type GitLabOptions, GitLabRepository } from "./gitlab/gitlab.js";
28
+ export * from "./issue/errors.js";
29
+ export * from "./issue/issue.js";
30
+ export * from "./issue/repository.js";
31
+ export { NotSupportedError, TicketService, UnknownBackendError } from "./issue/service.js";
32
+ export { type JiraOptions, JiraRepository } from "./jira/jira.js";
33
+ export type { TicketOperation, TicketOpInputs, TicketOpOutputs } from "./rpc/ops.js";
34
+ export type { FocusStatus, TicketFocusState } from "./sqlite/focus.js";
@@ -2,8 +2,8 @@
2
2
  * Outbound ports — contracts driven adapters (GitHub, GitLab, Jira, ...) implement.
3
3
  * The application layer depends only on these interfaces, never on a concrete adapter.
4
4
  */
5
- import type { Comment, CreateInput, Issue, ListFilter, UpdateInput } from "../domain/issue.js";
6
- import type { Template } from "../domain/template.js";
5
+ import type { Comment, CreateInput, Issue, ListFilter, UpdateInput } from "./issue.js";
6
+ import type { Template } from "./template.js";
7
7
 
8
8
  export interface IssueRepository {
9
9
  /** Backend identifier used in refs, e.g. "github", "gitlab", "jira". */
@@ -4,9 +4,8 @@
4
4
  * routes every call to the named backend's repository. Depends only on ports,
5
5
  * never on a concrete adapter.
6
6
  */
7
- import type { Comment, CreateInput, Issue, ListFilter, UpdateInput } from "../domain/issue.js";
8
- import { parseRef } from "../domain/issue.js";
9
- import type { Template } from "../domain/template.js";
7
+ import type { Comment, CreateInput, Issue, ListFilter, UpdateInput } from "./issue.js";
8
+ import { parseRef } from "./issue.js";
10
9
  import {
11
10
  hasBoardFilterDiscovery,
12
11
  hasBoardQuickFilterDiscovery,
@@ -17,7 +16,8 @@ import {
17
16
  hasSyncScopeExpansion,
18
17
  hasTemplateDiscovery,
19
18
  type IssueRepository,
20
- } from "../ports/repository.js";
19
+ } from "./repository.js";
20
+ import type { Template } from "./template.js";
21
21
 
22
22
  export interface BackendCapabilities {
23
23
  readonly name: string;
@@ -92,7 +92,7 @@ export class TicketService {
92
92
 
93
93
  /**
94
94
  * Fetches issues for the poller's own background sync pass (see
95
- * daemon/poller.ts). Prefers a backend's own expanded sync scope
95
+ * process/poller.ts). Prefers a backend's own expanded sync scope
96
96
  * (SyncScopeExpandable -- Jira: multiple configured projects plus
97
97
  * everything assigned to the authenticated user, unioned into one query)
98
98
  * over its plain default-project list() when one is configured; falls
@@ -16,11 +16,11 @@
16
16
  import type { AxiosAdapter } from "axios";
17
17
  import type { HttpException, Config as JiraClientConfig } from "jira.js";
18
18
  import { AgileClient, Version2Client } from "jira.js";
19
- import type { Comment, CreateInput, Issue, IssueLink, ListFilter, parsePriority, Status, UpdateInput } from "../domain/issue.js";
20
- import type { Template } from "../domain/template.js";
21
- import { buildTemplateBody, extractTemplateSections } from "../domain/template.js";
22
- import * as manifest from "../manifest/manifest.js";
23
- import { ApiError, IssueNotFoundError } from "./errors.js";
19
+ import { ApiError, IssueNotFoundError } from "../issue/errors.js";
20
+ import type { Comment, CreateInput, Issue, IssueLink, ListFilter, parsePriority, Status, UpdateInput } from "../issue/issue.js";
21
+ import type { Template } from "../issue/template.js";
22
+ import { buildTemplateBody, extractTemplateSections } from "../issue/template.js";
23
+ import * as manifest from "./manifest.js";
24
24
 
25
25
  /**
26
26
  * Basic-auth mode (email + API token) hits the tenant's own *.atlassian.net
@@ -48,7 +48,7 @@ export interface JiraBasicAuthOptions {
48
48
  axiosAdapter?: AxiosAdapter;
49
49
  /**
50
50
  * Directory holding this daemon's persisted field/status discovery manifests
51
- * (see ../manifest/manifest.ts), typically configDir() from config.ts. When
51
+ * (see ./manifest.ts), typically configDir() from config.ts. When
52
52
  * omitted, discovery still works but nothing is persisted across restarts —
53
53
  * every test and any caller that doesn't care about persistence can leave it out.
54
54
  */
@@ -404,7 +404,7 @@ export class JiraRepository {
404
404
  * Discovers every custom field's display name -> customfield_XXXXX ID via
405
405
  * client.issueFields.getFields() (GET /rest/api/2/field), same live call
406
406
  * resolveCustomField already made lazily -- this just also persists the
407
- * result to a manifest (see ../manifest/manifest.ts) so a later inbound
407
+ * result to a manifest (see ./manifest.ts) so a later inbound
408
408
  * lookup (fieldDisplayName) doesn't need a network round trip at all, and
409
409
  * survives a daemon restart. Ported from emcee's FieldService.DiscoverFields
410
410
  * (~/Workspace/emcee), same manifest file shape.
@@ -444,7 +444,7 @@ export class JiraRepository {
444
444
  /**
445
445
  * Samples the most recently created issues for a project/issue-type pair
446
446
  * and extracts the description section headers common to all of them --
447
- * see ../domain/template.ts. Ported from emcee's TemplateService.DiscoverTemplate.
447
+ * see ../issue/template.ts. Ported from emcee's TemplateService.DiscoverTemplate.
448
448
  */
449
449
  async discoverTemplate(project: string, issueType: string, sampleSize = 5): Promise<Template | undefined> {
450
450
  const jql = `project = ${jqlQuote(project)} AND issuetype = ${jqlQuote(issueType)} ORDER BY created DESC`;
@@ -10,16 +10,16 @@ import type { StartDaemonOptions } from "@danypops/vehicle-server/daemon";
10
10
  import { createLogger, type Logger } from "@danypops/vehicle-server/logging";
11
11
  import { ensureAuthToken, type PathEnvironment, resolveDaemonPaths } from "@danypops/vehicle-server/paths";
12
12
  import { checkpoint, openSqliteWithPragmas } from "@danypops/vehicle-server/storage";
13
- import { TicketService } from "../application/service.js";
13
+ import { createTicketsVehicleRegistry, syncDiscoverAvailability } from "../agent-tools/tickets-vehicle.js";
14
14
  import { type BuildRepositories, buildRepositories, type Config, createBackendRefreshTask, loadConfig } from "../config/config.js";
15
- import type { IssueRepository } from "../ports/repository.js";
16
- import { createTicketsVehicleRegistry, syncDiscoverAvailability } from "../vehicle/tickets-vehicle.js";
17
- import { FOCUS_MIGRATIONS, FocusStore } from "./focus.js";
18
- import { LEDGER_MIGRATIONS, Ledger } from "./ledger.js";
19
- import { TICKETS_DAEMON_NAMES } from "./ops.js";
15
+ import type { IssueRepository } from "../issue/repository.js";
16
+ import { TicketService } from "../issue/service.js";
17
+ import { TICKETS_DAEMON_NAMES } from "../rpc/ops.js";
18
+ import { buildApp, type TicketsAppDeps } from "../rpc/server.js";
19
+ import { FOCUS_MIGRATIONS, FocusStore } from "../sqlite/focus.js";
20
+ import { LEDGER_MIGRATIONS, Ledger } from "../sqlite/ledger.js";
21
+ import { SAVED_QUERY_MIGRATIONS, SavedQueryStore } from "../sqlite/saved-queries.js";
20
22
  import { createSyncTask } from "./poller.js";
21
- import { SAVED_QUERY_MIGRATIONS, SavedQueryStore } from "./saved-queries.js";
22
- import { buildApp, type TicketsAppDeps } from "./server.js";
23
23
 
24
24
  export interface BootstrapOptions {
25
25
  pathEnv?: PathEnvironment;
@@ -8,8 +8,8 @@
8
8
 
9
9
  import type { MaintenanceTask } from "@danypops/vehicle-server/daemon";
10
10
  import type { Logger } from "@danypops/vehicle-server/logging";
11
- import type { TicketService } from "../application/service.js";
12
- import type { Ledger } from "./ledger.js";
11
+ import type { TicketService } from "../issue/service.js";
12
+ import type { Ledger } from "../sqlite/ledger.js";
13
13
 
14
14
  const DEFAULT_SYNC_LIMIT = 50;
15
15
 
@@ -4,10 +4,10 @@
4
4
  * whatever consumes this package). Pure types, zero runtime imports, safe to
5
5
  * import from either side without pulling in bun:sqlite or Bun.serve.
6
6
  */
7
- import type { Comment, CreateInput, Issue, ListFilter, UpdateInput } from "../domain/issue.js";
8
- import type { Template } from "../domain/template.js";
9
- import type { TicketFocusState } from "./focus.js";
10
- import type { SavedQuery } from "./saved-queries.js";
7
+ import type { Comment, CreateInput, Issue, ListFilter, UpdateInput } from "../issue/issue.js";
8
+ import type { Template } from "../issue/template.js";
9
+ import type { TicketFocusState } from "../sqlite/focus.js";
10
+ import type { SavedQuery } from "../sqlite/saved-queries.js";
11
11
 
12
12
  export type TicketOperation =
13
13
  | "backends.list"
@@ -1,7 +1,7 @@
1
1
  /**
2
2
  * Daemon HTTP surface: Bearer-token auth, /health, /ready, a single
3
3
  * dispatch endpoint (/api/v1/ops) per vehicle-server's http.ts convention,
4
- * and a VehicleRegistry (see ../vehicle/tickets-vehicle.ts) mounted at
4
+ * and a VehicleRegistry (see ../agent-tools/tickets-vehicle.ts) mounted at
5
5
  * /vehicle/* -- same daemon, same auth, same port, not a second service to
6
6
  * stand up. Every operation here has a CLI command (cli/index.ts) and a
7
7
  * pi-tickets tool action — no operation exists only for one caller.
@@ -11,13 +11,13 @@ import type { VehicleRegistry } from "@danypops/vehicle-server";
11
11
  import { createVehicleHttpApp } from "@danypops/vehicle-server/http";
12
12
  import type { Logger } from "@danypops/vehicle-server/logging";
13
13
  import { errorResponse, healthResponse, jsonResponse, readyResponse, requireBearerToken } from "@danypops/vehicle-server/rpc-http";
14
- import { AuthRequiredError, IssueNotFoundError } from "../adapters/errors.js";
15
- import { NotSupportedError, type TicketService, UnknownBackendError } from "../application/service.js";
16
- import { parseRef } from "../domain/issue.js";
17
- import { FocusError, type FocusStore } from "./focus.js";
18
- import type { Ledger } from "./ledger.js";
14
+ import { AuthRequiredError, IssueNotFoundError } from "../issue/errors.js";
15
+ import { parseRef } from "../issue/issue.js";
16
+ import { NotSupportedError, type TicketService, UnknownBackendError } from "../issue/service.js";
17
+ import { FocusError, type FocusStore } from "../sqlite/focus.js";
18
+ import type { Ledger } from "../sqlite/ledger.js";
19
+ import { SavedQueryNotFoundError, type SavedQueryStore } from "../sqlite/saved-queries.js";
19
20
  import { TICKET_OPERATIONS, type TicketOperation, type TicketOpInputs, type TicketOpOutputs } from "./ops.js";
20
- import { SavedQueryNotFoundError, type SavedQueryStore } from "./saved-queries.js";
21
21
 
22
22
  export interface TicketsAppDeps {
23
23
  service: TicketService;
@@ -36,7 +36,7 @@ export interface TicketsAppDeps {
36
36
  */
37
37
  onShutdownRequested?: () => void;
38
38
  /**
39
- * Built by ../vehicle/tickets-vehicle.ts's createTicketsVehicleRegistry,
39
+ * Built by ../agent-tools/tickets-vehicle.ts's createTicketsVehicleRegistry,
40
40
  * from the same base deps this interface describes -- passed in rather
41
41
  * than built here to avoid a server.ts <-> tickets-vehicle.ts import cycle
42
42
  * (tickets-vehicle.ts already imports TICKET_OP_HANDLERS and this type
@@ -46,7 +46,7 @@ export interface TicketsAppDeps {
46
46
  }
47
47
 
48
48
  // Narrower than TicketsAppDeps on purpose: no real handler reads
49
- // deps.vehicleRegistry, and vehicle/tickets-vehicle.ts's own registry
49
+ // deps.vehicleRegistry, and agent-tools/tickets-vehicle.ts's own registry
50
50
  // builder needs to call these before a registry exists to put there.
51
51
  export type Handler<Op extends TicketOperation> = (
52
52
  deps: Omit<TicketsAppDeps, "vehicleRegistry">,
@@ -55,7 +55,7 @@ export type Handler<Op extends TicketOperation> = (
55
55
 
56
56
  /**
57
57
  * The one real implementation of every ticket operation, shared verbatim by
58
- * the hand-rolled /api/v1/ops dispatch below and vehicle/tickets-vehicle.ts's
58
+ * the hand-rolled /api/v1/ops dispatch below and agent-tools/tickets-vehicle.ts's
59
59
  * VehicleRegistry projection -- never reimplemented a second time for the
60
60
  * newer surface.
61
61
  */
@@ -125,7 +125,7 @@ function statusFor(error: unknown): number {
125
125
 
126
126
  export function buildApp(deps: TicketsAppDeps): { fetch(request: Request): Promise<Response> } {
127
127
  // Same Bearer token as the rest of this API -- the Vehicle-projected
128
- // domain (see ../vehicle/tickets-vehicle.ts) rides the same daemon, same
128
+ // domain (see ../agent-tools/tickets-vehicle.ts) rides the same daemon, same
129
129
  // auth, same port; it is not a second service to stand up or
130
130
  // authenticate against separately.
131
131
  const vehicleApp = createVehicleHttpApp({ registry: deps.vehicleRegistry, token: deps.token });
@@ -8,7 +8,7 @@
8
8
  */
9
9
  import type { Database } from "bun:sqlite";
10
10
  import type { Migration } from "@danypops/vehicle-server/storage";
11
- import type { Issue } from "../domain/issue.js";
11
+ import type { Issue } from "../issue/issue.js";
12
12
 
13
13
  export const LEDGER_MIGRATIONS: Migration[] = [
14
14
  {
@@ -1,6 +1,6 @@
1
1
  /**
2
2
  * Saved queries — a name plus a raw query string (Jira JQL today; the backend
3
- * decides what "raw query" means via ports/repository.ts's RawQueryable) that
3
+ * decides what "raw query" means via issue/repository.ts's RawQueryable) that
4
4
  * can be run again by name instead of re-typing the query every time. This is
5
5
  * how a board/backlog view (e.g. a Jira board's quickFilter, or its backlog's
6
6
  * customFilter) becomes something the CLI/TUI/tool surface can browse
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes
File without changes