harvask-cli 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (106) hide show
  1. package/LICENSE +21 -0
  2. package/README.md +147 -0
  3. package/dist/api-base.js +8 -0
  4. package/dist/api-base.js.map +1 -0
  5. package/dist/api-client.js +221 -0
  6. package/dist/api-client.js.map +1 -0
  7. package/dist/cli.js +154 -0
  8. package/dist/cli.js.map +1 -0
  9. package/dist/commands/_exec.js +63 -0
  10. package/dist/commands/_exec.js.map +1 -0
  11. package/dist/commands/api/index.js +88 -0
  12. package/dist/commands/api/index.js.map +1 -0
  13. package/dist/commands/attachment/index.js +54 -0
  14. package/dist/commands/attachment/index.js.map +1 -0
  15. package/dist/commands/auth/index.js +238 -0
  16. package/dist/commands/auth/index.js.map +1 -0
  17. package/dist/commands/calendar/index.js +167 -0
  18. package/dist/commands/calendar/index.js.map +1 -0
  19. package/dist/commands/chat/index.js +97 -0
  20. package/dist/commands/chat/index.js.map +1 -0
  21. package/dist/commands/file/index.js +42 -0
  22. package/dist/commands/file/index.js.map +1 -0
  23. package/dist/commands/global-wiki/index.js +196 -0
  24. package/dist/commands/global-wiki/index.js.map +1 -0
  25. package/dist/commands/issue/builds.js +160 -0
  26. package/dist/commands/issue/builds.js.map +1 -0
  27. package/dist/commands/issue/index.js +169 -0
  28. package/dist/commands/issue/index.js.map +1 -0
  29. package/dist/commands/issue/sub.js +149 -0
  30. package/dist/commands/issue/sub.js.map +1 -0
  31. package/dist/commands/issue/subbuilds.js +174 -0
  32. package/dist/commands/issue/subbuilds.js.map +1 -0
  33. package/dist/commands/milestone/index.js +104 -0
  34. package/dist/commands/milestone/index.js.map +1 -0
  35. package/dist/commands/note/builds.js +68 -0
  36. package/dist/commands/note/builds.js.map +1 -0
  37. package/dist/commands/note/index.js +122 -0
  38. package/dist/commands/note/index.js.map +1 -0
  39. package/dist/commands/preview-config/index.js +87 -0
  40. package/dist/commands/preview-config/index.js.map +1 -0
  41. package/dist/commands/project/builds.js +78 -0
  42. package/dist/commands/project/builds.js.map +1 -0
  43. package/dist/commands/project/index.js +103 -0
  44. package/dist/commands/project/index.js.map +1 -0
  45. package/dist/commands/scheduled-task/index.js +196 -0
  46. package/dist/commands/scheduled-task/index.js.map +1 -0
  47. package/dist/commands/site-credential/index.js +23 -0
  48. package/dist/commands/site-credential/index.js.map +1 -0
  49. package/dist/commands/skill/index.js +121 -0
  50. package/dist/commands/skill/index.js.map +1 -0
  51. package/dist/commands/storage/index.js +103 -0
  52. package/dist/commands/storage/index.js.map +1 -0
  53. package/dist/commands/user/index.js +55 -0
  54. package/dist/commands/user/index.js.map +1 -0
  55. package/dist/commands/wiki/builds.js +135 -0
  56. package/dist/commands/wiki/builds.js.map +1 -0
  57. package/dist/commands/wiki/index.js +177 -0
  58. package/dist/commands/wiki/index.js.map +1 -0
  59. package/dist/commands/workflow/index.js +111 -0
  60. package/dist/commands/workflow/index.js.map +1 -0
  61. package/dist/config.js +123 -0
  62. package/dist/config.js.map +1 -0
  63. package/dist/context.js +61 -0
  64. package/dist/context.js.map +1 -0
  65. package/dist/errors/hint-map.js +81 -0
  66. package/dist/errors/hint-map.js.map +1 -0
  67. package/dist/errors/index.js +132 -0
  68. package/dist/errors/index.js.map +1 -0
  69. package/dist/index.js +17 -0
  70. package/dist/index.js.map +1 -0
  71. package/dist/output/format.js +108 -0
  72. package/dist/output/format.js.map +1 -0
  73. package/dist/output/index.js +3 -0
  74. package/dist/output/index.js.map +1 -0
  75. package/dist/output/tty.js +22 -0
  76. package/dist/output/tty.js.map +1 -0
  77. package/dist/registry.js +47 -0
  78. package/dist/registry.js.map +1 -0
  79. package/dist/token-store.js +92 -0
  80. package/dist/token-store.js.map +1 -0
  81. package/dist/types/api.js +8 -0
  82. package/dist/types/api.js.map +1 -0
  83. package/dist/utils/bulk.js +29 -0
  84. package/dist/utils/bulk.js.map +1 -0
  85. package/dist/utils/download.js +36 -0
  86. package/dist/utils/download.js.map +1 -0
  87. package/dist/utils/file-utils.js +58 -0
  88. package/dist/utils/file-utils.js.map +1 -0
  89. package/dist/utils/input.js +66 -0
  90. package/dist/utils/input.js.map +1 -0
  91. package/dist/utils/issue-resolver.js +20 -0
  92. package/dist/utils/issue-resolver.js.map +1 -0
  93. package/dist/utils/loopback.js +86 -0
  94. package/dist/utils/loopback.js.map +1 -0
  95. package/dist/utils/pkce.js +20 -0
  96. package/dist/utils/pkce.js.map +1 -0
  97. package/dist/utils/project-resolver.js +63 -0
  98. package/dist/utils/project-resolver.js.map +1 -0
  99. package/dist/utils/prompt.js +17 -0
  100. package/dist/utils/prompt.js.map +1 -0
  101. package/dist/utils/upload.js +32 -0
  102. package/dist/utils/upload.js.map +1 -0
  103. package/package.json +44 -0
  104. package/skills/harvask/AGENTS.md +131 -0
  105. package/skills/harvask/GEMINI.md +131 -0
  106. package/skills/harvask/SKILL.md +134 -0
package/LICENSE ADDED
@@ -0,0 +1,21 @@
1
+ MIT License
2
+
3
+ Copyright (c) 2026 wown
4
+
5
+ Permission is hereby granted, free of charge, to any person obtaining a copy
6
+ of this software and associated documentation files (the "Software"), to deal
7
+ in the Software without restriction, including without limitation the rights
8
+ to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
9
+ copies of the Software, and to permit persons to whom the Software is
10
+ furnished to do so, subject to the following conditions:
11
+
12
+ The above copyright notice and this permission notice shall be included in all
13
+ copies or substantial portions of the Software.
14
+
15
+ THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
16
+ IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
17
+ FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
18
+ AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
19
+ LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
20
+ OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
21
+ SOFTWARE.
package/README.md ADDED
@@ -0,0 +1,147 @@
1
+ # harvask CLI
2
+
3
+ A command-line client for a **harvask tenant**, built for coding agents.
4
+ It covers issues, wiki, projects, notes, milestones, calendar, files, storage,
5
+ chat, workflows, scheduled tasks, and more. Output is JSON by default; errors
6
+ are structured as `Error / Why / Hint`.
7
+
8
+ This CLI targets **tenant** functionality only (central is out of scope).
9
+
10
+ ## Install
11
+
12
+ ```bash
13
+ npm install -g harvask-cli # exposes the `harvask` command globally
14
+ # or run without installing:
15
+ npx harvask-cli --help
16
+ ```
17
+
18
+ ### From source (development)
19
+
20
+ ```bash
21
+ npm install
22
+ npm run build # compiles to dist/, makes dist/index.js executable
23
+ npm link # optional: exposes `harvask` globally for local dev
24
+ ```
25
+
26
+ Requires Node.js >= 18.
27
+
28
+ ## Authenticate
29
+
30
+ Login is **browser-based** (no password is typed into the CLI):
31
+
32
+ ```bash
33
+ harvask login --tenant acme.harvask.app
34
+ # → opens your browser to approve, then receives the token automatically (loopback)
35
+
36
+ harvask login --tenant acme.harvask.app --no-browser
37
+ # → prints a URL; approve in any browser and paste the shown code (remote/headless)
38
+ ```
39
+
40
+ Flow: the CLI opens your browser for approval (PKCE-protected); you approve while
41
+ logged into the web app, and the CLI receives a one-time code and exchanges it
42
+ for a token. The token is stored per-tenant in your OS config dir
43
+ (`tokens.json`, mode `0600`) and never appears in the browser URL. Verify with
44
+ `harvask whoami`; `harvask logout` revokes and removes it.
45
+
46
+ ### Tenant resolution
47
+
48
+ The connection is determined by the tenant domain, so the API URL's host must
49
+ equal the tenant domain. In production, `--tenant` is enough.
50
+
51
+ For **local development**, map the tenant domain to your dev server in
52
+ `/etc/hosts` and point `--api-url` at that host:
53
+
54
+ ```
55
+ # /etc/hosts
56
+ 127.0.0.1 acme.harvask.test
57
+ ```
58
+ ```bash
59
+ harvask login --tenant acme.harvask.test --api-url http://acme.harvask.test:8080/api
60
+ ```
61
+
62
+ The API URL must be `https` except for `localhost` / `127.0.0.1` /
63
+ `*.harvask.test` / `*.localhost` (dev allowlist).
64
+
65
+ ## Usage
66
+
67
+ ```bash
68
+ harvask project list
69
+ harvask issue search -p PRJ "login bug"
70
+ harvask issue show -p PRJ 1234 --comments
71
+ harvask issue create -p PRJ --title "Fix login" --type bug --priority high
72
+ harvask issue status -p PRJ 1234 in_progress
73
+ harvask issue comment create -p PRJ 1234 --content "done"
74
+ harvask wiki create -p PRJ --title "Docs" --content @docs.md
75
+ harvask note create --content "remember this" --pinned
76
+ harvask milestone list -p PRJ
77
+ harvask calendar list --from 2026-06-01 --to 2026-06-30
78
+ harvask user search alice
79
+ harvask file search -p PRJ "screenshot"
80
+ harvask storage upload -p PRJ --file ./report.pdf
81
+ harvask api GET projects # escape hatch
82
+ ```
83
+
84
+ Command groups: `project`, `issue` (+ `comment`/`todo`/`memory`/`dependency`/
85
+ `bulk-create`/`bulk-update`), `wiki`, `global-wiki`, `note`, `milestone`,
86
+ `calendar`, `user`, `workflow`, `scheduled-task`, `chat`, `file`, `storage`,
87
+ `attachment`, `site-credential`, `preview-config`, `skill`, plus
88
+ `login`/`logout`/`whoami` and the `api` escape hatch.
89
+
90
+ - `-p, --project <key|id>` accepts a project key (`PRJ`) or numeric id.
91
+ - `--content` accepts a literal string, `@file`, or `-` (stdin).
92
+ - Global flags: `--json` (machine-readable), `--data` (payload only),
93
+ `--raw` (unformatted), `--profile <tenant>`, `--no-color`.
94
+
95
+ Run `harvask --help` and `harvask <command> --help` for the full reference.
96
+
97
+ ## Output & exit codes
98
+
99
+ - Default output is pretty JSON on stdout. Errors print `Error / Why / Hint` to
100
+ stderr (or JSON with `--json`).
101
+ - Exit codes: `1` validation / 4xx, `2` network / 5xx, `3` auth (401/403).
102
+
103
+ ## Environment variables
104
+
105
+ These override stored config (mainly for CI):
106
+
107
+ - `HARVASK_TOKEN`, `HARVASK_API_URL`, `HARVASK_TENANT`
108
+ - `HARVASK_TIMEOUT`, `HARVASK_RETRY_ATTEMPTS`, `HARVASK_RETRY_DELAY`
109
+ - `NO_COLOR` / `FORCE_COLOR`
110
+
111
+ ## Develop
112
+
113
+ ```bash
114
+ npm run build # tsc → dist/
115
+ npm test # build + node:test (pure build*Call / config / errors / output / token-store)
116
+ ```
117
+
118
+ Each command is split into three parts: a pure `buildXxxCall()` (args →
119
+ `{method, path, query, body}`), execution via the shared API client, and
120
+ `printOutput()`. Tests focus on the pure functions. New categories are added by
121
+ implementing a `CategoryModule` under `src/commands/<cat>/` and adding one line
122
+ to `src/registry.ts`.
123
+
124
+ ## Notes
125
+
126
+ - Notes and calendar are personal to the logged-in human user. The CLI acts as
127
+ the human user (not an AI user).
128
+ - `personal-wiki` is intentionally not exposed by the CLI.
129
+ - Token files use mode `0600` (POSIX). Windows is not a primary target.
130
+
131
+ ## Agent skill
132
+
133
+ `skills/harvask/SKILL.md` documents the discover → fetch → act workflow for
134
+ coding agents and is shipped with the package. `npm link` only installs the
135
+ `harvask` command — to make Claude Code discover the skill, install it:
136
+
137
+ ```bash
138
+ harvask skill install # symlink into ~/.claude/skills/harvask
139
+ harvask skill install --project # into ./.claude/skills/harvask
140
+ harvask skill install --copy # copy instead of symlink
141
+ harvask skill uninstall
142
+ harvask skill path # show source and install targets
143
+ ```
144
+
145
+ ## License
146
+
147
+ MIT
@@ -0,0 +1,8 @@
1
+ /**
2
+ * テナント API の名前空間プレフィックス(`/api` 以下)。
3
+ *
4
+ * 公開API向けの `/v1` を使用する。バックエンドには同一定義のエイリアスとして
5
+ * 旧 `/ai-worker` も存在する(後方互換)。名前空間を切り替えたい場合はここ1箇所を変える。
6
+ */
7
+ export const API_NS = '/v1';
8
+ //# sourceMappingURL=api-base.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-base.js","sourceRoot":"","sources":["../src/api-base.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AACH,MAAM,CAAC,MAAM,MAAM,GAAG,KAAK,CAAC"}
@@ -0,0 +1,221 @@
1
+ /**
2
+ * harvask API Client
3
+ *
4
+ * テナント API (既定の名前空間 /v1。/ai-worker は後方互換エイリアス) への HTTP クライアント。
5
+ * project-management-tool の kairon MCP (mcp-servers/kairon/src/api-client.ts) から流用し、
6
+ * 以下を変更:
7
+ * - クラス名 KaironApiClient -> HarvaskApiClient
8
+ * - 認証ヘッダは Authorization: Bearer のみ(X-AI-User-Id / X-Chat-Id は付けない)。
9
+ * これにより operator_user_id == ai_user_id == トークン所有者(人間)となり、
10
+ * notes / personal-wiki / calendar など個人スコープ API も正しく動作する。
11
+ * - tenantDomain が指定された場合は Host ヘッダを明示付与(開発時の Host 偽装用)。
12
+ * - 設定は HarvaskConfig 経由(環境変数の直接参照を廃止)。
13
+ */
14
+ export class HarvaskApiClient {
15
+ config;
16
+ constructor(config) {
17
+ this.config = config;
18
+ }
19
+ /**
20
+ * 認証ヘッダーを生成
21
+ *
22
+ * 注: テナント解決はサーバ側で Host ヘッダにより行われるが、Node の fetch(undici) は
23
+ * 手動の Host ヘッダを無視し URL のホストを使う。したがって apiUrl のホストが
24
+ * テナントドメインと一致している必要がある(本番は https://{tenant}/api、
25
+ * 開発は /etc/hosts で {tenant} を 127.0.0.1 に向けて http://{tenant}:port/api)。
26
+ */
27
+ getHeaders(isFormData = false) {
28
+ const headers = {
29
+ Accept: 'application/json',
30
+ Authorization: `Bearer ${this.config.token}`,
31
+ };
32
+ if (!isFormData) {
33
+ headers['Content-Type'] = 'application/json';
34
+ }
35
+ return headers;
36
+ }
37
+ /**
38
+ * APIリクエストを実行(リトライロジック付き)
39
+ */
40
+ async request(method, endpoint, body, options) {
41
+ const url = `${this.config.apiUrl}${endpoint}`;
42
+ let lastError = null;
43
+ const requestTimeout = options?.timeout || this.config.timeout;
44
+ for (let attempt = 0; attempt <= this.config.retryAttempts; attempt++) {
45
+ try {
46
+ const controller = new AbortController();
47
+ const timeoutId = setTimeout(() => controller.abort(), requestTimeout);
48
+ const response = await fetch(url, {
49
+ method,
50
+ headers: this.getHeaders(options?.isFormData),
51
+ body: options?.isFormData
52
+ ? body
53
+ : body
54
+ ? JSON.stringify(body)
55
+ : undefined,
56
+ signal: controller.signal,
57
+ });
58
+ clearTimeout(timeoutId);
59
+ if (!response.ok) {
60
+ const errorBody = (await response.json().catch(() => ({})));
61
+ const errorMessage = errorBody.message || `HTTP ${response.status}: ${response.statusText}`;
62
+ // 認証・認可・not found・バリデーションはリトライしない
63
+ if (response.status === 401 ||
64
+ response.status === 403 ||
65
+ response.status === 404 ||
66
+ response.status === 422) {
67
+ throw new ApiClientError(errorMessage, response.status, errorBody);
68
+ }
69
+ // 429(レート制限)は Retry-After に従って待機しリトライ
70
+ if (response.status === 429) {
71
+ const retryAfter = parseInt(response.headers.get('Retry-After') || '5', 10);
72
+ await this.sleep(retryAfter * 1000);
73
+ continue;
74
+ }
75
+ // 5xx はリトライ
76
+ if (response.status >= 500) {
77
+ lastError = new ApiClientError(errorMessage, response.status, errorBody);
78
+ await this.sleep(this.config.retryDelay * (attempt + 1));
79
+ continue;
80
+ }
81
+ throw new ApiClientError(errorMessage, response.status, errorBody);
82
+ }
83
+ // 204 No Content 等の空レスポンスに対応
84
+ const text = await response.text();
85
+ return (text ? JSON.parse(text) : {});
86
+ }
87
+ catch (error) {
88
+ if (error instanceof ApiClientError) {
89
+ throw error;
90
+ }
91
+ if (process.env.HARVASK_DEBUG) {
92
+ console.error('[harvask] fetch error:', {
93
+ url,
94
+ errorName: error instanceof Error ? error.name : 'unknown',
95
+ errorMessage: error instanceof Error ? error.message : String(error),
96
+ });
97
+ }
98
+ if (error instanceof Error && error.name === 'AbortError') {
99
+ lastError = new ApiClientError('Request timeout', 408);
100
+ }
101
+ else if (error instanceof Error) {
102
+ const causeInfo = error.cause
103
+ ? ` (cause: ${JSON.stringify(error.cause)})`
104
+ : '';
105
+ lastError = new ApiClientError(`Network error: ${error.message}${causeInfo}`, 0);
106
+ }
107
+ else {
108
+ lastError = new ApiClientError('Unknown error', 0);
109
+ }
110
+ if (attempt < this.config.retryAttempts) {
111
+ await this.sleep(this.config.retryDelay * (attempt + 1));
112
+ }
113
+ }
114
+ }
115
+ throw lastError || new ApiClientError('Request failed after all retries', 0);
116
+ }
117
+ sleep(ms) {
118
+ return new Promise((resolve) => setTimeout(resolve, ms));
119
+ }
120
+ async get(endpoint) {
121
+ return this.request('GET', endpoint);
122
+ }
123
+ async post(endpoint, body) {
124
+ return this.request('POST', endpoint, body);
125
+ }
126
+ async put(endpoint, body) {
127
+ return this.request('PUT', endpoint, body);
128
+ }
129
+ async patch(endpoint, body) {
130
+ return this.request('PATCH', endpoint, body);
131
+ }
132
+ async delete(endpoint) {
133
+ return this.request('DELETE', endpoint);
134
+ }
135
+ /**
136
+ * マルチパートPOST(ファイルアップロード用)
137
+ */
138
+ async postMultipart(endpoint, formData) {
139
+ return this.request('POST', endpoint, formData, { isFormData: true, timeout: 120000 });
140
+ }
141
+ /**
142
+ * バイナリGET(ファイルダウンロード用)。{buffer, contentType, filename} を返す。
143
+ */
144
+ async getBlob(endpoint) {
145
+ const url = `${this.config.apiUrl}${endpoint}`;
146
+ let lastError = null;
147
+ for (let attempt = 0; attempt <= this.config.retryAttempts; attempt++) {
148
+ try {
149
+ const controller = new AbortController();
150
+ const timeoutId = setTimeout(() => controller.abort(), 120000);
151
+ const headers = {
152
+ Authorization: `Bearer ${this.config.token}`,
153
+ };
154
+ const response = await fetch(url, { method: 'GET', headers, signal: controller.signal });
155
+ clearTimeout(timeoutId);
156
+ if (!response.ok) {
157
+ const errorBody = (await response.json().catch(() => ({})));
158
+ const errorMessage = errorBody.message || `HTTP ${response.status}: ${response.statusText}`;
159
+ if ([401, 403, 404, 422].includes(response.status)) {
160
+ throw new ApiClientError(errorMessage, response.status, errorBody);
161
+ }
162
+ if (response.status >= 500) {
163
+ lastError = new ApiClientError(errorMessage, response.status, errorBody);
164
+ await this.sleep(this.config.retryDelay * (attempt + 1));
165
+ continue;
166
+ }
167
+ throw new ApiClientError(errorMessage, response.status, errorBody);
168
+ }
169
+ const buffer = await response.arrayBuffer();
170
+ const contentType = response.headers.get('Content-Type') || 'application/octet-stream';
171
+ let filename;
172
+ const disposition = response.headers.get('Content-Disposition');
173
+ if (disposition) {
174
+ const utf8 = disposition.match(/filename\*=UTF-8''(.+?)(?:;|$)/i);
175
+ if (utf8) {
176
+ filename = decodeURIComponent(utf8[1]);
177
+ }
178
+ else {
179
+ const m = disposition.match(/filename="?(.+?)"?(?:;|$)/);
180
+ if (m) {
181
+ filename = m[1];
182
+ }
183
+ }
184
+ }
185
+ return { buffer, contentType, filename };
186
+ }
187
+ catch (error) {
188
+ if (error instanceof ApiClientError) {
189
+ throw error;
190
+ }
191
+ if (error instanceof Error && error.name === 'AbortError') {
192
+ lastError = new ApiClientError('Request timeout', 408);
193
+ }
194
+ else if (error instanceof Error) {
195
+ lastError = new ApiClientError(`Network error: ${error.message}`, 0);
196
+ }
197
+ else {
198
+ lastError = new ApiClientError('Unknown error', 0);
199
+ }
200
+ if (attempt < this.config.retryAttempts) {
201
+ await this.sleep(this.config.retryDelay * (attempt + 1));
202
+ }
203
+ }
204
+ }
205
+ throw lastError || new ApiClientError('Request failed after all retries', 0);
206
+ }
207
+ }
208
+ /**
209
+ * APIクライアントエラー
210
+ */
211
+ export class ApiClientError extends Error {
212
+ statusCode;
213
+ apiError;
214
+ constructor(message, statusCode, apiError) {
215
+ super(message);
216
+ this.name = 'ApiClientError';
217
+ this.statusCode = statusCode;
218
+ this.apiError = apiError;
219
+ }
220
+ }
221
+ //# sourceMappingURL=api-client.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"api-client.js","sourceRoot":"","sources":["../src/api-client.ts"],"names":[],"mappings":"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"}
package/dist/cli.js ADDED
@@ -0,0 +1,154 @@
1
+ /**
2
+ * commander プログラム構築とトップレベル実行
3
+ */
4
+ import { Command, CommanderError, Option } from 'commander';
5
+ import { CATEGORIES } from './registry.js';
6
+ import { CommandContext } from './context.js';
7
+ import { printError, exitCodeFor } from './errors/index.js';
8
+ export const VERSION = '0.1.0';
9
+ function isCommanderExit(err) {
10
+ return (err instanceof CommanderError ||
11
+ (typeof err === 'object' &&
12
+ err !== null &&
13
+ 'code' in err &&
14
+ String(err.code).startsWith('commander.')));
15
+ }
16
+ /**
17
+ * グローバル出力オプション(flag, 説明)の定義。
18
+ *
19
+ * ルートだけでなく各 leaf コマンドにも同じオプションを付けることで、
20
+ * `harvask --json issue list`(前置)と `harvask issue list --json`(後置)の
21
+ * 両方が動作する(後者はコーディングエージェントの自然な書き方)。
22
+ */
23
+ const OUTPUT_OPTIONS = [
24
+ ['--json', 'force machine-readable JSON output (no color)'],
25
+ ['--raw', 'print the raw API response without formatting'],
26
+ ['--data', 'print only the primary data payload (unwrap the response envelope)'],
27
+ ['--profile <tenant>', 'select a stored tenant profile (domain)'],
28
+ ['--no-color', 'disable ANSI color'],
29
+ ];
30
+ function addOutputOptions(cmd) {
31
+ for (const [flag, desc] of OUTPUT_OPTIONS) {
32
+ cmd.option(flag, desc);
33
+ }
34
+ return cmd;
35
+ }
36
+ /**
37
+ * leaf コマンドに出力オプションを付与する。ただし、コマンドが既に持つオプションと
38
+ * long 名または属性名が衝突するものはスキップする。
39
+ * 例: calendar の `--event-color`(属性 eventColor)とは衝突しないが、仮に属性 `color` を
40
+ * 持つコマンドがあれば `--no-color`(属性 color)を上書きしてしまうため除外する。
41
+ */
42
+ function addOutputOptionsToLeaf(cmd) {
43
+ for (const [flag, desc] of OUTPUT_OPTIONS) {
44
+ const probe = new Option(flag);
45
+ const clashes = cmd.options.some((o) => o.attributeName() === probe.attributeName() || o.long === probe.long);
46
+ if (!clashes) {
47
+ cmd.option(flag, desc);
48
+ }
49
+ }
50
+ }
51
+ /**
52
+ * leaf コマンド(サブコマンドを持たない実行コマンド)すべてに出力オプションを付与する。
53
+ */
54
+ function applyOutputOptionsToLeaves(cmd) {
55
+ for (const sub of cmd.commands) {
56
+ if (sub.commands.length === 0) {
57
+ addOutputOptionsToLeaf(sub);
58
+ }
59
+ else {
60
+ applyOutputOptionsToLeaves(sub);
61
+ }
62
+ }
63
+ }
64
+ /**
65
+ * 実行されたコマンドからルートまで親チェーンを辿り、グローバルフラグを解決する。
66
+ * オプションがチェーンのどの位置に現れても拾えるようにする(前置・後置どちらも可)。
67
+ * - json/raw/data: いずれかの階層で true なら true
68
+ * - color: いずれかの階層で --no-color(color===false)が指定されたら false
69
+ * - profile: leaf 側を優先(チェーン末尾が後勝ち)
70
+ */
71
+ export function collectGlobalFlags(cmd) {
72
+ const chain = [];
73
+ for (let c = cmd; c; c = c.parent) {
74
+ chain.unshift(c);
75
+ }
76
+ let json = false;
77
+ let raw = false;
78
+ let data = false;
79
+ let color = true;
80
+ let profile;
81
+ for (const c of chain) {
82
+ const o = c.opts();
83
+ if (o.json)
84
+ json = true;
85
+ if (o.raw)
86
+ raw = true;
87
+ if (o.data)
88
+ data = true;
89
+ if (o.color === false)
90
+ color = false;
91
+ if (typeof o.profile === 'string')
92
+ profile = o.profile;
93
+ }
94
+ return { json, raw, data, color, profile };
95
+ }
96
+ function addRootHelp(program) {
97
+ program.addHelpText('after', `
98
+ Workflow (for coding agents):
99
+ 1. discover : harvask project list / harvask issue search -p PRJ "login bug"
100
+ 2. fetch : harvask issue show -p PRJ PRJ-12 --comments
101
+ 3. act : harvask issue create|update|status|assign ...
102
+
103
+ Auth:
104
+ Run \`harvask login --tenant <domain>\` first. Tokens are stored per-tenant.
105
+
106
+ Output:
107
+ Default output is JSON. Use --data to print only the payload, --raw for the
108
+ unformatted response. Output flags work before or after the subcommand.
109
+ Errors go to stderr as "Error / Why / Hint".
110
+
111
+ Escape hatch:
112
+ harvask api <method> <path> [json] # call any /v1/* endpoint directly
113
+ `);
114
+ }
115
+ /**
116
+ * commander プログラムを構築する(パースは行わない)。テストからも利用する。
117
+ */
118
+ export function buildProgram(ctx) {
119
+ const program = new Command('harvask')
120
+ .description('harvask tenant CLI for coding agents — a command-line client for a harvask tenant')
121
+ .version(VERSION)
122
+ .enablePositionalOptions()
123
+ .showHelpAfterError('(add --help for usage)');
124
+ addOutputOptions(program);
125
+ // グローバルフラグを ctx に反映(各コマンド実行前)。実行コマンドから親チェーンを辿る。
126
+ program.hook('preAction', (_thisCommand, actionCommand) => {
127
+ ctx.flags = collectGlobalFlags(actionCommand);
128
+ });
129
+ for (const category of CATEGORIES) {
130
+ category.register(program, ctx);
131
+ }
132
+ // 全 leaf コマンドにも出力オプションを付与(後置フラグ対応)。
133
+ applyOutputOptionsToLeaves(program);
134
+ addRootHelp(program);
135
+ return program;
136
+ }
137
+ export async function run(argv) {
138
+ const ctx = new CommandContext();
139
+ const program = buildProgram(ctx);
140
+ program.exitOverride();
141
+ try {
142
+ await program.parseAsync(argv);
143
+ }
144
+ catch (err) {
145
+ if (isCommanderExit(err)) {
146
+ // help / version / 引数エラーは commander が既に出力済み
147
+ process.exitCode = err.exitCode ?? 0;
148
+ return;
149
+ }
150
+ printError(err, ctx.out);
151
+ process.exitCode = exitCodeFor(err);
152
+ }
153
+ }
154
+ //# sourceMappingURL=cli.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cli.js","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,63 @@
1
+ /**
2
+ * コマンド実行ヘルパ
3
+ *
4
+ * buildXxxCall(純粋関数)が返す ApiCall を、project 解決・クエリ付与した上で実行する。
5
+ * buildPath は純粋関数(テスト対象)。
6
+ */
7
+ import { resolveProjectId } from '../utils/project-resolver.js';
8
+ /**
9
+ * 位置引数の文字列を ProjectArg に正規化する(数値=id, それ以外=key)。
10
+ */
11
+ export function parseProjectArg(value) {
12
+ if (value === undefined || value === '') {
13
+ return undefined;
14
+ }
15
+ if (/^\d+$/.test(value)) {
16
+ return { id: parseInt(value, 10) };
17
+ }
18
+ return { key: value };
19
+ }
20
+ /**
21
+ * ApiCall から実際のパス({project} 置換 + クエリ付与)を構築する純粋関数。
22
+ */
23
+ export function buildPath(call, resolvedProjectId) {
24
+ let path = call.path;
25
+ if (path.includes('{project}')) {
26
+ if (resolvedProjectId === undefined) {
27
+ throw new Error('internal: project id not resolved for path with {project}');
28
+ }
29
+ path = path.replace('{project}', String(resolvedProjectId));
30
+ }
31
+ if (call.query && Object.keys(call.query).length > 0) {
32
+ const qs = new URLSearchParams(call.query).toString();
33
+ path += (path.includes('?') ? '&' : '?') + qs;
34
+ }
35
+ return path;
36
+ }
37
+ async function callApi(client, call, path) {
38
+ switch (call.method) {
39
+ case 'GET':
40
+ return client.get(path);
41
+ case 'POST':
42
+ return client.post(path, call.body);
43
+ case 'PUT':
44
+ return client.put(path, call.body);
45
+ case 'PATCH':
46
+ return client.patch(path, call.body);
47
+ case 'DELETE':
48
+ return client.delete(path);
49
+ }
50
+ }
51
+ /**
52
+ * ApiCall を実行する。path に {project} を含む場合は project を解決してから実行する。
53
+ */
54
+ export async function execCall(ctx, call, projectArg) {
55
+ const client = ctx.getApiClient();
56
+ let projectId;
57
+ if (call.path.includes('{project}')) {
58
+ projectId = await resolveProjectId(client, projectArg ?? {});
59
+ }
60
+ const path = buildPath(call, projectId);
61
+ return callApi(client, call, path);
62
+ }
63
+ //# sourceMappingURL=_exec.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"_exec.js","sourceRoot":"","sources":["../../src/commands/_exec.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AAKH,OAAO,EAAE,gBAAgB,EAAmB,MAAM,8BAA8B,CAAC;AAEjF;;GAEG;AACH,MAAM,UAAU,eAAe,CAAC,KAAc;IAC5C,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,EAAE,EAAE,CAAC;QACxC,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,IAAI,OAAO,CAAC,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC;QACxB,OAAO,EAAE,EAAE,EAAE,QAAQ,CAAC,KAAK,EAAE,EAAE,CAAC,EAAE,CAAC;IACrC,CAAC;IACD,OAAO,EAAE,GAAG,EAAE,KAAK,EAAE,CAAC;AACxB,CAAC;AAED;;GAEG;AACH,MAAM,UAAU,SAAS,CAAC,IAAa,EAAE,iBAA0B;IACjE,IAAI,IAAI,GAAG,IAAI,CAAC,IAAI,CAAC;IACrB,IAAI,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QAC/B,IAAI,iBAAiB,KAAK,SAAS,EAAE,CAAC;YACpC,MAAM,IAAI,KAAK,CAAC,2DAA2D,CAAC,CAAC;QAC/E,CAAC;QACD,IAAI,GAAG,IAAI,CAAC,OAAO,CAAC,WAAW,EAAE,MAAM,CAAC,iBAAiB,CAAC,CAAC,CAAC;IAC9D,CAAC;IACD,IAAI,IAAI,CAAC,KAAK,IAAI,MAAM,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QACrD,MAAM,EAAE,GAAG,IAAI,eAAe,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,QAAQ,EAAE,CAAC;QACtD,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,GAAG,CAAC,CAAC,CAAC,GAAG,CAAC,GAAG,EAAE,CAAC;IAChD,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED,KAAK,UAAU,OAAO,CACpB,MAAwB,EACxB,IAAa,EACb,IAAY;IAEZ,QAAQ,IAAI,CAAC,MAAM,EAAE,CAAC;QACpB,KAAK,KAAK;YACR,OAAO,MAAM,CAAC,GAAG,CAAC,IAAI,CAAC,CAAC;QAC1B,KAAK,MAAM;YACT,OAAO,MAAM,CAAC,IAAI,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QACtC,KAAK,KAAK;YACR,OAAO,MAAM,CAAC,GAAG,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QACrC,KAAK,OAAO;YACV,OAAO,MAAM,CAAC,KAAK,CAAC,IAAI,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;QACvC,KAAK,QAAQ;YACX,OAAO,MAAM,CAAC,MAAM,CAAC,IAAI,CAAC,CAAC;IAC/B,CAAC;AACH,CAAC;AAED;;GAEG;AACH,MAAM,CAAC,KAAK,UAAU,QAAQ,CAC5B,GAAmB,EACnB,IAAa,EACb,UAAuB;IAEvB,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC;IAClC,IAAI,SAA6B,CAAC;IAClC,IAAI,IAAI,CAAC,IAAI,CAAC,QAAQ,CAAC,WAAW,CAAC,EAAE,CAAC;QACpC,SAAS,GAAG,MAAM,gBAAgB,CAAC,MAAM,EAAE,UAAU,IAAI,EAAE,CAAC,CAAC;IAC/D,CAAC;IACD,MAAM,IAAI,GAAG,SAAS,CAAC,IAAI,EAAE,SAAS,CAAC,CAAC;IACxC,OAAO,OAAO,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;AACrC,CAAC"}