/ clis / ones / tasks.js
tasks.js
 1  import { cli, Strategy } from '@jackwener/opencli/registry';
 2  import { CliError } from '@jackwener/opencli/errors';
 3  import { gotoOnesHome, onesFetchInPage } from './common.js';
 4  import { enrichPeekEntriesWithDetails } from './enrich-tasks.js';
 5  import { resolveTaskListLabels } from './resolve-labels.js';
 6  import { defaultPeekBody, flattenPeekGroups, mapTaskEntry, parsePeekLimit } from './task-helpers.js';
 7  function buildQuery(project, assign) {
 8      const must = [];
 9      if (project?.trim()) {
10          must.push({ in: { 'field_values.field006': [project.trim()] } });
11      }
12      if (assign?.trim()) {
13          must.push({ equal: { assign: assign.trim() } });
14      }
15      if (must.length === 0) {
16          return { must: [] };
17      }
18      return { must };
19  }
20  cli({
21      site: 'ones',
22      name: 'tasks',
23      description: 'ONES Project API — list work items (POST team/:team/filters/peek); use token-info -f json for team uuid',
24      domain: 'ones.cn',
25      strategy: Strategy.COOKIE,
26      browser: true,
27      navigateBefore: false,
28      args: [
29          {
30              name: 'team',
31              type: 'str',
32              required: false,
33              positional: true,
34              help: 'Team UUID (8 chars), or set ONES_TEAM_UUID',
35          },
36          {
37              name: 'project',
38              type: 'str',
39              required: false,
40              help: 'Filter by project UUID (field006 / 所属项目)',
41          },
42          {
43              name: 'assign',
44              type: 'str',
45              required: false,
46              help: 'Filter by assignee user UUID (负责人 assign)',
47          },
48          {
49              name: 'limit',
50              type: 'int',
51              default: 30,
52              help: 'Max rows after flattening groups (default 30)',
53          },
54      ],
55      columns: ['title', 'status', 'project', 'uuid', 'updated', '工时'],
56      func: async (page, kwargs) => {
57          const team = kwargs.team?.trim() ||
58              process.env.ONES_TEAM_UUID?.trim() ||
59              process.env.ONES_TEAM_ID?.trim();
60          if (!team) {
61              throw new CliError('CONFIG', 'team UUID required', 'Pass team as first argument or set ONES_TEAM_UUID (see `opencli ones token-info -f json` → teams[].uuid).');
62          }
63          const project = kwargs.project?.trim();
64          const assign = kwargs.assign?.trim();
65          const limit = parsePeekLimit(kwargs.limit, 30);
66          await gotoOnesHome(page);
67          const body = defaultPeekBody(buildQuery(project, assign));
68          const path = `team/${team}/filters/peek`;
69          const parsed = (await onesFetchInPage(page, path, {
70              method: 'POST',
71              body: JSON.stringify(body),
72              skipGoto: true,
73          }));
74          const entries = flattenPeekGroups(parsed, limit);
75          const enriched = await enrichPeekEntriesWithDetails(page, team, entries, true);
76          const labels = await resolveTaskListLabels(page, team, enriched, true);
77          return enriched.map((e) => mapTaskEntry(e, labels));
78      },
79  });