opctl 0.1.0 → 0.1.2

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
@@ -2,13 +2,29 @@
2
2
 
3
3
  `opctl` is a small local Node.js + TypeScript CLI bridge for OpenProject API v3. It uses the current user's personal API token and is read-only by default.
4
4
 
5
- ## Setup
5
+ ## Install
6
+
7
+ Published package:
8
+
9
+ - npm: <https://www.npmjs.com/package/opctl>
10
+ - current package: `opctl@0.1.2`
11
+ - binary: `opctl`
12
+
13
+ Install globally:
6
14
 
7
15
  ```sh
8
- pnpm install
9
- cp .env.example .env
16
+ npm install -g opctl
17
+ opctl --help
10
18
  ```
11
19
 
20
+ Or run without a global install:
21
+
22
+ ```sh
23
+ npx opctl --help
24
+ ```
25
+
26
+ ## Configuration
27
+
12
28
  Export variables in your shell; `opctl` intentionally does not read `.env` files.
13
29
 
14
30
  Required:
@@ -22,22 +38,65 @@ Optional:
22
38
  - `OPENPROJECT_DEFAULT_PROJECT`: project identifier/id used by `wp search` when `--project` is omitted.
23
39
  - `OPENPROJECT_ALLOW_WRITE`: must be exactly `1` to allow write-capable commands.
24
40
 
25
- ## Commands
41
+ ## Usage
42
+
43
+ Show the authenticated OpenProject user:
44
+
45
+ ```sh
46
+ opctl me
47
+ opctl me --json
48
+ ```
49
+
50
+ Inspect API root links:
51
+
52
+ ```sh
53
+ opctl api-root
54
+ opctl api-root --json
55
+ ```
56
+
57
+ List projects:
58
+
59
+ ```sh
60
+ opctl projects --page-size 20
61
+ opctl projects --json
62
+ ```
63
+
64
+ Read work packages:
65
+
66
+ ```sh
67
+ opctl wp get 123
68
+ opctl wp get 123 --json
69
+ opctl wp get 123 --raw-json
70
+ ```
71
+
72
+ Search work packages:
73
+
74
+ ```sh
75
+ opctl wp search --project my-project --subject "pump"
76
+ opctl wp search --project my-project --assignee-me --status open
77
+ opctl wp search --subject "pump" --json
78
+ ```
79
+
80
+ If `--project` is omitted, `opctl wp search` uses `OPENPROJECT_DEFAULT_PROJECT` when set. Without either, it searches the instance-wide work package endpoint.
81
+
82
+ List work packages assigned to the authenticated user:
83
+
84
+ ```sh
85
+ opctl wp mine
86
+ opctl wp mine --project my-project --page-size 50
87
+ ```
88
+
89
+ Pull the OpenAPI spec from your configured instance:
26
90
 
27
91
  ```sh
28
- npm run dev -- me
29
- npm run dev -- api-root
30
- npm run dev -- projects --page-size 20
31
- npm run dev -- wp get 123 --json
32
- npm run dev -- wp search --project my-project --subject "pump" --assignee-me
33
- npm run dev -- wp mine --project my-project
92
+ opctl spec pull
34
93
  ```
35
94
 
36
95
  Write-capable command:
37
96
 
38
97
  ```sh
39
- OPENPROJECT_ALLOW_WRITE=1 npm run dev -- wp comment 123 "Investigating" --dry-run
40
- OPENPROJECT_ALLOW_WRITE=1 npm run dev -- wp comment 123 "Investigating"
98
+ OPENPROJECT_ALLOW_WRITE=1 opctl wp comment 123 "Investigating" --dry-run
99
+ OPENPROJECT_ALLOW_WRITE=1 opctl wp comment 123 "Investigating"
41
100
  ```
42
101
 
43
102
  `wp comment` fetches the work package first and posts only when a documented HAL comment action link is present. It fails safely instead of guessing a mutation URL.
package/dist/cli.js CHANGED
@@ -1,4 +1,6 @@
1
1
  #!/usr/bin/env node
2
+ import { realpathSync } from "node:fs";
3
+ import { fileURLToPath } from "node:url";
2
4
  import { Command } from "commander";
3
5
  import createClient from "openapi-fetch";
4
6
  import { mkdir, writeFile } from "node:fs/promises";
@@ -597,11 +599,45 @@ function parseId(id) {
597
599
  if (!Number.isInteger(parsed) || parsed < 1) throw new OpctlError("work package id must be a positive integer", EXIT_CODES.validation);
598
600
  return parsed;
599
601
  }
602
+ var package_default = {
603
+ name: "opctl",
604
+ version: "0.1.2",
605
+ description: "Conservative local CLI bridge for OpenProject API v3",
606
+ type: "module",
607
+ bin: { "opctl": "./dist/cli.js" },
608
+ files: ["dist"],
609
+ scripts: {
610
+ "dev": "tsx src/cli.ts",
611
+ "build": "npm run typecheck && vite build",
612
+ "typecheck": "tsc --noEmit",
613
+ "test": "vitest run",
614
+ "openapi:pull": "tsx scripts/pull-openapi-spec.ts",
615
+ "openapi:generate": "tsx scripts/generate-openapi-types.ts",
616
+ "openapi:update": "npm run openapi:pull && npm run openapi:generate"
617
+ },
618
+ keywords: ["openproject", "cli"],
619
+ author: "",
620
+ license: "ISC",
621
+ dependencies: {
622
+ "commander": "latest",
623
+ "openapi-fetch": "latest"
624
+ },
625
+ devDependencies: {
626
+ "@types/node": "latest",
627
+ "openapi-typescript": "latest",
628
+ "tsx": "latest",
629
+ "typescript": "latest",
630
+ "vite": "latest",
631
+ "vitest": "latest",
632
+ "yaml": "^2.9.0"
633
+ },
634
+ packageManager: "pnpm@11.1.3"
635
+ };
600
636
  //#endregion
601
637
  //#region src/cli.ts
602
638
  function buildProgram(context) {
603
639
  const program = new Command();
604
- program.name("opctl").description("Conservative local CLI bridge for OpenProject API v3").version("0.1.0").showHelpAfterError().configureOutput({
640
+ program.name("opctl").description("Conservative local CLI bridge for OpenProject API v3").version(package_default.version).showHelpAfterError().configureOutput({
605
641
  writeOut: (text) => context.stdout.write(text),
606
642
  writeErr: (text) => context.stderr.write(text)
607
643
  });
@@ -626,7 +662,15 @@ async function run(argv, context) {
626
662
  return opctlError.exitCode;
627
663
  }
628
664
  }
629
- if (import.meta.url === `file://${process.argv[1]}`) {
665
+ function isCliEntrypoint(metaUrl, argvPath = process.argv[1]) {
666
+ if (!argvPath) return false;
667
+ try {
668
+ return realpathSync(fileURLToPath(metaUrl)) === realpathSync(argvPath);
669
+ } catch {
670
+ return false;
671
+ }
672
+ }
673
+ if (isCliEntrypoint(import.meta.url)) {
630
674
  const exitCode = await run(process.argv, {
631
675
  stdout: process.stdout,
632
676
  stderr: process.stderr,
@@ -635,6 +679,6 @@ if (import.meta.url === `file://${process.argv[1]}`) {
635
679
  process.exitCode = exitCode;
636
680
  }
637
681
  //#endregion
638
- export { buildProgram, run };
682
+ export { buildProgram, isCliEntrypoint, run };
639
683
 
640
684
  //# sourceMappingURL=cli.js.map
package/dist/cli.js.map CHANGED
@@ -1 +1 @@
1
- {"version":3,"file":"cli.js","names":[],"sources":["../src/client/auth.ts","../src/client/errors.ts","../src/output/json.ts","../src/client/hal.ts","../src/output/text.ts","../src/client/pagination.ts","../src/client/openProjectClient.ts","../src/config.ts","../src/commands/context.ts","../src/commands/apiRoot.ts","../src/commands/me.ts","../src/output/table.ts","../src/commands/projects.ts","../scripts/pull-openapi-spec.ts","../src/commands/spec.ts","../src/commands/workPackages.ts","../src/cli.ts"],"sourcesContent":["import type { AuthMode } from \"../config.js\";\n\nexport function createAuthorizationHeader(mode: AuthMode, token: string): string {\n if (mode === \"basic\") {\n return `Basic ${Buffer.from(`apikey:${token}`, \"utf8\").toString(\"base64\")}`;\n }\n return `Bearer ${token}`;\n}\n\nexport function redactSecrets(value: string, token?: string): string {\n let redacted = value.replace(/Authorization:\\s*(Bearer|Basic)\\s+[^\\s,}]+/gi, \"Authorization: <redacted>\");\n redacted = redacted.replace(/\"Authorization\"\\s*:\\s*\"[^\"]+\"/gi, '\"Authorization\":\"<redacted>\"');\n if (token && token !== \"\") redacted = redacted.split(token).join(\"<redacted>\");\n return redacted;\n}\n","export const EXIT_CODES = {\n success: 0,\n general: 1,\n config: 2,\n auth: 3,\n notFound: 4,\n validation: 5,\n writeBlocked: 6,\n network: 7,\n openapi: 8,\n} as const;\n\nexport type ExitCode = (typeof EXIT_CODES)[keyof typeof EXIT_CODES];\n\nexport class OpctlError extends Error {\n public readonly exitCode: ExitCode;\n public readonly details: unknown;\n\n public constructor(message: string, exitCode: ExitCode = EXIT_CODES.general, details?: unknown) {\n super(message);\n this.name = \"OpctlError\";\n this.exitCode = exitCode;\n this.details = details;\n }\n}\n\nexport class ConfigurationError extends OpctlError {\n public constructor(message: string) {\n super(message, EXIT_CODES.config);\n this.name = \"ConfigurationError\";\n }\n}\n\nexport class WriteBlockedError extends OpctlError {\n public constructor() {\n super(\"OpenProject write blocked: set OPENPROJECT_ALLOW_WRITE=1 to enable write commands\", EXIT_CODES.writeBlocked);\n this.name = \"WriteBlockedError\";\n }\n}\n\nexport class NetworkError extends OpctlError {\n public constructor(message: string) {\n super(message, EXIT_CODES.network);\n this.name = \"NetworkError\";\n }\n}\n\nexport class OpenApiGenerationError extends OpctlError {\n public constructor(message: string) {\n super(message, EXIT_CODES.openapi);\n this.name = \"OpenApiGenerationError\";\n }\n}\n\nexport class OpenProjectHttpError extends OpctlError {\n public readonly status: number;\n public readonly responseBody: unknown;\n\n public constructor(status: number, responseBody: unknown) {\n super(httpStatusMessage(status, responseBody), exitCodeForStatus(status), responseBody);\n this.name = \"OpenProjectHttpError\";\n this.status = status;\n this.responseBody = responseBody;\n }\n}\n\nexport function exitCodeForStatus(status: number): ExitCode {\n if (status === 401 || status === 403) return EXIT_CODES.auth;\n if (status === 404) return EXIT_CODES.notFound;\n if (status === 422) return EXIT_CODES.validation;\n return EXIT_CODES.general;\n}\n\nexport function httpStatusMessage(status: number, body: unknown): string {\n if (status === 401) return \"authentication failed\";\n if (status === 403) return \"authenticated OpenProject user lacks permission\";\n if (status === 404) return \"resource not found or not visible to this user\";\n if (status === 409) return \"possible stale lockVersion or concurrent modification\";\n if (status === 422) return `validation failed${validationDetail(body)}`;\n return `OpenProject request failed with HTTP ${status}`;\n}\n\nfunction validationDetail(body: unknown): string {\n if (!body || typeof body !== \"object\") return \"\";\n const message = \"message\" in body && typeof body.message === \"string\" ? body.message : undefined;\n const errorIdentifier = \"errorIdentifier\" in body && typeof body.errorIdentifier === \"string\" ? body.errorIdentifier : undefined;\n const errors = \"_embedded\" in body ? body._embedded : undefined;\n const parts = [message, errorIdentifier, typeof errors === \"object\" && errors !== null ? JSON.stringify(errors) : undefined].filter(Boolean);\n return parts.length === 0 ? \"\" : `: ${parts.join(\"; \")}`;\n}\n\nexport function toOpctlError(error: unknown): OpctlError {\n if (error instanceof OpctlError) return error;\n if (error instanceof Error) return new OpctlError(error.message);\n return new OpctlError(\"unexpected failure\");\n}\n","import { redactSecrets } from \"../client/auth.js\";\n\nexport function stableJson(value: unknown, token?: string): string {\n return `${redactSecrets(JSON.stringify(sortForJson(value), null, 2), token)}\\n`;\n}\n\nfunction sortForJson(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(sortForJson);\n if (!value || typeof value !== \"object\") return value;\n const sorted: Record<string, unknown> = {};\n for (const key of Object.keys(value).sort()) sorted[key] = sortForJson((value as Record<string, unknown>)[key]);\n return sorted;\n}\n","import type { LinkSummary, ProjectSummary, UserSummary, WorkPackageDetail, WorkPackageSummary } from \"../types/domain.js\";\n\ntype HalObject = Record<string, unknown>;\n\nexport function asObject(value: unknown): HalObject | undefined {\n return value && typeof value === \"object\" ? (value as HalObject) : undefined;\n}\n\nexport function getLink(resource: unknown, name: string): LinkSummary | undefined {\n const object = asObject(resource);\n const links = asObject(object?._links);\n const raw = links?.[name];\n const link = Array.isArray(raw) ? asObject(raw[0]) : asObject(raw);\n if (!link) return undefined;\n const href = typeof link.href === \"string\" ? link.href : undefined;\n const title = typeof link.title === \"string\" ? link.title : undefined;\n const method = typeof link.method === \"string\" ? link.method : undefined;\n if (!href && !title && !method) return undefined;\n return { ...(href ? { href } : {}), ...(title ? { title } : {}), ...(method ? { method } : {}) };\n}\n\nexport function requireLinkHref(resource: unknown, name: string): string | undefined {\n return getLink(resource, name)?.href;\n}\n\nexport function collectionElements(resource: unknown): unknown[] {\n const embedded = asObject(asObject(resource)?._embedded);\n const elements = embedded?.elements;\n return Array.isArray(elements) ? elements : [];\n}\n\nexport function collectionTotal(resource: unknown): number | undefined {\n const total = asObject(resource)?.total;\n return typeof total === \"number\" ? total : undefined;\n}\n\nexport function normalizeUser(resource: unknown): UserSummary {\n const object = asObject(resource) ?? {};\n return {\n id: numberField(object.id),\n name: stringField(object.name),\n login: stringField(object.login),\n email: stringField(object.email),\n href: getLink(object, \"self\")?.href,\n };\n}\n\nexport function normalizeProject(resource: unknown): ProjectSummary {\n const object = asObject(resource) ?? {};\n return {\n id: numberField(object.id),\n identifier: stringField(object.identifier),\n name: stringField(object.name),\n href: getLink(object, \"self\")?.href,\n };\n}\n\nexport function normalizeWorkPackageSummary(resource: unknown): WorkPackageSummary {\n const object = asObject(resource) ?? {};\n return {\n id: numberField(object.id),\n subject: stringField(object.subject),\n status: getLink(object, \"status\")?.title,\n assignee: getLink(object, \"assignee\")?.title,\n project: getLink(object, \"project\")?.title,\n type: getLink(object, \"type\")?.title,\n href: getLink(object, \"self\")?.href,\n };\n}\n\nexport function normalizeWorkPackageDetail(resource: unknown): WorkPackageDetail {\n const object = asObject(resource) ?? {};\n return {\n ...normalizeWorkPackageSummary(object),\n description: extractDescription(object.description),\n lockVersion: numberField(object.lockVersion),\n actions: actionLinks(object),\n };\n}\n\nexport function actionLinks(resource: unknown): Record<string, LinkSummary> {\n const links = asObject(asObject(resource)?._links) ?? {};\n const actions: Record<string, LinkSummary> = {};\n for (const [name, value] of Object.entries(links)) {\n const link = Array.isArray(value) ? asObject(value[0]) : asObject(value);\n if (!link) continue;\n const method = typeof link.method === \"string\" ? link.method : undefined;\n if (!method && !name.startsWith(\"add\") && !name.includes(\"update\") && !name.includes(\"delete\")) continue;\n const summary = getLink(resource, name);\n if (summary) actions[name] = summary;\n }\n return actions;\n}\n\nexport function extractDescription(value: unknown): string | undefined {\n if (typeof value === \"string\") return value;\n const object = asObject(value);\n const raw = typeof object?.raw === \"string\" ? object.raw : undefined;\n const html = typeof object?.html === \"string\" ? object.html : undefined;\n return raw ?? (html ? html.replace(/<[^>]+>/g, \" \").replace(/\\s+/g, \" \").trim() : undefined);\n}\n\nfunction stringField(value: unknown): string | undefined {\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction numberField(value: unknown): number | undefined {\n return typeof value === \"number\" ? value : undefined;\n}\n","export function renderKeyValue(value: Record<string, unknown>): string {\n return `${Object.entries(value)\n .filter(([, item]) => item !== undefined)\n .map(([key, item]) => `${key}: ${String(item)}`)\n .join(\"\\n\")}\\n`;\n}\n","import { collectionElements, collectionTotal } from \"./hal.js\";\n\nexport interface PageOptions {\n readonly pageSize?: number;\n}\n\nexport interface NormalizedCollection<T> {\n readonly elements: readonly T[];\n readonly total?: number;\n readonly count: number;\n}\n\nexport function normalizePageSize(value: unknown, fallback = 25): number {\n if (value === undefined || value === null || value === \"\") return fallback;\n const parsed = typeof value === \"number\" ? value : Number(value);\n if (!Number.isInteger(parsed) || parsed < 1 || parsed > 100) throw new Error(\"page size must be an integer between 1 and 100\");\n return parsed;\n}\n\nexport function normalizeCollection<T>(resource: unknown, mapper: (value: unknown) => T): NormalizedCollection<T> {\n const elements = collectionElements(resource).map(mapper);\n const total = collectionTotal(resource);\n return { elements, ...(total === undefined ? {} : { total }), count: elements.length };\n}\n","import createClient, { type Client } from \"openapi-fetch\";\nimport { createAuthorizationHeader } from \"./auth.js\";\nimport { OpenProjectHttpError, NetworkError, WriteBlockedError, OpctlError, EXIT_CODES } from \"./errors.js\";\nimport { normalizeCollection, normalizePageSize, type NormalizedCollection } from \"./pagination.js\";\nimport { getLink, normalizeProject, normalizeUser, normalizeWorkPackageDetail, normalizeWorkPackageSummary, requireLinkHref } from \"./hal.js\";\nimport type { OpctlConfig } from \"../config.js\";\nimport type { paths } from \"../generated/openproject.js\";\nimport type { CommentResult, ProjectSummary, UserSummary, WorkPackageDetail, WorkPackageSummary } from \"../types/domain.js\";\n\nexport interface SearchWorkPackagesOptions {\n readonly project?: string;\n readonly subject?: string;\n readonly assigneeMe?: boolean;\n readonly status?: string;\n readonly open?: boolean;\n readonly pageSize?: number;\n}\n\nexport interface OpenProjectClientOptions {\n readonly config: OpctlConfig;\n readonly fetchImpl?: typeof fetch;\n readonly timeoutMs?: number;\n}\n\nexport class OpenProjectClient {\n private readonly config: OpctlConfig;\n private readonly fetchImpl: typeof fetch;\n private readonly timeoutMs: number;\n private readonly typedClient: Client<paths>;\n\n public constructor(options: OpenProjectClientOptions) {\n this.config = options.config;\n this.fetchImpl = options.fetchImpl ?? fetch;\n this.timeoutMs = options.timeoutMs ?? 30_000;\n this.typedClient = createClient<paths>({ baseUrl: `${this.config.baseUrl}/api/v3` });\n void this.typedClient;\n }\n\n public async getApiRoot(): Promise<unknown> {\n return this.request(\"GET\", \"/api/v3\");\n }\n\n public async getMe(): Promise<UserSummary> {\n return normalizeUser(await this.request(\"GET\", \"/api/v3/users/me\"));\n }\n\n public async listProjects(options: { readonly pageSize?: number } = {}): Promise<NormalizedCollection<ProjectSummary>> {\n const params = new URLSearchParams({ pageSize: String(normalizePageSize(options.pageSize)) });\n return normalizeCollection(await this.request(\"GET\", `/api/v3/projects?${params}`), normalizeProject);\n }\n\n public async getWorkPackageRaw(id: number): Promise<unknown> {\n return this.request(\"GET\", `/api/v3/work_packages/${encodeURIComponent(String(id))}`);\n }\n\n public async getWorkPackage(id: number): Promise<WorkPackageDetail> {\n return normalizeWorkPackageDetail(await this.getWorkPackageRaw(id));\n }\n\n public async searchWorkPackages(options: SearchWorkPackagesOptions): Promise<NormalizedCollection<WorkPackageSummary>> {\n const effectiveProject = options.project ?? this.config.defaultProject;\n const basePath = effectiveProject\n ? `/api/v3/projects/${encodeURIComponent(effectiveProject)}/work_packages`\n : \"/api/v3/work_packages\";\n const params = new URLSearchParams({ pageSize: String(normalizePageSize(options.pageSize)) });\n const filters = buildWorkPackageFilters(options);\n if (filters.length > 0) params.set(\"filters\", JSON.stringify(filters));\n return normalizeCollection(await this.request(\"GET\", `${basePath}?${params}`), normalizeWorkPackageSummary);\n }\n\n public async mine(options: Omit<SearchWorkPackagesOptions, \"assigneeMe\" | \"open\">): Promise<NormalizedCollection<WorkPackageSummary>> {\n await this.getMe();\n return this.searchWorkPackages({ ...options, assigneeMe: true, open: true });\n }\n\n public async commentWorkPackage(id: number, message: string, dryRun: boolean): Promise<CommentResult> {\n if (!this.config.allowWrite) throw new WriteBlockedError();\n if (message.trim() === \"\") throw new OpctlError(\"comment message must not be empty\", EXIT_CODES.validation);\n const raw = await this.getWorkPackageRaw(id);\n const detail = normalizeWorkPackageDetail(raw);\n const commentHref = findCommentHref(raw);\n if (!commentHref) {\n throw new OpctlError(\"commenting this work package is unsupported by the current OpenProject response/spec; no documented comment action link was found\", EXIT_CODES.validation);\n }\n const payload = { comment: { raw: message } };\n if (dryRun) {\n return { id, subject: detail.subject, status: \"dry-run\", request: { method: \"POST\", path: commentHref, payload } };\n }\n const response = await this.request(\"POST\", commentHref, payload);\n return { id, subject: detail.subject, status: \"comment posted\", link: getLink(response, \"self\")?.href ?? requireLinkHref(raw, \"self\") };\n }\n\n private async request(method: \"GET\" | \"POST\" | \"PATCH\", pathOrHref: string, body?: unknown): Promise<unknown> {\n const url = pathOrHref.startsWith(\"http://\") || pathOrHref.startsWith(\"https://\")\n ? pathOrHref\n : `${this.config.baseUrl}${pathOrHref.startsWith(\"/\") ? \"\" : \"/\"}${pathOrHref}`;\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.timeoutMs);\n try {\n const response = await this.fetchImpl(url, {\n method,\n signal: controller.signal,\n headers: {\n Accept: \"application/hal+json, application/json\",\n ...(body === undefined ? {} : { \"Content-Type\": \"application/json\" }),\n Authorization: createAuthorizationHeader(this.config.authMode, this.config.token),\n },\n ...(body === undefined ? {} : { body: JSON.stringify(body) }),\n });\n const parsed = await parseResponse(response);\n if (!response.ok) throw new OpenProjectHttpError(response.status, parsed);\n return parsed;\n } catch (error) {\n if (error instanceof OpenProjectHttpError || error instanceof OpctlError) throw error;\n if (error instanceof Error && error.name === \"AbortError\") throw new NetworkError(\"OpenProject request timed out\");\n throw new NetworkError(error instanceof Error ? error.message : \"OpenProject network request failed\");\n } finally {\n clearTimeout(timeout);\n }\n }\n}\n\nexport function buildWorkPackageFilters(options: Pick<SearchWorkPackagesOptions, \"subject\" | \"assigneeMe\" | \"status\" | \"open\">): unknown[] {\n const filters: unknown[] = [];\n if (options.subject && options.subject.trim() !== \"\") filters.push({ subject: { operator: \"~\", values: [options.subject] } });\n if (options.assigneeMe) filters.push({ assignee: { operator: \"=\", values: [\"me\"] } });\n if (options.open) filters.push({ status: { operator: \"o\", values: [] } });\n if (options.status && options.status.trim() !== \"\") {\n if (options.status === \"open\") filters.push({ status: { operator: \"o\", values: [] } });\n else filters.push({ status: { operator: \"=\", values: [options.status] } });\n }\n return filters;\n}\n\nfunction findCommentHref(resource: unknown): string | undefined {\n for (const name of [\"addComment\", \"addCommentImmediately\", \"comment\", \"addWorkPackageComment\"]) {\n const link = getLink(resource, name);\n if (link?.href && (!link.method || link.method.toUpperCase() === \"POST\")) return link.href;\n }\n return undefined;\n}\n\nasync function parseResponse(response: Response): Promise<unknown> {\n if (response.status === 204) return undefined;\n const text = await response.text();\n if (text.trim() === \"\") return undefined;\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (contentType.includes(\"json\") || contentType.includes(\"hal\")) {\n try {\n return JSON.parse(text);\n } catch {\n return { message: \"OpenProject returned invalid JSON\" };\n }\n }\n return { message: text };\n}\n","import { ConfigurationError } from \"./client/errors.js\";\n\nexport type AuthMode = \"bearer\" | \"basic\";\n\nexport interface OpctlConfig {\n readonly baseUrl: string;\n readonly token: string;\n readonly authMode: AuthMode;\n readonly allowWrite: boolean;\n readonly defaultProject?: string;\n}\n\nexport interface EnvReader {\n readonly OPENPROJECT_URL?: string;\n readonly OPENPROJECT_TOKEN?: string;\n readonly OPENPROJECT_AUTH_MODE?: string;\n readonly OPENPROJECT_ALLOW_WRITE?: string;\n readonly OPENPROJECT_DEFAULT_PROJECT?: string;\n}\n\nexport function loadConfig(env: EnvReader = process.env): OpctlConfig {\n const rawUrl = env.OPENPROJECT_URL;\n const rawToken = env.OPENPROJECT_TOKEN;\n if (!rawUrl || rawUrl.trim() === \"\") throw new ConfigurationError(\"OPENPROJECT_URL is required\");\n if (!rawToken || rawToken.trim() === \"\") throw new ConfigurationError(\"OPENPROJECT_TOKEN is required\");\n\n const authMode = parseAuthMode(env.OPENPROJECT_AUTH_MODE);\n const defaultProject = cleanOptional(env.OPENPROJECT_DEFAULT_PROJECT);\n return {\n baseUrl: normalizeBaseUrl(rawUrl),\n token: rawToken,\n authMode,\n allowWrite: env.OPENPROJECT_ALLOW_WRITE === \"1\",\n ...(defaultProject ? { defaultProject } : {}),\n };\n}\n\nexport function normalizeBaseUrl(rawUrl: string): string {\n let parsed: URL;\n try {\n parsed = new URL(rawUrl.trim());\n } catch {\n throw new ConfigurationError(\"OPENPROJECT_URL must be an absolute URL\");\n }\n if (parsed.protocol !== \"https:\" && parsed.protocol !== \"http:\") {\n throw new ConfigurationError(\"OPENPROJECT_URL must use http or https\");\n }\n parsed.hash = \"\";\n parsed.search = \"\";\n const withoutTrailing = parsed.toString().replace(/\\/+$/, \"\");\n return withoutTrailing;\n}\n\nfunction parseAuthMode(raw: string | undefined): AuthMode {\n if (!raw || raw.trim() === \"\") return \"bearer\";\n const normalized = raw.trim().toLowerCase();\n if (normalized === \"bearer\" || normalized === \"basic\") return normalized;\n throw new ConfigurationError(\"OPENPROJECT_AUTH_MODE must be bearer or basic\");\n}\n\nfunction cleanOptional(raw: string | undefined): string | undefined {\n if (!raw) return undefined;\n const value = raw.trim();\n return value === \"\" ? undefined : value;\n}\n","import type { Command } from \"commander\";\nimport { OpenProjectClient } from \"../client/openProjectClient.js\";\nimport { loadConfig } from \"../config.js\";\nimport { stableJson } from \"../output/json.js\";\n\nexport interface CommandContext {\n readonly stdout: Pick<NodeJS.WriteStream, \"write\">;\n readonly stderr: Pick<NodeJS.WriteStream, \"write\">;\n readonly env: NodeJS.ProcessEnv;\n readonly fetchImpl?: typeof fetch;\n}\n\nexport function createClient(context: CommandContext): OpenProjectClient {\n return new OpenProjectClient({\n config: loadConfig(context.env),\n ...(context.fetchImpl ? { fetchImpl: context.fetchImpl } : {}),\n });\n}\n\nexport function writeOutput(context: CommandContext, value: unknown, json: boolean, renderText: () => string): void {\n context.stdout.write(json ? stableJson(value, context.env.OPENPROJECT_TOKEN) : renderText());\n}\n\nexport function booleanOption(command: Command, name: string): boolean {\n return Boolean(command.opts<Record<string, unknown>>()[name]);\n}\n","import type { Command } from \"commander\";\nimport { asObject } from \"../client/hal.js\";\nimport { stableJson } from \"../output/json.js\";\nimport { renderKeyValue } from \"../output/text.js\";\nimport { createClient, type CommandContext } from \"./context.js\";\n\nexport function registerApiRoot(program: Command, context: CommandContext): void {\n program\n .command(\"api-root\")\n .description(\"Show compact OpenProject API root links\")\n .option(\"--json\", \"emit JSON\")\n .action(async (options: { json?: boolean }) => {\n const root = await createClient(context).getApiRoot();\n const links = compactLinks(root);\n context.stdout.write(options.json ? stableJson(links, context.env.OPENPROJECT_TOKEN) : renderKeyValue(links));\n });\n}\n\nexport function compactLinks(root: unknown): Record<string, string> {\n const links = asObject(asObject(root)?._links) ?? {};\n const output: Record<string, string> = {};\n for (const [name, raw] of Object.entries(links)) {\n const link = Array.isArray(raw) ? asObject(raw[0]) : asObject(raw);\n if (typeof link?.href === \"string\") output[name] = link.href;\n }\n return output;\n}\n","import type { Command } from \"commander\";\nimport { createClient, type CommandContext, writeOutput } from \"./context.js\";\nimport { renderKeyValue } from \"../output/text.js\";\n\nexport function registerMe(program: Command, context: CommandContext): void {\n program\n .command(\"me\")\n .description(\"Show the authenticated OpenProject user\")\n .option(\"--json\", \"emit JSON\")\n .action(async (options: { json?: boolean }) => {\n const me = await createClient(context).getMe();\n writeOutput(context, me, Boolean(options.json), () => renderKeyValue(me as unknown as Record<string, unknown>));\n });\n}\n","export function renderTable(rows: readonly object[], columns: readonly string[]): string {\n const widths = columns.map((column) => Math.max(column.length, ...rows.map((row) => cell((row as Record<string, unknown>)[column]).length)));\n const header = columns.map((column, index) => column.padEnd(widths[index] ?? column.length)).join(\" \");\n const divider = widths.map((width) => \"-\".repeat(width)).join(\" \");\n const body = rows.map((row) => columns.map((column, index) => cell((row as Record<string, unknown>)[column]).padEnd(widths[index] ?? 0)).join(\" \"));\n return `${[header, divider, ...body].join(\"\\n\")}\\n`;\n}\n\nfunction cell(value: unknown): string {\n if (value === undefined || value === null) return \"\";\n return String(value);\n}\n","import type { Command } from \"commander\";\nimport { renderTable } from \"../output/table.js\";\nimport { createClient, type CommandContext, writeOutput } from \"./context.js\";\n\nexport function registerProjects(program: Command, context: CommandContext): void {\n program\n .command(\"projects\")\n .description(\"List visible OpenProject projects\")\n .option(\"--json\", \"emit JSON\")\n .option(\"--page-size <n>\", \"page size\", Number)\n .action(async (options: { json?: boolean; pageSize?: number }) => {\n const projects = await createClient(context).listProjects(options.pageSize === undefined ? {} : { pageSize: options.pageSize });\n writeOutput(context, projects, Boolean(options.json), () => renderTable(projects.elements, [\"id\", \"identifier\", \"name\", \"href\"]));\n });\n}\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport { createAuthorizationHeader, redactSecrets } from \"../src/client/auth.js\";\nimport { OpenApiGenerationError } from \"../src/client/errors.js\";\nimport { normalizeBaseUrl, type AuthMode } from \"../src/config.js\";\n\nexport interface PullSpecOptions {\n readonly env?: NodeJS.ProcessEnv;\n readonly fetchImpl?: typeof fetch;\n readonly outputPath?: string;\n readonly timeoutMs?: number;\n readonly stdout?: Pick<typeof process.stdout, \"write\">;\n}\n\nexport interface PullSpecResult {\n readonly sourceHost: string;\n readonly outputPath: string;\n readonly title: string;\n readonly version: string;\n}\n\nexport async function pullOpenApiSpec(options: PullSpecOptions = {}): Promise<PullSpecResult> {\n const env = options.env ?? process.env;\n const outputPath = options.outputPath ?? \"openapi/openproject.json\";\n const fetchImpl = options.fetchImpl ?? fetch;\n const rawUrl = env.OPENPROJECT_URL;\n if (!rawUrl || rawUrl.trim() === \"\") throw new OpenApiGenerationError(\"OPENPROJECT_URL is required to pull the OpenProject spec\");\n const baseUrl = normalizeBaseUrl(rawUrl);\n const authMode = parseAuthMode(env.OPENPROJECT_AUTH_MODE);\n const headers: Record<string, string> = { Accept: \"application/json\" };\n if (env.OPENPROJECT_TOKEN && env.OPENPROJECT_TOKEN.trim() !== \"\") {\n headers.Authorization = createAuthorizationHeader(authMode, env.OPENPROJECT_TOKEN);\n }\n\n const specUrl = `${baseUrl}/api/v3/spec.json`;\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), options.timeoutMs ?? 15_000);\n let response: Response;\n try {\n response = await fetchImpl(specUrl, { headers, signal: controller.signal });\n } catch (error) {\n throw new OpenApiGenerationError(`failed to download OpenProject spec from ${new URL(baseUrl).host}: ${error instanceof Error ? redactSecrets(error.message, env.OPENPROJECT_TOKEN) : \"network error\"}`);\n } finally {\n clearTimeout(timeout);\n }\n\n if (!response.ok) {\n throw new OpenApiGenerationError(`failed to download OpenProject spec from ${new URL(baseUrl).host}: HTTP ${response.status}`);\n }\n\n const text = await response.text();\n let spec: unknown;\n try {\n spec = JSON.parse(text);\n } catch {\n throw new OpenApiGenerationError(\"OpenProject spec response was not valid JSON; spec.yml is not supported by this downloader\");\n }\n if (!spec || typeof spec !== \"object\") throw new OpenApiGenerationError(\"OpenProject spec response was not an object\");\n const info = \"info\" in spec && typeof spec.info === \"object\" && spec.info !== null ? spec.info : undefined;\n const title = info && \"title\" in info && typeof info.title === \"string\" ? info.title : \"OpenProject API\";\n const version = info && \"version\" in info && typeof info.version === \"string\" ? info.version : \"unknown\";\n\n await mkdir(dirname(outputPath), { recursive: true });\n await writeFile(outputPath, `${JSON.stringify(spec, null, 2)}\\n`, \"utf8\");\n const result = { sourceHost: new URL(baseUrl).host, outputPath, title, version };\n options.stdout?.write(`Downloaded OpenProject spec from ${result.sourceHost} to ${result.outputPath} (${result.title} ${result.version})\\n`);\n return result;\n}\n\nfunction parseAuthMode(raw: string | undefined): AuthMode {\n const normalized = raw?.trim().toLowerCase() ?? \"\";\n if (normalized === \"\" || normalized === \"bearer\") return \"bearer\";\n if (normalized === \"basic\") return \"basic\";\n throw new OpenApiGenerationError(\"OPENPROJECT_AUTH_MODE must be bearer or basic\");\n}\n\nif (import.meta.url === `file://${process.argv[1]}`) {\n pullOpenApiSpec({ stdout: process.stdout }).catch((error: unknown) => {\n const message = error instanceof Error ? error.message : \"failed to pull OpenProject spec\";\n process.stderr.write(`${redactSecrets(message, process.env.OPENPROJECT_TOKEN)}\\n`);\n process.exitCode = 8;\n });\n}\n","import type { Command } from \"commander\";\nimport { pullOpenApiSpec } from \"../../scripts/pull-openapi-spec.js\";\nimport type { CommandContext } from \"./context.js\";\n\nexport function registerSpec(program: Command, context: CommandContext): void {\n const spec = program.command(\"spec\").description(\"OpenAPI spec utilities\");\n spec.command(\"pull\")\n .description(\"Download OpenProject /api/v3/spec.json safely\")\n .action(async () => {\n await pullOpenApiSpec({ env: context.env, stdout: context.stdout, ...(context.fetchImpl ? { fetchImpl: context.fetchImpl } : {}) });\n });\n}\n","import type { Command } from \"commander\";\nimport { OpctlError, EXIT_CODES } from \"../client/errors.js\";\nimport { stableJson } from \"../output/json.js\";\nimport { renderKeyValue } from \"../output/text.js\";\nimport { renderTable } from \"../output/table.js\";\nimport { createClient, type CommandContext, writeOutput } from \"./context.js\";\n\ninterface SearchOptions {\n readonly json?: boolean;\n readonly project?: string;\n readonly subject?: string;\n readonly assigneeMe?: boolean;\n readonly status?: string;\n readonly pageSize?: number;\n}\n\nexport function registerWorkPackages(program: Command, context: CommandContext): void {\n const wp = program.command(\"wp\").description(\"Work package commands\");\n\n wp.command(\"get\")\n .description(\"Get one work package\")\n .argument(\"<id>\", \"work package id\")\n .option(\"--json\", \"emit normalized JSON\")\n .option(\"--raw-json\", \"emit raw OpenProject JSON\")\n .action(async (id: string, options: { json?: boolean; rawJson?: boolean }) => {\n const numericId = parseId(id);\n const client = createClient(context);\n if (options.rawJson) {\n context.stdout.write(stableJson(await client.getWorkPackageRaw(numericId), context.env.OPENPROJECT_TOKEN));\n return;\n }\n const workPackage = await client.getWorkPackage(numericId);\n writeOutput(context, workPackage, Boolean(options.json), () => renderKeyValue(workPackage as unknown as Record<string, unknown>));\n });\n\n wp.command(\"search\")\n .description(\"Search work packages\")\n .option(\"--json\", \"emit JSON\")\n .option(\"--project <identifier-or-id>\", \"project identifier or id\")\n .option(\"--subject <text>\", \"subject contains text\")\n .option(\"--assignee-me\", \"filter to current user\")\n .option(\"--status <id-or-open>\", \"status id, or open\")\n .option(\"--page-size <n>\", \"page size\", Number)\n .action(async (options: SearchOptions) => {\n const result = await createClient(context).searchWorkPackages(options);\n writeOutput(context, result, Boolean(options.json), () => renderTable(result.elements, [\"id\", \"subject\", \"status\", \"assignee\", \"project\", \"href\"]));\n });\n\n wp.command(\"mine\")\n .description(\"List open work packages assigned to the authenticated user\")\n .option(\"--json\", \"emit JSON\")\n .option(\"--project <identifier-or-id>\", \"project identifier or id\")\n .option(\"--page-size <n>\", \"page size\", Number)\n .action(async (options: Pick<SearchOptions, \"json\" | \"project\" | \"pageSize\">) => {\n const result = await createClient(context).mine(options);\n writeOutput(context, result, Boolean(options.json), () => renderTable(result.elements, [\"id\", \"subject\", \"status\", \"assignee\", \"project\", \"href\"]));\n });\n\n wp.command(\"comment\")\n .description(\"Add a comment to a work package; requires OPENPROJECT_ALLOW_WRITE=1\")\n .argument(\"<id>\", \"work package id\")\n .argument(\"<message>\", \"comment message\")\n .option(\"--dry-run\", \"print intended mutation without posting\")\n .option(\"--json\", \"emit JSON\")\n .action(async (id: string, message: string, options: { dryRun?: boolean; json?: boolean }) => {\n const result = await createClient(context).commentWorkPackage(parseId(id), message, Boolean(options.dryRun));\n writeOutput(context, result, Boolean(options.json), () => renderKeyValue(result as unknown as Record<string, unknown>));\n });\n}\n\nfunction parseId(id: string): number {\n const parsed = Number(id);\n if (!Number.isInteger(parsed) || parsed < 1) throw new OpctlError(\"work package id must be a positive integer\", EXIT_CODES.validation);\n return parsed;\n}\n","#!/usr/bin/env node\nimport { Command } from \"commander\";\nimport { redactSecrets } from \"./client/auth.js\";\nimport { EXIT_CODES, toOpctlError } from \"./client/errors.js\";\nimport { stableJson } from \"./output/json.js\";\nimport { registerApiRoot } from \"./commands/apiRoot.js\";\nimport { registerMe } from \"./commands/me.js\";\nimport { registerProjects } from \"./commands/projects.js\";\nimport { registerSpec } from \"./commands/spec.js\";\nimport { registerWorkPackages } from \"./commands/workPackages.js\";\nimport type { CommandContext } from \"./commands/context.js\";\n\nexport function buildProgram(context: CommandContext): Command {\n const program = new Command();\n program\n .name(\"opctl\")\n .description(\"Conservative local CLI bridge for OpenProject API v3\")\n .version(\"0.1.0\")\n .showHelpAfterError()\n .configureOutput({\n writeOut: (text) => context.stdout.write(text),\n writeErr: (text) => context.stderr.write(text),\n });\n registerMe(program, context);\n registerApiRoot(program, context);\n registerProjects(program, context);\n registerWorkPackages(program, context);\n registerSpec(program, context);\n return program;\n}\n\nexport async function run(argv: readonly string[], context: CommandContext): Promise<number> {\n try {\n await buildProgram(context).parseAsync(argv, { from: \"node\" });\n return EXIT_CODES.success;\n } catch (error) {\n const opctlError = toOpctlError(error);\n const wantsJson = argv.includes(\"--json\");\n if (wantsJson) context.stderr.write(stableJson({ error: opctlError.message, exitCode: opctlError.exitCode }, context.env.OPENPROJECT_TOKEN));\n else context.stderr.write(`${redactSecrets(opctlError.message, context.env.OPENPROJECT_TOKEN)}\\n`);\n return opctlError.exitCode;\n }\n}\n\nif (import.meta.url === `file://${process.argv[1]}`) {\n const exitCode = await run(process.argv, { stdout: process.stdout, stderr: process.stderr, env: process.env });\n process.exitCode = exitCode;\n}\n"],"mappings":"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"}
1
+ {"version":3,"file":"cli.js","names":[],"sources":["../src/client/auth.ts","../src/client/errors.ts","../src/output/json.ts","../src/client/hal.ts","../src/output/text.ts","../src/client/pagination.ts","../src/client/openProjectClient.ts","../src/config.ts","../src/commands/context.ts","../src/commands/apiRoot.ts","../src/commands/me.ts","../src/output/table.ts","../src/commands/projects.ts","../scripts/pull-openapi-spec.ts","../src/commands/spec.ts","../src/commands/workPackages.ts","../package.json","../src/cli.ts"],"sourcesContent":["import type { AuthMode } from \"../config.js\";\n\nexport function createAuthorizationHeader(mode: AuthMode, token: string): string {\n if (mode === \"basic\") {\n return `Basic ${Buffer.from(`apikey:${token}`, \"utf8\").toString(\"base64\")}`;\n }\n return `Bearer ${token}`;\n}\n\nexport function redactSecrets(value: string, token?: string): string {\n let redacted = value.replace(/Authorization:\\s*(Bearer|Basic)\\s+[^\\s,}]+/gi, \"Authorization: <redacted>\");\n redacted = redacted.replace(/\"Authorization\"\\s*:\\s*\"[^\"]+\"/gi, '\"Authorization\":\"<redacted>\"');\n if (token && token !== \"\") redacted = redacted.split(token).join(\"<redacted>\");\n return redacted;\n}\n","export const EXIT_CODES = {\n success: 0,\n general: 1,\n config: 2,\n auth: 3,\n notFound: 4,\n validation: 5,\n writeBlocked: 6,\n network: 7,\n openapi: 8,\n} as const;\n\nexport type ExitCode = (typeof EXIT_CODES)[keyof typeof EXIT_CODES];\n\nexport class OpctlError extends Error {\n public readonly exitCode: ExitCode;\n public readonly details: unknown;\n\n public constructor(message: string, exitCode: ExitCode = EXIT_CODES.general, details?: unknown) {\n super(message);\n this.name = \"OpctlError\";\n this.exitCode = exitCode;\n this.details = details;\n }\n}\n\nexport class ConfigurationError extends OpctlError {\n public constructor(message: string) {\n super(message, EXIT_CODES.config);\n this.name = \"ConfigurationError\";\n }\n}\n\nexport class WriteBlockedError extends OpctlError {\n public constructor() {\n super(\"OpenProject write blocked: set OPENPROJECT_ALLOW_WRITE=1 to enable write commands\", EXIT_CODES.writeBlocked);\n this.name = \"WriteBlockedError\";\n }\n}\n\nexport class NetworkError extends OpctlError {\n public constructor(message: string) {\n super(message, EXIT_CODES.network);\n this.name = \"NetworkError\";\n }\n}\n\nexport class OpenApiGenerationError extends OpctlError {\n public constructor(message: string) {\n super(message, EXIT_CODES.openapi);\n this.name = \"OpenApiGenerationError\";\n }\n}\n\nexport class OpenProjectHttpError extends OpctlError {\n public readonly status: number;\n public readonly responseBody: unknown;\n\n public constructor(status: number, responseBody: unknown) {\n super(httpStatusMessage(status, responseBody), exitCodeForStatus(status), responseBody);\n this.name = \"OpenProjectHttpError\";\n this.status = status;\n this.responseBody = responseBody;\n }\n}\n\nexport function exitCodeForStatus(status: number): ExitCode {\n if (status === 401 || status === 403) return EXIT_CODES.auth;\n if (status === 404) return EXIT_CODES.notFound;\n if (status === 422) return EXIT_CODES.validation;\n return EXIT_CODES.general;\n}\n\nexport function httpStatusMessage(status: number, body: unknown): string {\n if (status === 401) return \"authentication failed\";\n if (status === 403) return \"authenticated OpenProject user lacks permission\";\n if (status === 404) return \"resource not found or not visible to this user\";\n if (status === 409) return \"possible stale lockVersion or concurrent modification\";\n if (status === 422) return `validation failed${validationDetail(body)}`;\n return `OpenProject request failed with HTTP ${status}`;\n}\n\nfunction validationDetail(body: unknown): string {\n if (!body || typeof body !== \"object\") return \"\";\n const message = \"message\" in body && typeof body.message === \"string\" ? body.message : undefined;\n const errorIdentifier = \"errorIdentifier\" in body && typeof body.errorIdentifier === \"string\" ? body.errorIdentifier : undefined;\n const errors = \"_embedded\" in body ? body._embedded : undefined;\n const parts = [message, errorIdentifier, typeof errors === \"object\" && errors !== null ? JSON.stringify(errors) : undefined].filter(Boolean);\n return parts.length === 0 ? \"\" : `: ${parts.join(\"; \")}`;\n}\n\nexport function toOpctlError(error: unknown): OpctlError {\n if (error instanceof OpctlError) return error;\n if (error instanceof Error) return new OpctlError(error.message);\n return new OpctlError(\"unexpected failure\");\n}\n","import { redactSecrets } from \"../client/auth.js\";\n\nexport function stableJson(value: unknown, token?: string): string {\n return `${redactSecrets(JSON.stringify(sortForJson(value), null, 2), token)}\\n`;\n}\n\nfunction sortForJson(value: unknown): unknown {\n if (Array.isArray(value)) return value.map(sortForJson);\n if (!value || typeof value !== \"object\") return value;\n const sorted: Record<string, unknown> = {};\n for (const key of Object.keys(value).sort()) sorted[key] = sortForJson((value as Record<string, unknown>)[key]);\n return sorted;\n}\n","import type { LinkSummary, ProjectSummary, UserSummary, WorkPackageDetail, WorkPackageSummary } from \"../types/domain.js\";\n\ntype HalObject = Record<string, unknown>;\n\nexport function asObject(value: unknown): HalObject | undefined {\n return value && typeof value === \"object\" ? (value as HalObject) : undefined;\n}\n\nexport function getLink(resource: unknown, name: string): LinkSummary | undefined {\n const object = asObject(resource);\n const links = asObject(object?._links);\n const raw = links?.[name];\n const link = Array.isArray(raw) ? asObject(raw[0]) : asObject(raw);\n if (!link) return undefined;\n const href = typeof link.href === \"string\" ? link.href : undefined;\n const title = typeof link.title === \"string\" ? link.title : undefined;\n const method = typeof link.method === \"string\" ? link.method : undefined;\n if (!href && !title && !method) return undefined;\n return { ...(href ? { href } : {}), ...(title ? { title } : {}), ...(method ? { method } : {}) };\n}\n\nexport function requireLinkHref(resource: unknown, name: string): string | undefined {\n return getLink(resource, name)?.href;\n}\n\nexport function collectionElements(resource: unknown): unknown[] {\n const embedded = asObject(asObject(resource)?._embedded);\n const elements = embedded?.elements;\n return Array.isArray(elements) ? elements : [];\n}\n\nexport function collectionTotal(resource: unknown): number | undefined {\n const total = asObject(resource)?.total;\n return typeof total === \"number\" ? total : undefined;\n}\n\nexport function normalizeUser(resource: unknown): UserSummary {\n const object = asObject(resource) ?? {};\n return {\n id: numberField(object.id),\n name: stringField(object.name),\n login: stringField(object.login),\n email: stringField(object.email),\n href: getLink(object, \"self\")?.href,\n };\n}\n\nexport function normalizeProject(resource: unknown): ProjectSummary {\n const object = asObject(resource) ?? {};\n return {\n id: numberField(object.id),\n identifier: stringField(object.identifier),\n name: stringField(object.name),\n href: getLink(object, \"self\")?.href,\n };\n}\n\nexport function normalizeWorkPackageSummary(resource: unknown): WorkPackageSummary {\n const object = asObject(resource) ?? {};\n return {\n id: numberField(object.id),\n subject: stringField(object.subject),\n status: getLink(object, \"status\")?.title,\n assignee: getLink(object, \"assignee\")?.title,\n project: getLink(object, \"project\")?.title,\n type: getLink(object, \"type\")?.title,\n href: getLink(object, \"self\")?.href,\n };\n}\n\nexport function normalizeWorkPackageDetail(resource: unknown): WorkPackageDetail {\n const object = asObject(resource) ?? {};\n return {\n ...normalizeWorkPackageSummary(object),\n description: extractDescription(object.description),\n lockVersion: numberField(object.lockVersion),\n actions: actionLinks(object),\n };\n}\n\nexport function actionLinks(resource: unknown): Record<string, LinkSummary> {\n const links = asObject(asObject(resource)?._links) ?? {};\n const actions: Record<string, LinkSummary> = {};\n for (const [name, value] of Object.entries(links)) {\n const link = Array.isArray(value) ? asObject(value[0]) : asObject(value);\n if (!link) continue;\n const method = typeof link.method === \"string\" ? link.method : undefined;\n if (!method && !name.startsWith(\"add\") && !name.includes(\"update\") && !name.includes(\"delete\")) continue;\n const summary = getLink(resource, name);\n if (summary) actions[name] = summary;\n }\n return actions;\n}\n\nexport function extractDescription(value: unknown): string | undefined {\n if (typeof value === \"string\") return value;\n const object = asObject(value);\n const raw = typeof object?.raw === \"string\" ? object.raw : undefined;\n const html = typeof object?.html === \"string\" ? object.html : undefined;\n return raw ?? (html ? html.replace(/<[^>]+>/g, \" \").replace(/\\s+/g, \" \").trim() : undefined);\n}\n\nfunction stringField(value: unknown): string | undefined {\n return typeof value === \"string\" ? value : undefined;\n}\n\nfunction numberField(value: unknown): number | undefined {\n return typeof value === \"number\" ? value : undefined;\n}\n","export function renderKeyValue(value: Record<string, unknown>): string {\n return `${Object.entries(value)\n .filter(([, item]) => item !== undefined)\n .map(([key, item]) => `${key}: ${String(item)}`)\n .join(\"\\n\")}\\n`;\n}\n","import { collectionElements, collectionTotal } from \"./hal.js\";\n\nexport interface PageOptions {\n readonly pageSize?: number;\n}\n\nexport interface NormalizedCollection<T> {\n readonly elements: readonly T[];\n readonly total?: number;\n readonly count: number;\n}\n\nexport function normalizePageSize(value: unknown, fallback = 25): number {\n if (value === undefined || value === null || value === \"\") return fallback;\n const parsed = typeof value === \"number\" ? value : Number(value);\n if (!Number.isInteger(parsed) || parsed < 1 || parsed > 100) throw new Error(\"page size must be an integer between 1 and 100\");\n return parsed;\n}\n\nexport function normalizeCollection<T>(resource: unknown, mapper: (value: unknown) => T): NormalizedCollection<T> {\n const elements = collectionElements(resource).map(mapper);\n const total = collectionTotal(resource);\n return { elements, ...(total === undefined ? {} : { total }), count: elements.length };\n}\n","import createClient, { type Client } from \"openapi-fetch\";\nimport { createAuthorizationHeader } from \"./auth.js\";\nimport { OpenProjectHttpError, NetworkError, WriteBlockedError, OpctlError, EXIT_CODES } from \"./errors.js\";\nimport { normalizeCollection, normalizePageSize, type NormalizedCollection } from \"./pagination.js\";\nimport { getLink, normalizeProject, normalizeUser, normalizeWorkPackageDetail, normalizeWorkPackageSummary, requireLinkHref } from \"./hal.js\";\nimport type { OpctlConfig } from \"../config.js\";\nimport type { paths } from \"../generated/openproject.js\";\nimport type { CommentResult, ProjectSummary, UserSummary, WorkPackageDetail, WorkPackageSummary } from \"../types/domain.js\";\n\nexport interface SearchWorkPackagesOptions {\n readonly project?: string;\n readonly subject?: string;\n readonly assigneeMe?: boolean;\n readonly status?: string;\n readonly open?: boolean;\n readonly pageSize?: number;\n}\n\nexport interface OpenProjectClientOptions {\n readonly config: OpctlConfig;\n readonly fetchImpl?: typeof fetch;\n readonly timeoutMs?: number;\n}\n\nexport class OpenProjectClient {\n private readonly config: OpctlConfig;\n private readonly fetchImpl: typeof fetch;\n private readonly timeoutMs: number;\n private readonly typedClient: Client<paths>;\n\n public constructor(options: OpenProjectClientOptions) {\n this.config = options.config;\n this.fetchImpl = options.fetchImpl ?? fetch;\n this.timeoutMs = options.timeoutMs ?? 30_000;\n this.typedClient = createClient<paths>({ baseUrl: `${this.config.baseUrl}/api/v3` });\n void this.typedClient;\n }\n\n public async getApiRoot(): Promise<unknown> {\n return this.request(\"GET\", \"/api/v3\");\n }\n\n public async getMe(): Promise<UserSummary> {\n return normalizeUser(await this.request(\"GET\", \"/api/v3/users/me\"));\n }\n\n public async listProjects(options: { readonly pageSize?: number } = {}): Promise<NormalizedCollection<ProjectSummary>> {\n const params = new URLSearchParams({ pageSize: String(normalizePageSize(options.pageSize)) });\n return normalizeCollection(await this.request(\"GET\", `/api/v3/projects?${params}`), normalizeProject);\n }\n\n public async getWorkPackageRaw(id: number): Promise<unknown> {\n return this.request(\"GET\", `/api/v3/work_packages/${encodeURIComponent(String(id))}`);\n }\n\n public async getWorkPackage(id: number): Promise<WorkPackageDetail> {\n return normalizeWorkPackageDetail(await this.getWorkPackageRaw(id));\n }\n\n public async searchWorkPackages(options: SearchWorkPackagesOptions): Promise<NormalizedCollection<WorkPackageSummary>> {\n const effectiveProject = options.project ?? this.config.defaultProject;\n const basePath = effectiveProject\n ? `/api/v3/projects/${encodeURIComponent(effectiveProject)}/work_packages`\n : \"/api/v3/work_packages\";\n const params = new URLSearchParams({ pageSize: String(normalizePageSize(options.pageSize)) });\n const filters = buildWorkPackageFilters(options);\n if (filters.length > 0) params.set(\"filters\", JSON.stringify(filters));\n return normalizeCollection(await this.request(\"GET\", `${basePath}?${params}`), normalizeWorkPackageSummary);\n }\n\n public async mine(options: Omit<SearchWorkPackagesOptions, \"assigneeMe\" | \"open\">): Promise<NormalizedCollection<WorkPackageSummary>> {\n await this.getMe();\n return this.searchWorkPackages({ ...options, assigneeMe: true, open: true });\n }\n\n public async commentWorkPackage(id: number, message: string, dryRun: boolean): Promise<CommentResult> {\n if (!this.config.allowWrite) throw new WriteBlockedError();\n if (message.trim() === \"\") throw new OpctlError(\"comment message must not be empty\", EXIT_CODES.validation);\n const raw = await this.getWorkPackageRaw(id);\n const detail = normalizeWorkPackageDetail(raw);\n const commentHref = findCommentHref(raw);\n if (!commentHref) {\n throw new OpctlError(\"commenting this work package is unsupported by the current OpenProject response/spec; no documented comment action link was found\", EXIT_CODES.validation);\n }\n const payload = { comment: { raw: message } };\n if (dryRun) {\n return { id, subject: detail.subject, status: \"dry-run\", request: { method: \"POST\", path: commentHref, payload } };\n }\n const response = await this.request(\"POST\", commentHref, payload);\n return { id, subject: detail.subject, status: \"comment posted\", link: getLink(response, \"self\")?.href ?? requireLinkHref(raw, \"self\") };\n }\n\n private async request(method: \"GET\" | \"POST\" | \"PATCH\", pathOrHref: string, body?: unknown): Promise<unknown> {\n const url = pathOrHref.startsWith(\"http://\") || pathOrHref.startsWith(\"https://\")\n ? pathOrHref\n : `${this.config.baseUrl}${pathOrHref.startsWith(\"/\") ? \"\" : \"/\"}${pathOrHref}`;\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), this.timeoutMs);\n try {\n const response = await this.fetchImpl(url, {\n method,\n signal: controller.signal,\n headers: {\n Accept: \"application/hal+json, application/json\",\n ...(body === undefined ? {} : { \"Content-Type\": \"application/json\" }),\n Authorization: createAuthorizationHeader(this.config.authMode, this.config.token),\n },\n ...(body === undefined ? {} : { body: JSON.stringify(body) }),\n });\n const parsed = await parseResponse(response);\n if (!response.ok) throw new OpenProjectHttpError(response.status, parsed);\n return parsed;\n } catch (error) {\n if (error instanceof OpenProjectHttpError || error instanceof OpctlError) throw error;\n if (error instanceof Error && error.name === \"AbortError\") throw new NetworkError(\"OpenProject request timed out\");\n throw new NetworkError(error instanceof Error ? error.message : \"OpenProject network request failed\");\n } finally {\n clearTimeout(timeout);\n }\n }\n}\n\nexport function buildWorkPackageFilters(options: Pick<SearchWorkPackagesOptions, \"subject\" | \"assigneeMe\" | \"status\" | \"open\">): unknown[] {\n const filters: unknown[] = [];\n if (options.subject && options.subject.trim() !== \"\") filters.push({ subject: { operator: \"~\", values: [options.subject] } });\n if (options.assigneeMe) filters.push({ assignee: { operator: \"=\", values: [\"me\"] } });\n if (options.open) filters.push({ status: { operator: \"o\", values: [] } });\n if (options.status && options.status.trim() !== \"\") {\n if (options.status === \"open\") filters.push({ status: { operator: \"o\", values: [] } });\n else filters.push({ status: { operator: \"=\", values: [options.status] } });\n }\n return filters;\n}\n\nfunction findCommentHref(resource: unknown): string | undefined {\n for (const name of [\"addComment\", \"addCommentImmediately\", \"comment\", \"addWorkPackageComment\"]) {\n const link = getLink(resource, name);\n if (link?.href && (!link.method || link.method.toUpperCase() === \"POST\")) return link.href;\n }\n return undefined;\n}\n\nasync function parseResponse(response: Response): Promise<unknown> {\n if (response.status === 204) return undefined;\n const text = await response.text();\n if (text.trim() === \"\") return undefined;\n const contentType = response.headers.get(\"content-type\") ?? \"\";\n if (contentType.includes(\"json\") || contentType.includes(\"hal\")) {\n try {\n return JSON.parse(text);\n } catch {\n return { message: \"OpenProject returned invalid JSON\" };\n }\n }\n return { message: text };\n}\n","import { ConfigurationError } from \"./client/errors.js\";\n\nexport type AuthMode = \"bearer\" | \"basic\";\n\nexport interface OpctlConfig {\n readonly baseUrl: string;\n readonly token: string;\n readonly authMode: AuthMode;\n readonly allowWrite: boolean;\n readonly defaultProject?: string;\n}\n\nexport interface EnvReader {\n readonly OPENPROJECT_URL?: string;\n readonly OPENPROJECT_TOKEN?: string;\n readonly OPENPROJECT_AUTH_MODE?: string;\n readonly OPENPROJECT_ALLOW_WRITE?: string;\n readonly OPENPROJECT_DEFAULT_PROJECT?: string;\n}\n\nexport function loadConfig(env: EnvReader = process.env): OpctlConfig {\n const rawUrl = env.OPENPROJECT_URL;\n const rawToken = env.OPENPROJECT_TOKEN;\n if (!rawUrl || rawUrl.trim() === \"\") throw new ConfigurationError(\"OPENPROJECT_URL is required\");\n if (!rawToken || rawToken.trim() === \"\") throw new ConfigurationError(\"OPENPROJECT_TOKEN is required\");\n\n const authMode = parseAuthMode(env.OPENPROJECT_AUTH_MODE);\n const defaultProject = cleanOptional(env.OPENPROJECT_DEFAULT_PROJECT);\n return {\n baseUrl: normalizeBaseUrl(rawUrl),\n token: rawToken,\n authMode,\n allowWrite: env.OPENPROJECT_ALLOW_WRITE === \"1\",\n ...(defaultProject ? { defaultProject } : {}),\n };\n}\n\nexport function normalizeBaseUrl(rawUrl: string): string {\n let parsed: URL;\n try {\n parsed = new URL(rawUrl.trim());\n } catch {\n throw new ConfigurationError(\"OPENPROJECT_URL must be an absolute URL\");\n }\n if (parsed.protocol !== \"https:\" && parsed.protocol !== \"http:\") {\n throw new ConfigurationError(\"OPENPROJECT_URL must use http or https\");\n }\n parsed.hash = \"\";\n parsed.search = \"\";\n const withoutTrailing = parsed.toString().replace(/\\/+$/, \"\");\n return withoutTrailing;\n}\n\nfunction parseAuthMode(raw: string | undefined): AuthMode {\n if (!raw || raw.trim() === \"\") return \"bearer\";\n const normalized = raw.trim().toLowerCase();\n if (normalized === \"bearer\" || normalized === \"basic\") return normalized;\n throw new ConfigurationError(\"OPENPROJECT_AUTH_MODE must be bearer or basic\");\n}\n\nfunction cleanOptional(raw: string | undefined): string | undefined {\n if (!raw) return undefined;\n const value = raw.trim();\n return value === \"\" ? undefined : value;\n}\n","import type { Command } from \"commander\";\nimport { OpenProjectClient } from \"../client/openProjectClient.js\";\nimport { loadConfig } from \"../config.js\";\nimport { stableJson } from \"../output/json.js\";\n\nexport interface CommandContext {\n readonly stdout: Pick<NodeJS.WriteStream, \"write\">;\n readonly stderr: Pick<NodeJS.WriteStream, \"write\">;\n readonly env: NodeJS.ProcessEnv;\n readonly fetchImpl?: typeof fetch;\n}\n\nexport function createClient(context: CommandContext): OpenProjectClient {\n return new OpenProjectClient({\n config: loadConfig(context.env),\n ...(context.fetchImpl ? { fetchImpl: context.fetchImpl } : {}),\n });\n}\n\nexport function writeOutput(context: CommandContext, value: unknown, json: boolean, renderText: () => string): void {\n context.stdout.write(json ? stableJson(value, context.env.OPENPROJECT_TOKEN) : renderText());\n}\n\nexport function booleanOption(command: Command, name: string): boolean {\n return Boolean(command.opts<Record<string, unknown>>()[name]);\n}\n","import type { Command } from \"commander\";\nimport { asObject } from \"../client/hal.js\";\nimport { stableJson } from \"../output/json.js\";\nimport { renderKeyValue } from \"../output/text.js\";\nimport { createClient, type CommandContext } from \"./context.js\";\n\nexport function registerApiRoot(program: Command, context: CommandContext): void {\n program\n .command(\"api-root\")\n .description(\"Show compact OpenProject API root links\")\n .option(\"--json\", \"emit JSON\")\n .action(async (options: { json?: boolean }) => {\n const root = await createClient(context).getApiRoot();\n const links = compactLinks(root);\n context.stdout.write(options.json ? stableJson(links, context.env.OPENPROJECT_TOKEN) : renderKeyValue(links));\n });\n}\n\nexport function compactLinks(root: unknown): Record<string, string> {\n const links = asObject(asObject(root)?._links) ?? {};\n const output: Record<string, string> = {};\n for (const [name, raw] of Object.entries(links)) {\n const link = Array.isArray(raw) ? asObject(raw[0]) : asObject(raw);\n if (typeof link?.href === \"string\") output[name] = link.href;\n }\n return output;\n}\n","import type { Command } from \"commander\";\nimport { createClient, type CommandContext, writeOutput } from \"./context.js\";\nimport { renderKeyValue } from \"../output/text.js\";\n\nexport function registerMe(program: Command, context: CommandContext): void {\n program\n .command(\"me\")\n .description(\"Show the authenticated OpenProject user\")\n .option(\"--json\", \"emit JSON\")\n .action(async (options: { json?: boolean }) => {\n const me = await createClient(context).getMe();\n writeOutput(context, me, Boolean(options.json), () => renderKeyValue(me as unknown as Record<string, unknown>));\n });\n}\n","export function renderTable(rows: readonly object[], columns: readonly string[]): string {\n const widths = columns.map((column) => Math.max(column.length, ...rows.map((row) => cell((row as Record<string, unknown>)[column]).length)));\n const header = columns.map((column, index) => column.padEnd(widths[index] ?? column.length)).join(\" \");\n const divider = widths.map((width) => \"-\".repeat(width)).join(\" \");\n const body = rows.map((row) => columns.map((column, index) => cell((row as Record<string, unknown>)[column]).padEnd(widths[index] ?? 0)).join(\" \"));\n return `${[header, divider, ...body].join(\"\\n\")}\\n`;\n}\n\nfunction cell(value: unknown): string {\n if (value === undefined || value === null) return \"\";\n return String(value);\n}\n","import type { Command } from \"commander\";\nimport { renderTable } from \"../output/table.js\";\nimport { createClient, type CommandContext, writeOutput } from \"./context.js\";\n\nexport function registerProjects(program: Command, context: CommandContext): void {\n program\n .command(\"projects\")\n .description(\"List visible OpenProject projects\")\n .option(\"--json\", \"emit JSON\")\n .option(\"--page-size <n>\", \"page size\", Number)\n .action(async (options: { json?: boolean; pageSize?: number }) => {\n const projects = await createClient(context).listProjects(options.pageSize === undefined ? {} : { pageSize: options.pageSize });\n writeOutput(context, projects, Boolean(options.json), () => renderTable(projects.elements, [\"id\", \"identifier\", \"name\", \"href\"]));\n });\n}\n","import { mkdir, writeFile } from \"node:fs/promises\";\nimport { dirname } from \"node:path\";\nimport { createAuthorizationHeader, redactSecrets } from \"../src/client/auth.js\";\nimport { OpenApiGenerationError } from \"../src/client/errors.js\";\nimport { normalizeBaseUrl, type AuthMode } from \"../src/config.js\";\n\nexport interface PullSpecOptions {\n readonly env?: NodeJS.ProcessEnv;\n readonly fetchImpl?: typeof fetch;\n readonly outputPath?: string;\n readonly timeoutMs?: number;\n readonly stdout?: Pick<typeof process.stdout, \"write\">;\n}\n\nexport interface PullSpecResult {\n readonly sourceHost: string;\n readonly outputPath: string;\n readonly title: string;\n readonly version: string;\n}\n\nexport async function pullOpenApiSpec(options: PullSpecOptions = {}): Promise<PullSpecResult> {\n const env = options.env ?? process.env;\n const outputPath = options.outputPath ?? \"openapi/openproject.json\";\n const fetchImpl = options.fetchImpl ?? fetch;\n const rawUrl = env.OPENPROJECT_URL;\n if (!rawUrl || rawUrl.trim() === \"\") throw new OpenApiGenerationError(\"OPENPROJECT_URL is required to pull the OpenProject spec\");\n const baseUrl = normalizeBaseUrl(rawUrl);\n const authMode = parseAuthMode(env.OPENPROJECT_AUTH_MODE);\n const headers: Record<string, string> = { Accept: \"application/json\" };\n if (env.OPENPROJECT_TOKEN && env.OPENPROJECT_TOKEN.trim() !== \"\") {\n headers.Authorization = createAuthorizationHeader(authMode, env.OPENPROJECT_TOKEN);\n }\n\n const specUrl = `${baseUrl}/api/v3/spec.json`;\n const controller = new AbortController();\n const timeout = setTimeout(() => controller.abort(), options.timeoutMs ?? 15_000);\n let response: Response;\n try {\n response = await fetchImpl(specUrl, { headers, signal: controller.signal });\n } catch (error) {\n throw new OpenApiGenerationError(`failed to download OpenProject spec from ${new URL(baseUrl).host}: ${error instanceof Error ? redactSecrets(error.message, env.OPENPROJECT_TOKEN) : \"network error\"}`);\n } finally {\n clearTimeout(timeout);\n }\n\n if (!response.ok) {\n throw new OpenApiGenerationError(`failed to download OpenProject spec from ${new URL(baseUrl).host}: HTTP ${response.status}`);\n }\n\n const text = await response.text();\n let spec: unknown;\n try {\n spec = JSON.parse(text);\n } catch {\n throw new OpenApiGenerationError(\"OpenProject spec response was not valid JSON; spec.yml is not supported by this downloader\");\n }\n if (!spec || typeof spec !== \"object\") throw new OpenApiGenerationError(\"OpenProject spec response was not an object\");\n const info = \"info\" in spec && typeof spec.info === \"object\" && spec.info !== null ? spec.info : undefined;\n const title = info && \"title\" in info && typeof info.title === \"string\" ? info.title : \"OpenProject API\";\n const version = info && \"version\" in info && typeof info.version === \"string\" ? info.version : \"unknown\";\n\n await mkdir(dirname(outputPath), { recursive: true });\n await writeFile(outputPath, `${JSON.stringify(spec, null, 2)}\\n`, \"utf8\");\n const result = { sourceHost: new URL(baseUrl).host, outputPath, title, version };\n options.stdout?.write(`Downloaded OpenProject spec from ${result.sourceHost} to ${result.outputPath} (${result.title} ${result.version})\\n`);\n return result;\n}\n\nfunction parseAuthMode(raw: string | undefined): AuthMode {\n const normalized = raw?.trim().toLowerCase() ?? \"\";\n if (normalized === \"\" || normalized === \"bearer\") return \"bearer\";\n if (normalized === \"basic\") return \"basic\";\n throw new OpenApiGenerationError(\"OPENPROJECT_AUTH_MODE must be bearer or basic\");\n}\n\nif (import.meta.url === `file://${process.argv[1]}`) {\n pullOpenApiSpec({ stdout: process.stdout }).catch((error: unknown) => {\n const message = error instanceof Error ? error.message : \"failed to pull OpenProject spec\";\n process.stderr.write(`${redactSecrets(message, process.env.OPENPROJECT_TOKEN)}\\n`);\n process.exitCode = 8;\n });\n}\n","import type { Command } from \"commander\";\nimport { pullOpenApiSpec } from \"../../scripts/pull-openapi-spec.js\";\nimport type { CommandContext } from \"./context.js\";\n\nexport function registerSpec(program: Command, context: CommandContext): void {\n const spec = program.command(\"spec\").description(\"OpenAPI spec utilities\");\n spec.command(\"pull\")\n .description(\"Download OpenProject /api/v3/spec.json safely\")\n .action(async () => {\n await pullOpenApiSpec({ env: context.env, stdout: context.stdout, ...(context.fetchImpl ? { fetchImpl: context.fetchImpl } : {}) });\n });\n}\n","import type { Command } from \"commander\";\nimport { OpctlError, EXIT_CODES } from \"../client/errors.js\";\nimport { stableJson } from \"../output/json.js\";\nimport { renderKeyValue } from \"../output/text.js\";\nimport { renderTable } from \"../output/table.js\";\nimport { createClient, type CommandContext, writeOutput } from \"./context.js\";\n\ninterface SearchOptions {\n readonly json?: boolean;\n readonly project?: string;\n readonly subject?: string;\n readonly assigneeMe?: boolean;\n readonly status?: string;\n readonly pageSize?: number;\n}\n\nexport function registerWorkPackages(program: Command, context: CommandContext): void {\n const wp = program.command(\"wp\").description(\"Work package commands\");\n\n wp.command(\"get\")\n .description(\"Get one work package\")\n .argument(\"<id>\", \"work package id\")\n .option(\"--json\", \"emit normalized JSON\")\n .option(\"--raw-json\", \"emit raw OpenProject JSON\")\n .action(async (id: string, options: { json?: boolean; rawJson?: boolean }) => {\n const numericId = parseId(id);\n const client = createClient(context);\n if (options.rawJson) {\n context.stdout.write(stableJson(await client.getWorkPackageRaw(numericId), context.env.OPENPROJECT_TOKEN));\n return;\n }\n const workPackage = await client.getWorkPackage(numericId);\n writeOutput(context, workPackage, Boolean(options.json), () => renderKeyValue(workPackage as unknown as Record<string, unknown>));\n });\n\n wp.command(\"search\")\n .description(\"Search work packages\")\n .option(\"--json\", \"emit JSON\")\n .option(\"--project <identifier-or-id>\", \"project identifier or id\")\n .option(\"--subject <text>\", \"subject contains text\")\n .option(\"--assignee-me\", \"filter to current user\")\n .option(\"--status <id-or-open>\", \"status id, or open\")\n .option(\"--page-size <n>\", \"page size\", Number)\n .action(async (options: SearchOptions) => {\n const result = await createClient(context).searchWorkPackages(options);\n writeOutput(context, result, Boolean(options.json), () => renderTable(result.elements, [\"id\", \"subject\", \"status\", \"assignee\", \"project\", \"href\"]));\n });\n\n wp.command(\"mine\")\n .description(\"List open work packages assigned to the authenticated user\")\n .option(\"--json\", \"emit JSON\")\n .option(\"--project <identifier-or-id>\", \"project identifier or id\")\n .option(\"--page-size <n>\", \"page size\", Number)\n .action(async (options: Pick<SearchOptions, \"json\" | \"project\" | \"pageSize\">) => {\n const result = await createClient(context).mine(options);\n writeOutput(context, result, Boolean(options.json), () => renderTable(result.elements, [\"id\", \"subject\", \"status\", \"assignee\", \"project\", \"href\"]));\n });\n\n wp.command(\"comment\")\n .description(\"Add a comment to a work package; requires OPENPROJECT_ALLOW_WRITE=1\")\n .argument(\"<id>\", \"work package id\")\n .argument(\"<message>\", \"comment message\")\n .option(\"--dry-run\", \"print intended mutation without posting\")\n .option(\"--json\", \"emit JSON\")\n .action(async (id: string, message: string, options: { dryRun?: boolean; json?: boolean }) => {\n const result = await createClient(context).commentWorkPackage(parseId(id), message, Boolean(options.dryRun));\n writeOutput(context, result, Boolean(options.json), () => renderKeyValue(result as unknown as Record<string, unknown>));\n });\n}\n\nfunction parseId(id: string): number {\n const parsed = Number(id);\n if (!Number.isInteger(parsed) || parsed < 1) throw new OpctlError(\"work package id must be a positive integer\", EXIT_CODES.validation);\n return parsed;\n}\n","{\n \"name\": \"opctl\",\n \"version\": \"0.1.2\",\n \"description\": \"Conservative local CLI bridge for OpenProject API v3\",\n \"type\": \"module\",\n \"bin\": {\n \"opctl\": \"./dist/cli.js\"\n },\n \"files\": [\n \"dist\"\n ],\n \"scripts\": {\n \"dev\": \"tsx src/cli.ts\",\n \"build\": \"npm run typecheck && vite build\",\n \"typecheck\": \"tsc --noEmit\",\n \"test\": \"vitest run\",\n \"openapi:pull\": \"tsx scripts/pull-openapi-spec.ts\",\n \"openapi:generate\": \"tsx scripts/generate-openapi-types.ts\",\n \"openapi:update\": \"npm run openapi:pull && npm run openapi:generate\"\n },\n \"keywords\": [\n \"openproject\",\n \"cli\"\n ],\n \"author\": \"\",\n \"license\": \"ISC\",\n \"dependencies\": {\n \"commander\": \"latest\",\n \"openapi-fetch\": \"latest\"\n },\n \"devDependencies\": {\n \"@types/node\": \"latest\",\n \"openapi-typescript\": \"latest\",\n \"tsx\": \"latest\",\n \"typescript\": \"latest\",\n \"vite\": \"latest\",\n \"vitest\": \"latest\",\n \"yaml\": \"^2.9.0\"\n },\n \"packageManager\": \"pnpm@11.1.3\"\n}\n","#!/usr/bin/env node\nimport { realpathSync } from \"node:fs\";\nimport { fileURLToPath } from \"node:url\";\nimport { Command } from \"commander\";\nimport { redactSecrets } from \"./client/auth.js\";\nimport { EXIT_CODES, toOpctlError } from \"./client/errors.js\";\nimport { stableJson } from \"./output/json.js\";\nimport { registerApiRoot } from \"./commands/apiRoot.js\";\nimport { registerMe } from \"./commands/me.js\";\nimport { registerProjects } from \"./commands/projects.js\";\nimport { registerSpec } from \"./commands/spec.js\";\nimport { registerWorkPackages } from \"./commands/workPackages.js\";\nimport type { CommandContext } from \"./commands/context.js\";\nimport pkg from \"../package.json\" with { type: \"json\" };\n\nexport function buildProgram(context: CommandContext): Command {\n const program = new Command();\n program\n .name(\"opctl\")\n .description(\"Conservative local CLI bridge for OpenProject API v3\")\n .version(pkg.version)\n .showHelpAfterError()\n .configureOutput({\n writeOut: (text) => context.stdout.write(text),\n writeErr: (text) => context.stderr.write(text),\n });\n registerMe(program, context);\n registerApiRoot(program, context);\n registerProjects(program, context);\n registerWorkPackages(program, context);\n registerSpec(program, context);\n return program;\n}\n\nexport async function run(argv: readonly string[], context: CommandContext): Promise<number> {\n try {\n await buildProgram(context).parseAsync(argv, { from: \"node\" });\n return EXIT_CODES.success;\n } catch (error) {\n const opctlError = toOpctlError(error);\n const wantsJson = argv.includes(\"--json\");\n if (wantsJson) context.stderr.write(stableJson({ error: opctlError.message, exitCode: opctlError.exitCode }, context.env.OPENPROJECT_TOKEN));\n else context.stderr.write(`${redactSecrets(opctlError.message, context.env.OPENPROJECT_TOKEN)}\\n`);\n return opctlError.exitCode;\n }\n}\n\nexport function isCliEntrypoint(metaUrl: string, argvPath: string | undefined = process.argv[1]): boolean {\n if (!argvPath) return false;\n try {\n return realpathSync(fileURLToPath(metaUrl)) === realpathSync(argvPath);\n } catch {\n return false;\n }\n}\n\nif (isCliEntrypoint(import.meta.url)) {\n const exitCode = await run(process.argv, { stdout: process.stdout, stderr: process.stderr, env: process.env });\n process.exitCode = exitCode;\n}\n"],"mappings":"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"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "opctl",
3
- "version": "0.1.0",
3
+ "version": "0.1.2",
4
4
  "description": "Conservative local CLI bridge for OpenProject API v3",
5
5
  "type": "module",
6
6
  "bin": {