Skip to content

Commit 9f562ae

Browse files
author
Prompsit CI
committed
Mirror 2b8c398 (2026-03-17)
1 parent bcf84d5 commit 9f562ae

19 files changed

Lines changed: 338 additions & 101 deletions

.github/pull_request_template.md

Lines changed: 22 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,22 @@
1+
## What
2+
3+
<!-- Brief description of what this PR does. -->
4+
5+
## Why
6+
7+
<!-- Motivation: what problem does this solve? -->
8+
9+
## How
10+
11+
<!-- Key implementation details, trade-offs. -->
12+
13+
## Checklist
14+
15+
- [ ] `npm run lint:all` passes
16+
- [ ] `npm run test` passes
17+
- [ ] Changes follow [CONTRIBUTING.md](CONTRIBUTING.md) guidelines
18+
- [ ] Documentation updated (if applicable)
19+
20+
## Related Issues
21+
22+
<!-- Closes #123, Related to #456 -->

.github/workflows/ci.yml

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
name: CI
2+
3+
on:
4+
push:
5+
branches: [main]
6+
pull_request:
7+
branches: [main]
8+
9+
permissions:
10+
contents: read
11+
12+
jobs:
13+
check:
14+
name: Lint & Test
15+
runs-on: ubuntu-latest
16+
steps:
17+
- uses: actions/checkout@v4
18+
19+
- uses: actions/setup-node@v4
20+
with:
21+
node-version: 22
22+
cache: npm
23+
24+
- run: npm ci
25+
26+
- name: Typecheck
27+
run: npm run typecheck
28+
29+
- name: Lint
30+
run: npm run lint
31+
32+
- name: Format check
33+
run: npm run format:check
34+
35+
- name: Unit tests
36+
run: npm run test:unit
37+
38+
- name: Build
39+
run: npm run build

.github/workflows/publish.yml

Lines changed: 41 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,41 @@
1+
name: Publish
2+
3+
on:
4+
release:
5+
types: [published]
6+
7+
permissions:
8+
contents: read
9+
10+
jobs:
11+
publish:
12+
name: Publish to npm
13+
runs-on: ubuntu-latest
14+
permissions:
15+
contents: read
16+
id-token: write
17+
steps:
18+
- uses: actions/checkout@v4
19+
20+
- uses: actions/setup-node@v4
21+
with:
22+
node-version: 22
23+
registry-url: https://registry.npmjs.org
24+
cache: npm
25+
26+
- run: npm ci
27+
28+
- name: Typecheck
29+
run: npm run typecheck
30+
31+
- name: Unit tests
32+
run: npm run test:unit
33+
34+
- run: npm run build
35+
36+
- name: Set version from release tag
37+
run: npm version --no-git-tag-version "${GITHUB_REF_NAME#v}" --allow-same-version
38+
39+
- run: npm publish --provenance
40+
env:
41+
NODE_AUTH_TOKEN: ${{ secrets.NPM_TOKEN }}

README.md

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,11 @@
11
# Prompsit CLI
22

3+
[![CI](https://github.com/Prompsit/prompsit-cli/actions/workflows/ci.yml/badge.svg)](https://github.com/Prompsit/prompsit-cli/actions/workflows/ci.yml)
34
[![npm version](https://img.shields.io/npm/v/prompsit-cli)](https://www.npmjs.com/package/prompsit-cli)
45
[![license](https://img.shields.io/npm/l/prompsit-cli)](https://www.npmjs.com/package/prompsit-cli)
56
[![node](https://img.shields.io/node/v/prompsit-cli)](https://nodejs.org/)
67

7-
One CLI for many services from the Prompsit API. Translate text and documents, evaluate translation quality, score parallel corpora with Bicleaner-AI, and annotate monolingual data with Monotextor — from your terminal or an interactive REPL.
8+
One CLI for the entire Prompsit Translation API. Translate text and documents, evaluate translation quality, score parallel corpora with Bicleaner-AI, and annotate monolingual data with Monotextor — from your terminal or an interactive REPL.
89

910
## Quick Start
1011

package-lock.json

Lines changed: 2 additions & 2 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

src/api/auth-session.ts

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,10 @@
33
// Pattern: public fallback -> proactive refresh -> request -> reactive 401 retry
44

55
import type { Method, Options as GotOptions } from "got";
6+
import type { Progress } from "./transport.ts";
67
import type { HttpTransport, RawResponse } from "./transport.ts";
8+
9+
export type { Progress } from "./transport.ts";
710
import { AuthResource } from "./resources/auth.ts";
811
import { AuthenticationError, NetworkError, ServerError } from "./errors.ts";
912
import {
@@ -43,10 +46,12 @@ export class AuthSession {
4346
method: Method,
4447
url: string,
4548
options: Partial<GotOptions> = {},
46-
signal?: AbortSignal
49+
signal?: AbortSignal,
50+
onUploadProgress?: (progress: Progress) => void
4751
): Promise<T> {
4852
return this.withAuth(
49-
(publicFlag, sig) => this.transport.request<T>(method, url, options, publicFlag, sig),
53+
(publicFlag, sig) =>
54+
this.transport.request<T>(method, url, options, publicFlag, sig, onUploadProgress),
5055
signal
5156
);
5257
}
@@ -70,11 +75,20 @@ export class AuthSession {
7075
url: string,
7176
outputPath: string,
7277
options: Partial<GotOptions> = {},
73-
signal?: AbortSignal
78+
signal?: AbortSignal,
79+
onDownloadProgress?: (progress: Progress) => void
7480
): Promise<string> {
7581
return this.withAuth(
7682
(publicFlag, sig) =>
77-
this.transport.requestToFile(method, url, outputPath, options, publicFlag, sig),
83+
this.transport.requestToFile(
84+
method,
85+
url,
86+
outputPath,
87+
options,
88+
publicFlag,
89+
sig,
90+
onDownloadProgress
91+
),
7892
signal
7993
);
8094
}

src/api/resources/data.ts

Lines changed: 19 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -4,7 +4,7 @@
44

55
import { openAsBlob } from "node:fs";
66
import { basename } from "node:path";
7-
import type { AuthSession } from "../auth-session.ts";
7+
import type { AuthSession, Progress } from "../auth-session.ts";
88
import {
99
DataJobCreateResponseSchema,
1010
type DataJobCreateResponse,
@@ -35,7 +35,10 @@ export class DataResource {
3535
* @param params - Annotation parameters (file, lang, pipeline, optional filters)
3636
* @returns DataJobCreateResponse with job_id for tracking
3737
*/
38-
async annotate(params: AnnotateParams): Promise<DataJobCreateResponse> {
38+
async annotate(
39+
params: AnnotateParams,
40+
onUploadProgress?: (progress: Progress) => void
41+
): Promise<DataJobCreateResponse> {
3942
const { filePath, lang, pipeline, minLen, minAvgWords, lidModel } = params;
4043
const fileBlob = await openAsBlob(filePath);
4144
const fileName = basename(filePath);
@@ -51,7 +54,9 @@ export class DataResource {
5154
const data = await this.session.request<unknown>(
5255
"POST",
5356
`${this.baseUrl}${Endpoint.DATA_ANNOTATE}`,
54-
{ body: formData }
57+
{ body: formData },
58+
undefined,
59+
onUploadProgress
5560
);
5661

5762
return DataJobCreateResponseSchema.parse(data);
@@ -70,7 +75,10 @@ export class DataResource {
7075
* @throws ZodError if response schema mismatch
7176
* @throws APIError on API errors
7277
*/
73-
async score(params: ScoreParams): Promise<DataJobCreateResponse> {
78+
async score(
79+
params: ScoreParams,
80+
onUploadProgress?: (progress: Progress) => void
81+
): Promise<DataJobCreateResponse> {
7482
const { sourceFile, targetFile, outputFormat, sourceLang } = params;
7583
const baseUrl = this.baseUrl;
7684
const sourceBlob = await openAsBlob(sourceFile);
@@ -91,9 +99,13 @@ export class DataResource {
9199
formData.append("source_lang", sourceLang);
92100
}
93101

94-
const data = await this.session.request<unknown>("POST", `${baseUrl}${Endpoint.DATA_SCORE}`, {
95-
body: formData,
96-
});
102+
const data = await this.session.request<unknown>(
103+
"POST",
104+
`${baseUrl}${Endpoint.DATA_SCORE}`,
105+
{ body: formData },
106+
undefined,
107+
onUploadProgress
108+
);
97109

98110
return DataJobCreateResponseSchema.parse(data);
99111
}

src/api/resources/jobs.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22
// Used by translate file and data commands for job lifecycle.
33
// All methods go through AuthSession for auth, retry, hooks, and error classification.
44

5-
import type { AuthSession } from "../auth-session.ts";
5+
import type { AuthSession, Progress } from "../auth-session.ts";
66
import { JobStatusResponseSchema, type JobStatusResponse } from "../models.ts";
77
import { Endpoint } from "../../shared/constants.ts";
88

@@ -54,9 +54,14 @@ export class JobsResource {
5454
* @param signal - Optional abort signal for cancellation
5555
* @returns The output path
5656
*/
57-
async download(resultUrl: string, outputPath: string, signal?: AbortSignal): Promise<string> {
57+
async download(
58+
resultUrl: string,
59+
outputPath: string,
60+
signal?: AbortSignal,
61+
onDownloadProgress?: (progress: Progress) => void
62+
): Promise<string> {
5863
const url = `${this.baseUrl}${resultUrl}`;
5964

60-
return this.session.requestToFile("GET", url, outputPath, {}, signal);
65+
return this.session.requestToFile("GET", url, outputPath, {}, signal, onDownloadProgress);
6166
}
6267
}

src/api/resources/translation.ts

Lines changed: 8 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,7 @@
11
// See API-469, API-494: Translation resource - text translation + document upload
22
// Uses AuthSession (authenticated requests with auto-refresh).
33

4-
import type { AuthSession } from "../auth-session.ts";
4+
import type { AuthSession, Progress } from "../auth-session.ts";
55
import {
66
TranslationResponseSchema,
77
type TranslationResponse,
@@ -72,7 +72,10 @@ export class TranslationResource {
7272
* @throws AuthenticationError if not authenticated
7373
* @throws APIError on API errors (422 unsupported format, 413 file too large)
7474
*/
75-
async uploadDocument(params: UploadDocumentParams): Promise<DocJobCreateResponse> {
75+
async uploadDocument(
76+
params: UploadDocumentParams,
77+
onUploadProgress?: (progress: Progress) => void
78+
): Promise<DocJobCreateResponse> {
7679
const { filePath, sourceLang, targetLang, outputFormat } = params;
7780
const baseUrl = this.baseUrl;
7881

@@ -91,7 +94,9 @@ export class TranslationResource {
9194
const data = await this.session.request<unknown>(
9295
"POST",
9396
`${baseUrl}${Endpoint.DOCUMENT_TRANSLATE}`,
94-
{ body: formData }
97+
{ body: formData },
98+
undefined,
99+
onUploadProgress
95100
);
96101

97102
return DocJobCreateResponseSchema.parse(data);

src/api/transport.ts

Lines changed: 18 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -9,6 +9,7 @@ import got, {
99
type Got,
1010
type Method,
1111
type Options as GotOptions,
12+
type Progress,
1213
type Response,
1314
type RetryObject,
1415
HTTPError,
@@ -18,6 +19,8 @@ import got, {
1819
type BeforeErrorHook,
1920
type BeforeRetryHook,
2021
} from "got";
22+
23+
export type { Progress } from "got";
2124
import { getSettings } from "../config/settings.ts";
2225
import { getAccessToken } from "../config/credentials.ts";
2326
import { generateTraceId } from "./trace.ts";
@@ -228,7 +231,8 @@ export class HttpTransport {
228231
url: string,
229232
options: Partial<GotOptions> = {},
230233
publicFlag = false,
231-
signal?: AbortSignal
234+
signal?: AbortSignal,
235+
onUploadProgress?: (progress: Progress) => void
232236
): Promise<T> {
233237
const gotInstance = publicFlag ? this.publicClient : this.client;
234238

@@ -241,7 +245,15 @@ export class HttpTransport {
241245
...(effectiveSignal ? { signal: effectiveSignal } : {}),
242246
} as GotOptions;
243247

244-
const response = (await gotInstance(url, mergedOptions)) as Response<T>;
248+
const request = gotInstance(url, mergedOptions);
249+
// got's CancelableRequest has conflicting .on() overloads (PCancelable + RequestEvents);
250+
// narrow via type assertion to resolve the union.
251+
if (onUploadProgress)
252+
(request as { on(e: "uploadProgress", l: (p: Progress) => void): unknown }).on(
253+
"uploadProgress",
254+
onUploadProgress
255+
);
256+
const response = (await request) as Response<T>;
245257

246258
return response.body;
247259
} catch (error: unknown) {
@@ -299,7 +311,8 @@ export class HttpTransport {
299311
outputPath: string,
300312
options: Partial<GotOptions> = {},
301313
publicFlag = false,
302-
signal?: AbortSignal
314+
signal?: AbortSignal,
315+
onDownloadProgress?: (progress: Progress) => void
303316
): Promise<string> {
304317
const gotInstance = publicFlag ? this.publicClient : this.client;
305318

@@ -311,6 +324,8 @@ export class HttpTransport {
311324
...(effectiveSignal ? { signal: effectiveSignal } : {}),
312325
} as GotOptions & { isStream: true });
313326

327+
if (onDownloadProgress) stream.on("downloadProgress", onDownloadProgress);
328+
314329
const fileStream = createWriteStream(outputPath);
315330
await pipeline(stream, fileStream, ...(effectiveSignal ? [{ signal: effectiveSignal }] : []));
316331

0 commit comments

Comments
 (0)