@lumenkey/cli 0.3.0 → 0.4.0-rc.1
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 +51 -2
- package/dist/cli/copied.js +86 -85
- package/dist/cli/index.js +56 -44
- package/dist/cli/render.js +5 -1
- package/dist/core/asset-stream.d.ts +16 -0
- package/dist/core/asset-stream.js +64 -0
- package/dist/core/atomic-config-file.js +8 -7
- package/dist/core/chinese-messages.d.ts +4 -0
- package/dist/core/chinese-messages.js +907 -0
- package/dist/core/chinese-script.d.ts +7 -0
- package/dist/core/chinese-script.js +28 -0
- package/dist/core/client.js +2 -1
- package/dist/core/config-dir.js +2 -1
- package/dist/core/config.js +7 -6
- package/dist/core/download-root.d.ts +5 -0
- package/dist/core/download-root.js +64 -0
- package/dist/core/download.js +15 -12
- package/dist/core/generation-input.js +3 -2
- package/dist/core/generation.d.ts +8 -1
- package/dist/core/generation.js +13 -10
- package/dist/core/job-display.js +7 -6
- package/dist/core/locale.d.ts +2 -0
- package/dist/core/locale.js +172 -142
- package/dist/core/outcome.d.ts +6 -0
- package/dist/core/outcome.js +17 -4
- package/dist/core/output-path.d.ts +3 -1
- package/dist/core/output-path.js +5 -2
- package/dist/core/params.js +26 -25
- package/dist/core/profiles.js +5 -4
- package/dist/core/set-values.d.ts +0 -1
- package/dist/core/set-values.js +7 -7
- package/dist/core/submission-journal.js +43 -17
- package/dist/core/version.js +2 -3
- package/dist/mcp/server.js +30 -29
- package/dist/studio/asset-integrity-hash.d.ts +28 -0
- package/dist/studio/asset-integrity-hash.js +93 -0
- package/dist/studio/asset-integrity-queue.d.ts +24 -0
- package/dist/studio/asset-integrity-queue.js +94 -0
- package/dist/studio/asset-store.d.ts +52 -0
- package/dist/studio/asset-store.js +352 -0
- package/dist/studio/canvas/LICENSES.txt +1590 -0
- package/dist/studio/canvas/dependencies.json +862 -0
- package/dist/studio/canvas/director-source-manifest.json +47 -0
- package/dist/studio/canvas/editor.css +239 -0
- package/dist/studio/canvas/editor.js +4613 -0
- package/dist/studio/canvas/integration-source-manifest.json +384 -0
- package/dist/studio/canvas/source-manifest.json +240 -0
- package/dist/studio/canvas-store.d.ts +1254 -0
- package/dist/studio/canvas-store.js +205 -0
- package/dist/studio/capture-placement.d.ts +11 -0
- package/dist/studio/capture-placement.js +85 -0
- package/dist/studio/cloud-contract.d.ts +128 -0
- package/dist/studio/cloud-contract.js +229 -0
- package/dist/studio/cloud-service.d.ts +178 -0
- package/dist/studio/cloud-service.js +202 -0
- package/dist/studio/director-captures.d.ts +59 -0
- package/dist/studio/director-captures.js +141 -0
- package/dist/studio/director-contract.d.ts +1489 -0
- package/dist/studio/director-contract.js +288 -0
- package/dist/studio/director-png.d.ts +6 -0
- package/dist/studio/director-png.js +41 -0
- package/dist/studio/director-relations.d.ts +40 -0
- package/dist/studio/director-relations.js +103 -0
- package/dist/studio/document-authority.d.ts +7 -0
- package/dist/studio/document-authority.js +50 -0
- package/dist/studio/draft-store.d.ts +95 -0
- package/dist/studio/draft-store.js +100 -0
- package/dist/studio/errors.d.ts +85 -0
- package/dist/studio/errors.js +94 -0
- package/dist/studio/launch.d.ts +5 -0
- package/dist/studio/launch.js +31 -0
- package/dist/studio/media.d.ts +9 -0
- package/dist/studio/media.js +50 -0
- package/dist/studio/output-save-contract.d.ts +1321 -0
- package/dist/studio/output-save-contract.js +26 -0
- package/dist/studio/output-save-journal.d.ts +971 -0
- package/dist/studio/output-save-journal.js +287 -0
- package/dist/studio/output-save-recovery.d.ts +18 -0
- package/dist/studio/output-save-recovery.js +161 -0
- package/dist/studio/output-save-service.d.ts +436 -0
- package/dist/studio/output-save-service.js +251 -0
- package/dist/studio/output-save-worker.d.ts +40 -0
- package/dist/studio/output-save-worker.js +360 -0
- package/dist/studio/paths.d.ts +6 -0
- package/dist/studio/paths.js +68 -0
- package/dist/studio/run-journal.d.ts +993 -0
- package/dist/studio/run-journal.js +125 -0
- package/dist/studio/server.d.ts +17 -0
- package/dist/studio/server.js +440 -0
- package/dist/studio/session.d.ts +6 -0
- package/dist/studio/session.js +26 -0
- package/dist/studio/shell.d.ts +3 -0
- package/dist/studio/shell.js +23 -0
- package/dist/studio/style.d.ts +2 -0
- package/dist/studio/style.js +29 -0
- package/dist/studio/types.d.ts +26 -0
- package/dist/studio/types.js +2 -0
- package/dist/studio/web/app.d.ts +2 -0
- package/dist/studio/web/app.js +662 -0
- package/dist/studio/web/asset-controller.d.ts +37 -0
- package/dist/studio/web/asset-controller.js +191 -0
- package/dist/studio/web/asset-model.d.ts +29 -0
- package/dist/studio/web/asset-model.js +51 -0
- package/dist/studio/web/controller.d.ts +113 -0
- package/dist/studio/web/controller.js +401 -0
- package/dist/studio/web/messages.d.ts +2 -0
- package/dist/studio/web/messages.js +74 -0
- package/dist/studio/web/model.d.ts +75 -0
- package/dist/studio/web/model.js +182 -0
- package/dist/studio/web/save-controller.d.ts +85 -0
- package/dist/studio/web/save-controller.js +495 -0
- package/dist/studio/web/save-model.d.ts +63 -0
- package/dist/studio/web/save-model.js +64 -0
- package/dist/studio/web/save-queue.d.ts +7 -0
- package/dist/studio/web/save-queue.js +62 -0
- package/dist/studio/web/save-view.d.ts +9 -0
- package/dist/studio/web/save-view.js +19 -0
- package/dist/studio/writer-lock.d.ts +5 -0
- package/dist/studio/writer-lock.js +88 -0
- package/package.json +11 -5
- package/dist/cli/copied.d.ts.map +0 -1
- package/dist/cli/copied.js.map +0 -1
- package/dist/cli/index.d.ts.map +0 -1
- package/dist/cli/index.js.map +0 -1
- package/dist/cli/render.d.ts.map +0 -1
- package/dist/cli/render.js.map +0 -1
- package/dist/core/atomic-config-file.d.ts.map +0 -1
- package/dist/core/atomic-config-file.js.map +0 -1
- package/dist/core/chat.d.ts.map +0 -1
- package/dist/core/chat.js.map +0 -1
- package/dist/core/client.d.ts.map +0 -1
- package/dist/core/client.js.map +0 -1
- package/dist/core/config-dir.d.ts.map +0 -1
- package/dist/core/config-dir.js.map +0 -1
- package/dist/core/config-error.d.ts.map +0 -1
- package/dist/core/config-error.js.map +0 -1
- package/dist/core/config.d.ts.map +0 -1
- package/dist/core/config.js.map +0 -1
- package/dist/core/credit-cap.d.ts.map +0 -1
- package/dist/core/credit-cap.js.map +0 -1
- package/dist/core/download.d.ts.map +0 -1
- package/dist/core/download.js.map +0 -1
- package/dist/core/error-result.d.ts.map +0 -1
- package/dist/core/error-result.js.map +0 -1
- package/dist/core/explain.d.ts.map +0 -1
- package/dist/core/explain.js.map +0 -1
- package/dist/core/generation-input.d.ts.map +0 -1
- package/dist/core/generation-input.js.map +0 -1
- package/dist/core/generation-result.d.ts.map +0 -1
- package/dist/core/generation-result.js.map +0 -1
- package/dist/core/generation.d.ts.map +0 -1
- package/dist/core/generation.js.map +0 -1
- package/dist/core/job-display.d.ts.map +0 -1
- package/dist/core/job-display.js.map +0 -1
- package/dist/core/locale.d.ts.map +0 -1
- package/dist/core/locale.js.map +0 -1
- package/dist/core/origin.d.ts.map +0 -1
- package/dist/core/origin.js.map +0 -1
- package/dist/core/outcome.d.ts.map +0 -1
- package/dist/core/outcome.js.map +0 -1
- package/dist/core/output-path.d.ts.map +0 -1
- package/dist/core/output-path.js.map +0 -1
- package/dist/core/params.d.ts.map +0 -1
- package/dist/core/params.js.map +0 -1
- package/dist/core/poller.d.ts.map +0 -1
- package/dist/core/poller.js.map +0 -1
- package/dist/core/profiles.d.ts.map +0 -1
- package/dist/core/profiles.js.map +0 -1
- package/dist/core/set-values.d.ts.map +0 -1
- package/dist/core/set-values.js.map +0 -1
- package/dist/core/submission-journal.d.ts.map +0 -1
- package/dist/core/submission-journal.js.map +0 -1
- package/dist/core/types.d.ts.map +0 -1
- package/dist/core/types.js.map +0 -1
- package/dist/core/version.d.ts.map +0 -1
- package/dist/core/version.js.map +0 -1
- package/dist/core/wait.d.ts.map +0 -1
- package/dist/core/wait.js.map +0 -1
- package/dist/index.d.ts.map +0 -1
- package/dist/index.js.map +0 -1
- package/dist/mcp/render.d.ts.map +0 -1
- package/dist/mcp/render.js.map +0 -1
- package/dist/mcp/server.d.ts.map +0 -1
- package/dist/mcp/server.js.map +0 -1
package/dist/core/locale.js
CHANGED
|
@@ -1,4 +1,8 @@
|
|
|
1
|
+
import { zhText } from '../core/chinese-messages.js';
|
|
1
2
|
const EN = {
|
|
3
|
+
DOWNLOAD_ROOT_INVALID: 'LUMENKEY_DOWNLOAD_ROOT must be an absolute path.',
|
|
4
|
+
DOWNLOAD_OUTSIDE_ROOT: 'The download target is outside the allowed root or contains parent traversal.',
|
|
5
|
+
DOWNLOAD_UNSAFE_PATH: 'The download path contains an unsafe link or cannot be verified.',
|
|
2
6
|
API_KEY_NOT_CONFIGURED: 'key: not configured. Set LUMENKEY_API_KEY or run lumenkey login.',
|
|
3
7
|
INVALID_API_KEY: 'This key was rejected. Check LUMENKEY_API_KEY or run lumenkey login.',
|
|
4
8
|
MODEL_REQUIRED: 'Choose a model with -m <modelId>.',
|
|
@@ -106,111 +110,114 @@ const EN = {
|
|
|
106
110
|
CLI_COMMAND_FAILED: 'The command failed before it could finish.',
|
|
107
111
|
};
|
|
108
112
|
const ZH = {
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
|
|
112
|
-
|
|
113
|
-
|
|
114
|
-
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
|
|
118
|
-
|
|
119
|
-
|
|
120
|
-
|
|
121
|
-
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
125
|
-
|
|
126
|
-
|
|
127
|
-
|
|
128
|
-
|
|
129
|
-
|
|
130
|
-
|
|
131
|
-
|
|
132
|
-
|
|
133
|
-
|
|
134
|
-
|
|
135
|
-
|
|
136
|
-
|
|
137
|
-
|
|
138
|
-
|
|
139
|
-
|
|
140
|
-
|
|
141
|
-
|
|
142
|
-
|
|
143
|
-
|
|
144
|
-
|
|
145
|
-
|
|
146
|
-
|
|
147
|
-
|
|
148
|
-
|
|
149
|
-
|
|
150
|
-
|
|
151
|
-
|
|
152
|
-
|
|
153
|
-
|
|
154
|
-
|
|
155
|
-
|
|
156
|
-
|
|
157
|
-
|
|
158
|
-
|
|
159
|
-
|
|
160
|
-
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
|
|
166
|
-
|
|
167
|
-
|
|
168
|
-
|
|
169
|
-
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
173
|
-
|
|
174
|
-
|
|
175
|
-
|
|
176
|
-
|
|
177
|
-
|
|
178
|
-
|
|
179
|
-
|
|
180
|
-
|
|
181
|
-
|
|
182
|
-
|
|
183
|
-
|
|
184
|
-
|
|
185
|
-
|
|
186
|
-
|
|
187
|
-
|
|
188
|
-
|
|
189
|
-
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
199
|
-
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
205
|
-
|
|
206
|
-
|
|
207
|
-
|
|
208
|
-
|
|
209
|
-
|
|
210
|
-
|
|
211
|
-
|
|
212
|
-
|
|
213
|
-
|
|
113
|
+
DOWNLOAD_ROOT_INVALID: () => zhText('downloadRootInvalid'),
|
|
114
|
+
DOWNLOAD_OUTSIDE_ROOT: () => zhText('downloadOutsideRoot'),
|
|
115
|
+
DOWNLOAD_UNSAFE_PATH: () => zhText('downloadUnsafePath'),
|
|
116
|
+
API_KEY_NOT_CONFIGURED: () => zhText("m213"),
|
|
117
|
+
INVALID_API_KEY: () => zhText("m212"),
|
|
118
|
+
MODEL_REQUIRED: () => zhText("m211"),
|
|
119
|
+
MODEL_NOT_IN_CATALOG: () => zhText("m210"),
|
|
120
|
+
BASE_URL_INVALID: () => zhText("m209"),
|
|
121
|
+
TRANSPORT_FAILED: () => zhText("m208"),
|
|
122
|
+
PROXY_URL_INVALID: () => zhText("m207"),
|
|
123
|
+
PROXY_PROTOCOL_UNSUPPORTED: () => zhText("m206"),
|
|
124
|
+
CLI_ARGUMENTS_INVALID: () => zhText("m205"),
|
|
125
|
+
HTTP_ERROR: () => zhText("m204"),
|
|
126
|
+
API_REQUEST_FAILED: () => zhText("m204"),
|
|
127
|
+
JOB_ID_INVALID: () => zhText("m203"),
|
|
128
|
+
JOB_NOT_FOUND: () => zhText("m202"),
|
|
129
|
+
CHAT_CREDIT_LIMIT_INVALID: () => zhText("m201"),
|
|
130
|
+
CHAT_CREDIT_LIMIT_EXCEEDED: () => zhText("m200"),
|
|
131
|
+
STREAM_SETTLEMENT_PENDING: () => zhText("m199"),
|
|
132
|
+
STREAM_INPUT_SETTLEMENT_PENDING: () => zhText("m198"),
|
|
133
|
+
STREAM_ALREADY_CONSUMED: () => zhText("m197"),
|
|
134
|
+
IDEMPOTENCY_CONFLICT: () => zhText("m196"),
|
|
135
|
+
IDEMPOTENCY_RESULT_EXPIRED: () => zhText("m195"),
|
|
136
|
+
REQUEST_IN_PROGRESS: () => zhText("m194"),
|
|
137
|
+
INPUT_INVALID: () => zhText("m193"),
|
|
138
|
+
SUBMISSION_RETRY_MISMATCH: () => zhText("m192"),
|
|
139
|
+
SUBMISSION_CREDENTIALS_MISMATCH: () => zhText("m191"),
|
|
140
|
+
SUBMISSION_JOURNAL_UNWRITABLE: () => zhText("m190"),
|
|
141
|
+
SUBMISSION_RECORD_NOT_FOUND: () => zhText("m22"),
|
|
142
|
+
SUBMISSION_PENDING_IDENTICAL: () => zhText("m189"),
|
|
143
|
+
QUOTE_NOT_AVAILABLE: () => zhText("m188"),
|
|
144
|
+
QUOTE_ALREADY_CONSUMED: () => zhText("m187"),
|
|
145
|
+
SUBMISSION_RECORD_EXPIRED: () => zhText("m186"),
|
|
146
|
+
SUBMISSION_JOURNAL_INVALID: () => zhText("m185"),
|
|
147
|
+
IDEMPOTENCY_KEY_REQUIRED: () => zhText("m99"),
|
|
148
|
+
IDEMPOTENCY_KEY_INVALID: () => zhText("m97"),
|
|
149
|
+
IDEMPOTENCY_KEY_TOO_LONG: () => zhText("m98"),
|
|
150
|
+
SDK_STREAM_NOT_IMPLEMENTED: () => zhText("m184"),
|
|
151
|
+
LANG_INVALID: () => zhText("m183"),
|
|
152
|
+
BALANCE_RESPONSE_INVALID: () => zhText("m182"),
|
|
153
|
+
CATALOG_RESPONSE_INVALID: () => zhText("m181"),
|
|
154
|
+
CHAT_BILLING_INVALID: () => zhText("m180"),
|
|
155
|
+
CHAT_EMPTY_RESPONSE: () => zhText("m179"),
|
|
156
|
+
JOB_ID_MISMATCH: () => zhText("m178"),
|
|
157
|
+
JOB_RESPONSE_INVALID: () => zhText("m177"),
|
|
158
|
+
MODEL_INPUT_SCHEMA_INVALID: () => zhText("m176"),
|
|
159
|
+
MODEL_PARAM_INVALID: () => zhText("m175"),
|
|
160
|
+
MODEL_PARAM_ALIAS_CONFLICT: () => zhText("m174"),
|
|
161
|
+
SUBMISSION_INPUT_POLICY_CHANGED: () => zhText("m173"),
|
|
162
|
+
MODEL_PARAM_UNKNOWN: () => zhText("m172"),
|
|
163
|
+
MODEL_PARAM_SYNTAX_INVALID: () => zhText("m171"),
|
|
164
|
+
QUOTE_EXPIRED: () => zhText("m170"),
|
|
165
|
+
QUOTE_RESPONSE_INVALID: () => zhText("m169"),
|
|
166
|
+
QUOTE_CREDIT_LIMIT: () => zhText("m168"),
|
|
167
|
+
REQUEST_TIMEOUT: () => zhText("m167"),
|
|
168
|
+
RESPONSE_JSON_INVALID: () => zhText("m166"),
|
|
169
|
+
RESPONSE_TOO_LARGE: () => zhText("m165"),
|
|
170
|
+
TIMEOUT_INVALID: () => zhText("m164"),
|
|
171
|
+
VIDEO_DURATION_INVALID: () => zhText("m163"),
|
|
172
|
+
WAIT_OPTIONS_INVALID: () => zhText("m162"),
|
|
173
|
+
WAIT_TIMEOUT: () => zhText("m161"),
|
|
174
|
+
UPSTREAM_UNAVAILABLE: () => zhText("m160"),
|
|
175
|
+
UPSTREAM_TIMEOUT: () => zhText("m159"),
|
|
176
|
+
UPSTREAM_INVALID_RESPONSE: () => zhText("m158"),
|
|
177
|
+
STREAM_FAILED: () => zhText("m157"),
|
|
178
|
+
STREAM_ROUTE_NOT_AVAILABLE: () => zhText("m156"),
|
|
179
|
+
STREAM_RUNTIME_UNAVAILABLE: () => zhText("m155"),
|
|
180
|
+
MODEL_NOT_AVAILABLE: () => zhText("m154"),
|
|
181
|
+
CONTENT_REJECTED: () => zhText("m153"),
|
|
182
|
+
IDEMPOTENCY_INPUT_INVALID: () => zhText("m152"),
|
|
183
|
+
CONFIG_INVALID: () => zhText("m151"),
|
|
184
|
+
CONFIG_UNREADABLE: () => zhText("m150"),
|
|
185
|
+
CONFIG_UNSAFE_PATH: () => zhText("m149"),
|
|
186
|
+
CONFIG_NOT_A_FILE: () => zhText("m148"),
|
|
187
|
+
CHAT_REQUEST_INVALID: () => zhText("m147"),
|
|
188
|
+
CANCELLED: () => zhText("m146"),
|
|
189
|
+
ACCOUNT_NOT_ELIGIBLE: () => zhText("m145"),
|
|
190
|
+
CHAT_UPSTREAM_ERROR: () => zhText("m144"),
|
|
191
|
+
UNAUTHORIZED: () => zhText("m143"),
|
|
192
|
+
FORBIDDEN: () => zhText("m142"),
|
|
193
|
+
INSUFFICIENT_CREDITS: () => zhText("m141"),
|
|
194
|
+
NOT_FOUND: () => zhText("m140"),
|
|
195
|
+
RATE_LIMITED: () => zhText("m139"),
|
|
196
|
+
GATEWAY_REDIRECTED: () => zhText("m138"),
|
|
197
|
+
JOB_CANCELLED: () => zhText("m137"),
|
|
198
|
+
JOB_EXPIRED: () => zhText("m136"),
|
|
199
|
+
JOB_OUTPUT_MISSING: () => zhText("m135"),
|
|
200
|
+
JOB_TERMINAL_FAILURE: () => zhText("m134"),
|
|
201
|
+
DOWNLOAD_URL_INVALID: () => zhText("m133"),
|
|
202
|
+
DOWNLOAD_TOO_LARGE: () => zhText("m132"),
|
|
203
|
+
DOWNLOAD_EXISTS: () => zhText("m131"),
|
|
204
|
+
DOWNLOAD_IS_DIRECTORY: () => zhText("m130"),
|
|
205
|
+
DOWNLOAD_NETWORK_ERROR: () => zhText("m129"),
|
|
206
|
+
DOWNLOAD_TIMEOUT: () => zhText("m128"),
|
|
207
|
+
DOWNLOAD_INTERRUPTED: () => zhText("m127"),
|
|
208
|
+
DOWNLOAD_WRITE_ERROR: () => zhText("m126"),
|
|
209
|
+
DOWNLOAD_HTTP_ERROR: () => zhText("m125"),
|
|
210
|
+
DOWNLOAD_PATH_NOT_ABSOLUTE: () => zhText("m124"),
|
|
211
|
+
WAIT_INTERRUPTED: () => zhText("m123"),
|
|
212
|
+
REQUEST_ABORTED: () => zhText("m122"),
|
|
213
|
+
PROFILE_INVALID: () => zhText("m121"),
|
|
214
|
+
PROFILE_UNREADABLE: () => zhText("m120"),
|
|
215
|
+
PROFILE_MISSING: () => zhText("m119"),
|
|
216
|
+
PROFILE_EXISTS: () => zhText("m118"),
|
|
217
|
+
INPUT_CLOSED: () => zhText("m117"),
|
|
218
|
+
CANCEL_CONFIRMATION_REQUIRED: () => zhText("m116"),
|
|
219
|
+
CREDIT_LIMIT_INVALID: () => zhText("m115"),
|
|
220
|
+
CLI_COMMAND_FAILED: () => zhText("m114"),
|
|
214
221
|
};
|
|
215
222
|
export function langFlag(argv = process.argv) {
|
|
216
223
|
const args = argv.slice(2);
|
|
@@ -229,7 +236,7 @@ function primarySubtag(raw) {
|
|
|
229
236
|
return (raw.trim().replace(/-/g, '_').split(/[._@]/)[0] ?? '').toLowerCase();
|
|
230
237
|
}
|
|
231
238
|
function localeLang(env) {
|
|
232
|
-
return primarySubtag(env.LC_ALL || env.LANG || '') === 'en' ? 'en' : 'zh';
|
|
239
|
+
return primarySubtag(env.LC_ALL || env.LC_MESSAGES || env.LANG || '') === 'en' ? 'en' : 'zh';
|
|
233
240
|
}
|
|
234
241
|
/** --lang zh|en, then LUMENKEY_LANG, then LC_ALL / LANG, then zh. Invalid values are ignored here. */
|
|
235
242
|
export function resolveLang(argv = process.argv, env = process.env) {
|
|
@@ -247,22 +254,21 @@ export function hasErrorSentence(code) {
|
|
|
247
254
|
return Object.prototype.hasOwnProperty.call(EN, code);
|
|
248
255
|
}
|
|
249
256
|
export function errorSentence(code, lang = resolveLang()) {
|
|
250
|
-
|
|
251
|
-
return table[code] ?? code;
|
|
257
|
+
return lang === 'zh' ? ZH[code]?.() ?? code : EN[code] ?? code;
|
|
252
258
|
}
|
|
253
259
|
export function transportFailureDetail(baseUrl, lang = resolveLang()) {
|
|
254
260
|
return lang === 'zh'
|
|
255
|
-
?
|
|
261
|
+
? (zhText("m112") + (baseUrl) + zhText("m113"))
|
|
256
262
|
: `Network connection to ${baseUrl} failed. Check the gateway address and connection.`;
|
|
257
263
|
}
|
|
258
264
|
export function proxyTransportDetail(baseUrl, lang = resolveLang()) {
|
|
259
265
|
return lang === 'zh'
|
|
260
|
-
?
|
|
266
|
+
? (zhText("m110") + (baseUrl) + zhText("m111"))
|
|
261
267
|
: `The request to ${baseUrl} failed through HTTP(S)_PROXY or ALL_PROXY. Check that proxy; this is not a gateway-address failure.`;
|
|
262
268
|
}
|
|
263
269
|
export function chatFailureSettlementAdvice(lang = resolveLang()) {
|
|
264
270
|
return lang === 'zh'
|
|
265
|
-
?
|
|
271
|
+
? zhText("m109")
|
|
266
272
|
: 'Settlement was not reported and is unknown; credits may still be reserved. Check your balance and ledger before retrying.';
|
|
267
273
|
}
|
|
268
274
|
const INVISIBLE_PROMPT = /[\p{Cf}\p{Mn}\p{Me}\p{Zs}\p{Zl}\p{Zp}\u115F\u1160\u2800\u3164\uFFA0]/gu;
|
|
@@ -273,23 +279,23 @@ export function isBlankPrompt(value) {
|
|
|
273
279
|
export function textCatalogMissDetail(model, lang = resolveLang()) {
|
|
274
280
|
const shown = JSON.stringify(model);
|
|
275
281
|
return lang === 'zh'
|
|
276
|
-
?
|
|
282
|
+
? (zhText("m107") + (shown) + zhText("m108"))
|
|
277
283
|
: `Model ${shown} is not in your available text catalog. Use an exact model ID.`;
|
|
278
284
|
}
|
|
279
285
|
export function missingModelSentence(name, lang = resolveLang()) {
|
|
280
286
|
return lang === 'zh'
|
|
281
|
-
?
|
|
287
|
+
? (zhText("m105") + (name) + zhText("m106") + (name) + "")
|
|
282
288
|
: `No exact model named ${name}. Run: lumenkey model search ${name}`;
|
|
283
289
|
}
|
|
284
290
|
export function billingSentence(status, credits, lang = resolveLang()) {
|
|
285
291
|
if (lang === 'zh') {
|
|
286
292
|
if (status === 'PENDING')
|
|
287
|
-
return
|
|
293
|
+
return zhText("m104");
|
|
288
294
|
if (status === 'RELEASED')
|
|
289
|
-
return
|
|
295
|
+
return zhText("m103");
|
|
290
296
|
if (status === 'SETTLED')
|
|
291
|
-
return
|
|
292
|
-
return
|
|
297
|
+
return (zhText("m101") + (credits) + zhText("m102"));
|
|
298
|
+
return zhText("m100");
|
|
293
299
|
}
|
|
294
300
|
if (status === 'PENDING')
|
|
295
301
|
return 'Settlement pending; credits may still be reserved.';
|
|
@@ -301,7 +307,7 @@ export function billingSentence(status, credits, lang = resolveLang()) {
|
|
|
301
307
|
}
|
|
302
308
|
export function idempotencyKeyMessages(lang = resolveLang()) {
|
|
303
309
|
return lang === 'zh'
|
|
304
|
-
? { required:
|
|
310
|
+
? { required: zhText("m99"), max: zhText("m98"), breaks: zhText("m97") }
|
|
305
311
|
: {
|
|
306
312
|
required: 'An idempotency key is required.',
|
|
307
313
|
max: 'The idempotency key must be at most 128 bytes.',
|
|
@@ -313,56 +319,80 @@ export function ui(en, zh, lang = resolveLang()) {
|
|
|
313
319
|
}
|
|
314
320
|
export function waitTimeoutDetail(jobId, timeoutMs, lang = resolveLang()) {
|
|
315
321
|
const seconds = timeoutMs / 1000;
|
|
316
|
-
return ui(`Timed out waiting after ${seconds} seconds. The task may still be running; it was not cancelled. Resume with: lumenkey status ${jobId}`,
|
|
322
|
+
return ui(`Timed out waiting after ${seconds} seconds. The task may still be running; it was not cancelled. Resume with: lumenkey status ${jobId}`, (zhText("m95") + (seconds) + zhText("m96") + (jobId) + ""), lang);
|
|
317
323
|
}
|
|
318
324
|
export function waitInterruptedDetail(jobId, lang = resolveLang()) {
|
|
319
|
-
return ui(`${errorSentence('WAIT_INTERRUPTED', 'en')} Resume with: lumenkey status ${jobId}`,
|
|
325
|
+
return ui(`${errorSentence('WAIT_INTERRUPTED', 'en')} Resume with: lumenkey status ${jobId}`, ("" + (errorSentence('WAIT_INTERRUPTED', 'zh')) + zhText("m94") + (jobId) + ""), lang);
|
|
326
|
+
}
|
|
327
|
+
/** Local display only; recovery's machine deadline stays ISO UTC in the outcome. */
|
|
328
|
+
export function submissionUnknownMessage(recovery, deadline, lang = resolveLang()) {
|
|
329
|
+
const head = ui('Submission result unknown; do not retry with different key or input.', zhText("m93"), lang);
|
|
330
|
+
const pad = (value) => String(value).padStart(2, '0');
|
|
331
|
+
let local;
|
|
332
|
+
if (deadline && Number.isFinite(deadline.getTime())) {
|
|
333
|
+
const offset = -deadline.getTimezoneOffset();
|
|
334
|
+
local = `${deadline.getFullYear()}-${pad(deadline.getMonth() + 1)}-${pad(deadline.getDate())} ${pad(deadline.getHours())}:${pad(deadline.getMinutes())} (${offset >= 0 ? '+' : '-'}${pad(Math.floor(Math.abs(offset) / 60))}:${pad(Math.abs(offset) % 60)})`;
|
|
335
|
+
}
|
|
336
|
+
return `${head} ${RECOVERY_COPY[recovery].message(local, lang)}`;
|
|
320
337
|
}
|
|
321
338
|
/** The recovery verb on both surfaces, named wherever a keyless rerun will not do. */
|
|
322
339
|
export function resumeCommandText(idempotencyKey, lang = resolveLang()) {
|
|
323
|
-
return ui(`lumenkey tasks resume ${idempotencyKey} (MCP: lumenkey_resume_submission with idempotencyKey "${idempotencyKey}")`,
|
|
340
|
+
return ui(`lumenkey tasks resume ${idempotencyKey} (MCP: lumenkey_resume_submission with idempotencyKey "${idempotencyKey}")`, ("lumenkey tasks resume " + (idempotencyKey) + zhText("m92") + (idempotencyKey) + "\")"), lang);
|
|
324
341
|
}
|
|
325
342
|
export function submissionUnknownAdvice(idempotencyKey, recovery = 'ledger', recordedAt, lang = resolveLang()) {
|
|
326
|
-
const head = ui('The gateway may already have accepted this job and reserved credits. Do not submit again with a different key.',
|
|
343
|
+
const head = ui('The gateway may already have accepted this job and reserved credits. Do not submit again with a different key.', zhText("m91"), lang);
|
|
327
344
|
const deadline = recordedAt && Number.isFinite(Date.parse(recordedAt)) ? new Date(Date.parse(recordedAt) + 23 * 60 * 60 * 1000).toISOString() : undefined;
|
|
328
|
-
|
|
329
|
-
return `${head} ${ui(`To recover, run the same command again with the same arguments${deadline ? ` before ${deadline} (23 hours after the submission was recorded)` : ''}; the client re-sends this recorded submission and the gateway replays the earlier job or creates it once. You can also run ${resumeCommandText(idempotencyKey, 'en')}, or check your balance and ledger first.`, `恢复方法:${deadline ? `在 ${deadline}(记录后 23 小时)之前` : ''}用相同参数再次运行同一命令,客户端会原样重发这次记录的提交,网关会回放之前的任务或只创建一次。也可以运行 ${resumeCommandText(idempotencyKey, 'zh')},或先核对余额与流水。`, lang)}`;
|
|
330
|
-
if (recovery === 'resume-command')
|
|
331
|
-
return `${head} ${ui(`The recorded submission is still marked in flight, so a plain rerun will not resume it. To recover, run ${resumeCommandText(idempotencyKey, 'en')}; it re-sends the recorded body and the gateway replays the earlier job or creates it once. Or check your balance and ledger first.`, `记录的提交仍标记为进行中,直接重跑不会接续它。恢复方法:运行 ${resumeCommandText(idempotencyKey, 'zh')},它会原样重发记录的请求体,网关会回放之前的任务或只创建一次;也可以先核对余额与流水。`, lang)}`;
|
|
332
|
-
if (recovery === 'expired')
|
|
333
|
-
return `${head} ${ui(`The recorded submission is past the 23-hour window in which it can be re-sent safely, so it will not be resumed. Check your job list and balance before submitting again.`, `记录的提交已超过可安全重发的 23 小时窗口,不会再接续。请先核对任务列表与余额,再决定是否重新提交。`, lang)}`;
|
|
334
|
-
return `${head} ${ui(`No local record of this submission remains (idempotency key ${idempotencyKey}), so it cannot be re-sent from here. Check your job list and balance before submitting again.`, `本机已没有这次提交的记录(幂等键 ${idempotencyKey}),无法从这里重发。请先核对任务列表与余额,再决定是否重新提交。`, lang)}`;
|
|
345
|
+
return `${head} ${RECOVERY_COPY[recovery].advice(idempotencyKey, deadline, lang)}`;
|
|
335
346
|
}
|
|
347
|
+
/** Each recovery state owns both short and compatibility copy: no independent fallthroughs. */
|
|
348
|
+
const RECOVERY_COPY = {
|
|
349
|
+
rerun: {
|
|
350
|
+
message: (local, lang) => ui(`Run the same command again with the same arguments${local ? ` before ${local}` : ''}; or use lumenkey tasks resume <idempotencyKey> (MCP: lumenkey_resume_submission).`, (zhText("m89") + (local ? (zhText("m83") + (local) + "") : '') + zhText("m90")), lang),
|
|
351
|
+
advice: (idempotencyKey, deadline, lang) => ui(`To recover, run the same command again with the same arguments${deadline ? ` before ${deadline} (23 hours after the submission was recorded)` : ''}; the client re-sends this recorded submission and the gateway replays the earlier job or creates it once. You can also run ${resumeCommandText(idempotencyKey, 'en')}, or check your balance and ledger first.`, (zhText("m84") + (deadline ? (zhText("m85") + (deadline) + zhText("m86")) : '') + zhText("m87") + (resumeCommandText(idempotencyKey, 'zh')) + zhText("m88")), lang),
|
|
352
|
+
},
|
|
353
|
+
'resume-command': {
|
|
354
|
+
message: (local, lang) => ui(`Record still in flight; a plain rerun will not resume it. Use lumenkey tasks resume <idempotencyKey> (MCP: lumenkey_resume_submission)${local ? ` before ${local}` : ''}.`, (zhText("m82") + (local ? (zhText("m83") + (local) + "") : '') + "。"), lang),
|
|
355
|
+
advice: (idempotencyKey, _deadline, lang) => ui(`The recorded submission is still marked in flight, so a plain rerun will not resume it. To recover, run ${resumeCommandText(idempotencyKey, 'en')}; it re-sends the recorded body and the gateway replays the earlier job or creates it once. Or check your balance and ledger first.`, (zhText("m80") + (resumeCommandText(idempotencyKey, 'zh')) + zhText("m81")), lang),
|
|
356
|
+
},
|
|
357
|
+
expired: {
|
|
358
|
+
message: (local, lang) => ui(`Past the 23-hour window${local ? ` (${local})` : ''}; check your job list and balance.`, (zhText("m78") + (local ? `(${local})` : '') + zhText("m79")), lang),
|
|
359
|
+
advice: (_idempotencyKey, _deadline, lang) => ui(`The recorded submission is past the 23-hour window in which it can be re-sent safely, so it will not be resumed. Check your job list and balance before submitting again.`, zhText("m77"), lang),
|
|
360
|
+
},
|
|
361
|
+
ledger: {
|
|
362
|
+
message: (_local, lang) => ui('Check your job list and balance; no safe replay is available here.', zhText("m76"), lang),
|
|
363
|
+
advice: (idempotencyKey, _deadline, lang) => ui(`No local record of this submission remains (idempotency key ${idempotencyKey}), so it cannot be re-sent from here. Check your job list and balance before submitting again.`, (zhText("m74") + (idempotencyKey) + zhText("m75")), lang),
|
|
364
|
+
},
|
|
365
|
+
};
|
|
336
366
|
/** A replay was refused inside the gateway's create step, which is only reached when no job exists for the key. */
|
|
337
367
|
export function replaySettledAdvice(lang = resolveLang()) {
|
|
338
|
-
return ui('The earlier submission with this idempotency key was never created, so nothing was charged for it. It is safe to run the command again to get a new quote.',
|
|
368
|
+
return ui('The earlier submission with this idempotency key was never created, so nothing was charged for it. It is safe to run the command again to get a new quote.', zhText("m73"), lang);
|
|
339
369
|
}
|
|
340
370
|
/** A replay met a record for the same key with a different body: the earlier job exists, but this client cannot see it. */
|
|
341
371
|
export function replayConflictAdvice(lang = resolveLang()) {
|
|
342
|
-
return ui('A job for this idempotency key already exists with a different request body. Check your job list and balance before submitting again; do not retry with a new key.',
|
|
372
|
+
return ui('A job for this idempotency key already exists with a different request body. Check your job list and balance before submitting again; do not retry with a new key.', zhText("m72"), lang);
|
|
343
373
|
}
|
|
344
374
|
/** Chat requests are replayed by key, so the safe retry is the identical request with the same key. */
|
|
345
375
|
export function chatRetryAdvice(idempotencyKey, lang = resolveLang()) {
|
|
346
|
-
return ui(`To retry safely, send the identical request again with the same idempotency key ${idempotencyKey}; the gateway replays the earlier result instead of charging twice.`,
|
|
376
|
+
return ui(`To retry safely, send the identical request again with the same idempotency key ${idempotencyKey}; the gateway replays the earlier result instead of charging twice.`, (zhText("m70") + (idempotencyKey) + zhText("m71")), lang);
|
|
347
377
|
}
|
|
348
378
|
export function downloadPathNotAbsoluteDetail(lang = resolveLang()) {
|
|
349
|
-
return ui('The download path must be absolute, or start with ~/ for the home directory. This server cannot resolve a relative path on behalf of the caller.',
|
|
379
|
+
return ui('The download path must be absolute, or start with ~/ for the home directory. This server cannot resolve a relative path on behalf of the caller.', zhText("m69"), lang);
|
|
350
380
|
}
|
|
351
381
|
export function jobStatusText(status, lang = resolveLang()) {
|
|
352
382
|
const names = {
|
|
353
|
-
accepted:
|
|
354
|
-
provider_running:
|
|
355
|
-
rejected:
|
|
383
|
+
accepted: zhText("m68"), policy_checking: zhText("m67"), queued: zhText("m66"), submitting: zhText("m65"),
|
|
384
|
+
provider_running: zhText("m64"), output_checking: zhText("m63"), succeeded: zhText("m62"),
|
|
385
|
+
rejected: zhText("m61"), failed: zhText("m60"), cancelled: zhText("m59"), expired: zhText("m58"),
|
|
356
386
|
};
|
|
357
387
|
return lang === 'zh' && names[status] ? `${names[status]} (${status})` : status;
|
|
358
388
|
}
|
|
359
389
|
export function blankPromptSentence(kind, lang = resolveLang()) {
|
|
360
390
|
if (lang === 'zh') {
|
|
361
391
|
if (kind === 'flag')
|
|
362
|
-
return
|
|
392
|
+
return zhText("m57");
|
|
363
393
|
if (kind === 'field')
|
|
364
|
-
return
|
|
365
|
-
return
|
|
394
|
+
return zhText("m56");
|
|
395
|
+
return zhText("m55");
|
|
366
396
|
}
|
|
367
397
|
if (kind === 'flag')
|
|
368
398
|
return '--prompt is required and must not be blank.';
|
|
@@ -372,16 +402,16 @@ export function blankPromptSentence(kind, lang = resolveLang()) {
|
|
|
372
402
|
}
|
|
373
403
|
/** Surface-neutral: neither a CLI flag nor an MCP field is named. */
|
|
374
404
|
export function promptRequiredSentence(lang = resolveLang()) {
|
|
375
|
-
return ui('A prompt is required and must not be blank.',
|
|
405
|
+
return ui('A prompt is required and must not be blank.', zhText("m54"), lang);
|
|
376
406
|
}
|
|
377
407
|
export function spendingCapSentence(label, lang = resolveLang()) {
|
|
378
408
|
return lang === 'zh'
|
|
379
|
-
?
|
|
409
|
+
? ("" + (label) + zhText("m53"))
|
|
380
410
|
: `${label} must be a non-negative integer.`;
|
|
381
411
|
}
|
|
382
412
|
export function quoteCapSentence(label, lang = resolveLang()) {
|
|
383
413
|
return lang === 'zh'
|
|
384
|
-
?
|
|
414
|
+
? (zhText("m51") + (label) + zhText("m52"))
|
|
385
415
|
: `This quote is above the ${label} limit you set.`;
|
|
386
416
|
}
|
|
387
417
|
const INTERNAL_ERROR_TEXT = /^\s*\[error:\s*[a-z0-9_]+\]\s*$/i;
|
package/dist/core/outcome.d.ts
CHANGED
|
@@ -60,6 +60,12 @@ export interface Failure extends LegacyJobMirror {
|
|
|
60
60
|
quoteId?: string;
|
|
61
61
|
submission?: Submission;
|
|
62
62
|
resumed?: boolean;
|
|
63
|
+
/** Recovery state of an unknown submission; never an instruction to create a new job. */
|
|
64
|
+
recovery?: UnknownRecovery;
|
|
65
|
+
/** CLI argv, not a shell command string. Absent when replay is unsafe or no record remains. */
|
|
66
|
+
recoveryCommand?: string[];
|
|
67
|
+
/** The recorded 23-hour replay deadline, ISO UTC. */
|
|
68
|
+
resumeDeadline?: string;
|
|
63
69
|
billing?: ChatBilling;
|
|
64
70
|
/** The gateway task record, including its raw `error` object. */
|
|
65
71
|
job?: GenerationJobDetail;
|
package/dist/core/outcome.js
CHANGED
|
@@ -1,6 +1,7 @@
|
|
|
1
1
|
import { LumenKeyError, parseChatBilling } from './client.js';
|
|
2
|
-
import { errorSentence, submissionUnknownAdvice } from './locale.js';
|
|
2
|
+
import { errorSentence, submissionUnknownAdvice, submissionUnknownMessage } from './locale.js';
|
|
3
3
|
import { assertJobResult } from './poller.js';
|
|
4
|
+
import { RESUMABLE_WINDOW_MS } from './submission-journal.js';
|
|
4
5
|
export function chatText(response) {
|
|
5
6
|
const message = response.choices?.[0]?.message;
|
|
6
7
|
if (typeof message?.content === 'string' && message.content.trim())
|
|
@@ -24,7 +25,8 @@ function submissionOf(value) {
|
|
|
24
25
|
*/
|
|
25
26
|
export function failure(error, ctx = {}) {
|
|
26
27
|
const e = (error && typeof error === 'object' ? error : {});
|
|
27
|
-
const
|
|
28
|
+
const expired = e.code === 'SUBMISSION_RECORD_EXPIRED' || ctx.recovery === 'expired';
|
|
29
|
+
const code = expired ? 'SUBMISSION_RECORD_EXPIRED' : typeof e.code === 'string' && CODE.test(e.code) ? e.code : 'CLI_COMMAND_FAILED';
|
|
28
30
|
const job = ctx.job ?? (e.job && typeof e.job === 'object' ? e.job : undefined);
|
|
29
31
|
const jobId = ctx.jobId ?? text(e.jobId) ?? job?.jobId;
|
|
30
32
|
const jobStatus = ctx.jobStatus ?? text(e.jobStatus) ?? job?.status;
|
|
@@ -42,8 +44,16 @@ export function failure(error, ctx = {}) {
|
|
|
42
44
|
const pendingAgeSeconds = ctx.pendingAgeSeconds ?? (typeof e.pendingAgeSeconds === 'number' ? e.pendingAgeSeconds : undefined);
|
|
43
45
|
const waitStatus = code === 'WAIT_TIMEOUT' ? 'TIMEOUT' : code === 'WAIT_INTERRUPTED' ? 'INTERRUPTED' : undefined;
|
|
44
46
|
// IDEMPOTENCY_CONFLICT carries its own, more specific recovery text from the use case.
|
|
45
|
-
const
|
|
46
|
-
const
|
|
47
|
+
const recovery = expired ? 'expired' : submission === 'unknown' ? code === 'IDEMPOTENCY_CONFLICT' ? 'ledger' : ctx.recovery ?? 'ledger' : undefined;
|
|
48
|
+
const recordedAt = ctx.recordedAt ?? text(e.recordedAt);
|
|
49
|
+
const advice = (submission === 'unknown' || expired) && idempotencyKey && code !== 'IDEMPOTENCY_CONFLICT' ? ` ${submissionUnknownAdvice(idempotencyKey, recovery ?? 'ledger', recordedAt)}` : '';
|
|
50
|
+
const recorded = recordedAt ? Date.parse(recordedAt) : NaN;
|
|
51
|
+
const deadline = Number.isFinite(recorded) ? new Date(recorded + RESUMABLE_WINDOW_MS) : undefined;
|
|
52
|
+
const resumeDeadline = recovery && recovery !== 'ledger' ? deadline?.toISOString() : undefined;
|
|
53
|
+
const recoveryCommand = recovery === 'rerun' || recovery === 'resume-command'
|
|
54
|
+
? idempotencyKey ? ['lumenkey', 'tasks', 'resume', `--key=${idempotencyKey}`] : undefined : undefined;
|
|
55
|
+
const message = recovery ? submissionUnknownMessage(recovery, deadline)
|
|
56
|
+
: `${error instanceof LumenKeyError ? error.publicMessage : error instanceof Error ? error.message : errorSentence(code)}${advice}`;
|
|
47
57
|
const legacy = `${error instanceof Error ? error.message : errorSentence(code)}${advice}`;
|
|
48
58
|
const { error: _jobError, status: _jobState, jobId: _id, ...mirror } = job ?? {};
|
|
49
59
|
return {
|
|
@@ -57,6 +67,9 @@ export function failure(error, ctx = {}) {
|
|
|
57
67
|
...(quoteId ? { quoteId } : {}),
|
|
58
68
|
...(submission ? { submission } : {}),
|
|
59
69
|
...(resumed !== undefined ? { resumed } : {}),
|
|
70
|
+
...(recovery ? { recovery } : {}),
|
|
71
|
+
...(recoveryCommand ? { recoveryCommand } : {}),
|
|
72
|
+
...(resumeDeadline ? { resumeDeadline } : {}),
|
|
60
73
|
...(billing ? { billing } : {}),
|
|
61
74
|
...(job ? { job } : {}),
|
|
62
75
|
...(pendingIdempotencyKey ? { pendingIdempotencyKey } : {}),
|
|
@@ -6,5 +6,7 @@
|
|
|
6
6
|
*/
|
|
7
7
|
export type OutputPathPolicy = 'resolve-cwd' | 'absolute-only';
|
|
8
8
|
/** Expand a leading `~` / `~/` (never `~user`) to the home directory, then apply the surface policy. */
|
|
9
|
-
export declare function resolveOutputPath(raw: string, policy: OutputPathPolicy, home?: string
|
|
9
|
+
export declare function resolveOutputPath(raw: string, policy: OutputPathPolicy, home?: string, downloadPolicy?: {
|
|
10
|
+
configuredRoot: string | undefined;
|
|
11
|
+
}): string;
|
|
10
12
|
//# sourceMappingURL=output-path.d.ts.map
|
package/dist/core/output-path.js
CHANGED
|
@@ -2,14 +2,17 @@ import os from 'node:os';
|
|
|
2
2
|
import path from 'node:path';
|
|
3
3
|
import { LumenKeyError } from './client.js';
|
|
4
4
|
import { downloadPathNotAbsoluteDetail } from './locale.js';
|
|
5
|
+
import { assertDownloadPath } from './download-root.js';
|
|
5
6
|
/** Expand a leading `~` / `~/` (never `~user`) to the home directory, then apply the surface policy. */
|
|
6
|
-
export function resolveOutputPath(raw, policy, home = os.homedir()) {
|
|
7
|
+
export function resolveOutputPath(raw, policy, home = os.homedir(), downloadPolicy) {
|
|
8
|
+
if (raw.split(/[\\/]/).includes('..'))
|
|
9
|
+
throw new LumenKeyError('DOWNLOAD_OUTSIDE_ROOT');
|
|
7
10
|
let value = raw;
|
|
8
11
|
if (value === '~' || value.startsWith('~/') || (process.platform === 'win32' && value.startsWith('~\\')))
|
|
9
12
|
value = path.join(home, value.slice(1));
|
|
10
13
|
if (policy === 'absolute-only' && !path.isAbsolute(value)) {
|
|
11
14
|
throw Object.assign(new LumenKeyError('DOWNLOAD_PATH_NOT_ABSOLUTE', undefined, undefined, downloadPathNotAbsoluteDetail()), { path: raw });
|
|
12
15
|
}
|
|
13
|
-
return
|
|
16
|
+
return assertDownloadPath(value, downloadPolicy);
|
|
14
17
|
}
|
|
15
18
|
//# sourceMappingURL=output-path.js.map
|