harvask-cli 0.4.0 → 0.6.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,240 @@
1
+ /**
2
+ * workspace カテゴリ(AI ワークスペース, /v1/projects/{project}/workspace)。
3
+ *
4
+ * ローカルにある既存プロジェクトを、プロジェクトの AI ワークスペース
5
+ * (Web の Files タブ=AI セッションの `~/work`)へまとめて投入する。
6
+ * 契約の正本は project-management-tool の docs/features/workspace-file-api.md。
7
+ *
8
+ * ここだけ他カテゴリと形が違う(ApiCall を 1 本返すのではなく、preflight → 複数バッチの
9
+ * multipart POST という手順になる)。判定はすべて collect.ts / batch.ts の純粋関数に寄せ、
10
+ * このファイルは手順と出力の組み立てに徹する。
11
+ */
12
+ import { resolve } from 'node:path';
13
+ import { statSync } from 'node:fs';
14
+ import { parseProjectArg, requireConfirmation } from '../_exec.js';
15
+ import { resolveProjectId } from '../../utils/project-resolver.js';
16
+ import { printOutput } from '../../output/index.js';
17
+ import { ValidationError } from '../../errors/index.js';
18
+ import { parseIntArg } from '../../utils/input.js';
19
+ import { buildFilesFormData } from '../../utils/upload.js';
20
+ import { API_NS } from '../../api-base.js';
21
+ import { collectFiles, detectProtectedPaths, joinWorkspacePath, normalizeDestPath, shouldAbortForInvalid, } from './collect.js';
22
+ import { chunk, DEFAULT_MAX_BATCH_BYTES, MAX_FILE_BYTES, MAX_PREFLIGHT_PATHS, partitionOversized, planBatches, totalBytes, } from './batch.js';
23
+ /** `post_max_size`(1GB)。--max-batch-bytes をこれ以上にしても 413 になるだけ。 */
24
+ const POST_MAX_SIZE = 1024 * 1024 * 1024;
25
+ /** 出力に載せるサンプル件数(全部出すと数千行になるため)。 */
26
+ const SAMPLE_LIMIT = 10;
27
+ function collectRepeatable(value, previous) {
28
+ return previous.concat([value]);
29
+ }
30
+ function sample(items) {
31
+ const head = items.slice(0, SAMPLE_LIMIT).join(', ');
32
+ return items.length > SAMPLE_LIMIT ? `${head}, … (+${items.length - SAMPLE_LIMIT} more)` : head;
33
+ }
34
+ /**
35
+ * バッチのサイズからリクエストタイムアウトを決める。
36
+ * 既定の 120 秒固定では 100MB 級のバッチが上り帯域次第で必ず落ちる(しかもリトライで倍払う)。
37
+ */
38
+ function timeoutForBytes(bytes) {
39
+ const megabytes = Math.ceil(bytes / (1024 * 1024));
40
+ return Math.min(120_000 + megabytes * 2_000, 900_000);
41
+ }
42
+ /**
43
+ * preflight を MAX_PREFLIGHT_PATHS 件ずつ投げて結果をまとめる。
44
+ */
45
+ async function preflightAll(client, projectId, paths, dest) {
46
+ const merged = {
47
+ conflicts: [],
48
+ blocked: [],
49
+ invalid: [],
50
+ blocked_extensions: [],
51
+ };
52
+ for (const part of chunk(paths, MAX_PREFLIGHT_PATHS)) {
53
+ const body = { paths: part };
54
+ if (dest !== '') {
55
+ body.path = dest;
56
+ }
57
+ const res = await client.post(`${API_NS}/projects/${projectId}/workspace/upload/preflight`, body);
58
+ merged.conflicts.push(...(res.conflicts ?? []));
59
+ merged.blocked.push(...(res.blocked ?? []));
60
+ merged.invalid.push(...(res.invalid ?? []));
61
+ if (merged.blocked_extensions.length === 0) {
62
+ merged.blocked_extensions = res.blocked_extensions ?? [];
63
+ }
64
+ }
65
+ return merged;
66
+ }
67
+ export const workspaceModule = {
68
+ name: 'workspace',
69
+ describe: 'AI workspace (push a local directory into the project workspace)',
70
+ register(program, ctx) {
71
+ const ws = program
72
+ .command('workspace')
73
+ .description('AI workspace (Files tab / ~/work in AI sessions)');
74
+ ws.command('push')
75
+ .description('Push a local directory into the project AI workspace')
76
+ .argument('<dir>', 'local directory to push')
77
+ .option('-p, --project <key|id>', 'project key (PRJ) or numeric id')
78
+ .option('--dest <path>', 'destination directory inside the workspace (default: root)')
79
+ .option('--dry-run', 'preflight only: print the plan and send no bytes')
80
+ .option('--include-ignored', 'ignore .gitignore and the default excludes (.env* stays excluded)')
81
+ .option('--exclude <glob>', 'additional exclude (repeatable)', collectRepeatable, [])
82
+ .option('--include <glob>', 'restore a default-excluded path (repeatable)', collectRepeatable, [])
83
+ .option('--force', 'allow pushing into apps/ or canvas/')
84
+ .option('--max-batch-bytes <n>', 'max total bytes per request (default 200MB)', parseIntArg)
85
+ .option('--yes', 'approve overwrites in non-interactive mode')
86
+ .addHelpText('after', `
87
+ Sends a local tree to the project workspace (Web: Files tab, AI sessions: ~/work).
88
+ Same relative path = overwrite; there is no version history. Always --dry-run first.
89
+
90
+ harvask workspace push ./legacy-app -p PRJ --dest legacy --dry-run
91
+ harvask workspace push ./legacy-app -p PRJ --dest legacy
92
+
93
+ Excluded no matter what: .env* and .git/ (the workspace is visible to every member).
94
+ Excluded by default (--include-ignored / --include <glob> to restore):
95
+ node_modules/ vendor/ dist/ build/ __pycache__/ .venv/ .DS_Store
96
+ In a git repository, .gitignore decides the rest.
97
+
98
+ Windows binaries (.exe .bat .cmd .ps1 .vbs .com .msi .dll) cannot be stored: they
99
+ are reported under "skipped", not treated as an error. .sh is allowed.
100
+
101
+ Batches are not atomic. If it fails partway, the result JSON lists "remaining";
102
+ re-running the same command resumes (re-uploading overwrites).
103
+ A live mini-app / browser-agent session makes this fail with 409 — end the
104
+ session instead of retrying, or the upload is silently rolled back.
105
+ `)
106
+ .action(async (dirArg, opts) => {
107
+ const root = resolve(dirArg);
108
+ let rootStat;
109
+ try {
110
+ rootStat = statSync(root);
111
+ }
112
+ catch (e) {
113
+ throw new ValidationError(`Directory not found or unreadable: ${root} (${e.message})`);
114
+ }
115
+ if (!rootStat.isDirectory()) {
116
+ throw new ValidationError(`Not a directory: ${root}`);
117
+ }
118
+ const dest = normalizeDestPath(opts.dest);
119
+ const maxBatchBytes = opts.maxBatchBytes ?? DEFAULT_MAX_BATCH_BYTES;
120
+ if (maxBatchBytes < 1 || maxBatchBytes > POST_MAX_SIZE) {
121
+ throw new ValidationError(`--max-batch-bytes must be between 1 and ${POST_MAX_SIZE} (post_max_size)`);
122
+ }
123
+ // 1. ローカルを集める(ネットワークより先に。引数の誤りはここで落とす)
124
+ const collected = collectFiles(root, {
125
+ includeIgnored: Boolean(opts.includeIgnored),
126
+ exclude: opts.exclude,
127
+ include: opts.include,
128
+ });
129
+ const sized = partitionOversized(collected.files);
130
+ const excluded = [
131
+ ...collected.excluded,
132
+ ...sized.oversized.map((f) => ({
133
+ path: f.path,
134
+ reason: 'too_large',
135
+ detail: `${f.size} bytes > ${MAX_FILE_BYTES} (per-file limit)`,
136
+ })),
137
+ ];
138
+ const client = ctx.getApiClient();
139
+ const projectId = await resolveProjectId(client, parseProjectArg(opts.project) ?? {});
140
+ if (sized.ok.length === 0) {
141
+ printOutput({
142
+ project_id: projectId,
143
+ dest,
144
+ source: collected.source,
145
+ planned: 0,
146
+ uploaded: 0,
147
+ overwritten: 0,
148
+ skipped: [],
149
+ excluded,
150
+ batches: { total: 0, completed: 0 },
151
+ remaining: [],
152
+ note: 'nothing to push (everything was excluded or the directory is empty)',
153
+ }, ctx.out);
154
+ return;
155
+ }
156
+ // 2. preflight(何が上書きになり、何が置けないか)
157
+ const pre = await preflightAll(client, projectId, sized.ok.map((f) => f.path), dest);
158
+ if (shouldAbortForInvalid(pre.invalid)) {
159
+ // 1 件でも不正なパスがあると upload は丸ごと 422 になる。部分的には送らない。
160
+ throw new ValidationError(`${pre.invalid.length} path(s) cannot be stored in the workspace: ${sample(pre.invalid)}`);
161
+ }
162
+ const blocked = new Set(pre.blocked.map((b) => b.path));
163
+ const files = sized.ok.filter((f) => !blocked.has(f.path));
164
+ const skipped = pre.blocked.map((b) => ({
165
+ path: b.path,
166
+ reason: 'blocked_extension',
167
+ extension: b.extension,
168
+ }));
169
+ const protectedHits = detectProtectedPaths(files.map((f) => joinWorkspacePath(dest, f.path)));
170
+ if (protectedHits.length > 0 && !opts.force) {
171
+ throw new ValidationError(`${protectedHits.length} path(s) would land under apps/ or canvas/, where mini-app sources, their SQLite data and Canvas documents live: ${sample(protectedHits)}. Use a different --dest, or --force if you really mean it.`);
172
+ }
173
+ const conflicts = new Set(pre.conflicts);
174
+ const willOverwrite = files.filter((f) => conflicts.has(f.path)).length;
175
+ const batches = planBatches(files, { maxBytes: maxBatchBytes });
176
+ if (opts.dryRun) {
177
+ printOutput({
178
+ dry_run: true,
179
+ project_id: projectId,
180
+ dest,
181
+ source: collected.source,
182
+ planned: files.length,
183
+ would_create: files.length - willOverwrite,
184
+ would_overwrite: willOverwrite,
185
+ total_bytes: totalBytes(files),
186
+ batches: { total: batches.length },
187
+ protected: protectedHits,
188
+ skipped,
189
+ excluded,
190
+ }, ctx.out);
191
+ return;
192
+ }
193
+ // 上書きの承認は 1 バイトも送らない --dry-run の後で聞く(計画を見るのに --yes は要らない)
194
+ if (willOverwrite > 0) {
195
+ requireConfirmation(opts, `overwrite ${willOverwrite} existing workspace file(s)`);
196
+ }
197
+ // 3. 投入。バッチ間は原子的でないので、落ちたら未送信分を remaining に載せて終わる
198
+ // (同名は上書きなので、同じコマンドをもう一度流せばそこから再開になる)
199
+ const uploaded = [];
200
+ let overwritten = 0;
201
+ let completed = 0;
202
+ let remaining = files.map((f) => f.path);
203
+ const result = () => ({
204
+ project_id: projectId,
205
+ dest,
206
+ source: collected.source,
207
+ planned: files.length,
208
+ uploaded: uploaded.length,
209
+ overwritten,
210
+ skipped,
211
+ excluded,
212
+ batches: { total: batches.length, completed },
213
+ remaining,
214
+ });
215
+ try {
216
+ for (const batch of batches) {
217
+ const form = buildFilesFormData(batch, dest);
218
+ const res = await client.postMultipart(`${API_NS}/projects/${projectId}/workspace/upload`, form, { timeout: timeoutForBytes(totalBytes(batch)) });
219
+ completed++;
220
+ for (const item of res.uploaded ?? []) {
221
+ uploaded.push(item.path);
222
+ }
223
+ for (const item of res.skipped ?? []) {
224
+ skipped.push(item);
225
+ }
226
+ overwritten += batch.filter((f) => conflicts.has(f.path)).length;
227
+ const done = new Set(batch.map((f) => f.path));
228
+ remaining = remaining.filter((p) => !done.has(p));
229
+ }
230
+ }
231
+ catch (err) {
232
+ // 結果は stdout(再開に使う remaining を含む)、理由は stderr(Error/Why/Hint)
233
+ printOutput(result(), ctx.out);
234
+ throw err;
235
+ }
236
+ printOutput(result(), ctx.out);
237
+ });
238
+ },
239
+ };
240
+ //# sourceMappingURL=index.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"index.js","sourceRoot":"","sources":["../../../src/commands/workspace/index.ts"],"names":[],"mappings":"AAAA;;;;;;;;;;GAUG;AAGH,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AACpC,OAAO,EAAE,QAAQ,EAAE,MAAM,SAAS,CAAC;AAInC,OAAO,EAAE,eAAe,EAAE,mBAAmB,EAAE,MAAM,aAAa,CAAC;AACnE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,WAAW,EAAE,MAAM,uBAAuB,CAAC;AACpD,OAAO,EAAE,eAAe,EAAE,MAAM,uBAAuB,CAAC;AACxD,OAAO,EAAE,WAAW,EAAE,MAAM,sBAAsB,CAAC;AACnD,OAAO,EAAE,kBAAkB,EAAE,MAAM,uBAAuB,CAAC;AAC3D,OAAO,EAAE,MAAM,EAAE,MAAM,mBAAmB,CAAC;AAC3C,OAAO,EACL,YAAY,EACZ,oBAAoB,EACpB,iBAAiB,EACjB,iBAAiB,EACjB,qBAAqB,GAGtB,MAAM,cAAc,CAAC;AACtB,OAAO,EACL,KAAK,EACL,uBAAuB,EACvB,cAAc,EACd,mBAAmB,EACnB,kBAAkB,EAClB,WAAW,EACX,UAAU,GACX,MAAM,YAAY,CAAC;AAEpB,kEAAkE;AAClE,MAAM,aAAa,GAAG,IAAI,GAAG,IAAI,GAAG,IAAI,CAAC;AAEzC,mCAAmC;AACnC,MAAM,YAAY,GAAG,EAAE,CAAC;AAoBxB,SAAS,iBAAiB,CAAC,KAAa,EAAE,QAAkB;IAC1D,OAAO,QAAQ,CAAC,MAAM,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC;AAClC,CAAC;AAED,SAAS,MAAM,CAAC,KAAe;IAC7B,MAAM,IAAI,GAAG,KAAK,CAAC,KAAK,CAAC,CAAC,EAAE,YAAY,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACrD,OAAO,KAAK,CAAC,MAAM,GAAG,YAAY,CAAC,CAAC,CAAC,GAAG,IAAI,SAAS,KAAK,CAAC,MAAM,GAAG,YAAY,QAAQ,CAAC,CAAC,CAAC,IAAI,CAAC;AAClG,CAAC;AAED;;;GAGG;AACH,SAAS,eAAe,CAAC,KAAa;IACpC,MAAM,SAAS,GAAG,IAAI,CAAC,IAAI,CAAC,KAAK,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,CAAC,CAAC;IACnD,OAAO,IAAI,CAAC,GAAG,CAAC,OAAO,GAAG,SAAS,GAAG,KAAK,EAAE,OAAO,CAAC,CAAC;AACxD,CAAC;AAED;;GAEG;AACH,KAAK,UAAU,YAAY,CACzB,MAAwB,EACxB,SAAiB,EACjB,KAAe,EACf,IAAY;IAEZ,MAAM,MAAM,GAAgC;QAC1C,SAAS,EAAE,EAAE;QACb,OAAO,EAAE,EAAE;QACX,OAAO,EAAE,EAAE;QACX,kBAAkB,EAAE,EAAE;KACvB,CAAC;IACF,KAAK,MAAM,IAAI,IAAI,KAAK,CAAC,KAAK,EAAE,mBAAmB,CAAC,EAAE,CAAC;QACrD,MAAM,IAAI,GAA4B,EAAE,KAAK,EAAE,IAAI,EAAE,CAAC;QACtD,IAAI,IAAI,KAAK,EAAE,EAAE,CAAC;YAChB,IAAI,CAAC,IAAI,GAAG,IAAI,CAAC;QACnB,CAAC;QACD,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,IAAI,CAC3B,GAAG,MAAM,aAAa,SAAS,6BAA6B,EAC5D,IAAI,CACL,CAAC;QACF,MAAM,CAAC,SAAS,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,SAAS,IAAI,EAAE,CAAC,CAAC,CAAC;QAChD,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC;QAC5C,MAAM,CAAC,OAAO,CAAC,IAAI,CAAC,GAAG,CAAC,GAAG,CAAC,OAAO,IAAI,EAAE,CAAC,CAAC,CAAC;QAC5C,IAAI,MAAM,CAAC,kBAAkB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC3C,MAAM,CAAC,kBAAkB,GAAG,GAAG,CAAC,kBAAkB,IAAI,EAAE,CAAC;QAC3D,CAAC;IACH,CAAC;IACD,OAAO,MAAM,CAAC;AAChB,CAAC;AAED,MAAM,CAAC,MAAM,eAAe,GAAmB;IAC7C,IAAI,EAAE,WAAW;IACjB,QAAQ,EAAE,kEAAkE;IAC5E,QAAQ,CAAC,OAAgB,EAAE,GAAmB;QAC5C,MAAM,EAAE,GAAG,OAAO;aACf,OAAO,CAAC,WAAW,CAAC;aACpB,WAAW,CAAC,kDAAkD,CAAC,CAAC;QAEnE,EAAE,CAAC,OAAO,CAAC,MAAM,CAAC;aACf,WAAW,CAAC,sDAAsD,CAAC;aACnE,QAAQ,CAAC,OAAO,EAAE,yBAAyB,CAAC;aAC5C,MAAM,CAAC,wBAAwB,EAAE,iCAAiC,CAAC;aACnE,MAAM,CAAC,eAAe,EAAE,4DAA4D,CAAC;aACrF,MAAM,CAAC,WAAW,EAAE,kDAAkD,CAAC;aACvE,MAAM,CAAC,mBAAmB,EAAE,mEAAmE,CAAC;aAChG,MAAM,CAAC,kBAAkB,EAAE,iCAAiC,EAAE,iBAAiB,EAAE,EAAE,CAAC;aACpF,MAAM,CAAC,kBAAkB,EAAE,8CAA8C,EAAE,iBAAiB,EAAE,EAAE,CAAC;aACjG,MAAM,CAAC,SAAS,EAAE,qCAAqC,CAAC;aACxD,MAAM,CAAC,uBAAuB,EAAE,6CAA6C,EAAE,WAAW,CAAC;aAC3F,MAAM,CAAC,OAAO,EAAE,4CAA4C,CAAC;aAC7D,WAAW,CACV,OAAO,EACP;;;;;;;;;;;;;;;;;;;CAmBP,CACM;aACA,MAAM,CAAC,KAAK,EAAE,MAAc,EAAE,IAAI,EAAE,EAAE;YACrC,MAAM,IAAI,GAAG,OAAO,CAAC,MAAM,CAAC,CAAC;YAC7B,IAAI,QAAQ,CAAC;YACb,IAAI,CAAC;gBACH,QAAQ,GAAG,QAAQ,CAAC,IAAI,CAAC,CAAC;YAC5B,CAAC;YAAC,OAAO,CAAC,EAAE,CAAC;gBACX,MAAM,IAAI,eAAe,CAAC,sCAAsC,IAAI,KAAM,CAAW,CAAC,OAAO,GAAG,CAAC,CAAC;YACpG,CAAC;YACD,IAAI,CAAC,QAAQ,CAAC,WAAW,EAAE,EAAE,CAAC;gBAC5B,MAAM,IAAI,eAAe,CAAC,oBAAoB,IAAI,EAAE,CAAC,CAAC;YACxD,CAAC;YAED,MAAM,IAAI,GAAG,iBAAiB,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;YAC1C,MAAM,aAAa,GAAW,IAAI,CAAC,aAAa,IAAI,uBAAuB,CAAC;YAC5E,IAAI,aAAa,GAAG,CAAC,IAAI,aAAa,GAAG,aAAa,EAAE,CAAC;gBACvD,MAAM,IAAI,eAAe,CACvB,2CAA2C,aAAa,kBAAkB,CAC3E,CAAC;YACJ,CAAC;YAED,uCAAuC;YACvC,MAAM,SAAS,GAAG,YAAY,CAAC,IAAI,EAAE;gBACnC,cAAc,EAAE,OAAO,CAAC,IAAI,CAAC,cAAc,CAAC;gBAC5C,OAAO,EAAE,IAAI,CAAC,OAAmB;gBACjC,OAAO,EAAE,IAAI,CAAC,OAAmB;aAClC,CAAC,CAAC;YACH,MAAM,KAAK,GAAG,kBAAkB,CAAC,SAAS,CAAC,KAAK,CAAC,CAAC;YAClD,MAAM,QAAQ,GAAoB;gBAChC,GAAG,SAAS,CAAC,QAAQ;gBACrB,GAAG,KAAK,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;oBAC7B,IAAI,EAAE,CAAC,CAAC,IAAI;oBACZ,MAAM,EAAE,WAAoB;oBAC5B,MAAM,EAAE,GAAG,CAAC,CAAC,IAAI,YAAY,cAAc,mBAAmB;iBAC/D,CAAC,CAAC;aACJ,CAAC;YAEF,MAAM,MAAM,GAAG,GAAG,CAAC,YAAY,EAAE,CAAC;YAClC,MAAM,SAAS,GAAG,MAAM,gBAAgB,CAAC,MAAM,EAAE,eAAe,CAAC,IAAI,CAAC,OAAO,CAAC,IAAI,EAAE,CAAC,CAAC;YAEtF,IAAI,KAAK,CAAC,EAAE,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;gBAC1B,WAAW,CACT;oBACE,UAAU,EAAE,SAAS;oBACrB,IAAI;oBACJ,MAAM,EAAE,SAAS,CAAC,MAAM;oBACxB,OAAO,EAAE,CAAC;oBACV,QAAQ,EAAE,CAAC;oBACX,WAAW,EAAE,CAAC;oBACd,OAAO,EAAE,EAAE;oBACX,QAAQ;oBACR,OAAO,EAAE,EAAE,KAAK,EAAE,CAAC,EAAE,SAAS,EAAE,CAAC,EAAE;oBACnC,SAAS,EAAE,EAAE;oBACb,IAAI,EAAE,qEAAqE;iBAC5E,EACD,GAAG,CAAC,GAAG,CACR,CAAC;gBACF,OAAO;YACT,CAAC;YAED,iCAAiC;YACjC,MAAM,GAAG,GAAG,MAAM,YAAY,CAC5B,MAAM,EACN,SAAS,EACT,KAAK,CAAC,EAAE,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,EAC3B,IAAI,CACL,CAAC;YAEF,IAAI,qBAAqB,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAAC;gBACvC,gDAAgD;gBAChD,MAAM,IAAI,eAAe,CACvB,GAAG,GAAG,CAAC,OAAO,CAAC,MAAM,+CAA+C,MAAM,CAAC,GAAG,CAAC,OAAO,CAAC,EAAE,CAC1F,CAAC;YACJ,CAAC;YAED,MAAM,OAAO,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;YACxD,MAAM,KAAK,GAAgB,KAAK,CAAC,EAAE,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;YACxE,MAAM,OAAO,GAAmB,GAAG,CAAC,OAAO,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC;gBACtD,IAAI,EAAE,CAAC,CAAC,IAAI;gBACZ,MAAM,EAAE,mBAAmB;gBAC3B,SAAS,EAAE,CAAC,CAAC,SAAS;aACvB,CAAC,CAAC,CAAC;YAEJ,MAAM,aAAa,GAAG,oBAAoB,CACxC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,CAAC,CAClD,CAAC;YACF,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,IAAI,CAAC,IAAI,CAAC,KAAK,EAAE,CAAC;gBAC5C,MAAM,IAAI,eAAe,CACvB,GAAG,aAAa,CAAC,MAAM,oHAAoH,MAAM,CAAC,aAAa,CAAC,6DAA6D,CAC9N,CAAC;YACJ,CAAC;YAED,MAAM,SAAS,GAAG,IAAI,GAAG,CAAC,GAAG,CAAC,SAAS,CAAC,CAAC;YACzC,MAAM,aAAa,GAAG,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;YACxE,MAAM,OAAO,GAAG,WAAW,CAAC,KAAK,EAAE,EAAE,QAAQ,EAAE,aAAa,EAAE,CAAC,CAAC;YAEhE,IAAI,IAAI,CAAC,MAAM,EAAE,CAAC;gBAChB,WAAW,CACT;oBACE,OAAO,EAAE,IAAI;oBACb,UAAU,EAAE,SAAS;oBACrB,IAAI;oBACJ,MAAM,EAAE,SAAS,CAAC,MAAM;oBACxB,OAAO,EAAE,KAAK,CAAC,MAAM;oBACrB,YAAY,EAAE,KAAK,CAAC,MAAM,GAAG,aAAa;oBAC1C,eAAe,EAAE,aAAa;oBAC9B,WAAW,EAAE,UAAU,CAAC,KAAK,CAAC;oBAC9B,OAAO,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE;oBAClC,SAAS,EAAE,aAAa;oBACxB,OAAO;oBACP,QAAQ;iBACT,EACD,GAAG,CAAC,GAAG,CACR,CAAC;gBACF,OAAO;YACT,CAAC;YAED,0DAA0D;YAC1D,IAAI,aAAa,GAAG,CAAC,EAAE,CAAC;gBACtB,mBAAmB,CAAC,IAAI,EAAE,aAAa,aAAa,6BAA6B,CAAC,CAAC;YACrF,CAAC;YAED,kDAAkD;YAClD,yCAAyC;YACzC,MAAM,QAAQ,GAAa,EAAE,CAAC;YAC9B,IAAI,WAAW,GAAG,CAAC,CAAC;YACpB,IAAI,SAAS,GAAG,CAAC,CAAC;YAClB,IAAI,SAAS,GAAG,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC;YAEzC,MAAM,MAAM,GAAG,GAA4B,EAAE,CAAC,CAAC;gBAC7C,UAAU,EAAE,SAAS;gBACrB,IAAI;gBACJ,MAAM,EAAE,SAAS,CAAC,MAAM;gBACxB,OAAO,EAAE,KAAK,CAAC,MAAM;gBACrB,QAAQ,EAAE,QAAQ,CAAC,MAAM;gBACzB,WAAW;gBACX,OAAO;gBACP,QAAQ;gBACR,OAAO,EAAE,EAAE,KAAK,EAAE,OAAO,CAAC,MAAM,EAAE,SAAS,EAAE;gBAC7C,SAAS;aACV,CAAC,CAAC;YAEH,IAAI,CAAC;gBACH,KAAK,MAAM,KAAK,IAAI,OAAO,EAAE,CAAC;oBAC5B,MAAM,IAAI,GAAG,kBAAkB,CAAC,KAAK,EAAE,IAAI,CAAC,CAAC;oBAC7C,MAAM,GAAG,GAAG,MAAM,MAAM,CAAC,aAAa,CACpC,GAAG,MAAM,aAAa,SAAS,mBAAmB,EAClD,IAAI,EACJ,EAAE,OAAO,EAAE,eAAe,CAAC,UAAU,CAAC,KAAK,CAAC,CAAC,EAAE,CAChD,CAAC;oBACF,SAAS,EAAE,CAAC;oBACZ,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,QAAQ,IAAI,EAAE,EAAE,CAAC;wBACtC,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBAC3B,CAAC;oBACD,KAAK,MAAM,IAAI,IAAI,GAAG,CAAC,OAAO,IAAI,EAAE,EAAE,CAAC;wBACrC,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;oBACrB,CAAC;oBACD,WAAW,IAAI,KAAK,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,SAAS,CAAC,GAAG,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,MAAM,CAAC;oBACjE,MAAM,IAAI,GAAG,IAAI,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC;oBAC/C,SAAS,GAAG,SAAS,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAC;gBACpD,CAAC;YACH,CAAC;YAAC,OAAO,GAAG,EAAE,CAAC;gBACb,6DAA6D;gBAC7D,WAAW,CAAC,MAAM,EAAE,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;gBAC/B,MAAM,GAAG,CAAC;YACZ,CAAC;YAED,WAAW,CAAC,MAAM,EAAE,EAAE,GAAG,CAAC,GAAG,CAAC,CAAC;QACjC,CAAC,CAAC,CAAC;IACP,CAAC;CACF,CAAC"}
@@ -49,7 +49,41 @@ export function hintFor(e) {
49
49
  why: apiMessage ?? 'Resource not found.',
50
50
  hint: 'Verify the id/key (e.g. project key PRJ, issue key PRJ-123). Use `harvask project list` / `harvask issue search` to find valid ids.',
51
51
  };
52
+ case 409:
53
+ if (code === 'workspace_session_active') {
54
+ return {
55
+ why: 'A mini-app / browser-agent session is live for this project; while it runs the workspace is synced from the session, so anything written now is silently rolled back.',
56
+ hint: 'End that session, then run the command again. Do not retry on a timer — this is a guard, not a transient error.',
57
+ };
58
+ }
59
+ return {
60
+ why: apiMessage ?? e.message,
61
+ hint: 'The resource is locked or was changed by someone else. Re-read the current state before trying again.',
62
+ };
63
+ case 413:
64
+ return {
65
+ why: apiMessage ?? 'Request body too large (HTTP 413).',
66
+ hint: 'Send less per request (e.g. `workspace push --max-batch-bytes 52428800`). Already-sent files are listed in the result; "remaining" shows what is left.',
67
+ };
52
68
  case 422:
69
+ if (code === 'missing_chat_id') {
70
+ return {
71
+ why: 'chat_message attachments identify the chat with the X-Chat-Id header, not a body field.',
72
+ hint: 'Pass `--chat-id <id>` (find it with `harvask chat list`).',
73
+ };
74
+ }
75
+ if (code === 'handover_approval_required') {
76
+ return {
77
+ why: 'This was generated by a handover and is still waiting for a human to approve it.',
78
+ hint: 'Approve it in the handover review screen first. It cannot be activated or run from the CLI before that.',
79
+ };
80
+ }
81
+ if (code === 'cannot_overwrite_folder') {
82
+ return {
83
+ why: 'A folder with that name already exists in the target directory.',
84
+ hint: 'Rename the file, pick another --parent-id, or drop --on-conflict overwrite.',
85
+ };
86
+ }
53
87
  return {
54
88
  why: formatValidationErrors(e.apiError?.errors) ?? apiMessage ?? e.message,
55
89
  hint: 'Fix the listed fields. See `--help` for allowed values (issue_type/priority enums, title<=255, content<=500000).',
@@ -1 +1 @@
1
- {"version":3,"file":"hint-map.js","sourceRoot":"","sources":["../../src/errors/hint-map.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AASH,MAAM,UAAU,sBAAsB,CAAC,MAAiC;IACtE,IAAI,CAAC,MAAM,EAAE,CAAC;QACZ,OAAO,SAAS,CAAC;IACnB,CAAC;IACD,OAAO,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC;SAC1B,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,QAAQ,CAAC,EAAE,EAAE,CAAC,GAAG,KAAK,KAAK,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC;SAC9D,IAAI,CAAC,IAAI,CAAC,CAAC;AAChB,CAAC;AAED,MAAM,UAAU,OAAO,CAAC,CAAiB;IACvC,MAAM,IAAI,GAAG,CAAC,CAAC,QAAQ,EAAE,IAAI,CAAC;IAC9B,MAAM,UAAU,GAAG,CAAC,CAAC,QAAQ,EAAE,OAAO,CAAC;IAEvC,QAAQ,CAAC,CAAC,UAAU,EAAE,CAAC;QACrB,KAAK,GAAG;YACN,OAAO;gBACL,GAAG,EAAE,UAAU,IAAI,2BAA2B;gBAC9C,IAAI,EAAE,gEAAgE;aACvE,CAAC;QACJ,KAAK,GAAG;YACN,IAAI,IAAI,KAAK,iBAAiB,EAAE,CAAC;gBAC/B,OAAO;oBACL,GAAG,EAAE,6CAA6C;oBAClD,IAAI,EAAE,uGAAuG;iBAC9G,CAAC;YACJ,CAAC;YACD,IAAI,IAAI,KAAK,oBAAoB,EAAE,CAAC;gBAClC,OAAO;oBACL,GAAG,EAAE,uCAAuC;oBAC5C,IAAI,EAAE,2FAA2F;iBAClG,CAAC;YACJ,CAAC;YACD,IAAI,IAAI,KAAK,oBAAoB,EAAE,CAAC;gBAClC,OAAO;oBACL,GAAG,EAAE,qDAAqD;oBAC1D,IAAI,EAAE,sEAAsE;iBAC7E,CAAC;YACJ,CAAC;YACD,OAAO;gBACL,GAAG,EAAE,UAAU,IAAI,gBAAgB;gBACnC,IAAI,EAAE,4FAA4F;aACnG,CAAC;QACJ,KAAK,GAAG;YACN,OAAO;gBACL,GAAG,EAAE,UAAU,IAAI,qBAAqB;gBACxC,IAAI,EAAE,qIAAqI;aAC5I,CAAC;QACJ,KAAK,GAAG;YACN,OAAO;gBACL,GAAG,EAAE,sBAAsB,CAAC,CAAC,CAAC,QAAQ,EAAE,MAAM,CAAC,IAAI,UAAU,IAAI,CAAC,CAAC,OAAO;gBAC1E,IAAI,EAAE,kHAAkH;aACzH,CAAC;QACJ,KAAK,GAAG;YACN,OAAO;gBACL,GAAG,EAAE,0BAA0B;gBAC/B,IAAI,EAAE,2FAA2F;aAClG,CAAC;QACJ,KAAK,GAAG,CAAC;QACT,KAAK,CAAC;YACJ,OAAO;gBACL,GAAG,EAAE,CAAC,CAAC,OAAO;gBACd,IAAI,EAAE,0FAA0F;aACjG,CAAC;QACJ;YACE,IAAI,CAAC,CAAC,UAAU,IAAI,GAAG,EAAE,CAAC;gBACxB,OAAO;oBACL,GAAG,EAAE,UAAU,IAAI,CAAC,CAAC,OAAO;oBAC5B,IAAI,EAAE,gGAAgG;iBACvG,CAAC;YACJ,CAAC;YACD,OAAO;gBACL,GAAG,EAAE,UAAU,IAAI,CAAC,CAAC,OAAO;gBAC5B,IAAI,EAAE,oFAAoF;aAC3F,CAAC;IACN,CAAC;AACH,CAAC"}
1
+ {"version":3,"file":"hint-map.js","sourceRoot":"","sources":["../../src/errors/hint-map.ts"],"names":[],"mappings":"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"}
package/dist/registry.js CHANGED
@@ -21,6 +21,7 @@ import { scheduledTaskModule } from './commands/scheduled-task/index.js';
21
21
  import { chatModule } from './commands/chat/index.js';
22
22
  import { fileModule } from './commands/file/index.js';
23
23
  import { storageModule } from './commands/storage/index.js';
24
+ import { workspaceModule } from './commands/workspace/index.js';
24
25
  import { attachmentModule } from './commands/attachment/index.js';
25
26
  import { skillModule } from './commands/skill/index.js';
26
27
  export const CATEGORIES = [
@@ -38,6 +39,7 @@ export const CATEGORIES = [
38
39
  chatModule,
39
40
  fileModule,
40
41
  storageModule,
42
+ workspaceModule,
41
43
  attachmentModule,
42
44
  siteCredentialModule,
43
45
  previewConfigModule,
@@ -1 +1 @@
1
- {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA4BH,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qCAAqC,CAAC;AAC3E,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAExD,MAAM,CAAC,MAAM,UAAU,GAAqB;IAC1C,UAAU;IACV,aAAa;IACb,WAAW;IACX,UAAU;IACV,gBAAgB;IAChB,UAAU;IACV,eAAe;IACf,cAAc;IACd,UAAU;IACV,cAAc;IACd,mBAAmB;IACnB,UAAU;IACV,UAAU;IACV,aAAa;IACb,gBAAgB;IAChB,oBAAoB;IACpB,mBAAmB;IACnB,WAAW;IACX,SAAS;CACV,CAAC"}
1
+ {"version":3,"file":"registry.js","sourceRoot":"","sources":["../src/registry.ts"],"names":[],"mappings":"AAAA;;;;;GAKG;AA4BH,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AACxD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,SAAS,EAAE,MAAM,yBAAyB,CAAC;AACpD,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAC;AACnE,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,oBAAoB,EAAE,MAAM,qCAAqC,CAAC;AAC3E,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,EAAE,cAAc,EAAE,MAAM,8BAA8B,CAAC;AAC9D,OAAO,EAAE,mBAAmB,EAAE,MAAM,oCAAoC,CAAC;AACzE,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,UAAU,EAAE,MAAM,0BAA0B,CAAC;AACtD,OAAO,EAAE,aAAa,EAAE,MAAM,6BAA6B,CAAC;AAC5D,OAAO,EAAE,eAAe,EAAE,MAAM,+BAA+B,CAAC;AAChE,OAAO,EAAE,gBAAgB,EAAE,MAAM,gCAAgC,CAAC;AAClE,OAAO,EAAE,WAAW,EAAE,MAAM,2BAA2B,CAAC;AAExD,MAAM,CAAC,MAAM,UAAU,GAAqB;IAC1C,UAAU;IACV,aAAa;IACb,WAAW;IACX,UAAU;IACV,gBAAgB;IAChB,UAAU;IACV,eAAe;IACf,cAAc;IACd,UAAU;IACV,cAAc;IACd,mBAAmB;IACnB,UAAU;IACV,UAAU;IACV,aAAa;IACb,eAAe;IACf,gBAAgB;IAChB,oBAAoB;IACpB,mBAAmB;IACnB,WAAW;IACX,SAAS;CACV,CAAC"}
@@ -29,4 +29,33 @@ export function buildFileFormData(filePath, fields = {}) {
29
29
  }
30
30
  return form;
31
31
  }
32
+ /**
33
+ * 複数ファイルを `files[]` / `paths[]` として積む(workspace upload の API 仕様)。
34
+ *
35
+ * `paths[i]` はファイル名込みのフル相対パスで、`files[i]` と同順・同数でなければならない。
36
+ * 添付名は `basename(paths[i])` と一致させる(食い違うとサーバーが 422
37
+ * `path_filename_mismatch` を返す — 意図した場所に違う名前で置かれる事故を防ぐため)。
38
+ *
39
+ * @param basePath ワークスペース内のベースディレクトリ(空ならルート直下)
40
+ */
41
+ export function buildFilesFormData(files, basePath = '') {
42
+ const form = new FormData();
43
+ for (const file of files) {
44
+ let buffer;
45
+ try {
46
+ buffer = readFileSync(file.absolute);
47
+ }
48
+ catch (e) {
49
+ throw new ValidationError(`File not found or unreadable: ${file.absolute} (${e.message})`);
50
+ }
51
+ const name = basename(file.path);
52
+ const blob = new Blob([new Uint8Array(buffer)], { type: getMimeType(name) });
53
+ form.append('files[]', blob, name);
54
+ form.append('paths[]', file.path);
55
+ }
56
+ if (basePath !== '') {
57
+ form.append('path', basePath);
58
+ }
59
+ return form;
60
+ }
32
61
  //# sourceMappingURL=upload.js.map
@@ -1 +1 @@
1
- {"version":3,"file":"upload.js","sourceRoot":"","sources":["../../src/utils/upload.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE9C;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAC/B,QAAgB,EAChB,SAAsD,EAAE;IAExD,IAAI,MAAc,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IAClC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,IAAI,eAAe,CAAC,iCAAiC,QAAQ,KAAM,CAAW,CAAC,OAAO,GAAG,CAAC,CAAC;IACnG,CAAC;IACD,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAChC,MAAM,IAAI,GAAG,IAAI,QAAQ,EAAE,CAAC;IAC5B,0EAA0E;IAC1E,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC7E,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAChC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YAC1C,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAClC,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
1
+ {"version":3,"file":"upload.js","sourceRoot":"","sources":["../../src/utils/upload.ts"],"names":[],"mappings":"AAAA;;GAEG;AAEH,OAAO,EAAE,YAAY,EAAE,MAAM,SAAS,CAAC;AACvC,OAAO,EAAE,QAAQ,EAAE,MAAM,WAAW,CAAC;AACrC,OAAO,EAAE,eAAe,EAAE,MAAM,oBAAoB,CAAC;AACrD,OAAO,EAAE,WAAW,EAAE,MAAM,iBAAiB,CAAC;AAE9C;;;GAGG;AACH,MAAM,UAAU,iBAAiB,CAC/B,QAAgB,EAChB,SAAsD,EAAE;IAExD,IAAI,MAAc,CAAC;IACnB,IAAI,CAAC;QACH,MAAM,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;IAClC,CAAC;IAAC,OAAO,CAAC,EAAE,CAAC;QACX,MAAM,IAAI,eAAe,CAAC,iCAAiC,QAAQ,KAAM,CAAW,CAAC,OAAO,GAAG,CAAC,CAAC;IACnG,CAAC;IACD,MAAM,IAAI,GAAG,QAAQ,CAAC,QAAQ,CAAC,CAAC;IAChC,MAAM,IAAI,GAAG,IAAI,QAAQ,EAAE,CAAC;IAC5B,0EAA0E;IAC1E,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC7E,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;IAChC,KAAK,MAAM,CAAC,GAAG,EAAE,KAAK,CAAC,IAAI,MAAM,CAAC,OAAO,CAAC,MAAM,CAAC,EAAE,CAAC;QAClD,IAAI,KAAK,KAAK,SAAS,IAAI,KAAK,KAAK,IAAI,EAAE,CAAC;YAC1C,IAAI,CAAC,MAAM,CAAC,GAAG,EAAE,MAAM,CAAC,KAAK,CAAC,CAAC,CAAC;QAClC,CAAC;IACH,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC;AAED;;;;;;;;GAQG;AACH,MAAM,UAAU,kBAAkB,CAChC,KAAgD,EAChD,QAAQ,GAAG,EAAE;IAEb,MAAM,IAAI,GAAG,IAAI,QAAQ,EAAE,CAAC;IAC5B,KAAK,MAAM,IAAI,IAAI,KAAK,EAAE,CAAC;QACzB,IAAI,MAAc,CAAC;QACnB,IAAI,CAAC;YACH,MAAM,GAAG,YAAY,CAAC,IAAI,CAAC,QAAQ,CAAC,CAAC;QACvC,CAAC;QAAC,OAAO,CAAC,EAAE,CAAC;YACX,MAAM,IAAI,eAAe,CACvB,iCAAiC,IAAI,CAAC,QAAQ,KAAM,CAAW,CAAC,OAAO,GAAG,CAC3E,CAAC;QACJ,CAAC;QACD,MAAM,IAAI,GAAG,QAAQ,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QACjC,MAAM,IAAI,GAAG,IAAI,IAAI,CAAC,CAAC,IAAI,UAAU,CAAC,MAAM,CAAC,CAAC,EAAE,EAAE,IAAI,EAAE,WAAW,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;QAC7E,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,EAAE,IAAI,CAAC,CAAC;QACnC,IAAI,CAAC,MAAM,CAAC,SAAS,EAAE,IAAI,CAAC,IAAI,CAAC,CAAC;IACpC,CAAC;IACD,IAAI,QAAQ,KAAK,EAAE,EAAE,CAAC;QACpB,IAAI,CAAC,MAAM,CAAC,MAAM,EAAE,QAAQ,CAAC,CAAC;IAChC,CAAC;IACD,OAAO,IAAI,CAAC;AACd,CAAC"}
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "harvask-cli",
3
- "version": "0.4.0",
3
+ "version": "0.6.0",
4
4
  "description": "Command-line client for a harvask tenant, built for coding agents",
5
5
  "type": "module",
6
6
  "bin": {
@@ -40,6 +40,12 @@ If a command fails with an auth error (exit code 3), run `harvask login` again.
40
40
  harvask issue assign -p PRJ 1234 --assignee-id 42
41
41
  ```
42
42
 
43
+ ## Migrating an existing project
44
+
45
+ Bringing a local directory (or another tool's export) into a harvask project has its own
46
+ rules — where files should go, what must never be uploaded, and why a live session blocks
47
+ writes. Read `migration.md` in this skill directory before pushing anything.
48
+
43
49
  ## project key vs id
44
50
 
45
51
  - Humans know the **key** (e.g. `PRJ`); the API uses a numeric **id**.
@@ -127,9 +133,10 @@ harvask issue bulk-create | bulk-update (--items @file.json [--atomic])
127
133
  harvask wiki list | show | create | update (--base-version required) | search | set-home | history | delete | bulk-create | bulk-update
128
134
  harvask milestone list | create | update
129
135
  harvask workflow list | show | create | update | execute (non-idempotent, --yes required non-interactively)
130
- harvask scheduled-task list | show | create | update | delete
136
+ harvask scheduled-task list | show | create | update | execute (non-idempotent, --yes required non-interactively) | delete
131
137
  harvask file search | stats
132
- harvask storage list | search | stats | upload | folder | move | rename | delete | download | content
138
+ harvask storage list | search | stats | upload (--on-conflict rename|overwrite|error) | folder | move | rename | delete | download | content
139
+ harvask workspace push <dir> (--dest, --dry-run, --exclude) # local tree -> AI workspace
133
140
  harvask preview-config show | update
134
141
  harvask site-credential # list browser credentials
135
142
 
@@ -148,5 +155,14 @@ Notes:
148
155
  - `personal-wiki` is intentionally not available via the CLI.
149
156
  - File/binary: `storage upload` / `attachment upload` take `--file <path>`;
150
157
  `storage download` / `attachment download` save with `--out <path>`.
158
+ `attachment upload --type chat_message` also needs `--chat-id <id>`.
159
+ - `project create --key` is optional; without it the server derives a unique key
160
+ from `--name`.
161
+ - `scheduled-task` has three execution types: `issue`, `workflow` and `chat`
162
+ (`--chat-message` is the body, required for chat). `update` changes only the
163
+ fields you pass, including the schedule (`--frequency` / `--time` /
164
+ `--day-of-week` / `--day-of-month` / `--cron`). Fields that do not belong to
165
+ the resulting execution type are rejected by the CLI, because the server
166
+ silently drops them.
151
167
 
152
168
  Use `harvask <command> --help` for options, examples, and prerequisites.
@@ -40,6 +40,12 @@ If a command fails with an auth error (exit code 3), run `harvask login` again.
40
40
  harvask issue assign -p PRJ 1234 --assignee-id 42
41
41
  ```
42
42
 
43
+ ## Migrating an existing project
44
+
45
+ Bringing a local directory (or another tool's export) into a harvask project has its own
46
+ rules — where files should go, what must never be uploaded, and why a live session blocks
47
+ writes. Read `migration.md` in this skill directory before pushing anything.
48
+
43
49
  ## project key vs id
44
50
 
45
51
  - Humans know the **key** (e.g. `PRJ`); the API uses a numeric **id**.
@@ -127,9 +133,10 @@ harvask issue bulk-create | bulk-update (--items @file.json [--atomic])
127
133
  harvask wiki list | show | create | update (--base-version required) | search | set-home | history | delete | bulk-create | bulk-update
128
134
  harvask milestone list | create | update
129
135
  harvask workflow list | show | create | update | execute (non-idempotent, --yes required non-interactively)
130
- harvask scheduled-task list | show | create | update | delete
136
+ harvask scheduled-task list | show | create | update | execute (non-idempotent, --yes required non-interactively) | delete
131
137
  harvask file search | stats
132
- harvask storage list | search | stats | upload | folder | move | rename | delete | download | content
138
+ harvask storage list | search | stats | upload (--on-conflict rename|overwrite|error) | folder | move | rename | delete | download | content
139
+ harvask workspace push <dir> (--dest, --dry-run, --exclude) # local tree -> AI workspace
133
140
  harvask preview-config show | update
134
141
  harvask site-credential # list browser credentials
135
142
 
@@ -148,5 +155,14 @@ Notes:
148
155
  - `personal-wiki` is intentionally not available via the CLI.
149
156
  - File/binary: `storage upload` / `attachment upload` take `--file <path>`;
150
157
  `storage download` / `attachment download` save with `--out <path>`.
158
+ `attachment upload --type chat_message` also needs `--chat-id <id>`.
159
+ - `project create --key` is optional; without it the server derives a unique key
160
+ from `--name`.
161
+ - `scheduled-task` has three execution types: `issue`, `workflow` and `chat`
162
+ (`--chat-message` is the body, required for chat). `update` changes only the
163
+ fields you pass, including the schedule (`--frequency` / `--time` /
164
+ `--day-of-week` / `--day-of-month` / `--cron`). Fields that do not belong to
165
+ the resulting execution type are rejected by the CLI, because the server
166
+ silently drops them.
151
167
 
152
168
  Use `harvask <command> --help` for options, examples, and prerequisites.
@@ -43,6 +43,12 @@ If a command fails with an auth error (exit code 3), run `harvask login` again.
43
43
  harvask issue assign -p PRJ 1234 --assignee-id 42
44
44
  ```
45
45
 
46
+ ## Migrating an existing project
47
+
48
+ Bringing a local directory (or another tool's export) into a harvask project has its own
49
+ rules — where files should go, what must never be uploaded, and why a live session blocks
50
+ writes. Read `migration.md` in this skill directory before pushing anything.
51
+
46
52
  ## project key vs id
47
53
 
48
54
  - Humans know the **key** (e.g. `PRJ`); the API uses a numeric **id**.
@@ -130,9 +136,10 @@ harvask issue bulk-create | bulk-update (--items @file.json [--atomic])
130
136
  harvask wiki list | show | create | update (--base-version required) | search | set-home | history | delete | bulk-create | bulk-update
131
137
  harvask milestone list | create | update
132
138
  harvask workflow list | show | create | update | execute (non-idempotent, --yes required non-interactively)
133
- harvask scheduled-task list | show | create | update | delete
139
+ harvask scheduled-task list | show | create | update | execute (non-idempotent, --yes required non-interactively) | delete
134
140
  harvask file search | stats
135
- harvask storage list | search | stats | upload | folder | move | rename | delete | download | content
141
+ harvask storage list | search | stats | upload (--on-conflict rename|overwrite|error) | folder | move | rename | delete | download | content
142
+ harvask workspace push <dir> (--dest, --dry-run, --exclude) # local tree -> AI workspace
136
143
  harvask preview-config show | update
137
144
  harvask site-credential # list browser credentials
138
145
 
@@ -151,5 +158,14 @@ Notes:
151
158
  - `personal-wiki` is intentionally not available via the CLI.
152
159
  - File/binary: `storage upload` / `attachment upload` take `--file <path>`;
153
160
  `storage download` / `attachment download` save with `--out <path>`.
161
+ `attachment upload --type chat_message` also needs `--chat-id <id>`.
162
+ - `project create --key` is optional; without it the server derives a unique key
163
+ from `--name`.
164
+ - `scheduled-task` has three execution types: `issue`, `workflow` and `chat`
165
+ (`--chat-message` is the body, required for chat). `update` changes only the
166
+ fields you pass, including the schedule (`--frequency` / `--time` /
167
+ `--day-of-week` / `--day-of-month` / `--cron`). Fields that do not belong to
168
+ the resulting execution type are rejected by the CLI, because the server
169
+ silently drops them.
154
170
 
155
171
  Use `harvask <command> --help` for options, examples, and prerequisites.
@@ -0,0 +1,72 @@
1
+ # Migrating an existing local project into harvask
2
+
3
+ Use this when someone wants to bring a project that lives on their machine (or in another
4
+ tool) into a harvask project: source trees, design docs, spreadsheets, legacy assets.
5
+
6
+ ## First: pick the destination. They are not interchangeable.
7
+
8
+ | What you have | Where it goes | How |
9
+ |---|---|---|
10
+ | Code in a git repository | **Keep it in git.** Link the repo in the project settings (Web UI: Settings > Repository) | No migration needed — AI sessions clone it |
11
+ | Files the AI should work on directly: docs, data, assets, legacy scripts, a non-git tree | **AI workspace** (Files tab = `~/work` in AI sessions) | `harvask workspace push` |
12
+ | Reference documents people will search and share | **Storage** | `harvask storage upload` |
13
+ | Knowledge that should be read, edited and versioned as text | **Wiki** | `harvask wiki create` / `global-wiki` |
14
+
15
+ If the answer is "code that is already in git", say so and stop — pushing a clone into the
16
+ workspace duplicates it and the copies drift apart.
17
+
18
+ ## Workspace push
19
+
20
+ ```bash
21
+ harvask workspace push ./legacy-app -p PRJ --dest legacy --dry-run # plan only, sends nothing
22
+ harvask workspace push ./legacy-app -p PRJ --dest legacy --yes # do it
23
+ ```
24
+
25
+ Always run `--dry-run` first and show the plan (`would_create` / `would_overwrite` /
26
+ `skipped` / `excluded`) before sending anything. Overwrites are silent and there is no
27
+ version history, so `--yes` is required to overwrite in a non-interactive shell.
28
+
29
+ ### Rules that bite
30
+
31
+ - **Never push `.env` or credentials.** The CLI excludes `.env*` and cannot be told
32
+ otherwise, because the workspace is visible to every project member. If secrets are
33
+ needed by the AI, use project secrets (Web UI), not files.
34
+ - `.gitignore` is respected when the directory is a git repo (the CLI lets `git ls-files`
35
+ enumerate, so `.git/info/exclude` and your global gitignore count too). `node_modules/`,
36
+ `vendor/`, `dist/`, `build/`, `__pycache__/`, `.venv/`, `.DS_Store` are excluded by
37
+ default; `--include-ignored` (everything) or `--include <glob>` (one path) brings them
38
+ back. `--exclude <glob>` wins over `--include`.
39
+ - Windows binaries and scripts (`.exe .bat .cmd .ps1 .vbs .com .msi .dll`) cannot be
40
+ stored. They are reported as `skipped`, not treated as an error. `.sh` is allowed, but
41
+ the workspace has no execute bit — run it as `sh script.sh`.
42
+ - Do not push into `apps/` or `canvas/`. Mini-app sources plus their SQLite data and
43
+ Canvas documents live there; overwriting them breaks the running app. The CLI refuses
44
+ unless `--force`, and you should ask the user before reaching for it.
45
+ - Symlinks are not followed (reported as `excluded`), and empty directories are not
46
+ reproduced (object storage has no directories).
47
+
48
+ ### When it stops
49
+
50
+ - **409 `workspace_session_active`** — a mini-app or browser-agent session is live for
51
+ that project. Do **not** retry: while a session runs, the workspace is synced from the
52
+ session and anything you upload is silently rolled back. End the session, then push.
53
+ - **Invalid paths** — the dry run reports them and the CLI refuses to send. Those paths
54
+ can never be stored (`..`, empty segments, deeper than 20 levels); one bad path fails a
55
+ whole request, so fix or drop them.
56
+ - **Partial failure** — batches are not atomic. The result JSON lists `remaining`; re-run
57
+ the same command to continue. Re-uploading is safe: same path = overwrite.
58
+ - **413 / timeouts** on a slow link — send less per request with
59
+ `--max-batch-bytes 52428800` and re-run; what already landed is not sent again.
60
+
61
+ ## After the files land
62
+
63
+ Migration is not finished when the bytes arrive. Leave the AI something to work from:
64
+
65
+ 1. Tell the user what landed and where (`--dest` path), and what was skipped or excluded.
66
+ 2. Write down what the project is, how it runs, and what is missing — a project Wiki page
67
+ (`harvask wiki create -p PRJ`) is the right home; the AI reads it before working.
68
+ 3. If the migration exists to get work done, file the first issue
69
+ (`harvask issue create -p PRJ`) describing that work.
70
+
71
+ Check the result in the Files tab (`/projects/{id}/files`) or with a fresh `--dry-run`:
72
+ everything should now report as `would_overwrite`, nothing as `would_create`.