@abe-ing/cli 0.2.0

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.
@@ -0,0 +1,32 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import { buildProgram } from '../index.js';
3
+ function okFetch(body) {
4
+ return vi.fn().mockResolvedValue({ ok: true, status: 200, text: async () => JSON.stringify(body) });
5
+ }
6
+ beforeEach(() => {
7
+ process.env.ABE_NO_CONFIG = '1';
8
+ });
9
+ afterEach(() => {
10
+ vi.unstubAllGlobals();
11
+ delete process.env.ABE_NO_CONFIG;
12
+ });
13
+ describe('board create', () => {
14
+ it('normalizes columns and posts a nested task_board payload', async () => {
15
+ const f = okFetch({ board: { id: 1, name: 'Eng', slug: 'eng', columns: [] } });
16
+ vi.stubGlobal('fetch', f);
17
+ await buildProgram().parseAsync([
18
+ 'node', 'abe', 'board', 'create', 'Engineering',
19
+ '--columns', 'Backlog, In Progress, Done',
20
+ '--description', 'eng board',
21
+ '--token', 'abe_pat_x', '--api-url', 'http://h',
22
+ ]);
23
+ const body = JSON.parse(f.mock.calls[0][1].body);
24
+ // Flat top-level params — the endpoint does NOT accept a { task_board: ... } wrapper.
25
+ expect(body).toEqual({
26
+ name: 'Engineering',
27
+ description: 'eng board',
28
+ columns: ['backlog', 'in_progress', 'done'],
29
+ });
30
+ });
31
+ });
32
+ //# sourceMappingURL=boards.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"boards.test.js","sourceRoot":"","sources":["../../src/commands/boards.test.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,EAAE,EAAE,MAAM,EAAE,EAAE,EAAE,UAAU,EAAE,SAAS,EAAE,MAAM,QAAQ,CAAA;AAExE,OAAO,EAAE,YAAY,EAAE,MAAM,aAAa,CAAA;AAE1C,SAAS,OAAO,CAAC,IAAa;IAC5B,OAAO,EAAE,CAAC,EAAE,EAAE,CAAC,iBAAiB,CAAC,EAAE,EAAE,EAAE,IAAI,EAAE,MAAM,EAAE,GAAG,EAAE,IAAI,EAAE,KAAK,IAAI,EAAE,CAAC,IAAI,CAAC,SAAS,CAAC,IAAI,CAAC,EAAc,CAAC,CAAA;AACjH,CAAC;AAED,UAAU,CAAC,GAAG,EAAE;IACd,OAAO,CAAC,GAAG,CAAC,aAAa,GAAG,GAAG,CAAA;AACjC,CAAC,CAAC,CAAA;AACF,SAAS,CAAC,GAAG,EAAE;IACb,EAAE,CAAC,gBAAgB,EAAE,CAAA;IACrB,OAAO,OAAO,CAAC,GAAG,CAAC,aAAa,CAAA;AAClC,CAAC,CAAC,CAAA;AAEF,QAAQ,CAAC,cAAc,EAAE,GAAG,EAAE;IAC5B,EAAE,CAAC,0DAA0D,EAAE,KAAK,IAAI,EAAE;QACxE,MAAM,CAAC,GAAG,OAAO,CAAC,EAAE,KAAK,EAAE,EAAE,EAAE,EAAE,CAAC,EAAE,IAAI,EAAE,KAAK,EAAE,IAAI,EAAE,KAAK,EAAE,OAAO,EAAE,EAAE,EAAE,EAAE,CAAC,CAAA;QAC9E,EAAE,CAAC,UAAU,CAAC,OAAO,EAAE,CAAC,CAAC,CAAA;QACzB,MAAM,YAAY,EAAE,CAAC,UAAU,CAAC;YAC9B,MAAM,EAAE,KAAK,EAAE,OAAO,EAAE,QAAQ,EAAE,aAAa;YAC/C,WAAW,EAAE,4BAA4B;YACzC,eAAe,EAAE,WAAW;YAC5B,SAAS,EAAE,WAAW,EAAE,WAAW,EAAE,UAAU;SAChD,CAAC,CAAA;QACF,MAAM,IAAI,GAAG,IAAI,CAAC,KAAK,CAAE,CAAC,CAAC,IAAI,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,CAAC,CAAiB,CAAC,IAAc,CAAC,CAAA;QAC3E,sFAAsF;QACtF,MAAM,CAAC,IAAI,CAAC,CAAC,OAAO,CAAC;YACnB,IAAI,EAAE,aAAa;YACnB,WAAW,EAAE,WAAW;YACxB,OAAO,EAAE,CAAC,SAAS,EAAE,aAAa,EAAE,MAAM,CAAC;SAC5C,CAAC,CAAA;IACJ,CAAC,CAAC,CAAA;AACJ,CAAC,CAAC,CAAA"}
@@ -0,0 +1,29 @@
1
+ import { buildContext } from '../context.js';
2
+ import { emit, status } from '../output.js';
3
+ export function registerMembersCommands(program) {
4
+ program
5
+ .command('members')
6
+ .description('List workspace members (admin/full token required)')
7
+ .command('list')
8
+ .description('List members. NOTE: assigning by email/name does NOT need this — the server resolves assignees on task create/update.')
9
+ .action(async (_o, cmd) => {
10
+ const { client, json } = buildContext(cmd.optsWithGlobals());
11
+ const { members } = (await client.listMembers());
12
+ if (json) {
13
+ emit({ members }, { json });
14
+ return;
15
+ }
16
+ if (!members.length) {
17
+ status('No members.');
18
+ return;
19
+ }
20
+ const widths = { name: 24, email: 30, role: 8 };
21
+ const pad = (s, w) => (s.length >= w ? s : s + ' '.repeat(w - s.length));
22
+ process.stdout.write(`${pad('NAME', widths.name)}${pad('EMAIL', widths.email)}${pad('ROLE', widths.role)}TITLE\n`);
23
+ for (const m of members) {
24
+ const name = m.display_name || m.name || m.email.split('@')[0];
25
+ process.stdout.write(`${pad(name, widths.name)}${pad(m.email, widths.email)}${pad(m.role, widths.role)}${m.title ?? ''}\n`);
26
+ }
27
+ });
28
+ }
29
+ //# sourceMappingURL=members.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"members.js","sourceRoot":"","sources":["../../src/commands/members.ts"],"names":[],"mappings":"AAEA,OAAO,EAAE,YAAY,EAAc,MAAM,eAAe,CAAA;AACxD,OAAO,EAAE,IAAI,EAAE,MAAM,EAAE,MAAM,cAAc,CAAA;AAW3C,MAAM,UAAU,uBAAuB,CAAC,OAAgB;IACtD,OAAO;SACJ,OAAO,CAAC,SAAS,CAAC;SAClB,WAAW,CAAC,oDAAoD,CAAC;SACjE,OAAO,CAAC,MAAM,CAAC;SACf,WAAW,CAAC,uHAAuH,CAAC;SACpI,MAAM,CAAC,KAAK,EAAE,EAAW,EAAE,GAAY,EAAE,EAAE;QAC1C,MAAM,EAAE,MAAM,EAAE,IAAI,EAAE,GAAG,YAAY,CAAC,GAAG,CAAC,eAAe,EAAgB,CAAC,CAAA;QAC1E,MAAM,EAAE,OAAO,EAAE,GAAG,CAAC,MAAM,MAAM,CAAC,WAAW,EAAE,CAA0B,CAAA;QACzE,IAAI,IAAI,EAAE,CAAC;YACT,IAAI,CAAC,EAAE,OAAO,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,CAAA;YAC3B,OAAM;QACR,CAAC;QACD,IAAI,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC;YACpB,MAAM,CAAC,aAAa,CAAC,CAAA;YACrB,OAAM;QACR,CAAC;QACD,MAAM,MAAM,GAAG,EAAE,IAAI,EAAE,EAAE,EAAE,KAAK,EAAE,EAAE,EAAE,IAAI,EAAE,CAAC,EAAE,CAAA;QAC/C,MAAM,GAAG,GAAG,CAAC,CAAS,EAAE,CAAS,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,MAAM,IAAI,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,CAAC,GAAG,GAAG,CAAC,MAAM,CAAC,CAAC,GAAG,CAAC,CAAC,MAAM,CAAC,CAAC,CAAA;QACxF,OAAO,CAAC,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,OAAO,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,MAAM,EAAE,MAAM,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;QAClH,KAAK,MAAM,CAAC,IAAI,OAAO,EAAE,CAAC;YACxB,MAAM,IAAI,GAAG,CAAC,CAAC,YAAY,IAAI,CAAC,CAAC,IAAI,IAAI,CAAC,CAAC,KAAK,CAAC,KAAK,CAAC,GAAG,CAAC,CAAC,CAAC,CAAC,CAAA;YAC9D,OAAO,CAAC,MAAM,CAAC,KAAK,CAClB,GAAG,GAAG,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,KAAK,EAAE,MAAM,CAAC,KAAK,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC,IAAI,EAAE,MAAM,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,KAAK,IAAI,EAAE,IAAI,CACtG,CAAA;QACH,CAAC;IACH,CAAC,CAAC,CAAA;AACN,CAAC"}
@@ -0,0 +1,193 @@
1
+ import { CliError, EXIT } from '../errors.js';
2
+ import { buildContext } from '../context.js';
3
+ import { printTasks, printTask, emit, status } from '../output.js';
4
+ import { PRIORITIES, TASK_TYPES, SIZES, STATUSES, assertEnum } from '../enums.js';
5
+ // Resolve a board reference (numeric id or slug/name) to a numeric id.
6
+ async function resolveBoardId(client, ref) {
7
+ if (/^\d+$/.test(ref))
8
+ return Number(ref);
9
+ const { boards } = await client.listBoards();
10
+ const match = boards.find((b) => b.slug === ref) || boards.find((b) => b.name === ref);
11
+ if (!match) {
12
+ throw new CliError(`No board matches "${ref}". Run \`abe board list\` to see slugs.`, EXIT.NOT_FOUND);
13
+ }
14
+ return match.id;
15
+ }
16
+ function validateEnums(o) {
17
+ assertEnum(o.priority, PRIORITIES, 'priority');
18
+ assertEnum(o.type, TASK_TYPES, 'type');
19
+ assertEnum(o.size, SIZES, 'size');
20
+ assertEnum(o.status, STATUSES, 'status');
21
+ // --column is intentionally NOT validated here (per-board; server enumerates).
22
+ }
23
+ function normalizeColumn(c) {
24
+ return c ? c.trim().toLowerCase().replace(/[\s-]+/g, '_') : undefined;
25
+ }
26
+ // Build the request body from provided flags only. `assignee_id` wins; else
27
+ // `--assignee` is passed as assignee_email and resolved server-side.
28
+ function buildBody(o, extra = {}) {
29
+ const body = { ...extra };
30
+ if (o.description !== undefined)
31
+ body.description = o.description;
32
+ if (o.type !== undefined)
33
+ body.task_type = o.type;
34
+ if (o.priority !== undefined)
35
+ body.priority = o.priority;
36
+ if (o.size !== undefined)
37
+ body.size = o.size;
38
+ if (o.status !== undefined)
39
+ body.status = o.status;
40
+ const col = normalizeColumn(o.column);
41
+ if (col !== undefined)
42
+ body.board_column = col;
43
+ if (o.labels !== undefined)
44
+ body.labels = o.labels.split(',').map((l) => l.trim()).filter(Boolean);
45
+ if (o.assigneeId !== undefined)
46
+ body.assignee_id = o.assigneeId;
47
+ else if (o.assignee !== undefined)
48
+ body.assignee_email = o.assignee;
49
+ if (o.due !== undefined)
50
+ body.due_date = o.due;
51
+ if (o.start !== undefined)
52
+ body.start_date = o.start;
53
+ if (o.end !== undefined)
54
+ body.end_date = o.end;
55
+ if (o.estimate !== undefined)
56
+ body.estimate = o.estimate;
57
+ if (o.parent !== undefined)
58
+ body.parent_task_id = o.parent;
59
+ if (o.keyResult !== undefined)
60
+ body.key_result_id = o.keyResult;
61
+ return body;
62
+ }
63
+ function addTaskFlags(cmd) {
64
+ return cmd
65
+ .option('--description <text>')
66
+ .option('--type <type>', `task type (${TASK_TYPES.join('|')})`)
67
+ .option('--priority <p>', `priority (${PRIORITIES.join('|')})`)
68
+ .option('--size <s>', `size (${SIZES.join('|')})`)
69
+ .option('--column <key>', 'board column key')
70
+ .option('--labels <csv>', 'comma-separated labels')
71
+ .option('--assignee <emailOrName>', 'assignee email or name (resolved server-side)')
72
+ .option('--assignee-id <n>', 'assignee user id', (v) => Number(v))
73
+ .option('--due <date>', 'due date (YYYY-MM-DD)')
74
+ .option('--start <date>', 'start date (YYYY-MM-DD)')
75
+ .option('--end <date>', 'end date (YYYY-MM-DD)')
76
+ .option('--estimate <n>', 'estimate', (v) => Number(v))
77
+ .option('--parent <id>', 'parent task id', (v) => Number(v))
78
+ .option('--key-result <id>', 'key result id', (v) => Number(v));
79
+ }
80
+ export function registerTaskCommands(program) {
81
+ const task = program.command('task').description('Create, update, move, complete, and list tasks');
82
+ addTaskFlags(task
83
+ .command('create <title>')
84
+ .description('Create a task on a board')
85
+ .requiredOption('--board <slugOrId>', 'target board (slug or id)')
86
+ .option('--source <source>', 'origin marker', 'abe_cli')).action(async (title, o, cmd) => {
87
+ validateEnums(o);
88
+ const { client, json } = buildContext(cmd.optsWithGlobals());
89
+ const boardId = await resolveBoardId(client, o.board);
90
+ const body = buildBody(o, { title, task_board_id: boardId, source: o.source ?? 'abe_cli' });
91
+ const { task: created } = await client.createTask(body);
92
+ if (json)
93
+ emit({ task: created }, { json });
94
+ else
95
+ status(`Created task #${created.id} "${created.title}" on board ${boardId}.`);
96
+ });
97
+ addTaskFlags(task
98
+ .command('update <id>')
99
+ .description('Update any task property')
100
+ .option('--title <text>', 'new title')
101
+ .option('--board <slugOrId>', 'move to another board')
102
+ .option('--status <status>', `status (${STATUSES.join('|')})`)
103
+ .option('--display-order <n>', 'sort order', (v) => Number(v))).action(async (id, o, cmd) => {
104
+ validateEnums(o);
105
+ const { client, json } = buildContext(cmd.optsWithGlobals());
106
+ const extra = {};
107
+ if (o.board !== undefined)
108
+ extra.task_board_id = await resolveBoardId(client, o.board);
109
+ if (o.displayOrder !== undefined)
110
+ extra.display_order = o.displayOrder;
111
+ const titleOpt = o.title;
112
+ if (titleOpt !== undefined)
113
+ extra.title = titleOpt;
114
+ const { task: updated } = await client.updateTask(Number(id), buildBody(o, extra));
115
+ if (json)
116
+ emit({ task: updated }, { json });
117
+ else
118
+ status(`Updated task #${updated.id}.`);
119
+ });
120
+ task
121
+ .command('move <id>')
122
+ .description('Move a task to a column')
123
+ .requiredOption('--column <key>', 'destination column key')
124
+ .action(async (id, o, cmd) => {
125
+ const { client, json } = buildContext(cmd.optsWithGlobals());
126
+ const { task: moved } = await client.moveTask(Number(id), normalizeColumn(o.column));
127
+ if (json)
128
+ emit({ task: moved }, { json });
129
+ else
130
+ status(`Moved task #${moved.id} to ${moved.board_column}.`);
131
+ });
132
+ task
133
+ .command('complete <id>')
134
+ .description('Mark a task complete')
135
+ .action(async (id, _o, cmd) => {
136
+ const { client, json } = buildContext(cmd.optsWithGlobals());
137
+ const { task: done } = await client.completeTask(Number(id));
138
+ if (json)
139
+ emit({ task: done }, { json });
140
+ else
141
+ status(`Completed task #${done.id}.`);
142
+ });
143
+ task
144
+ .command('list')
145
+ .description('List tasks (default: your open tasks; use --all / --include-done / --status to widen)')
146
+ .option('--board <slugOrId>')
147
+ .option('--column <key>')
148
+ .option('--type <type>')
149
+ .option('--label <label>')
150
+ .option('--status <status>', `status (${STATUSES.join('|')})`)
151
+ .option('--all', 'all assignees (admin/full token only; server-enforced)')
152
+ .option('--include-done', 'include done tasks')
153
+ .option('--limit <n>', 'max rows', (v) => Number(v))
154
+ .action(async (o, cmd) => {
155
+ assertEnum(o.status, STATUSES, 'status');
156
+ assertEnum(o.type, TASK_TYPES, 'type');
157
+ const { client, json } = buildContext(cmd.optsWithGlobals());
158
+ const query = {
159
+ column: o.column,
160
+ type: o.type,
161
+ label: o.label,
162
+ status: o.status,
163
+ all: o.all ? true : undefined,
164
+ include_done: o.includeDone ? true : undefined,
165
+ limit: o.limit,
166
+ };
167
+ if (o.board !== undefined)
168
+ query.board_id = await resolveBoardId(client, o.board);
169
+ const { tasks } = await client.listTasks(query);
170
+ printTasks(tasks, { json });
171
+ });
172
+ task
173
+ .command('board')
174
+ .description('Full board state (all columns incl. done) — the truest source for reconciliation')
175
+ .requiredOption('--board <slugOrId>')
176
+ .action(async (o, cmd) => {
177
+ const { client, json } = buildContext(cmd.optsWithGlobals());
178
+ const boardId = await resolveBoardId(client, o.board);
179
+ const state = await client.boardState(boardId);
180
+ emit(state, { json });
181
+ if (!json)
182
+ status(JSON.stringify(state, null, 2));
183
+ });
184
+ task
185
+ .command('show <id>')
186
+ .description('Show a task')
187
+ .action(async (id, _o, cmd) => {
188
+ const { client, json } = buildContext(cmd.optsWithGlobals());
189
+ const { task: found } = await client.getTask(Number(id));
190
+ printTask(found, { json });
191
+ });
192
+ }
193
+ //# sourceMappingURL=tasks.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tasks.js","sourceRoot":"","sources":["../../src/commands/tasks.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,85 @@
1
+ import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
2
+ import { buildProgram } from '../index.js';
3
+ import { EXIT } from '../errors.js';
4
+ // Parse-and-run helper: runs a command line through the real program with a
5
+ // stubbed fetch, returning the captured fetch mock.
6
+ function run(argv, fetchImpl) {
7
+ vi.stubGlobal('fetch', fetchImpl);
8
+ return buildProgram().parseAsync(['node', 'abe', ...argv, '--token', 'abe_pat_x', '--api-url', 'http://h']);
9
+ }
10
+ function okFetch(body) {
11
+ return vi.fn().mockResolvedValue({ ok: true, status: 200, text: async () => JSON.stringify(body) });
12
+ }
13
+ beforeEach(() => {
14
+ process.env.ABE_NO_CONFIG = '1';
15
+ });
16
+ afterEach(() => {
17
+ vi.unstubAllGlobals();
18
+ delete process.env.ABE_NO_CONFIG;
19
+ });
20
+ describe('task create', () => {
21
+ it('maps flags to the exact create_params keys', async () => {
22
+ const f = okFetch({ task: { id: 1, title: 'x' } });
23
+ await run([
24
+ 'task', 'create', 'Ship it',
25
+ '--board', '5',
26
+ '--type', 'bug',
27
+ '--priority', 'P1',
28
+ '--size', 'M',
29
+ '--labels', 'backend, security',
30
+ '--assignee', 'matt@viewcy.com',
31
+ '--due', '2026-07-01',
32
+ ], f);
33
+ const [, init] = f.mock.calls[0];
34
+ const body = JSON.parse(init.body);
35
+ expect(body).toMatchObject({
36
+ title: 'Ship it',
37
+ task_board_id: 5,
38
+ task_type: 'bug',
39
+ priority: 'P1',
40
+ size: 'M',
41
+ labels: ['backend', 'security'],
42
+ assignee_email: 'matt@viewcy.com',
43
+ due_date: '2026-07-01',
44
+ source: 'abe_cli',
45
+ });
46
+ });
47
+ it('passes --assignee-id as assignee_id and omits assignee_email', async () => {
48
+ const f = okFetch({ task: { id: 1 } });
49
+ await run(['task', 'create', 'x', '--board', '5', '--assignee-id', '42'], f);
50
+ const body = JSON.parse(f.mock.calls[0][1].body);
51
+ expect(body.assignee_id).toBe(42);
52
+ expect(body.assignee_email).toBeUndefined();
53
+ });
54
+ it('rejects an invalid --priority before any fetch (exit 2)', async () => {
55
+ const f = okFetch({});
56
+ await expect(run(['task', 'create', 'x', '--board', '5', '--priority', 'nope'], f)).rejects.toMatchObject({
57
+ exitCode: EXIT.USAGE,
58
+ });
59
+ expect(f).not.toHaveBeenCalled();
60
+ });
61
+ it('does not client-validate --column (relies on the server 422)', async () => {
62
+ const f = okFetch({ task: { id: 1 } });
63
+ await run(['task', 'create', 'x', '--board', '5', '--column', 'Weird Column'], f);
64
+ const body = JSON.parse(f.mock.calls[0][1].body);
65
+ expect(body.board_column).toBe('weird_column'); // normalized, not rejected
66
+ });
67
+ });
68
+ describe('task update / move', () => {
69
+ it('sends only the provided fields', async () => {
70
+ const f = okFetch({ task: { id: 7 } });
71
+ await run(['task', 'update', '7', '--priority', 'P0'], f);
72
+ const url = f.mock.calls[0][0];
73
+ const body = JSON.parse(f.mock.calls[0][1].body);
74
+ expect(url).toBe('http://h/api/v1/tasks/7');
75
+ expect(body).toEqual({ priority: 'P0' });
76
+ });
77
+ it('move without --column errors before any fetch', async () => {
78
+ const f = okFetch({});
79
+ // Commander rejects the missing required option during parse (main() maps it
80
+ // to exit 2); the action — and therefore fetch — never runs.
81
+ await expect(run(['task', 'move', '7'], f)).rejects.toBeTruthy();
82
+ expect(f).not.toHaveBeenCalled();
83
+ });
84
+ });
85
+ //# sourceMappingURL=tasks.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"tasks.test.js","sourceRoot":"","sources":["../../src/commands/tasks.test.ts"],"names":[],"mappings":"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"}
package/dist/config.js ADDED
@@ -0,0 +1,56 @@
1
+ import os from 'node:os';
2
+ import path from 'node:path';
3
+ import fs from 'node:fs';
4
+ import { CliError, EXIT } from './errors.js';
5
+ const DEFAULT_API_URL = 'https://api.abe.ing';
6
+ // Resolved at call time (not import time) so an overridden HOME / ABE_CONFIG_DIR
7
+ // is honored — important for tests and CI, and so we never clobber the wrong
8
+ // home directory.
9
+ export function configDir() {
10
+ return process.env.ABE_CONFIG_DIR || path.join(os.homedir(), '.abe');
11
+ }
12
+ export function configFile() {
13
+ return path.join(configDir(), 'config.json');
14
+ }
15
+ export function readConfig() {
16
+ try {
17
+ return JSON.parse(fs.readFileSync(configFile(), 'utf8'));
18
+ }
19
+ catch {
20
+ return {}; // missing or unreadable/garbage → empty config
21
+ }
22
+ }
23
+ export function writeConfig(cfg) {
24
+ fs.mkdirSync(configDir(), { recursive: true, mode: 0o700 });
25
+ fs.writeFileSync(configFile(), JSON.stringify(cfg, null, 2));
26
+ try {
27
+ fs.chmodSync(configFile(), 0o600);
28
+ }
29
+ catch {
30
+ // NTFS ignores POSIX modes; on Windows the file relies on the user-profile ACL.
31
+ }
32
+ }
33
+ // Precedence: explicit flag > environment variable > config file > default.
34
+ // `tenant` is display-only — the PAT is already tenant-bound, so it is never
35
+ // sent to the server.
36
+ export function resolveSettings(flags, env = process.env) {
37
+ const file = env.ABE_NO_CONFIG ? {} : readConfig();
38
+ return {
39
+ apiUrl: flags.apiUrl ?? env.ABE_API_URL ?? file.apiUrl ?? DEFAULT_API_URL,
40
+ token: flags.token ?? env.ABE_TOKEN ?? file.token,
41
+ tenant: flags.tenant ?? env.ABE_TENANT ?? file.tenant,
42
+ };
43
+ }
44
+ export function requireToken(s) {
45
+ if (!s.token) {
46
+ throw new CliError('No API token configured. Run `abe auth login --token <pat>` or set ABE_TOKEN.', EXIT.AUTH);
47
+ }
48
+ return s.token;
49
+ }
50
+ // Never print a full token. Show only enough to recognize which one it is.
51
+ export function redactToken(t) {
52
+ if (!t)
53
+ return '(none)';
54
+ return `abe_pat_…${t.slice(-4)}`;
55
+ }
56
+ //# sourceMappingURL=config.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.js","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,MAAM,SAAS,CAAA;AACxB,OAAO,IAAI,MAAM,WAAW,CAAA;AAC5B,OAAO,EAAE,MAAM,SAAS,CAAA;AAExB,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAE5C,MAAM,eAAe,GAAG,qBAAqB,CAAA;AAE7C,iFAAiF;AACjF,6EAA6E;AAC7E,kBAAkB;AAClB,MAAM,UAAU,SAAS;IACvB,OAAO,OAAO,CAAC,GAAG,CAAC,cAAc,IAAI,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,OAAO,EAAE,EAAE,MAAM,CAAC,CAAA;AACtE,CAAC;AAED,MAAM,UAAU,UAAU;IACxB,OAAO,IAAI,CAAC,IAAI,CAAC,SAAS,EAAE,EAAE,aAAa,CAAC,CAAA;AAC9C,CAAC;AAcD,MAAM,UAAU,UAAU;IACxB,IAAI,CAAC;QACH,OAAO,IAAI,CAAC,KAAK,CAAC,EAAE,CAAC,YAAY,CAAC,UAAU,EAAE,EAAE,MAAM,CAAC,CAAc,CAAA;IACvE,CAAC;IAAC,MAAM,CAAC;QACP,OAAO,EAAE,CAAA,CAAC,+CAA+C;IAC3D,CAAC;AACH,CAAC;AAED,MAAM,UAAU,WAAW,CAAC,GAAc;IACxC,EAAE,CAAC,SAAS,CAAC,SAAS,EAAE,EAAE,EAAE,SAAS,EAAE,IAAI,EAAE,IAAI,EAAE,KAAK,EAAE,CAAC,CAAA;IAC3D,EAAE,CAAC,aAAa,CAAC,UAAU,EAAE,EAAE,IAAI,CAAC,SAAS,CAAC,GAAG,EAAE,IAAI,EAAE,CAAC,CAAC,CAAC,CAAA;IAC5D,IAAI,CAAC;QACH,EAAE,CAAC,SAAS,CAAC,UAAU,EAAE,EAAE,KAAK,CAAC,CAAA;IACnC,CAAC;IAAC,MAAM,CAAC;QACP,gFAAgF;IAClF,CAAC;AACH,CAAC;AAED,4EAA4E;AAC5E,6EAA6E;AAC7E,sBAAsB;AACtB,MAAM,UAAU,eAAe,CAC7B,KAA2D,EAC3D,MAAyB,OAAO,CAAC,GAAG;IAEpC,MAAM,IAAI,GAAG,GAAG,CAAC,aAAa,CAAC,CAAC,CAAC,EAAE,CAAC,CAAC,CAAC,UAAU,EAAE,CAAA;IAClD,OAAO;QACL,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,GAAG,CAAC,WAAW,IAAI,IAAI,CAAC,MAAM,IAAI,eAAe;QACzE,KAAK,EAAE,KAAK,CAAC,KAAK,IAAI,GAAG,CAAC,SAAS,IAAI,IAAI,CAAC,KAAK;QACjD,MAAM,EAAE,KAAK,CAAC,MAAM,IAAI,GAAG,CAAC,UAAU,IAAI,IAAI,CAAC,MAAM;KACtD,CAAA;AACH,CAAC;AAED,MAAM,UAAU,YAAY,CAAC,CAAmB;IAC9C,IAAI,CAAC,CAAC,CAAC,KAAK,EAAE,CAAC;QACb,MAAM,IAAI,QAAQ,CAChB,+EAA+E,EAC/E,IAAI,CAAC,IAAI,CACV,CAAA;IACH,CAAC;IACD,OAAO,CAAC,CAAC,KAAK,CAAA;AAChB,CAAC;AAED,2EAA2E;AAC3E,MAAM,UAAU,WAAW,CAAC,CAAU;IACpC,IAAI,CAAC,CAAC;QAAE,OAAO,QAAQ,CAAA;IACvB,OAAO,YAAY,CAAC,CAAC,KAAK,CAAC,CAAC,CAAC,CAAC,EAAE,CAAA;AAClC,CAAC"}
@@ -0,0 +1,70 @@
1
+ import { describe, it, expect, beforeEach, afterEach } from 'vitest';
2
+ import fs from 'node:fs';
3
+ import os from 'node:os';
4
+ import path from 'node:path';
5
+ import { resolveSettings, requireToken, redactToken, writeConfig, readConfig, configFile } from './config.js';
6
+ import { CliError, EXIT } from './errors.js';
7
+ describe('resolveSettings precedence', () => {
8
+ const env = { ABE_NO_CONFIG: '1' }; // ignore any real ~/.abe during unit tests
9
+ it('defaults the apiUrl when nothing is set', () => {
10
+ expect(resolveSettings({}, env).apiUrl).toBe('https://api.abe.ing');
11
+ });
12
+ it('prefers flag > env for each key', () => {
13
+ const e = { ...env, ABE_API_URL: 'http://env', ABE_TOKEN: 'env-tok', ABE_TENANT: 'env-ten' };
14
+ expect(resolveSettings({ apiUrl: 'http://flag', token: 'flag-tok', tenant: 'flag-ten' }, e)).toEqual({
15
+ apiUrl: 'http://flag',
16
+ token: 'flag-tok',
17
+ tenant: 'flag-ten',
18
+ });
19
+ });
20
+ it('falls back to env when no flag', () => {
21
+ const e = { ...env, ABE_API_URL: 'http://env', ABE_TOKEN: 'env-tok' };
22
+ const s = resolveSettings({}, e);
23
+ expect(s.apiUrl).toBe('http://env');
24
+ expect(s.token).toBe('env-tok');
25
+ });
26
+ });
27
+ describe('requireToken', () => {
28
+ it('throws EXIT.AUTH when no token', () => {
29
+ try {
30
+ requireToken({ apiUrl: 'x' });
31
+ throw new Error('should have thrown');
32
+ }
33
+ catch (e) {
34
+ expect(e).toBeInstanceOf(CliError);
35
+ expect(e.exitCode).toBe(EXIT.AUTH);
36
+ }
37
+ });
38
+ it('returns the token when present', () => {
39
+ expect(requireToken({ apiUrl: 'x', token: 'abe_pat_z' })).toBe('abe_pat_z');
40
+ });
41
+ });
42
+ describe('redactToken', () => {
43
+ it('reveals only the last 4 chars', () => {
44
+ expect(redactToken('abe_pat_abcdEFGH')).toBe('abe_pat_…EFGH');
45
+ expect(redactToken(undefined)).toBe('(none)');
46
+ });
47
+ });
48
+ describe('config file', () => {
49
+ let tmp;
50
+ beforeEach(() => {
51
+ tmp = fs.mkdtempSync(path.join(os.tmpdir(), 'abe-cli-'));
52
+ process.env.ABE_CONFIG_DIR = tmp; // never touch the real ~/.abe
53
+ });
54
+ afterEach(() => {
55
+ delete process.env.ABE_CONFIG_DIR;
56
+ fs.rmSync(tmp, { recursive: true, force: true });
57
+ });
58
+ it('readConfig tolerates a missing or garbage file', () => {
59
+ expect(readConfig()).toEqual({});
60
+ fs.writeFileSync(configFile(), 'not json');
61
+ expect(readConfig()).toEqual({});
62
+ });
63
+ it('writeConfig persists 0600 and round-trips', () => {
64
+ writeConfig({ apiUrl: 'http://x', token: 'abe_pat_secret', tenant: 't' });
65
+ const mode = fs.statSync(configFile()).mode & 0o777;
66
+ expect(mode).toBe(0o600);
67
+ expect(readConfig()).toEqual({ apiUrl: 'http://x', token: 'abe_pat_secret', tenant: 't' });
68
+ });
69
+ });
70
+ //# sourceMappingURL=config.test.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"config.test.js","sourceRoot":"","sources":["../src/config.test.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,10 @@
1
+ import { ApiClient } from './api.js';
2
+ import { resolveSettings, requireToken } from './config.js';
3
+ // Build an authenticated client from the merged global options of a command.
4
+ // Throws EXIT.AUTH (via requireToken) when no token is configured.
5
+ export function buildContext(opts) {
6
+ const settings = resolveSettings({ apiUrl: opts.apiUrl, token: opts.token, tenant: opts.tenant });
7
+ const token = requireToken(settings);
8
+ return { client: new ApiClient(settings.apiUrl, token), json: !!opts.json, settings };
9
+ }
10
+ //# sourceMappingURL=context.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"context.js","sourceRoot":"","sources":["../src/context.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,SAAS,EAAE,MAAM,UAAU,CAAA;AACpC,OAAO,EAAE,eAAe,EAAE,YAAY,EAAoB,MAAM,aAAa,CAAA;AAe7E,6EAA6E;AAC7E,mEAAmE;AACnE,MAAM,UAAU,YAAY,CAAC,IAAgB;IAC3C,MAAM,QAAQ,GAAG,eAAe,CAAC,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,KAAK,EAAE,IAAI,CAAC,KAAK,EAAE,MAAM,EAAE,IAAI,CAAC,MAAM,EAAE,CAAC,CAAA;IACjG,MAAM,KAAK,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAA;IACpC,OAAO,EAAE,MAAM,EAAE,IAAI,SAAS,CAAC,QAAQ,CAAC,MAAM,EAAE,KAAK,CAAC,EAAE,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,EAAE,QAAQ,EAAE,CAAA;AACvF,CAAC"}
package/dist/enums.js ADDED
@@ -0,0 +1,18 @@
1
+ import { CliError, EXIT } from './errors.js';
2
+ // Global task enums — mirror apps/backend/app/models/task.rb. These are
3
+ // client-validated for a fast, fetch-free failure. `board_column` is NOT here:
4
+ // columns are per-board arbitrary keys, validated server-side (a bad column
5
+ // returns a 422 that enumerates the valid set, which we surface verbatim).
6
+ export const PRIORITIES = ['P0', 'P1', 'P2', 'urgent', 'high', 'normal'];
7
+ export const TASK_TYPES = ['task', 'feature', 'bug', 'suggestion', 'improvement', 'ops'];
8
+ export const SIZES = ['XS', 'S', 'M', 'L', 'XL'];
9
+ export const STATUSES = ['open', 'completed'];
10
+ // Throws EXIT.USAGE (before any network call) when `value` is set but invalid.
11
+ export function assertEnum(value, allowed, flag) {
12
+ if (value === undefined)
13
+ return;
14
+ if (!allowed.includes(value)) {
15
+ throw new CliError(`Invalid --${flag} "${value}". Allowed: ${allowed.join(', ')}.`, EXIT.USAGE);
16
+ }
17
+ }
18
+ //# sourceMappingURL=enums.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"enums.js","sourceRoot":"","sources":["../src/enums.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,QAAQ,EAAE,IAAI,EAAE,MAAM,aAAa,CAAA;AAE5C,wEAAwE;AACxE,+EAA+E;AAC/E,4EAA4E;AAC5E,2EAA2E;AAC3E,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,IAAI,EAAE,IAAI,EAAE,IAAI,EAAE,QAAQ,EAAE,MAAM,EAAE,QAAQ,CAAU,CAAA;AACjF,MAAM,CAAC,MAAM,UAAU,GAAG,CAAC,MAAM,EAAE,SAAS,EAAE,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,KAAK,CAAU,CAAA;AACjG,MAAM,CAAC,MAAM,KAAK,GAAG,CAAC,IAAI,EAAE,GAAG,EAAE,GAAG,EAAE,GAAG,EAAE,IAAI,CAAU,CAAA;AACzD,MAAM,CAAC,MAAM,QAAQ,GAAG,CAAC,MAAM,EAAE,WAAW,CAAU,CAAA;AAOtD,+EAA+E;AAC/E,MAAM,UAAU,UAAU,CAAC,KAAyB,EAAE,OAA0B,EAAE,IAAY;IAC5F,IAAI,KAAK,KAAK,SAAS;QAAE,OAAM;IAC/B,IAAI,CAAC,OAAO,CAAC,QAAQ,CAAC,KAAK,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,QAAQ,CAAC,aAAa,IAAI,KAAK,KAAK,eAAe,OAAO,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,EAAE,IAAI,CAAC,KAAK,CAAC,CAAA;IACjG,CAAC;AACH,CAAC"}
package/dist/errors.js ADDED
@@ -0,0 +1,23 @@
1
+ // A CLI error carries the process exit code to use. Exit codes are stable so
2
+ // scripts and agents can branch on them.
3
+ export class CliError extends Error {
4
+ exitCode;
5
+ constructor(message, exitCode = 1) {
6
+ super(message);
7
+ this.exitCode = exitCode;
8
+ this.name = 'CliError';
9
+ }
10
+ }
11
+ export const EXIT = {
12
+ OK: 0,
13
+ GENERIC: 1,
14
+ USAGE: 2,
15
+ AUTH: 4,
16
+ BILLING: 5,
17
+ FORBIDDEN: 6,
18
+ NOT_FOUND: 7,
19
+ VALIDATION: 8,
20
+ SERVER: 9,
21
+ NETWORK: 10,
22
+ };
23
+ //# sourceMappingURL=errors.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"errors.js","sourceRoot":"","sources":["../src/errors.ts"],"names":[],"mappings":"AAAA,6EAA6E;AAC7E,yCAAyC;AACzC,MAAM,OAAO,QAAS,SAAQ,KAAK;IAGxB;IAFT,YACE,OAAe,EACR,WAAmB,CAAC;QAE3B,KAAK,CAAC,OAAO,CAAC,CAAA;QAFP,aAAQ,GAAR,QAAQ,CAAY;QAG3B,IAAI,CAAC,IAAI,GAAG,UAAU,CAAA;IACxB,CAAC;CACF;AAED,MAAM,CAAC,MAAM,IAAI,GAAG;IAClB,EAAE,EAAE,CAAC;IACL,OAAO,EAAE,CAAC;IACV,KAAK,EAAE,CAAC;IACR,IAAI,EAAE,CAAC;IACP,OAAO,EAAE,CAAC;IACV,SAAS,EAAE,CAAC;IACZ,SAAS,EAAE,CAAC;IACZ,UAAU,EAAE,CAAC;IACb,MAAM,EAAE,CAAC;IACT,OAAO,EAAE,EAAE;CACH,CAAA"}