@kb-labs/clickup-entry 2.96.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.
- package/README.md +69 -0
- package/dist/commands/folder-create.d.ts +13 -0
- package/dist/commands/folder-create.js +94 -0
- package/dist/commands/folder-create.js.map +1 -0
- package/dist/commands/folder-delete.d.ts +14 -0
- package/dist/commands/folder-delete.js +92 -0
- package/dist/commands/folder-delete.js.map +1 -0
- package/dist/commands/folder-update.d.ts +13 -0
- package/dist/commands/folder-update.js +94 -0
- package/dist/commands/folder-update.js.map +1 -0
- package/dist/commands/list-create.d.ts +15 -0
- package/dist/commands/list-create.js +96 -0
- package/dist/commands/list-create.js.map +1 -0
- package/dist/commands/list-delete.d.ts +14 -0
- package/dist/commands/list-delete.js +92 -0
- package/dist/commands/list-delete.js.map +1 -0
- package/dist/commands/list-statuses.d.ts +11 -0
- package/dist/commands/list-statuses.js +88 -0
- package/dist/commands/list-statuses.js.map +1 -0
- package/dist/commands/list-tasks.d.ts +16 -0
- package/dist/commands/list-tasks.js +118 -0
- package/dist/commands/list-tasks.js.map +1 -0
- package/dist/commands/list-update.d.ts +13 -0
- package/dist/commands/list-update.js +92 -0
- package/dist/commands/list-update.js.map +1 -0
- package/dist/commands/space-create.d.ts +15 -0
- package/dist/commands/space-create.js +94 -0
- package/dist/commands/space-create.js.map +1 -0
- package/dist/commands/space-delete.d.ts +14 -0
- package/dist/commands/space-delete.js +92 -0
- package/dist/commands/space-delete.js.map +1 -0
- package/dist/commands/space-update.d.ts +14 -0
- package/dist/commands/space-update.js +93 -0
- package/dist/commands/space-update.js.map +1 -0
- package/dist/commands/task-comment-add.d.ts +15 -0
- package/dist/commands/task-comment-add.js +95 -0
- package/dist/commands/task-comment-add.js.map +1 -0
- package/dist/commands/task-comment-list.d.ts +11 -0
- package/dist/commands/task-comment-list.js +91 -0
- package/dist/commands/task-comment-list.js.map +1 -0
- package/dist/commands/task-create.d.ts +20 -0
- package/dist/commands/task-create.js +116 -0
- package/dist/commands/task-create.js.map +1 -0
- package/dist/commands/task-delete.d.ts +14 -0
- package/dist/commands/task-delete.js +92 -0
- package/dist/commands/task-delete.js.map +1 -0
- package/dist/commands/task-get.d.ts +14 -0
- package/dist/commands/task-get.js +128 -0
- package/dist/commands/task-get.js.map +1 -0
- package/dist/commands/task-search.d.ts +16 -0
- package/dist/commands/task-search.js +112 -0
- package/dist/commands/task-search.js.map +1 -0
- package/dist/commands/task-update.d.ts +19 -0
- package/dist/commands/task-update.js +124 -0
- package/dist/commands/task-update.js.map +1 -0
- package/dist/commands/workspace.d.ts +11 -0
- package/dist/commands/workspace.js +102 -0
- package/dist/commands/workspace.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +474 -0
- package/dist/index.js.map +1 -0
- package/dist/manifest.d.ts +171 -0
- package/dist/manifest.js +474 -0
- package/dist/manifest.js.map +1 -0
- package/dist/rest/handlers/folder-create-handler.d.ts +11 -0
- package/dist/rest/handlers/folder-create-handler.js +57 -0
- package/dist/rest/handlers/folder-create-handler.js.map +1 -0
- package/dist/rest/handlers/folder-delete-handler.d.ts +11 -0
- package/dist/rest/handlers/folder-delete-handler.js +57 -0
- package/dist/rest/handlers/folder-delete-handler.js.map +1 -0
- package/dist/rest/handlers/folder-update-handler.d.ts +11 -0
- package/dist/rest/handlers/folder-update-handler.js +57 -0
- package/dist/rest/handlers/folder-update-handler.js.map +1 -0
- package/dist/rest/handlers/list-create-handler.d.ts +17 -0
- package/dist/rest/handlers/list-create-handler.js +59 -0
- package/dist/rest/handlers/list-create-handler.js.map +1 -0
- package/dist/rest/handlers/list-delete-handler.d.ts +11 -0
- package/dist/rest/handlers/list-delete-handler.js +57 -0
- package/dist/rest/handlers/list-delete-handler.js.map +1 -0
- package/dist/rest/handlers/list-statuses-handler.d.ts +9 -0
- package/dist/rest/handlers/list-statuses-handler.js +57 -0
- package/dist/rest/handlers/list-statuses-handler.js.map +1 -0
- package/dist/rest/handlers/list-tasks-handler.d.ts +16 -0
- package/dist/rest/handlers/list-tasks-handler.js +64 -0
- package/dist/rest/handlers/list-tasks-handler.js.map +1 -0
- package/dist/rest/handlers/list-update-handler.d.ts +15 -0
- package/dist/rest/handlers/list-update-handler.js +57 -0
- package/dist/rest/handlers/list-update-handler.js.map +1 -0
- package/dist/rest/handlers/search-handler.d.ts +16 -0
- package/dist/rest/handlers/search-handler.js +65 -0
- package/dist/rest/handlers/search-handler.js.map +1 -0
- package/dist/rest/handlers/space-create-handler.d.ts +11 -0
- package/dist/rest/handlers/space-create-handler.js +55 -0
- package/dist/rest/handlers/space-create-handler.js.map +1 -0
- package/dist/rest/handlers/space-delete-handler.d.ts +11 -0
- package/dist/rest/handlers/space-delete-handler.js +57 -0
- package/dist/rest/handlers/space-delete-handler.js.map +1 -0
- package/dist/rest/handlers/space-update-handler.d.ts +13 -0
- package/dist/rest/handlers/space-update-handler.js +57 -0
- package/dist/rest/handlers/space-update-handler.js.map +1 -0
- package/dist/rest/handlers/task-comment-add-handler.d.ts +13 -0
- package/dist/rest/handlers/task-comment-add-handler.js +61 -0
- package/dist/rest/handlers/task-comment-add-handler.js.map +1 -0
- package/dist/rest/handlers/task-comments-handler.d.ts +9 -0
- package/dist/rest/handlers/task-comments-handler.js +57 -0
- package/dist/rest/handlers/task-comments-handler.js.map +1 -0
- package/dist/rest/handlers/task-create-handler.d.ts +18 -0
- package/dist/rest/handlers/task-create-handler.js +58 -0
- package/dist/rest/handlers/task-create-handler.js.map +1 -0
- package/dist/rest/handlers/task-delete-handler.d.ts +11 -0
- package/dist/rest/handlers/task-delete-handler.js +58 -0
- package/dist/rest/handlers/task-delete-handler.js.map +1 -0
- package/dist/rest/handlers/task-get-handler.d.ts +12 -0
- package/dist/rest/handlers/task-get-handler.js +61 -0
- package/dist/rest/handlers/task-get-handler.js.map +1 -0
- package/dist/rest/handlers/task-update-handler.d.ts +19 -0
- package/dist/rest/handlers/task-update-handler.js +58 -0
- package/dist/rest/handlers/task-update-handler.js.map +1 -0
- package/dist/rest/handlers/workspace-handler.d.ts +6 -0
- package/dist/rest/handlers/workspace-handler.js +56 -0
- package/dist/rest/handlers/workspace-handler.js.map +1 -0
- package/package.json +54 -0
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { defineCommand, validationError } from '@kb-labs/sdk';
|
|
2
|
+
import { deleteList, requireApiKey, ClickUpApiError } from '@kb-labs/clickup-core';
|
|
3
|
+
|
|
4
|
+
// src/commands/list-delete.ts
|
|
5
|
+
function apiHint(err) {
|
|
6
|
+
switch (err.status) {
|
|
7
|
+
case 401:
|
|
8
|
+
return "CLICKUP_API_KEY is invalid or expired \u2014 check the token in your environment";
|
|
9
|
+
case 403:
|
|
10
|
+
return "You don't have permission for this action in ClickUp \u2014 check workspace access";
|
|
11
|
+
case 404:
|
|
12
|
+
return "Resource not found \u2014 verify the ID is correct (use `kb clickup workspace` to browse IDs)";
|
|
13
|
+
case 429:
|
|
14
|
+
return "ClickUp rate limit reached \u2014 wait a moment and retry";
|
|
15
|
+
default:
|
|
16
|
+
return "Unexpected ClickUp API error";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function handleError(ctx, err, isJson) {
|
|
20
|
+
if (err instanceof ClickUpApiError) {
|
|
21
|
+
const hint = apiHint(err);
|
|
22
|
+
if (isJson) {
|
|
23
|
+
ctx.ui?.json?.({ ok: false, error: { code: err.code, message: err.message, status: err.status, hint } });
|
|
24
|
+
} else {
|
|
25
|
+
ctx.ui?.error?.(err.message, { hint, cause: `ClickUp API ${err.status} (${err.code})` });
|
|
26
|
+
}
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
30
|
+
const isEnvMissing = /CLICKUP_API_KEY|CLICKUP_TEAM_ID/.test(message);
|
|
31
|
+
if (isJson) {
|
|
32
|
+
ctx.ui?.json?.({
|
|
33
|
+
ok: false,
|
|
34
|
+
error: {
|
|
35
|
+
code: isEnvMissing ? "ENV_MISSING" : "INTERNAL_ERROR",
|
|
36
|
+
message,
|
|
37
|
+
...isEnvMissing && {
|
|
38
|
+
hint: "Set CLICKUP_API_KEY (and CLICKUP_TEAM_ID for workspace commands) as environment variables"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
} else {
|
|
43
|
+
ctx.ui?.error?.(message, {
|
|
44
|
+
...isEnvMissing && {
|
|
45
|
+
hint: "Set CLICKUP_API_KEY (and CLICKUP_TEAM_ID for workspace commands) as environment variables",
|
|
46
|
+
command: "export CLICKUP_API_KEY=pk_xxx CLICKUP_TEAM_ID=yyy"
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// src/commands/list-delete.ts
|
|
53
|
+
var list_delete_default = defineCommand({
|
|
54
|
+
id: "clickup:list.delete",
|
|
55
|
+
description: "Delete a list",
|
|
56
|
+
handler: {
|
|
57
|
+
async intent(_ctx, input) {
|
|
58
|
+
const [listId] = input.argv;
|
|
59
|
+
return {
|
|
60
|
+
summary: `Delete list ${listId ?? "(unknown)"}`,
|
|
61
|
+
operations: [{ type: "delete", resource: "list", details: { listId } }]
|
|
62
|
+
};
|
|
63
|
+
},
|
|
64
|
+
async execute(ctx, input) {
|
|
65
|
+
const listId = input.argv[0];
|
|
66
|
+
if (!listId) {
|
|
67
|
+
validationError(ctx, "listId is required", "Usage: kb clickup list delete <listId> --force", input.flags.json);
|
|
68
|
+
return { exitCode: 1, result: null };
|
|
69
|
+
}
|
|
70
|
+
if (!input.flags.force) {
|
|
71
|
+
validationError(ctx, `--force is required to delete list ${listId}`, "Add --force to confirm deletion", input.flags.json);
|
|
72
|
+
return { exitCode: 1, result: null };
|
|
73
|
+
}
|
|
74
|
+
try {
|
|
75
|
+
await deleteList(requireApiKey(), listId);
|
|
76
|
+
if (input.flags.json) {
|
|
77
|
+
ctx.ui?.json?.({ ok: true, deleted: true, listId });
|
|
78
|
+
} else {
|
|
79
|
+
ctx.ui?.success?.(`Deleted list ${listId}`);
|
|
80
|
+
}
|
|
81
|
+
return { exitCode: 0, result: { deleted: true, listId } };
|
|
82
|
+
} catch (err) {
|
|
83
|
+
handleError(ctx, err, input.flags.json);
|
|
84
|
+
return { exitCode: 1, result: null };
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
export { list_delete_default as default };
|
|
91
|
+
//# sourceMappingURL=list-delete.js.map
|
|
92
|
+
//# sourceMappingURL=list-delete.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/error.ts","../../src/commands/list-delete.ts"],"names":[],"mappings":"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","file":"list-delete.js","sourcesContent":["import type { PluginContextV3 } from '@kb-labs/sdk';\nimport { ClickUpApiError } from '@kb-labs/clickup-core';\n\nexport { validationError } from '@kb-labs/sdk';\n\nfunction apiHint(err: ClickUpApiError): string {\n switch (err.status) {\n case 401: return 'CLICKUP_API_KEY is invalid or expired — check the token in your environment';\n case 403: return 'You don\\'t have permission for this action in ClickUp — check workspace access';\n case 404: return 'Resource not found — verify the ID is correct (use `kb clickup workspace` to browse IDs)';\n case 429: return 'ClickUp rate limit reached — wait a moment and retry';\n default: return 'Unexpected ClickUp API error';\n }\n}\n\n/**\n * Output a structured error and return — call right before `return { exitCode: 1, result: null }`.\n * In JSON mode emits `{ ok: false, error: { code, message, hint?, status? } }`.\n * In CLI mode uses ctx.ui.error() with hint and cause.\n */\nexport function handleError(ctx: PluginContextV3, err: unknown, isJson?: boolean): void {\n if (err instanceof ClickUpApiError) {\n const hint = apiHint(err);\n if (isJson) {\n ctx.ui?.json?.({ ok: false, error: { code: err.code, message: err.message, status: err.status, hint } });\n } else {\n ctx.ui?.error?.(err.message, { hint, cause: `ClickUp API ${err.status} (${err.code})` });\n }\n return;\n }\n\n const message = err instanceof Error ? err.message : String(err);\n const isEnvMissing = /CLICKUP_API_KEY|CLICKUP_TEAM_ID/.test(message);\n\n if (isJson) {\n ctx.ui?.json?.({\n ok: false,\n error: {\n code: isEnvMissing ? 'ENV_MISSING' : 'INTERNAL_ERROR',\n message,\n ...(isEnvMissing && {\n hint: 'Set CLICKUP_API_KEY (and CLICKUP_TEAM_ID for workspace commands) as environment variables',\n }),\n },\n });\n } else {\n ctx.ui?.error?.(message, {\n ...(isEnvMissing && {\n hint: 'Set CLICKUP_API_KEY (and CLICKUP_TEAM_ID for workspace commands) as environment variables',\n command: 'export CLICKUP_API_KEY=pk_xxx CLICKUP_TEAM_ID=yyy',\n }),\n });\n }\n}\n\n/**\n * Re-throws `err` as an HTTP-aware error for REST handlers.\n * `ClickUpApiError` → preserves HTTP status code; env errors → 400; others → 500.\n * The envelope middleware in rest-api reads `err.statusCode` to set the response status.\n */\nexport function rethrowForRest(err: unknown): never {\n if (err instanceof ClickUpApiError) {\n const hint = apiHint(err);\n const restErr = Object.assign(new Error(err.message), {\n statusCode: err.status,\n code: err.code,\n details: { hint },\n });\n throw restErr;\n }\n const message = err instanceof Error ? err.message : String(err);\n const isEnvMissing = /CLICKUP_API_KEY|CLICKUP_TEAM_ID/.test(message);\n if (isEnvMissing) {\n throw Object.assign(new Error(message), {\n statusCode: 400,\n code: 'ENV_MISSING',\n details: { hint: 'Set CLICKUP_API_KEY (and CLICKUP_TEAM_ID for workspace commands) as environment variables' },\n });\n }\n throw err;\n}\n","import { defineCommand, type CLIInput, type PluginContextV3 } from '@kb-labs/sdk';\nimport { requireApiKey, deleteList } from '@kb-labs/clickup-core';\nimport { handleError, validationError } from '../utils/error.js';\n\ntype ListDeleteFlags = {\n force?: boolean;\n json?: boolean;\n 'dry-run'?: boolean;\n};\n\nexport default defineCommand({\n id: 'clickup:list.delete',\n description: 'Delete a list',\n\n handler: {\n async intent(_ctx: PluginContextV3, input: CLIInput<ListDeleteFlags>) {\n const [listId] = input.argv;\n return {\n summary: `Delete list ${listId ?? '(unknown)'}`,\n operations: [{ type: 'delete' as const, resource: 'list', details: { listId } }],\n };\n },\n\n async execute(ctx: PluginContextV3, input: CLIInput<ListDeleteFlags>) {\n const listId = input.argv[0] as string | undefined;\n if (!listId) {\n validationError(ctx, 'listId is required', 'Usage: kb clickup list delete <listId> --force', input.flags.json);\n return { exitCode: 1, result: null };\n }\n if (!input.flags.force) {\n validationError(ctx, `--force is required to delete list ${listId}`, 'Add --force to confirm deletion', input.flags.json);\n return { exitCode: 1, result: null };\n }\n\n try {\n await deleteList(requireApiKey(), listId);\n\n if (input.flags.json) {\n ctx.ui?.json?.({ ok: true, deleted: true, listId });\n } else {\n ctx.ui?.success?.(`Deleted list ${listId}`);\n }\n\n return { exitCode: 0, result: { deleted: true, listId } };\n } catch (err) {\n handleError(ctx, err, input.flags.json);\n return { exitCode: 1, result: null };\n }\n },\n },\n});\n"]}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import * as _kb_labs_shared_command_kit from '@kb-labs/shared-command-kit';
|
|
2
|
+
import * as _kb_labs_clickup_contracts from '@kb-labs/clickup-contracts';
|
|
3
|
+
import { CLIInput } from '@kb-labs/sdk';
|
|
4
|
+
|
|
5
|
+
type ListStatusesFlags = {
|
|
6
|
+
json?: boolean;
|
|
7
|
+
full?: boolean;
|
|
8
|
+
};
|
|
9
|
+
declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, CLIInput<ListStatusesFlags>, _kb_labs_clickup_contracts.ClickUpStatus[] | null>;
|
|
10
|
+
|
|
11
|
+
export { _default as default };
|
|
@@ -0,0 +1,88 @@
|
|
|
1
|
+
import { defineCommand, validationError } from '@kb-labs/sdk';
|
|
2
|
+
import { getListStatuses, requireApiKey, ClickUpApiError } from '@kb-labs/clickup-core';
|
|
3
|
+
|
|
4
|
+
// src/commands/list-statuses.ts
|
|
5
|
+
function apiHint(err) {
|
|
6
|
+
switch (err.status) {
|
|
7
|
+
case 401:
|
|
8
|
+
return "CLICKUP_API_KEY is invalid or expired \u2014 check the token in your environment";
|
|
9
|
+
case 403:
|
|
10
|
+
return "You don't have permission for this action in ClickUp \u2014 check workspace access";
|
|
11
|
+
case 404:
|
|
12
|
+
return "Resource not found \u2014 verify the ID is correct (use `kb clickup workspace` to browse IDs)";
|
|
13
|
+
case 429:
|
|
14
|
+
return "ClickUp rate limit reached \u2014 wait a moment and retry";
|
|
15
|
+
default:
|
|
16
|
+
return "Unexpected ClickUp API error";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function handleError(ctx, err, isJson) {
|
|
20
|
+
if (err instanceof ClickUpApiError) {
|
|
21
|
+
const hint = apiHint(err);
|
|
22
|
+
if (isJson) {
|
|
23
|
+
ctx.ui?.json?.({ ok: false, error: { code: err.code, message: err.message, status: err.status, hint } });
|
|
24
|
+
} else {
|
|
25
|
+
ctx.ui?.error?.(err.message, { hint, cause: `ClickUp API ${err.status} (${err.code})` });
|
|
26
|
+
}
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
30
|
+
const isEnvMissing = /CLICKUP_API_KEY|CLICKUP_TEAM_ID/.test(message);
|
|
31
|
+
if (isJson) {
|
|
32
|
+
ctx.ui?.json?.({
|
|
33
|
+
ok: false,
|
|
34
|
+
error: {
|
|
35
|
+
code: isEnvMissing ? "ENV_MISSING" : "INTERNAL_ERROR",
|
|
36
|
+
message,
|
|
37
|
+
...isEnvMissing && {
|
|
38
|
+
hint: "Set CLICKUP_API_KEY (and CLICKUP_TEAM_ID for workspace commands) as environment variables"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
} else {
|
|
43
|
+
ctx.ui?.error?.(message, {
|
|
44
|
+
...isEnvMissing && {
|
|
45
|
+
hint: "Set CLICKUP_API_KEY (and CLICKUP_TEAM_ID for workspace commands) as environment variables",
|
|
46
|
+
command: "export CLICKUP_API_KEY=pk_xxx CLICKUP_TEAM_ID=yyy"
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// src/commands/list-statuses.ts
|
|
53
|
+
var list_statuses_default = defineCommand({
|
|
54
|
+
id: "clickup:list.statuses",
|
|
55
|
+
description: "List available statuses for a list",
|
|
56
|
+
handler: {
|
|
57
|
+
async execute(ctx, input) {
|
|
58
|
+
const [listId] = input.argv;
|
|
59
|
+
if (!listId) {
|
|
60
|
+
validationError(ctx, "List ID is required", "Usage: kb clickup list statuses <listId> (get IDs via `kb clickup workspace`)", input.flags.json);
|
|
61
|
+
return { exitCode: 1, result: null };
|
|
62
|
+
}
|
|
63
|
+
try {
|
|
64
|
+
const statuses = await getListStatuses(requireApiKey(), listId);
|
|
65
|
+
if (input.flags.json) {
|
|
66
|
+
ctx.ui?.json?.(input.flags.full ? statuses : statuses.map((s) => ({ status: s.status, type: s.type, color: s.color })));
|
|
67
|
+
return { exitCode: 0, result: statuses };
|
|
68
|
+
}
|
|
69
|
+
ctx.ui?.table?.(
|
|
70
|
+
statuses.map((s) => ({ Status: s.status, Type: s.type, Color: s.color })),
|
|
71
|
+
[
|
|
72
|
+
{ header: "Status", key: "Status" },
|
|
73
|
+
{ header: "Type", key: "Type" },
|
|
74
|
+
{ header: "Color", key: "Color" }
|
|
75
|
+
]
|
|
76
|
+
);
|
|
77
|
+
return { exitCode: 0, result: statuses };
|
|
78
|
+
} catch (err) {
|
|
79
|
+
handleError(ctx, err, input.flags.json);
|
|
80
|
+
return { exitCode: 1, result: null };
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
}
|
|
84
|
+
});
|
|
85
|
+
|
|
86
|
+
export { list_statuses_default as default };
|
|
87
|
+
//# sourceMappingURL=list-statuses.js.map
|
|
88
|
+
//# sourceMappingURL=list-statuses.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/error.ts","../../src/commands/list-statuses.ts"],"names":[],"mappings":"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","file":"list-statuses.js","sourcesContent":["import type { PluginContextV3 } from '@kb-labs/sdk';\nimport { ClickUpApiError } from '@kb-labs/clickup-core';\n\nexport { validationError } from '@kb-labs/sdk';\n\nfunction apiHint(err: ClickUpApiError): string {\n switch (err.status) {\n case 401: return 'CLICKUP_API_KEY is invalid or expired — check the token in your environment';\n case 403: return 'You don\\'t have permission for this action in ClickUp — check workspace access';\n case 404: return 'Resource not found — verify the ID is correct (use `kb clickup workspace` to browse IDs)';\n case 429: return 'ClickUp rate limit reached — wait a moment and retry';\n default: return 'Unexpected ClickUp API error';\n }\n}\n\n/**\n * Output a structured error and return — call right before `return { exitCode: 1, result: null }`.\n * In JSON mode emits `{ ok: false, error: { code, message, hint?, status? } }`.\n * In CLI mode uses ctx.ui.error() with hint and cause.\n */\nexport function handleError(ctx: PluginContextV3, err: unknown, isJson?: boolean): void {\n if (err instanceof ClickUpApiError) {\n const hint = apiHint(err);\n if (isJson) {\n ctx.ui?.json?.({ ok: false, error: { code: err.code, message: err.message, status: err.status, hint } });\n } else {\n ctx.ui?.error?.(err.message, { hint, cause: `ClickUp API ${err.status} (${err.code})` });\n }\n return;\n }\n\n const message = err instanceof Error ? err.message : String(err);\n const isEnvMissing = /CLICKUP_API_KEY|CLICKUP_TEAM_ID/.test(message);\n\n if (isJson) {\n ctx.ui?.json?.({\n ok: false,\n error: {\n code: isEnvMissing ? 'ENV_MISSING' : 'INTERNAL_ERROR',\n message,\n ...(isEnvMissing && {\n hint: 'Set CLICKUP_API_KEY (and CLICKUP_TEAM_ID for workspace commands) as environment variables',\n }),\n },\n });\n } else {\n ctx.ui?.error?.(message, {\n ...(isEnvMissing && {\n hint: 'Set CLICKUP_API_KEY (and CLICKUP_TEAM_ID for workspace commands) as environment variables',\n command: 'export CLICKUP_API_KEY=pk_xxx CLICKUP_TEAM_ID=yyy',\n }),\n });\n }\n}\n\n/**\n * Re-throws `err` as an HTTP-aware error for REST handlers.\n * `ClickUpApiError` → preserves HTTP status code; env errors → 400; others → 500.\n * The envelope middleware in rest-api reads `err.statusCode` to set the response status.\n */\nexport function rethrowForRest(err: unknown): never {\n if (err instanceof ClickUpApiError) {\n const hint = apiHint(err);\n const restErr = Object.assign(new Error(err.message), {\n statusCode: err.status,\n code: err.code,\n details: { hint },\n });\n throw restErr;\n }\n const message = err instanceof Error ? err.message : String(err);\n const isEnvMissing = /CLICKUP_API_KEY|CLICKUP_TEAM_ID/.test(message);\n if (isEnvMissing) {\n throw Object.assign(new Error(message), {\n statusCode: 400,\n code: 'ENV_MISSING',\n details: { hint: 'Set CLICKUP_API_KEY (and CLICKUP_TEAM_ID for workspace commands) as environment variables' },\n });\n }\n throw err;\n}\n","import { defineCommand, type CLIInput, type PluginContextV3 } from '@kb-labs/sdk';\nimport { requireApiKey, getListStatuses } from '@kb-labs/clickup-core';\nimport { handleError, validationError } from '../utils/error.js';\n\ntype ListStatusesFlags = { json?: boolean; full?: boolean };\n\nexport default defineCommand({\n id: 'clickup:list.statuses',\n description: 'List available statuses for a list',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<ListStatusesFlags>) {\n const [listId] = input.argv;\n if (!listId) {\n validationError(ctx, 'List ID is required', 'Usage: kb clickup list statuses <listId> (get IDs via `kb clickup workspace`)', input.flags.json);\n return { exitCode: 1, result: null };\n }\n\n try {\n const statuses = await getListStatuses(requireApiKey(), listId);\n\n if (input.flags.json) {\n ctx.ui?.json?.(input.flags.full ? statuses : statuses.map(s => ({ status: s.status, type: s.type, color: s.color })));\n return { exitCode: 0, result: statuses };\n }\n\n ctx.ui?.table?.(\n statuses.map(s => ({ Status: s.status, Type: s.type, Color: s.color })),\n [\n { header: 'Status', key: 'Status' },\n { header: 'Type', key: 'Type' },\n { header: 'Color', key: 'Color' },\n ],\n );\n\n return { exitCode: 0, result: statuses };\n } catch (err) {\n handleError(ctx, err, input.flags.json);\n return { exitCode: 1, result: null };\n }\n },\n },\n});\n"]}
|
|
@@ -0,0 +1,16 @@
|
|
|
1
|
+
import * as _kb_labs_shared_command_kit from '@kb-labs/shared-command-kit';
|
|
2
|
+
import * as _kb_labs_clickup_contracts from '@kb-labs/clickup-contracts';
|
|
3
|
+
import { CLIInput } from '@kb-labs/sdk';
|
|
4
|
+
|
|
5
|
+
type ListTasksFlags = {
|
|
6
|
+
status?: string;
|
|
7
|
+
assignee?: string;
|
|
8
|
+
limit?: number;
|
|
9
|
+
page?: number;
|
|
10
|
+
closed?: boolean;
|
|
11
|
+
json?: boolean;
|
|
12
|
+
full?: boolean;
|
|
13
|
+
};
|
|
14
|
+
declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, CLIInput<ListTasksFlags>, _kb_labs_clickup_contracts.ClickUpTask[] | null>;
|
|
15
|
+
|
|
16
|
+
export { _default as default };
|
|
@@ -0,0 +1,118 @@
|
|
|
1
|
+
import { defineCommand, validationError } from '@kb-labs/sdk';
|
|
2
|
+
import { getListTasks, requireApiKey, ClickUpApiError } from '@kb-labs/clickup-core';
|
|
3
|
+
|
|
4
|
+
// src/commands/list-tasks.ts
|
|
5
|
+
function apiHint(err) {
|
|
6
|
+
switch (err.status) {
|
|
7
|
+
case 401:
|
|
8
|
+
return "CLICKUP_API_KEY is invalid or expired \u2014 check the token in your environment";
|
|
9
|
+
case 403:
|
|
10
|
+
return "You don't have permission for this action in ClickUp \u2014 check workspace access";
|
|
11
|
+
case 404:
|
|
12
|
+
return "Resource not found \u2014 verify the ID is correct (use `kb clickup workspace` to browse IDs)";
|
|
13
|
+
case 429:
|
|
14
|
+
return "ClickUp rate limit reached \u2014 wait a moment and retry";
|
|
15
|
+
default:
|
|
16
|
+
return "Unexpected ClickUp API error";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function handleError(ctx, err, isJson) {
|
|
20
|
+
if (err instanceof ClickUpApiError) {
|
|
21
|
+
const hint = apiHint(err);
|
|
22
|
+
if (isJson) {
|
|
23
|
+
ctx.ui?.json?.({ ok: false, error: { code: err.code, message: err.message, status: err.status, hint } });
|
|
24
|
+
} else {
|
|
25
|
+
ctx.ui?.error?.(err.message, { hint, cause: `ClickUp API ${err.status} (${err.code})` });
|
|
26
|
+
}
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
30
|
+
const isEnvMissing = /CLICKUP_API_KEY|CLICKUP_TEAM_ID/.test(message);
|
|
31
|
+
if (isJson) {
|
|
32
|
+
ctx.ui?.json?.({
|
|
33
|
+
ok: false,
|
|
34
|
+
error: {
|
|
35
|
+
code: isEnvMissing ? "ENV_MISSING" : "INTERNAL_ERROR",
|
|
36
|
+
message,
|
|
37
|
+
...isEnvMissing && {
|
|
38
|
+
hint: "Set CLICKUP_API_KEY (and CLICKUP_TEAM_ID for workspace commands) as environment variables"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
} else {
|
|
43
|
+
ctx.ui?.error?.(message, {
|
|
44
|
+
...isEnvMissing && {
|
|
45
|
+
hint: "Set CLICKUP_API_KEY (and CLICKUP_TEAM_ID for workspace commands) as environment variables",
|
|
46
|
+
command: "export CLICKUP_API_KEY=pk_xxx CLICKUP_TEAM_ID=yyy"
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// src/utils/slim.ts
|
|
53
|
+
function slimTask(task) {
|
|
54
|
+
return {
|
|
55
|
+
id: task.id,
|
|
56
|
+
name: task.name,
|
|
57
|
+
status: task.status.status,
|
|
58
|
+
priority: task.priority?.id ? Number(task.priority.id) : null,
|
|
59
|
+
due_date: task.due_date ? Number(task.due_date) : null,
|
|
60
|
+
url: task.url
|
|
61
|
+
};
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
// src/commands/list-tasks.ts
|
|
65
|
+
var list_tasks_default = defineCommand({
|
|
66
|
+
id: "clickup:list.tasks",
|
|
67
|
+
description: "List tasks in a specific list",
|
|
68
|
+
handler: {
|
|
69
|
+
async execute(ctx, input) {
|
|
70
|
+
const [listId] = input.argv;
|
|
71
|
+
if (!listId) {
|
|
72
|
+
validationError(ctx, "List ID is required", "Usage: kb clickup list tasks <listId> (get IDs via `kb clickup workspace`)", input.flags.json);
|
|
73
|
+
return { exitCode: 1, result: null };
|
|
74
|
+
}
|
|
75
|
+
try {
|
|
76
|
+
const tasks = await getListTasks(requireApiKey(), listId, {
|
|
77
|
+
statuses: input.flags.status ? input.flags.status.split(",") : void 0,
|
|
78
|
+
assignees: input.flags.assignee ? input.flags.assignee.split(",") : void 0,
|
|
79
|
+
limit: input.flags.limit ?? 50,
|
|
80
|
+
page: input.flags.page ?? 0,
|
|
81
|
+
include_closed: input.flags.closed
|
|
82
|
+
});
|
|
83
|
+
if (input.flags.json) {
|
|
84
|
+
ctx.ui?.json?.(input.flags.full ? tasks : tasks.map(slimTask));
|
|
85
|
+
return { exitCode: 0, result: tasks };
|
|
86
|
+
}
|
|
87
|
+
if (!tasks.length) {
|
|
88
|
+
ctx.ui?.info?.("No tasks found.");
|
|
89
|
+
return { exitCode: 0, result: tasks };
|
|
90
|
+
}
|
|
91
|
+
ctx.ui?.table?.(
|
|
92
|
+
tasks.map((task) => ({
|
|
93
|
+
ID: task.id,
|
|
94
|
+
Name: task.name,
|
|
95
|
+
Status: task.status.status,
|
|
96
|
+
Priority: task.priority?.priority ?? "\u2013",
|
|
97
|
+
Assignees: task.assignees.map((a) => a.username).join(", ") || "\u2013"
|
|
98
|
+
})),
|
|
99
|
+
[
|
|
100
|
+
{ header: "ID", key: "ID" },
|
|
101
|
+
{ header: "Name", key: "Name" },
|
|
102
|
+
{ header: "Status", key: "Status" },
|
|
103
|
+
{ header: "Priority", key: "Priority" },
|
|
104
|
+
{ header: "Assignees", key: "Assignees" }
|
|
105
|
+
]
|
|
106
|
+
);
|
|
107
|
+
return { exitCode: 0, result: tasks };
|
|
108
|
+
} catch (err) {
|
|
109
|
+
handleError(ctx, err, input.flags.json);
|
|
110
|
+
return { exitCode: 1, result: null };
|
|
111
|
+
}
|
|
112
|
+
}
|
|
113
|
+
}
|
|
114
|
+
});
|
|
115
|
+
|
|
116
|
+
export { list_tasks_default as default };
|
|
117
|
+
//# sourceMappingURL=list-tasks.js.map
|
|
118
|
+
//# sourceMappingURL=list-tasks.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/error.ts","../../src/utils/slim.ts","../../src/commands/list-tasks.ts"],"names":[],"mappings":"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","file":"list-tasks.js","sourcesContent":["import type { PluginContextV3 } from '@kb-labs/sdk';\nimport { ClickUpApiError } from '@kb-labs/clickup-core';\n\nexport { validationError } from '@kb-labs/sdk';\n\nfunction apiHint(err: ClickUpApiError): string {\n switch (err.status) {\n case 401: return 'CLICKUP_API_KEY is invalid or expired — check the token in your environment';\n case 403: return 'You don\\'t have permission for this action in ClickUp — check workspace access';\n case 404: return 'Resource not found — verify the ID is correct (use `kb clickup workspace` to browse IDs)';\n case 429: return 'ClickUp rate limit reached — wait a moment and retry';\n default: return 'Unexpected ClickUp API error';\n }\n}\n\n/**\n * Output a structured error and return — call right before `return { exitCode: 1, result: null }`.\n * In JSON mode emits `{ ok: false, error: { code, message, hint?, status? } }`.\n * In CLI mode uses ctx.ui.error() with hint and cause.\n */\nexport function handleError(ctx: PluginContextV3, err: unknown, isJson?: boolean): void {\n if (err instanceof ClickUpApiError) {\n const hint = apiHint(err);\n if (isJson) {\n ctx.ui?.json?.({ ok: false, error: { code: err.code, message: err.message, status: err.status, hint } });\n } else {\n ctx.ui?.error?.(err.message, { hint, cause: `ClickUp API ${err.status} (${err.code})` });\n }\n return;\n }\n\n const message = err instanceof Error ? err.message : String(err);\n const isEnvMissing = /CLICKUP_API_KEY|CLICKUP_TEAM_ID/.test(message);\n\n if (isJson) {\n ctx.ui?.json?.({\n ok: false,\n error: {\n code: isEnvMissing ? 'ENV_MISSING' : 'INTERNAL_ERROR',\n message,\n ...(isEnvMissing && {\n hint: 'Set CLICKUP_API_KEY (and CLICKUP_TEAM_ID for workspace commands) as environment variables',\n }),\n },\n });\n } else {\n ctx.ui?.error?.(message, {\n ...(isEnvMissing && {\n hint: 'Set CLICKUP_API_KEY (and CLICKUP_TEAM_ID for workspace commands) as environment variables',\n command: 'export CLICKUP_API_KEY=pk_xxx CLICKUP_TEAM_ID=yyy',\n }),\n });\n }\n}\n\n/**\n * Re-throws `err` as an HTTP-aware error for REST handlers.\n * `ClickUpApiError` → preserves HTTP status code; env errors → 400; others → 500.\n * The envelope middleware in rest-api reads `err.statusCode` to set the response status.\n */\nexport function rethrowForRest(err: unknown): never {\n if (err instanceof ClickUpApiError) {\n const hint = apiHint(err);\n const restErr = Object.assign(new Error(err.message), {\n statusCode: err.status,\n code: err.code,\n details: { hint },\n });\n throw restErr;\n }\n const message = err instanceof Error ? err.message : String(err);\n const isEnvMissing = /CLICKUP_API_KEY|CLICKUP_TEAM_ID/.test(message);\n if (isEnvMissing) {\n throw Object.assign(new Error(message), {\n statusCode: 400,\n code: 'ENV_MISSING',\n details: { hint: 'Set CLICKUP_API_KEY (and CLICKUP_TEAM_ID for workspace commands) as environment variables' },\n });\n }\n throw err;\n}\n","import type { ClickUpTask } from '@kb-labs/clickup-contracts';\n\nexport function slimTask(task: ClickUpTask) {\n return {\n id: task.id,\n name: task.name,\n status: task.status.status,\n priority: task.priority?.id ? Number(task.priority.id) : null,\n due_date: task.due_date ? Number(task.due_date) : null,\n url: task.url,\n };\n}\n\nexport function slimTaskWithDesc(task: ClickUpTask) {\n return { ...slimTask(task), description: task.description ?? '' };\n}\n","import { defineCommand, type CLIInput, type PluginContextV3 } from '@kb-labs/sdk';\nimport { requireApiKey, getListTasks } from '@kb-labs/clickup-core';\nimport { handleError, validationError } from '../utils/error.js';\nimport { slimTask } from '../utils/slim.js';\n\ntype ListTasksFlags = {\n status?: string;\n assignee?: string;\n limit?: number;\n page?: number;\n closed?: boolean;\n json?: boolean;\n full?: boolean;\n};\n\nexport default defineCommand({\n id: 'clickup:list.tasks',\n description: 'List tasks in a specific list',\n\n handler: {\n async execute(ctx: PluginContextV3, input: CLIInput<ListTasksFlags>) {\n const [listId] = input.argv;\n if (!listId) {\n validationError(ctx, 'List ID is required', 'Usage: kb clickup list tasks <listId> (get IDs via `kb clickup workspace`)', input.flags.json);\n return { exitCode: 1, result: null };\n }\n\n try {\n const tasks = await getListTasks(requireApiKey(), listId, {\n statuses: input.flags.status ? input.flags.status.split(',') : undefined,\n assignees: input.flags.assignee ? input.flags.assignee.split(',') : undefined,\n limit: input.flags.limit ?? 50,\n page: input.flags.page ?? 0,\n include_closed: input.flags.closed,\n });\n\n if (input.flags.json) {\n ctx.ui?.json?.(input.flags.full ? tasks : tasks.map(slimTask));\n return { exitCode: 0, result: tasks };\n }\n\n if (!tasks.length) {\n ctx.ui?.info?.('No tasks found.');\n return { exitCode: 0, result: tasks };\n }\n\n ctx.ui?.table?.(\n tasks.map(task => ({\n ID: task.id,\n Name: task.name,\n Status: task.status.status,\n Priority: task.priority?.priority ?? '–',\n Assignees: task.assignees.map(a => a.username).join(', ') || '–',\n })),\n [\n { header: 'ID', key: 'ID' },\n { header: 'Name', key: 'Name' },\n { header: 'Status', key: 'Status' },\n { header: 'Priority', key: 'Priority' },\n { header: 'Assignees', key: 'Assignees' },\n ],\n );\n\n return { exitCode: 0, result: tasks };\n } catch (err) {\n handleError(ctx, err, input.flags.json);\n return { exitCode: 1, result: null };\n }\n },\n },\n});\n"]}
|
|
@@ -0,0 +1,13 @@
|
|
|
1
|
+
import * as _kb_labs_shared_command_kit from '@kb-labs/shared-command-kit';
|
|
2
|
+
import * as _kb_labs_clickup_contracts from '@kb-labs/clickup-contracts';
|
|
3
|
+
import { CLIInput } from '@kb-labs/sdk';
|
|
4
|
+
|
|
5
|
+
type ListUpdateFlags = {
|
|
6
|
+
name?: string;
|
|
7
|
+
json?: boolean;
|
|
8
|
+
full?: boolean;
|
|
9
|
+
'dry-run'?: boolean;
|
|
10
|
+
};
|
|
11
|
+
declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, CLIInput<ListUpdateFlags>, _kb_labs_clickup_contracts.ClickUpList | null>;
|
|
12
|
+
|
|
13
|
+
export { _default as default };
|
|
@@ -0,0 +1,92 @@
|
|
|
1
|
+
import { defineCommand, validationError } from '@kb-labs/sdk';
|
|
2
|
+
import { updateList, requireApiKey, ClickUpApiError } from '@kb-labs/clickup-core';
|
|
3
|
+
|
|
4
|
+
// src/commands/list-update.ts
|
|
5
|
+
function apiHint(err) {
|
|
6
|
+
switch (err.status) {
|
|
7
|
+
case 401:
|
|
8
|
+
return "CLICKUP_API_KEY is invalid or expired \u2014 check the token in your environment";
|
|
9
|
+
case 403:
|
|
10
|
+
return "You don't have permission for this action in ClickUp \u2014 check workspace access";
|
|
11
|
+
case 404:
|
|
12
|
+
return "Resource not found \u2014 verify the ID is correct (use `kb clickup workspace` to browse IDs)";
|
|
13
|
+
case 429:
|
|
14
|
+
return "ClickUp rate limit reached \u2014 wait a moment and retry";
|
|
15
|
+
default:
|
|
16
|
+
return "Unexpected ClickUp API error";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function handleError(ctx, err, isJson) {
|
|
20
|
+
if (err instanceof ClickUpApiError) {
|
|
21
|
+
const hint = apiHint(err);
|
|
22
|
+
if (isJson) {
|
|
23
|
+
ctx.ui?.json?.({ ok: false, error: { code: err.code, message: err.message, status: err.status, hint } });
|
|
24
|
+
} else {
|
|
25
|
+
ctx.ui?.error?.(err.message, { hint, cause: `ClickUp API ${err.status} (${err.code})` });
|
|
26
|
+
}
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
30
|
+
const isEnvMissing = /CLICKUP_API_KEY|CLICKUP_TEAM_ID/.test(message);
|
|
31
|
+
if (isJson) {
|
|
32
|
+
ctx.ui?.json?.({
|
|
33
|
+
ok: false,
|
|
34
|
+
error: {
|
|
35
|
+
code: isEnvMissing ? "ENV_MISSING" : "INTERNAL_ERROR",
|
|
36
|
+
message,
|
|
37
|
+
...isEnvMissing && {
|
|
38
|
+
hint: "Set CLICKUP_API_KEY (and CLICKUP_TEAM_ID for workspace commands) as environment variables"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
} else {
|
|
43
|
+
ctx.ui?.error?.(message, {
|
|
44
|
+
...isEnvMissing && {
|
|
45
|
+
hint: "Set CLICKUP_API_KEY (and CLICKUP_TEAM_ID for workspace commands) as environment variables",
|
|
46
|
+
command: "export CLICKUP_API_KEY=pk_xxx CLICKUP_TEAM_ID=yyy"
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// src/commands/list-update.ts
|
|
53
|
+
var list_update_default = defineCommand({
|
|
54
|
+
id: "clickup:list.update",
|
|
55
|
+
description: "Update a list",
|
|
56
|
+
handler: {
|
|
57
|
+
async intent(_ctx, input) {
|
|
58
|
+
const [listId] = input.argv;
|
|
59
|
+
const skipKeys = /* @__PURE__ */ new Set(["json", "full", "dry-run"]);
|
|
60
|
+
const changes = Object.entries(input.flags).filter(([k, v]) => !skipKeys.has(k) && v !== void 0).map(([k, v]) => `${k}=${JSON.stringify(v)}`);
|
|
61
|
+
return {
|
|
62
|
+
summary: `Update list ${listId ?? "(unknown)"}`,
|
|
63
|
+
operations: [{ type: "update", resource: "list", details: { listId, changes } }]
|
|
64
|
+
};
|
|
65
|
+
},
|
|
66
|
+
async execute(ctx, input) {
|
|
67
|
+
const listId = input.argv[0];
|
|
68
|
+
if (!listId) {
|
|
69
|
+
validationError(ctx, "listId is required", 'Usage: kb clickup list update <listId> --name "new name"', input.flags.json);
|
|
70
|
+
return { exitCode: 1, result: null };
|
|
71
|
+
}
|
|
72
|
+
try {
|
|
73
|
+
const list = await updateList(requireApiKey(), listId, { name: input.flags.name });
|
|
74
|
+
if (input.flags.json) {
|
|
75
|
+
ctx.ui?.json?.(input.flags.full ? list : { id: list.id, name: list.name });
|
|
76
|
+
} else {
|
|
77
|
+
ctx.ui?.success?.("List updated", {
|
|
78
|
+
sections: [{ items: [`id: ${list.id}`, `name: ${list.name}`] }]
|
|
79
|
+
});
|
|
80
|
+
}
|
|
81
|
+
return { exitCode: 0, result: list };
|
|
82
|
+
} catch (err) {
|
|
83
|
+
handleError(ctx, err, input.flags.json);
|
|
84
|
+
return { exitCode: 1, result: null };
|
|
85
|
+
}
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
});
|
|
89
|
+
|
|
90
|
+
export { list_update_default as default };
|
|
91
|
+
//# sourceMappingURL=list-update.js.map
|
|
92
|
+
//# sourceMappingURL=list-update.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/error.ts","../../src/commands/list-update.ts"],"names":[],"mappings":"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","file":"list-update.js","sourcesContent":["import type { PluginContextV3 } from '@kb-labs/sdk';\nimport { ClickUpApiError } from '@kb-labs/clickup-core';\n\nexport { validationError } from '@kb-labs/sdk';\n\nfunction apiHint(err: ClickUpApiError): string {\n switch (err.status) {\n case 401: return 'CLICKUP_API_KEY is invalid or expired — check the token in your environment';\n case 403: return 'You don\\'t have permission for this action in ClickUp — check workspace access';\n case 404: return 'Resource not found — verify the ID is correct (use `kb clickup workspace` to browse IDs)';\n case 429: return 'ClickUp rate limit reached — wait a moment and retry';\n default: return 'Unexpected ClickUp API error';\n }\n}\n\n/**\n * Output a structured error and return — call right before `return { exitCode: 1, result: null }`.\n * In JSON mode emits `{ ok: false, error: { code, message, hint?, status? } }`.\n * In CLI mode uses ctx.ui.error() with hint and cause.\n */\nexport function handleError(ctx: PluginContextV3, err: unknown, isJson?: boolean): void {\n if (err instanceof ClickUpApiError) {\n const hint = apiHint(err);\n if (isJson) {\n ctx.ui?.json?.({ ok: false, error: { code: err.code, message: err.message, status: err.status, hint } });\n } else {\n ctx.ui?.error?.(err.message, { hint, cause: `ClickUp API ${err.status} (${err.code})` });\n }\n return;\n }\n\n const message = err instanceof Error ? err.message : String(err);\n const isEnvMissing = /CLICKUP_API_KEY|CLICKUP_TEAM_ID/.test(message);\n\n if (isJson) {\n ctx.ui?.json?.({\n ok: false,\n error: {\n code: isEnvMissing ? 'ENV_MISSING' : 'INTERNAL_ERROR',\n message,\n ...(isEnvMissing && {\n hint: 'Set CLICKUP_API_KEY (and CLICKUP_TEAM_ID for workspace commands) as environment variables',\n }),\n },\n });\n } else {\n ctx.ui?.error?.(message, {\n ...(isEnvMissing && {\n hint: 'Set CLICKUP_API_KEY (and CLICKUP_TEAM_ID for workspace commands) as environment variables',\n command: 'export CLICKUP_API_KEY=pk_xxx CLICKUP_TEAM_ID=yyy',\n }),\n });\n }\n}\n\n/**\n * Re-throws `err` as an HTTP-aware error for REST handlers.\n * `ClickUpApiError` → preserves HTTP status code; env errors → 400; others → 500.\n * The envelope middleware in rest-api reads `err.statusCode` to set the response status.\n */\nexport function rethrowForRest(err: unknown): never {\n if (err instanceof ClickUpApiError) {\n const hint = apiHint(err);\n const restErr = Object.assign(new Error(err.message), {\n statusCode: err.status,\n code: err.code,\n details: { hint },\n });\n throw restErr;\n }\n const message = err instanceof Error ? err.message : String(err);\n const isEnvMissing = /CLICKUP_API_KEY|CLICKUP_TEAM_ID/.test(message);\n if (isEnvMissing) {\n throw Object.assign(new Error(message), {\n statusCode: 400,\n code: 'ENV_MISSING',\n details: { hint: 'Set CLICKUP_API_KEY (and CLICKUP_TEAM_ID for workspace commands) as environment variables' },\n });\n }\n throw err;\n}\n","import { defineCommand, type CLIInput, type PluginContextV3 } from '@kb-labs/sdk';\nimport { requireApiKey, updateList } from '@kb-labs/clickup-core';\nimport { handleError, validationError } from '../utils/error.js';\n\ntype ListUpdateFlags = {\n name?: string;\n json?: boolean;\n full?: boolean;\n 'dry-run'?: boolean;\n};\n\nexport default defineCommand({\n id: 'clickup:list.update',\n description: 'Update a list',\n\n handler: {\n async intent(_ctx: PluginContextV3, input: CLIInput<ListUpdateFlags>) {\n const [listId] = input.argv;\n const skipKeys = new Set(['json', 'full', 'dry-run']);\n const changes = Object.entries(input.flags)\n .filter(([k, v]) => !skipKeys.has(k) && v !== undefined)\n .map(([k, v]) => `${k}=${JSON.stringify(v)}`);\n return {\n summary: `Update list ${listId ?? '(unknown)'}`,\n operations: [{ type: 'update' as const, resource: 'list', details: { listId, changes } }],\n };\n },\n\n async execute(ctx: PluginContextV3, input: CLIInput<ListUpdateFlags>) {\n const listId = input.argv[0] as string | undefined;\n if (!listId) {\n validationError(ctx, 'listId is required', 'Usage: kb clickup list update <listId> --name \"new name\"', input.flags.json);\n return { exitCode: 1, result: null };\n }\n\n try {\n const list = await updateList(requireApiKey(), listId, { name: input.flags.name });\n\n if (input.flags.json) {\n ctx.ui?.json?.(input.flags.full ? list : { id: list.id, name: list.name });\n } else {\n ctx.ui?.success?.('List updated', {\n sections: [{ items: [`id: ${list.id}`, `name: ${list.name}`] }],\n });\n }\n\n return { exitCode: 0, result: list };\n } catch (err) {\n handleError(ctx, err, input.flags.json);\n return { exitCode: 1, result: null };\n }\n },\n },\n});\n"]}
|
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
import * as _kb_labs_shared_command_kit from '@kb-labs/shared-command-kit';
|
|
2
|
+
import * as _kb_labs_clickup_contracts from '@kb-labs/clickup-contracts';
|
|
3
|
+
import { CLIInput } from '@kb-labs/sdk';
|
|
4
|
+
|
|
5
|
+
type SpaceCreateFlags = {
|
|
6
|
+
name: string;
|
|
7
|
+
color?: string;
|
|
8
|
+
private?: boolean;
|
|
9
|
+
json?: boolean;
|
|
10
|
+
full?: boolean;
|
|
11
|
+
'dry-run'?: boolean;
|
|
12
|
+
};
|
|
13
|
+
declare const _default: _kb_labs_shared_command_kit.CommandHandlerV3<unknown, CLIInput<SpaceCreateFlags>, _kb_labs_clickup_contracts.ClickUpSpaceDetail | null>;
|
|
14
|
+
|
|
15
|
+
export { _default as default };
|
|
@@ -0,0 +1,94 @@
|
|
|
1
|
+
import { defineCommand, validationError } from '@kb-labs/sdk';
|
|
2
|
+
import { createSpace, requireApiKey, requireTeamId, ClickUpApiError } from '@kb-labs/clickup-core';
|
|
3
|
+
|
|
4
|
+
// src/commands/space-create.ts
|
|
5
|
+
function apiHint(err) {
|
|
6
|
+
switch (err.status) {
|
|
7
|
+
case 401:
|
|
8
|
+
return "CLICKUP_API_KEY is invalid or expired \u2014 check the token in your environment";
|
|
9
|
+
case 403:
|
|
10
|
+
return "You don't have permission for this action in ClickUp \u2014 check workspace access";
|
|
11
|
+
case 404:
|
|
12
|
+
return "Resource not found \u2014 verify the ID is correct (use `kb clickup workspace` to browse IDs)";
|
|
13
|
+
case 429:
|
|
14
|
+
return "ClickUp rate limit reached \u2014 wait a moment and retry";
|
|
15
|
+
default:
|
|
16
|
+
return "Unexpected ClickUp API error";
|
|
17
|
+
}
|
|
18
|
+
}
|
|
19
|
+
function handleError(ctx, err, isJson) {
|
|
20
|
+
if (err instanceof ClickUpApiError) {
|
|
21
|
+
const hint = apiHint(err);
|
|
22
|
+
if (isJson) {
|
|
23
|
+
ctx.ui?.json?.({ ok: false, error: { code: err.code, message: err.message, status: err.status, hint } });
|
|
24
|
+
} else {
|
|
25
|
+
ctx.ui?.error?.(err.message, { hint, cause: `ClickUp API ${err.status} (${err.code})` });
|
|
26
|
+
}
|
|
27
|
+
return;
|
|
28
|
+
}
|
|
29
|
+
const message = err instanceof Error ? err.message : String(err);
|
|
30
|
+
const isEnvMissing = /CLICKUP_API_KEY|CLICKUP_TEAM_ID/.test(message);
|
|
31
|
+
if (isJson) {
|
|
32
|
+
ctx.ui?.json?.({
|
|
33
|
+
ok: false,
|
|
34
|
+
error: {
|
|
35
|
+
code: isEnvMissing ? "ENV_MISSING" : "INTERNAL_ERROR",
|
|
36
|
+
message,
|
|
37
|
+
...isEnvMissing && {
|
|
38
|
+
hint: "Set CLICKUP_API_KEY (and CLICKUP_TEAM_ID for workspace commands) as environment variables"
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
});
|
|
42
|
+
} else {
|
|
43
|
+
ctx.ui?.error?.(message, {
|
|
44
|
+
...isEnvMissing && {
|
|
45
|
+
hint: "Set CLICKUP_API_KEY (and CLICKUP_TEAM_ID for workspace commands) as environment variables",
|
|
46
|
+
command: "export CLICKUP_API_KEY=pk_xxx CLICKUP_TEAM_ID=yyy"
|
|
47
|
+
}
|
|
48
|
+
});
|
|
49
|
+
}
|
|
50
|
+
}
|
|
51
|
+
|
|
52
|
+
// src/commands/space-create.ts
|
|
53
|
+
var space_create_default = defineCommand({
|
|
54
|
+
id: "clickup:space.create",
|
|
55
|
+
description: "Create a new space",
|
|
56
|
+
handler: {
|
|
57
|
+
async intent(_ctx, input) {
|
|
58
|
+
const { name } = input.flags;
|
|
59
|
+
return {
|
|
60
|
+
summary: `Create space "${name ?? "(unnamed)"}"`,
|
|
61
|
+
operations: [{ type: "create", resource: "space", details: { name } }]
|
|
62
|
+
};
|
|
63
|
+
},
|
|
64
|
+
async execute(ctx, input) {
|
|
65
|
+
const { name, color, json, full } = input.flags;
|
|
66
|
+
if (!name) {
|
|
67
|
+
validationError(ctx, "--name is required", void 0, json);
|
|
68
|
+
return { exitCode: 1, result: null };
|
|
69
|
+
}
|
|
70
|
+
try {
|
|
71
|
+
const space = await createSpace(requireApiKey(), requireTeamId(), {
|
|
72
|
+
name,
|
|
73
|
+
color,
|
|
74
|
+
private: input.flags.private ?? false
|
|
75
|
+
});
|
|
76
|
+
if (json) {
|
|
77
|
+
ctx.ui?.json?.(full ? space : { id: space.id, name: space.name });
|
|
78
|
+
} else {
|
|
79
|
+
ctx.ui?.success?.("Space created", {
|
|
80
|
+
sections: [{ items: [`id: ${space.id}`, `name: ${space.name}`] }]
|
|
81
|
+
});
|
|
82
|
+
}
|
|
83
|
+
return { exitCode: 0, result: space };
|
|
84
|
+
} catch (err) {
|
|
85
|
+
handleError(ctx, err, json);
|
|
86
|
+
return { exitCode: 1, result: null };
|
|
87
|
+
}
|
|
88
|
+
}
|
|
89
|
+
}
|
|
90
|
+
});
|
|
91
|
+
|
|
92
|
+
export { space_create_default as default };
|
|
93
|
+
//# sourceMappingURL=space-create.js.map
|
|
94
|
+
//# sourceMappingURL=space-create.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../../src/utils/error.ts","../../src/commands/space-create.ts"],"names":[],"mappings":"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","file":"space-create.js","sourcesContent":["import type { PluginContextV3 } from '@kb-labs/sdk';\nimport { ClickUpApiError } from '@kb-labs/clickup-core';\n\nexport { validationError } from '@kb-labs/sdk';\n\nfunction apiHint(err: ClickUpApiError): string {\n switch (err.status) {\n case 401: return 'CLICKUP_API_KEY is invalid or expired — check the token in your environment';\n case 403: return 'You don\\'t have permission for this action in ClickUp — check workspace access';\n case 404: return 'Resource not found — verify the ID is correct (use `kb clickup workspace` to browse IDs)';\n case 429: return 'ClickUp rate limit reached — wait a moment and retry';\n default: return 'Unexpected ClickUp API error';\n }\n}\n\n/**\n * Output a structured error and return — call right before `return { exitCode: 1, result: null }`.\n * In JSON mode emits `{ ok: false, error: { code, message, hint?, status? } }`.\n * In CLI mode uses ctx.ui.error() with hint and cause.\n */\nexport function handleError(ctx: PluginContextV3, err: unknown, isJson?: boolean): void {\n if (err instanceof ClickUpApiError) {\n const hint = apiHint(err);\n if (isJson) {\n ctx.ui?.json?.({ ok: false, error: { code: err.code, message: err.message, status: err.status, hint } });\n } else {\n ctx.ui?.error?.(err.message, { hint, cause: `ClickUp API ${err.status} (${err.code})` });\n }\n return;\n }\n\n const message = err instanceof Error ? err.message : String(err);\n const isEnvMissing = /CLICKUP_API_KEY|CLICKUP_TEAM_ID/.test(message);\n\n if (isJson) {\n ctx.ui?.json?.({\n ok: false,\n error: {\n code: isEnvMissing ? 'ENV_MISSING' : 'INTERNAL_ERROR',\n message,\n ...(isEnvMissing && {\n hint: 'Set CLICKUP_API_KEY (and CLICKUP_TEAM_ID for workspace commands) as environment variables',\n }),\n },\n });\n } else {\n ctx.ui?.error?.(message, {\n ...(isEnvMissing && {\n hint: 'Set CLICKUP_API_KEY (and CLICKUP_TEAM_ID for workspace commands) as environment variables',\n command: 'export CLICKUP_API_KEY=pk_xxx CLICKUP_TEAM_ID=yyy',\n }),\n });\n }\n}\n\n/**\n * Re-throws `err` as an HTTP-aware error for REST handlers.\n * `ClickUpApiError` → preserves HTTP status code; env errors → 400; others → 500.\n * The envelope middleware in rest-api reads `err.statusCode` to set the response status.\n */\nexport function rethrowForRest(err: unknown): never {\n if (err instanceof ClickUpApiError) {\n const hint = apiHint(err);\n const restErr = Object.assign(new Error(err.message), {\n statusCode: err.status,\n code: err.code,\n details: { hint },\n });\n throw restErr;\n }\n const message = err instanceof Error ? err.message : String(err);\n const isEnvMissing = /CLICKUP_API_KEY|CLICKUP_TEAM_ID/.test(message);\n if (isEnvMissing) {\n throw Object.assign(new Error(message), {\n statusCode: 400,\n code: 'ENV_MISSING',\n details: { hint: 'Set CLICKUP_API_KEY (and CLICKUP_TEAM_ID for workspace commands) as environment variables' },\n });\n }\n throw err;\n}\n","import { defineCommand, type CLIInput, type PluginContextV3 } from '@kb-labs/sdk';\nimport { requireApiKey, requireTeamId, createSpace } from '@kb-labs/clickup-core';\nimport { handleError, validationError } from '../utils/error.js';\n\ntype SpaceCreateFlags = {\n name: string;\n color?: string;\n private?: boolean;\n json?: boolean;\n full?: boolean;\n 'dry-run'?: boolean;\n};\n\nexport default defineCommand({\n id: 'clickup:space.create',\n description: 'Create a new space',\n\n handler: {\n async intent(_ctx: PluginContextV3, input: CLIInput<SpaceCreateFlags>) {\n const { name } = input.flags;\n return {\n summary: `Create space \"${name ?? '(unnamed)'}\"`,\n operations: [{ type: 'create' as const, resource: 'space', details: { name } }],\n };\n },\n\n async execute(ctx: PluginContextV3, input: CLIInput<SpaceCreateFlags>) {\n const { name, color, json, full } = input.flags;\n if (!name) {\n validationError(ctx, '--name is required', undefined, json);\n return { exitCode: 1, result: null };\n }\n\n try {\n const space = await createSpace(requireApiKey(), requireTeamId(), {\n name,\n color,\n private: input.flags.private ?? false,\n });\n\n if (json) {\n ctx.ui?.json?.(full ? space : { id: space.id, name: space.name });\n } else {\n ctx.ui?.success?.('Space created', {\n sections: [{ items: [`id: ${space.id}`, `name: ${space.name}`] }],\n });\n }\n\n return { exitCode: 0, result: space };\n } catch (err) {\n handleError(ctx, err, json);\n return { exitCode: 1, result: null };\n }\n },\n },\n});\n"]}
|