@quecue/dev-notify 0.1.3 → 0.1.5
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/CHANGELOG.en.md +89 -0
- package/CHANGELOG.md +15 -0
- package/README.en.md +275 -0
- package/README.md +9 -2
- package/SECURITY.en.md +78 -0
- package/SECURITY.md +4 -2
- package/dist/channels.js +14 -12
- package/dist/claude-code.js +30 -30
- package/dist/claude-hook.js +23 -23
- package/dist/cli.js +106 -81
- package/dist/config.js +37 -20
- package/dist/credentials.js +14 -13
- package/dist/formatting.js +6 -4
- package/dist/i18n.js +960 -0
- package/dist/maintenance.js +17 -16
- package/dist/prompts.js +7 -6
- package/dist/reply-bridge.js +11 -10
- package/dist/reply-engine.js +20 -19
- package/dist/reply-hooks.js +21 -20
- package/dist/reply-interactions.js +36 -35
- package/dist/reply-outcomes.js +46 -23
- package/dist/reply-platform.js +14 -13
- package/dist/reply-state.js +31 -30
- package/dist/reply-telegram.js +4 -3
- package/dist/setup.js +69 -51
- package/dist/update.js +23 -22
- package/package.json +4 -1
package/dist/setup.js
CHANGED
|
@@ -3,6 +3,7 @@ import path from 'node:path';
|
|
|
3
3
|
import { randomBytes } from 'node:crypto';
|
|
4
4
|
import { ConfigError, decodeUtf8, example, parseConfig, ready } from './config.js';
|
|
5
5
|
import { encodeBundle, nativeStore } from './credentials.js';
|
|
6
|
+
import { getLocale, joinList, t } from './i18n.js';
|
|
6
7
|
import { terminalPrompts } from './prompts.js';
|
|
7
8
|
const yes = (text) => /^(y|yes)$/i.test(text.trim());
|
|
8
9
|
const defaultYes = (text) => !text.trim() || yes(text);
|
|
@@ -13,7 +14,7 @@ export async function snapshot(file) {
|
|
|
13
14
|
catch (error) {
|
|
14
15
|
if (error.code === 'ENOENT')
|
|
15
16
|
return null;
|
|
16
|
-
throw new ConfigError('
|
|
17
|
+
throw new ConfigError(t('setup.readFailed'));
|
|
17
18
|
}
|
|
18
19
|
}
|
|
19
20
|
function same(left, right) { return left === null ? right === null : right !== null && left.equals(right); }
|
|
@@ -25,7 +26,7 @@ export function readRaw(raw) {
|
|
|
25
26
|
data = JSON.parse(decodeUtf8(raw));
|
|
26
27
|
}
|
|
27
28
|
catch {
|
|
28
|
-
throw new ConfigError('
|
|
29
|
+
throw new ConfigError(t('setup.parseFailed'));
|
|
29
30
|
}
|
|
30
31
|
parseConfig(data, {}, () => ({}));
|
|
31
32
|
return data;
|
|
@@ -49,6 +50,9 @@ export async function commitConfig(file, data, expected, store, values, options
|
|
|
49
50
|
target.credentials = { backend: 'keyring', id };
|
|
50
51
|
parseConfig(target, {}, () => values);
|
|
51
52
|
}
|
|
53
|
+
else if (options.keepCredentials) {
|
|
54
|
+
parseConfig(target, {}, () => ({}));
|
|
55
|
+
}
|
|
52
56
|
else {
|
|
53
57
|
delete target.credentials;
|
|
54
58
|
parseConfig(target, {});
|
|
@@ -60,20 +64,20 @@ export async function commitConfig(file, data, expected, store, values, options
|
|
|
60
64
|
lock = await open(lockPath, 'wx', 0o600);
|
|
61
65
|
}
|
|
62
66
|
catch {
|
|
63
|
-
throw new ConfigError('
|
|
67
|
+
throw new ConfigError(t('setup.lockUnavailable'));
|
|
64
68
|
}
|
|
65
69
|
const temporary = path.join(path.dirname(file), `.config-${id}.tmp`);
|
|
66
70
|
let created = false, committed = false, tempCreated = false;
|
|
67
71
|
try {
|
|
68
72
|
await lock.close();
|
|
69
73
|
if (!same(await snapshot(file), expected))
|
|
70
|
-
throw new ConfigError('
|
|
74
|
+
throw new ConfigError(t('setup.changedDuringWizard'));
|
|
71
75
|
if (values !== null) {
|
|
72
76
|
store.create(id, values);
|
|
73
77
|
created = true;
|
|
74
78
|
const check = store.read(id);
|
|
75
79
|
if (check === null || JSON.stringify(check) !== JSON.stringify(values))
|
|
76
|
-
throw new ConfigError('
|
|
80
|
+
throw new ConfigError(t('setup.credentialVerifyFailed'));
|
|
77
81
|
}
|
|
78
82
|
const stream = await open(temporary, 'wx', 0o600);
|
|
79
83
|
tempCreated = true;
|
|
@@ -85,7 +89,7 @@ export async function commitConfig(file, data, expected, store, values, options
|
|
|
85
89
|
await stream.close();
|
|
86
90
|
}
|
|
87
91
|
if (!same(await snapshot(file), expected))
|
|
88
|
-
throw new ConfigError('
|
|
92
|
+
throw new ConfigError(t('setup.changedDuringSave'));
|
|
89
93
|
await (options.replace ?? rename)(temporary, file);
|
|
90
94
|
committed = true;
|
|
91
95
|
}
|
|
@@ -95,7 +99,7 @@ export async function commitConfig(file, data, expected, store, values, options
|
|
|
95
99
|
await removeFile(temporary);
|
|
96
100
|
}
|
|
97
101
|
catch {
|
|
98
|
-
warn(
|
|
102
|
+
warn(t('setup.tempCleanupFailed', { name: path.basename(temporary) }));
|
|
99
103
|
}
|
|
100
104
|
}
|
|
101
105
|
if (created && !committed) {
|
|
@@ -103,40 +107,42 @@ export async function commitConfig(file, data, expected, store, values, options
|
|
|
103
107
|
store.remove(id);
|
|
104
108
|
}
|
|
105
109
|
catch {
|
|
106
|
-
warn(
|
|
110
|
+
warn(t('setup.credentialCleanupFailed', { id }));
|
|
107
111
|
}
|
|
108
112
|
}
|
|
109
113
|
try {
|
|
110
114
|
await removeFile(lockPath);
|
|
111
115
|
}
|
|
112
116
|
catch {
|
|
113
|
-
warn('
|
|
117
|
+
warn(t('setup.lockCleanupFailed'));
|
|
114
118
|
}
|
|
115
119
|
}
|
|
116
|
-
if (old?.backend === 'keyring') {
|
|
120
|
+
if (!options.keepCredentials && old?.backend === 'keyring') {
|
|
117
121
|
try {
|
|
118
122
|
store.remove(old.id);
|
|
119
123
|
}
|
|
120
124
|
catch {
|
|
121
|
-
warn(
|
|
125
|
+
warn(t('setup.oldCredentialCleanupFailed', { id: old.id }));
|
|
122
126
|
}
|
|
123
127
|
}
|
|
124
|
-
else if (old?.backend === 'system') {
|
|
125
|
-
warn('
|
|
128
|
+
else if (!options.keepCredentials && old?.backend === 'system') {
|
|
129
|
+
warn(t('setup.oldSystemRetained'));
|
|
126
130
|
}
|
|
127
131
|
}
|
|
128
132
|
export async function wizard(file, options = {}) {
|
|
129
133
|
const prompts = options.prompts ?? terminalPrompts();
|
|
130
134
|
const before = await snapshot(file), data = readRaw(before);
|
|
131
135
|
const { out } = prompts;
|
|
132
|
-
|
|
133
|
-
|
|
136
|
+
if (before === null)
|
|
137
|
+
data.language = getLocale();
|
|
138
|
+
out(t('setup.path', { file }));
|
|
139
|
+
out(t('setup.secretsNote'));
|
|
134
140
|
const telegramEnabled = data.telegram?.enabled !== false;
|
|
135
141
|
const feishuEnabled = data.feishu?.enabled !== false;
|
|
136
142
|
const current = before === null ? ''
|
|
137
143
|
: telegramEnabled && feishuEnabled ? '3'
|
|
138
144
|
: telegramEnabled ? '1' : feishuEnabled ? '2' : '';
|
|
139
|
-
const entered = await prompts.text(
|
|
145
|
+
const entered = await prompts.text(t('setup.channelPrompt', { current: current ? ` [${current}]` : '' }));
|
|
140
146
|
const selection = entered || current;
|
|
141
147
|
if (!['1', '2', '3'].includes(selection))
|
|
142
148
|
return false;
|
|
@@ -151,13 +157,13 @@ export async function wizard(file, options = {}) {
|
|
|
151
157
|
previous = existing;
|
|
152
158
|
}
|
|
153
159
|
catch {
|
|
154
|
-
out('
|
|
155
|
-
if (!yes(await prompts.text('
|
|
160
|
+
out(t('setup.credentialUnreadable'));
|
|
161
|
+
if (!yes(await prompts.text(t('setup.reenterPrompt'))))
|
|
156
162
|
return false;
|
|
157
163
|
}
|
|
158
164
|
}
|
|
159
165
|
else if (reference?.backend === 'system')
|
|
160
|
-
out('
|
|
166
|
+
out(t('setup.oldSystemDetected'));
|
|
161
167
|
data.telegram ??= {};
|
|
162
168
|
data.feishu ??= {};
|
|
163
169
|
data.telegram.enabled = selection !== '2';
|
|
@@ -165,12 +171,13 @@ export async function wizard(file, options = {}) {
|
|
|
165
171
|
const values = {};
|
|
166
172
|
const readValue = async (label, key, required) => {
|
|
167
173
|
while (true) {
|
|
168
|
-
const
|
|
169
|
-
|
|
170
|
-
|
|
174
|
+
const prompt = required
|
|
175
|
+
? previous[key] ? 'setup.secretRequiredKeep' : 'setup.secretRequiredNew'
|
|
176
|
+
: previous[key] ? 'setup.secretOptionalKeep' : 'setup.secretOptionalNew';
|
|
177
|
+
const answer = await prompts.secret(t(prompt, { label }));
|
|
171
178
|
const value = !required && answer === '-' ? '' : answer || previous[key] || '';
|
|
172
179
|
if (required && !value) {
|
|
173
|
-
out('
|
|
180
|
+
out(t('setup.requiredBlank'));
|
|
174
181
|
continue;
|
|
175
182
|
}
|
|
176
183
|
try {
|
|
@@ -180,15 +187,15 @@ export async function wizard(file, options = {}) {
|
|
|
180
187
|
return value;
|
|
181
188
|
}
|
|
182
189
|
catch {
|
|
183
|
-
out('
|
|
190
|
+
out(t('setup.invalidFormat'));
|
|
184
191
|
}
|
|
185
192
|
}
|
|
186
193
|
};
|
|
187
194
|
if (data.telegram.enabled) {
|
|
188
195
|
values.telegram_token = await readValue('Telegram Bot Token', 'telegram_token', true);
|
|
189
|
-
out('
|
|
196
|
+
out(t('setup.telegramChatInstruction'));
|
|
190
197
|
while (true) {
|
|
191
|
-
const entered = await prompts.text('
|
|
198
|
+
const entered = await prompts.text(t('setup.telegramChatPrompt'));
|
|
192
199
|
const ids = entered ? entered.split(',').map(item => item.trim()) : data.telegram.chat_ids ?? [];
|
|
193
200
|
try {
|
|
194
201
|
if (!ids.length)
|
|
@@ -198,13 +205,13 @@ export async function wizard(file, options = {}) {
|
|
|
198
205
|
break;
|
|
199
206
|
}
|
|
200
207
|
catch {
|
|
201
|
-
out('
|
|
208
|
+
out(t('setup.telegramChatInvalid'));
|
|
202
209
|
}
|
|
203
210
|
}
|
|
204
211
|
}
|
|
205
212
|
if (data.feishu.enabled) {
|
|
206
|
-
values.feishu_webhook = await readValue('
|
|
207
|
-
values.feishu_secret = await readValue('
|
|
213
|
+
values.feishu_webhook = await readValue(t('setup.labelFeishuWebhook'), 'feishu_webhook', true);
|
|
214
|
+
values.feishu_secret = await readValue(t('setup.labelFeishuSecret'), 'feishu_secret', false);
|
|
208
215
|
}
|
|
209
216
|
encodeBundle(values);
|
|
210
217
|
const preview = { ...data, credentials: { backend: 'keyring', id: '0'.repeat(32) } };
|
|
@@ -212,70 +219,81 @@ export async function wizard(file, options = {}) {
|
|
|
212
219
|
const env = options.env ?? process.env;
|
|
213
220
|
const channels = [];
|
|
214
221
|
if (data.telegram.enabled)
|
|
215
|
-
channels.push(
|
|
222
|
+
channels.push(t('setup.channelTelegram', { count: data.telegram.chat_ids.length }));
|
|
216
223
|
if (data.feishu.enabled)
|
|
217
|
-
channels.push('
|
|
218
|
-
out(
|
|
219
|
-
out('
|
|
224
|
+
channels.push(t('setup.channelFeishu'));
|
|
225
|
+
out(t('setup.channelsEnabled', { channels: joinList(channels) }));
|
|
226
|
+
out(t('setup.envPriority'));
|
|
220
227
|
const overrides = [data.telegram.token_env ?? 'TELEGRAM_BOT_TOKEN', data.feishu.webhook_env ?? 'FEISHU_WEBHOOK',
|
|
221
228
|
data.feishu.secret_env ?? 'FEISHU_SECRET', 'TELEGRAM_CHAT_ID', 'TELEGRAM_CHAT_IDS'].filter(name => Object.hasOwn(env, name));
|
|
222
229
|
if (overrides.length)
|
|
223
|
-
out('
|
|
230
|
+
out(t('setup.envOverrides', { names: joinList(overrides) }));
|
|
224
231
|
if (reference?.backend === 'keyring')
|
|
225
|
-
out('
|
|
226
|
-
out('
|
|
232
|
+
out(t('setup.oldDeleteWarning'));
|
|
233
|
+
out(t('setup.disabledChannels'));
|
|
227
234
|
for (const line of options.notes ?? [])
|
|
228
235
|
out(line);
|
|
229
|
-
const actions = ['
|
|
236
|
+
const actions = [t('setup.actionSave')];
|
|
230
237
|
if (options.testSend)
|
|
231
|
-
actions.push('
|
|
238
|
+
actions.push(t('setup.actionTest'));
|
|
232
239
|
if (options.afterSave)
|
|
233
|
-
actions.push('
|
|
234
|
-
if (!defaultYes(await prompts.text(
|
|
240
|
+
actions.push(t('setup.actionHooks'));
|
|
241
|
+
if (!defaultYes(await prompts.text(t('setup.continue', { actions: joinList(actions) }))))
|
|
235
242
|
return false;
|
|
236
243
|
await commitConfig(file, data, before, store, values, { warn: out });
|
|
237
|
-
out('
|
|
244
|
+
out(t('setup.saved'));
|
|
238
245
|
if (options.testSend) {
|
|
239
246
|
try {
|
|
240
247
|
const effective = parseConfig(preview, env, () => values);
|
|
241
248
|
const ok = await options.testSend(effective);
|
|
242
|
-
out(ok ? '
|
|
249
|
+
out(ok ? t('setup.testSuccess') : t('setup.testFailed'));
|
|
243
250
|
}
|
|
244
251
|
catch {
|
|
245
|
-
out('
|
|
252
|
+
out(t('setup.testFailedEnv'));
|
|
246
253
|
}
|
|
247
254
|
}
|
|
248
255
|
else
|
|
249
|
-
out('
|
|
256
|
+
out(t('setup.testSkipped'));
|
|
250
257
|
if (options.afterSave) {
|
|
251
258
|
try {
|
|
252
259
|
await options.afterSave();
|
|
253
260
|
}
|
|
254
261
|
catch (error) {
|
|
255
|
-
out(
|
|
262
|
+
out(t('setup.hooksFailed', { reason: error instanceof ConfigError ? error.message : t('setup.hooksCheckHint') }));
|
|
256
263
|
}
|
|
257
264
|
}
|
|
258
265
|
try {
|
|
259
266
|
if (ready(parseConfig(preview, env, () => values), 'telegram')) {
|
|
260
|
-
out('
|
|
267
|
+
out(t('setup.replyHint'));
|
|
261
268
|
}
|
|
262
269
|
}
|
|
263
270
|
catch { /* 环境覆盖无效时上方测试分支已报告。 */ }
|
|
264
271
|
return true;
|
|
265
272
|
}
|
|
273
|
+
export async function setConfigLanguage(file, language, warn) {
|
|
274
|
+
const before = await snapshot(file);
|
|
275
|
+
if (before === null)
|
|
276
|
+
throw new ConfigError(t('config.languageNoConfig', { file, language }));
|
|
277
|
+
const data = readRaw(before);
|
|
278
|
+
if ((data.language ?? 'zh') === language)
|
|
279
|
+
return false;
|
|
280
|
+
data.language = language;
|
|
281
|
+
await commitConfig(file, data, before, { read: () => null, create: () => { }, remove: () => { } }, null, { keepCredentials: true, warn });
|
|
282
|
+
return true;
|
|
283
|
+
}
|
|
266
284
|
export async function clearCredentials(file, prompts, store) {
|
|
267
285
|
const before = await snapshot(file), data = readRaw(before);
|
|
268
286
|
const reference = data.credentials;
|
|
269
287
|
if (!reference) {
|
|
270
|
-
prompts.out('
|
|
288
|
+
prompts.out(t('setup.clearNoReference'));
|
|
271
289
|
return true;
|
|
272
290
|
}
|
|
273
291
|
if (reference.backend !== 'keyring')
|
|
274
|
-
throw new ConfigError('
|
|
275
|
-
prompts.out('
|
|
276
|
-
if (!yes(await prompts.text('
|
|
292
|
+
throw new ConfigError(t('setup.clearOldBackend'));
|
|
293
|
+
prompts.out(t('setup.clearWarning'));
|
|
294
|
+
if (!yes(await prompts.text(t('setup.clearConfirm'))))
|
|
277
295
|
return false;
|
|
278
296
|
await commitConfig(file, data, before, store ?? nativeStore(), null, { warn: prompts.out });
|
|
279
|
-
prompts.out('
|
|
297
|
+
prompts.out(t('setup.cleared'));
|
|
280
298
|
return true;
|
|
281
299
|
}
|
package/dist/update.js
CHANGED
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import { spawnSync } from 'node:child_process';
|
|
2
2
|
import { ConfigError } from './config.js';
|
|
3
|
+
import { t } from './i18n.js';
|
|
3
4
|
import { terminalPrompts } from './prompts.js';
|
|
4
5
|
const NAME = '@quecue/dev-notify';
|
|
5
6
|
const VERSION = /^(0|[1-9]\d*)\.(0|[1-9]\d*)\.(0|[1-9]\d*)(?:-(alpha|beta|rc)\.(0|[1-9]\d*))?$/;
|
|
@@ -12,7 +13,7 @@ function npmRunner(args, capture) {
|
|
|
12
13
|
shell: process.platform === 'win32',
|
|
13
14
|
});
|
|
14
15
|
if (result.error)
|
|
15
|
-
throw new ConfigError('
|
|
16
|
+
throw new ConfigError(t('update.npmUnavailable'));
|
|
16
17
|
return { status: result.status, stdout: result.stdout ?? '', stderr: result.stderr ?? '' };
|
|
17
18
|
}
|
|
18
19
|
async function fetchLatest() {
|
|
@@ -25,25 +26,25 @@ async function fetchLatest() {
|
|
|
25
26
|
});
|
|
26
27
|
}
|
|
27
28
|
catch {
|
|
28
|
-
throw new ConfigError('
|
|
29
|
+
throw new ConfigError(t('update.checkNetwork'));
|
|
29
30
|
}
|
|
30
31
|
if (!response.ok)
|
|
31
|
-
throw new ConfigError(
|
|
32
|
+
throw new ConfigError(t('update.checkHttp', { status: response.status }));
|
|
32
33
|
let version;
|
|
33
34
|
try {
|
|
34
35
|
version = (await response.json())?.version;
|
|
35
36
|
}
|
|
36
37
|
catch {
|
|
37
|
-
throw new ConfigError('
|
|
38
|
+
throw new ConfigError(t('update.parseRegistry'));
|
|
38
39
|
}
|
|
39
40
|
if (typeof version !== 'string' || !VERSION.test(version))
|
|
40
|
-
throw new ConfigError('
|
|
41
|
+
throw new ConfigError(t('update.registryVersion'));
|
|
41
42
|
return version;
|
|
42
43
|
}
|
|
43
44
|
function parts(version) {
|
|
44
45
|
const match = VERSION.exec(version);
|
|
45
46
|
if (!match)
|
|
46
|
-
throw new ConfigError('
|
|
47
|
+
throw new ConfigError(t('update.versionFormat'));
|
|
47
48
|
const rank = match[4] === 'alpha' ? 1 : match[4] === 'beta' ? 2 : match[4] === 'rc' ? 3 : 4;
|
|
48
49
|
return [Number(match[1]), Number(match[2]), Number(match[3]), rank, Number(match[5] ?? 0)];
|
|
49
50
|
}
|
|
@@ -58,54 +59,54 @@ async function confirmUpdate(latest, options) {
|
|
|
58
59
|
if (options.yes)
|
|
59
60
|
return true;
|
|
60
61
|
if (!options.prompts && (!process.stdin.isTTY || !process.stdout.isTTY)) {
|
|
61
|
-
throw new ConfigError('
|
|
62
|
+
throw new ConfigError(t('update.terminalRequired'));
|
|
62
63
|
}
|
|
63
64
|
const prompts = options.prompts ?? terminalPrompts();
|
|
64
|
-
return /^(y|yes)$/i.test(await prompts.text(
|
|
65
|
+
return /^(y|yes)$/i.test(await prompts.text(t('update.confirm', { latest })));
|
|
65
66
|
}
|
|
66
67
|
async function runMaintenance(options, updated) {
|
|
67
68
|
if (!options.post) {
|
|
68
69
|
if (updated)
|
|
69
|
-
options.out('
|
|
70
|
+
options.out(t('update.manualPost'));
|
|
70
71
|
return 0;
|
|
71
72
|
}
|
|
72
73
|
const code = await options.post();
|
|
73
74
|
if (code !== 0) {
|
|
74
|
-
options.out(updated ? '
|
|
75
|
+
options.out(t(updated ? 'update.partialUpdated' : 'update.partial'));
|
|
75
76
|
return code;
|
|
76
77
|
}
|
|
77
|
-
options.out(updated ? '
|
|
78
|
+
options.out(t(updated ? 'update.postDoneUpdated' : 'update.postDone'));
|
|
78
79
|
return 0;
|
|
79
80
|
}
|
|
80
81
|
export async function updatePackage(current, options) {
|
|
81
82
|
if (!VERSION.test(current))
|
|
82
|
-
throw new ConfigError('
|
|
83
|
+
throw new ConfigError(t('update.currentFormat'));
|
|
83
84
|
const latest = await (options.latest ?? fetchLatest)();
|
|
84
85
|
if (!VERSION.test(latest))
|
|
85
|
-
throw new ConfigError('
|
|
86
|
+
throw new ConfigError(t('update.registryVersion'));
|
|
86
87
|
if (compareVersions(latest, current) <= 0) {
|
|
87
|
-
options.out(
|
|
88
|
+
options.out(t('update.upToDate', { version: current }));
|
|
88
89
|
if (options.check)
|
|
89
90
|
return 0;
|
|
90
91
|
if (options.post)
|
|
91
|
-
options.out('
|
|
92
|
+
options.out(t('update.maintenanceNote'));
|
|
92
93
|
return await runMaintenance(options, false);
|
|
93
94
|
}
|
|
94
|
-
options.out(
|
|
95
|
+
options.out(t('update.versions', { current, latest }));
|
|
95
96
|
if (options.check) {
|
|
96
|
-
options.out('
|
|
97
|
+
options.out(t('update.checkHint'));
|
|
97
98
|
return 0;
|
|
98
99
|
}
|
|
99
100
|
if (options.post)
|
|
100
|
-
options.out('
|
|
101
|
+
options.out(t('update.postNote'));
|
|
101
102
|
if (!await confirmUpdate(latest, options)) {
|
|
102
|
-
options.out('
|
|
103
|
+
options.out(t('update.cancelled'));
|
|
103
104
|
return 130;
|
|
104
105
|
}
|
|
105
|
-
options.out(
|
|
106
|
+
options.out(t('update.running', { name: NAME, latest }));
|
|
106
107
|
const result = (options.runner ?? npmRunner)(['install', '-g', `${NAME}@${latest}`], false);
|
|
107
108
|
if (result.status !== 0)
|
|
108
|
-
throw new ConfigError(
|
|
109
|
-
options.out(
|
|
109
|
+
throw new ConfigError(t('update.failed', { name: NAME }));
|
|
110
|
+
options.out(t('update.updated', { latest }));
|
|
110
111
|
return await runMaintenance(options, true);
|
|
111
112
|
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@quecue/dev-notify",
|
|
3
|
-
"version": "0.1.
|
|
3
|
+
"version": "0.1.5",
|
|
4
4
|
"description": "跨平台开发任务通知工具,支持 Telegram 与飞书",
|
|
5
5
|
"license": "MIT",
|
|
6
6
|
"repository": {
|
|
@@ -21,8 +21,11 @@
|
|
|
21
21
|
"files": [
|
|
22
22
|
"dist/*.js",
|
|
23
23
|
"README.md",
|
|
24
|
+
"README.en.md",
|
|
24
25
|
"SECURITY.md",
|
|
26
|
+
"SECURITY.en.md",
|
|
25
27
|
"CHANGELOG.md",
|
|
28
|
+
"CHANGELOG.en.md",
|
|
26
29
|
"LICENSE"
|
|
27
30
|
],
|
|
28
31
|
"scripts": {
|