@jackwener/opencli 1.7.14 → 1.7.15

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
Files changed (94) hide show
  1. package/cli-manifest.json +215 -45
  2. package/clis/bilibili/subtitle.js +1 -1
  3. package/clis/dianping/cityResolver.js +185 -0
  4. package/clis/dianping/dianping.test.js +154 -0
  5. package/clis/dianping/search.js +6 -3
  6. package/clis/douyin/_shared/browser-fetch.js +14 -2
  7. package/clis/douyin/_shared/browser-fetch.test.js +13 -0
  8. package/clis/douyin/stats.js +1 -1
  9. package/clis/douyin/update.js +1 -1
  10. package/clis/jike/search.js +1 -1
  11. package/clis/reddit/search.js +1 -1
  12. package/clis/reddit/subreddit.js +1 -1
  13. package/clis/reddit/user-comments.js +1 -1
  14. package/clis/reddit/user-posts.js +1 -1
  15. package/clis/reddit/user.js +1 -1
  16. package/clis/twitter/article.js +2 -1
  17. package/clis/twitter/bookmark-folder.js +189 -0
  18. package/clis/twitter/bookmark-folder.test.js +334 -0
  19. package/clis/twitter/bookmark-folders.js +117 -0
  20. package/clis/twitter/bookmark-folders.test.js +150 -0
  21. package/clis/twitter/bookmark.js +15 -6
  22. package/clis/twitter/bookmark.test.js +74 -0
  23. package/clis/twitter/bookmarks.js +7 -5
  24. package/clis/twitter/delete.js +11 -35
  25. package/clis/twitter/delete.test.js +21 -9
  26. package/clis/twitter/download.js +5 -5
  27. package/clis/twitter/followers.js +9 -3
  28. package/clis/twitter/following.js +11 -5
  29. package/clis/twitter/hide-reply.js +24 -5
  30. package/clis/twitter/hide-reply.test.js +76 -0
  31. package/clis/twitter/like.js +21 -11
  32. package/clis/twitter/like.test.js +73 -0
  33. package/clis/twitter/likes.js +8 -6
  34. package/clis/twitter/list-add.js +4 -4
  35. package/clis/twitter/list-remove.js +4 -4
  36. package/clis/twitter/list-tweets.js +6 -4
  37. package/clis/twitter/lists.js +3 -3
  38. package/clis/twitter/notifications.js +2 -2
  39. package/clis/twitter/profile.js +4 -3
  40. package/clis/twitter/quote.js +60 -32
  41. package/clis/twitter/quote.test.js +96 -8
  42. package/clis/twitter/reply.js +24 -178
  43. package/clis/twitter/reply.test.js +29 -11
  44. package/clis/twitter/retweet.js +9 -14
  45. package/clis/twitter/retweet.test.js +5 -1
  46. package/clis/twitter/search.js +175 -23
  47. package/clis/twitter/search.test.js +266 -1
  48. package/clis/twitter/shared.js +43 -0
  49. package/clis/twitter/shared.test.js +107 -1
  50. package/clis/twitter/thread.js +6 -4
  51. package/clis/twitter/timeline.js +8 -6
  52. package/clis/twitter/tweets.js +5 -3
  53. package/clis/twitter/unbookmark.js +13 -6
  54. package/clis/twitter/unbookmark.test.js +73 -0
  55. package/clis/twitter/unlike.js +6 -13
  56. package/clis/twitter/unlike.test.js +5 -2
  57. package/clis/twitter/unretweet.js +9 -14
  58. package/clis/twitter/unretweet.test.js +5 -1
  59. package/clis/twitter/utils.js +286 -0
  60. package/clis/twitter/utils.test.js +169 -0
  61. package/dist/src/browser/ax-snapshot.d.ts +37 -0
  62. package/dist/src/browser/ax-snapshot.js +217 -0
  63. package/dist/src/browser/ax-snapshot.test.d.ts +1 -0
  64. package/dist/src/browser/ax-snapshot.test.js +91 -0
  65. package/dist/src/browser/base-page.d.ts +51 -0
  66. package/dist/src/browser/base-page.js +545 -2
  67. package/dist/src/browser/base-page.test.js +520 -4
  68. package/dist/src/browser/cdp-click-fixture.test.d.ts +1 -0
  69. package/dist/src/browser/cdp-click-fixture.test.js +87 -0
  70. package/dist/src/browser/cdp.js +5 -0
  71. package/dist/src/browser/cdp.test.js +1 -0
  72. package/dist/src/browser/daemon-client.d.ts +3 -1
  73. package/dist/src/browser/find.d.ts +9 -1
  74. package/dist/src/browser/find.js +219 -0
  75. package/dist/src/browser/find.test.js +61 -1
  76. package/dist/src/browser/page.d.ts +2 -1
  77. package/dist/src/browser/page.js +13 -0
  78. package/dist/src/browser/page.test.js +28 -0
  79. package/dist/src/browser/target-errors.d.ts +3 -1
  80. package/dist/src/browser/target-errors.js +2 -0
  81. package/dist/src/browser/target-resolver.d.ts +14 -0
  82. package/dist/src/browser/target-resolver.js +28 -0
  83. package/dist/src/browser/visual-refs.d.ts +11 -0
  84. package/dist/src/browser/visual-refs.js +108 -0
  85. package/dist/src/build-manifest.d.ts +23 -0
  86. package/dist/src/build-manifest.js +34 -0
  87. package/dist/src/build-manifest.test.js +108 -1
  88. package/dist/src/cli.js +560 -58
  89. package/dist/src/cli.test.js +598 -0
  90. package/dist/src/help.d.ts +32 -0
  91. package/dist/src/help.js +145 -0
  92. package/dist/src/types.d.ts +82 -0
  93. package/package.json +1 -1
  94. package/scripts/typed-error-lint-baseline.json +18 -18
@@ -209,6 +209,28 @@ export async function buildManifest() {
209
209
  export function serializeManifest(manifest) {
210
210
  return `${JSON.stringify(manifest, null, 2)}\n`;
211
211
  }
212
+ export function findManifestMetadataIssues(entries) {
213
+ const issues = [];
214
+ for (const entry of entries) {
215
+ if (!Array.isArray(entry.args))
216
+ continue;
217
+ for (const arg of entry.args) {
218
+ if (!arg.positional)
219
+ continue;
220
+ const help = typeof arg.help === 'string' ? arg.help.trim() : '';
221
+ if (help === '') {
222
+ issues.push({
223
+ site: entry.site,
224
+ command: entry.name,
225
+ arg: arg.name,
226
+ sourceFile: entry.sourceFile,
227
+ reason: 'positional arg missing non-empty `help` text',
228
+ });
229
+ }
230
+ }
231
+ }
232
+ return issues;
233
+ }
212
234
  /**
213
235
  * Diff helper: returns site/name keys that exist in `prev` but not in
214
236
  * `next`. Used as a safety net to detect accidental mass-deletions caused
@@ -278,6 +300,18 @@ async function main() {
278
300
  + `Always run via tsx (\`npm run build-manifest\`), not against compiled dist/.\n`);
279
301
  process.exit(1);
280
302
  }
303
+ const metadataIssues = findManifestMetadataIssues(entries);
304
+ if (metadataIssues.length > 0) {
305
+ process.stderr.write(`❌ ${metadataIssues.length} positional arg(s) missing \`help\` text:\n`);
306
+ for (const issue of metadataIssues) {
307
+ const where = issue.sourceFile ? ` (${issue.sourceFile})` : '';
308
+ process.stderr.write(` - ${issue.site}/${issue.command} positional "${issue.arg}"${where}\n`);
309
+ }
310
+ process.stderr.write(`\nEvery positional arg must declare a non-empty \`help\` string so\n`
311
+ + `\`opencli <site> <cmd> --help\` shows callers what the parameter is for.\n`
312
+ + `Add \`help: '...'\` to each arg above and re-run the build.\n`);
313
+ process.exit(1);
314
+ }
281
315
  const existing = readExistingManifest(OUTPUT);
282
316
  if (existing) {
283
317
  const removed = diffRemovedEntries(existing, entries);
@@ -3,7 +3,7 @@ import * as fs from 'node:fs';
3
3
  import * as os from 'node:os';
4
4
  import * as path from 'node:path';
5
5
  import { cli, getRegistry, Strategy } from './registry.js';
6
- import { ManifestImportError, diffRemovedEntries, loadManifestEntries, normalizeManifestPath, parseBuildManifestArgs, scanClisDir, serializeManifest, } from './build-manifest.js';
6
+ import { ManifestImportError, diffRemovedEntries, findManifestMetadataIssues, loadManifestEntries, normalizeManifestPath, parseBuildManifestArgs, scanClisDir, serializeManifest, } from './build-manifest.js';
7
7
  describe('manifest helper rules', () => {
8
8
  const tempDirs = [];
9
9
  afterEach(() => {
@@ -222,6 +222,113 @@ describe('manifest helper rules', () => {
222
222
  expect(diffRemovedEntries(prev, prev)).toEqual([]);
223
223
  expect(diffRemovedEntries([], next)).toEqual([]);
224
224
  });
225
+ it('findManifestMetadataIssues flags positionals with empty/missing help', () => {
226
+ // The build-time hard gate. A positional with `help: ''` or no `help` at
227
+ // all renders `Arguments:\n <name>` with a blank trailing column —
228
+ // unrecoverable for both humans and agents reading help. Failing closed
229
+ // here is the only way to keep help text trustworthy as adapters land.
230
+ //
231
+ // Semantic quality (e.g. what does an *optional* positional mean when
232
+ // omitted?) is intentionally NOT enforced — that belongs to the planned
233
+ // Arg metadata v2 advisory pass.
234
+ const entries = [
235
+ // Positional with usable help — clean.
236
+ {
237
+ site: 'demo',
238
+ name: 'ok',
239
+ access: 'read',
240
+ description: '',
241
+ strategy: 'public',
242
+ browser: false,
243
+ args: [
244
+ { name: 'q', positional: true, required: true, help: 'Search query' },
245
+ ],
246
+ type: 'js',
247
+ sourceFile: 'demo/ok.js',
248
+ },
249
+ // Positional with empty help string — must flag.
250
+ {
251
+ site: 'demo',
252
+ name: 'empty-help',
253
+ access: 'read',
254
+ description: '',
255
+ strategy: 'public',
256
+ browser: false,
257
+ args: [
258
+ { name: 'user', positional: true, required: false, help: '' },
259
+ ],
260
+ type: 'js',
261
+ sourceFile: 'demo/empty.js',
262
+ },
263
+ // Positional with whitespace-only help — must flag.
264
+ {
265
+ site: 'demo',
266
+ name: 'whitespace-help',
267
+ access: 'read',
268
+ description: '',
269
+ strategy: 'public',
270
+ browser: false,
271
+ args: [
272
+ { name: 'id', positional: true, required: true, help: ' ' },
273
+ ],
274
+ type: 'js',
275
+ },
276
+ // Positional with no help field at all — must flag.
277
+ {
278
+ site: 'demo',
279
+ name: 'missing-help',
280
+ access: 'read',
281
+ description: '',
282
+ strategy: 'public',
283
+ browser: false,
284
+ args: [
285
+ { name: 'name', positional: true, required: true },
286
+ ],
287
+ type: 'js',
288
+ },
289
+ // NON-positional flag with empty help — must NOT flag (gate is
290
+ // intentionally scoped to positionals; named flags carry the flag
291
+ // name itself in the help line).
292
+ {
293
+ site: 'demo',
294
+ name: 'flag-only',
295
+ access: 'read',
296
+ description: '',
297
+ strategy: 'public',
298
+ browser: false,
299
+ args: [
300
+ { name: 'limit', required: false, help: '' },
301
+ ],
302
+ type: 'js',
303
+ },
304
+ ];
305
+ const issues = findManifestMetadataIssues(entries);
306
+ expect(issues).toHaveLength(3);
307
+ expect(issues.map(i => `${i.site}/${i.command}/${i.arg}`).sort()).toEqual([
308
+ 'demo/empty-help/user',
309
+ 'demo/missing-help/name',
310
+ 'demo/whitespace-help/id',
311
+ ]);
312
+ // sourceFile flows through when present so the build error points at the
313
+ // exact file to fix.
314
+ const emptyHelp = issues.find(i => i.command === 'empty-help');
315
+ expect(emptyHelp?.sourceFile).toBe('demo/empty.js');
316
+ });
317
+ it('findManifestMetadataIssues returns [] for fully-documented entries', () => {
318
+ expect(findManifestMetadataIssues([])).toEqual([]);
319
+ expect(findManifestMetadataIssues([
320
+ {
321
+ site: 'demo',
322
+ name: 'no-args',
323
+ access: 'read',
324
+ description: '',
325
+ strategy: 'public',
326
+ browser: false,
327
+ args: [],
328
+ type: 'js',
329
+ },
330
+ ])).toEqual([]);
331
+ });
225
332
  it('parseBuildManifestArgs reads --allow-removals[=N]', () => {
226
333
  expect(parseBuildManifestArgs([]).allowRemovals).toBe(0);
227
334
  expect(parseBuildManifestArgs(['--allow-removals=5']).allowRemovals).toBe(5);