@krodak/clickup-cli 1.5.2 → 1.6.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/.claude-plugin/plugin.json +1 -1
- package/README.md +28 -4
- package/dist/index.js +406 -110
- package/package.json +1 -1
- package/skills/clickup-cli/SKILL.md +24 -2
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "clickup-cli",
|
|
3
3
|
"description": "ClickUp CLI skills for managing tasks, sprints, comments, checklists, custom fields, tags, and time tracking via the cup command",
|
|
4
|
-
"version": "1.
|
|
4
|
+
"version": "1.6.0",
|
|
5
5
|
"author": {
|
|
6
6
|
"name": "Krzysztof Rodak"
|
|
7
7
|
},
|
package/README.md
CHANGED
|
@@ -165,18 +165,41 @@ Most commands scope to your assigned tasks by default - keeping output small and
|
|
|
165
165
|
|
|
166
166
|
## Configuration
|
|
167
167
|
|
|
168
|
+
### Profiles
|
|
169
|
+
|
|
170
|
+
Multiple profiles for different workspaces or accounts:
|
|
171
|
+
|
|
172
|
+
```bash
|
|
173
|
+
cup profile add work # interactive setup
|
|
174
|
+
cup profile add personal # another workspace
|
|
175
|
+
cup profile list # show all profiles
|
|
176
|
+
cup profile use personal # switch default
|
|
177
|
+
cup tasks -p work # one-off profile override
|
|
178
|
+
```
|
|
179
|
+
|
|
168
180
|
### Config file
|
|
169
181
|
|
|
170
182
|
`~/.config/cup/config.json` (or `$XDG_CONFIG_HOME/cup/config.json`):
|
|
171
183
|
|
|
172
184
|
```json
|
|
173
185
|
{
|
|
174
|
-
"
|
|
175
|
-
"
|
|
176
|
-
|
|
186
|
+
"defaultProfile": "work",
|
|
187
|
+
"profiles": {
|
|
188
|
+
"work": {
|
|
189
|
+
"apiToken": "pk_...",
|
|
190
|
+
"teamId": "12345678",
|
|
191
|
+
"sprintFolderId": "optional"
|
|
192
|
+
},
|
|
193
|
+
"personal": {
|
|
194
|
+
"apiToken": "pk_...",
|
|
195
|
+
"teamId": "87654321"
|
|
196
|
+
}
|
|
197
|
+
}
|
|
177
198
|
}
|
|
178
199
|
```
|
|
179
200
|
|
|
201
|
+
Old flat configs (pre-profiles) are auto-migrated on first load.
|
|
202
|
+
|
|
180
203
|
### Environment variables
|
|
181
204
|
|
|
182
205
|
Environment variables override config file values:
|
|
@@ -185,9 +208,10 @@ Environment variables override config file values:
|
|
|
185
208
|
| -------------- | ----------------------------------------------------------------- |
|
|
186
209
|
| `CU_API_TOKEN` | ClickUp personal API token (`pk_`) |
|
|
187
210
|
| `CU_TEAM_ID` | Workspace (team) ID |
|
|
211
|
+
| `CU_PROFILE` | Profile name (overrides `defaultProfile`, overridden by `-p`) |
|
|
188
212
|
| `CU_OUTPUT` | Set to `json` to force JSON output when piped (default: markdown) |
|
|
189
213
|
|
|
190
|
-
When both are set, the config file is not required. Useful for CI/CD and containerized agents.
|
|
214
|
+
When both `CU_API_TOKEN` and `CU_TEAM_ID` are set, the config file is not required. Useful for CI/CD and containerized agents.
|
|
191
215
|
|
|
192
216
|
## Custom Task IDs
|
|
193
217
|
|
package/dist/index.js
CHANGED
|
@@ -741,62 +741,243 @@ function migrateFromLegacy() {
|
|
|
741
741
|
function configPath() {
|
|
742
742
|
return join(configDir(), "config.json");
|
|
743
743
|
}
|
|
744
|
-
function
|
|
744
|
+
function migrateToMultiProfile(parsed, filePath) {
|
|
745
|
+
if (typeof parsed.apiToken === "string" && !parsed.profiles) {
|
|
746
|
+
const profile = {};
|
|
747
|
+
const token = trimConfigValue(parsed.apiToken);
|
|
748
|
+
if (token) profile.apiToken = token;
|
|
749
|
+
const team = typeof parsed.teamId === "string" ? trimConfigValue(parsed.teamId) : void 0;
|
|
750
|
+
if (team) profile.teamId = team;
|
|
751
|
+
const sprint = typeof parsed.sprintFolderId === "string" ? trimConfigValue(parsed.sprintFolderId) : void 0;
|
|
752
|
+
if (sprint) profile.sprintFolderId = sprint;
|
|
753
|
+
const migrated = {
|
|
754
|
+
defaultProfile: "default",
|
|
755
|
+
profiles: { default: profile }
|
|
756
|
+
};
|
|
757
|
+
const dir = configDir();
|
|
758
|
+
if (!fs.existsSync(dir)) {
|
|
759
|
+
fs.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
760
|
+
}
|
|
761
|
+
fs.writeFileSync(join(dir, "config.json"), JSON.stringify(migrated, null, 2) + "\n", {
|
|
762
|
+
encoding: "utf-8",
|
|
763
|
+
mode: 384
|
|
764
|
+
});
|
|
765
|
+
return migrated;
|
|
766
|
+
}
|
|
767
|
+
if (isRecord2(parsed.profiles)) {
|
|
768
|
+
const profiles = {};
|
|
769
|
+
for (const [name, value] of Object.entries(parsed.profiles)) {
|
|
770
|
+
if (isRecord2(value)) {
|
|
771
|
+
const p = {};
|
|
772
|
+
if (typeof value.apiToken === "string" && value.apiToken.trim())
|
|
773
|
+
p.apiToken = value.apiToken.trim();
|
|
774
|
+
if (typeof value.teamId === "string" && value.teamId.trim()) p.teamId = value.teamId.trim();
|
|
775
|
+
if (typeof value.sprintFolderId === "string" && value.sprintFolderId.trim())
|
|
776
|
+
p.sprintFolderId = value.sprintFolderId.trim();
|
|
777
|
+
profiles[name] = p;
|
|
778
|
+
}
|
|
779
|
+
}
|
|
780
|
+
return {
|
|
781
|
+
defaultProfile: typeof parsed.defaultProfile === "string" ? parsed.defaultProfile : "",
|
|
782
|
+
profiles
|
|
783
|
+
};
|
|
784
|
+
}
|
|
785
|
+
throw new Error(`Config file at ${filePath} has unrecognized format.`);
|
|
786
|
+
}
|
|
787
|
+
function parseRawConfig(filePath) {
|
|
788
|
+
const raw = fs.readFileSync(filePath, "utf-8");
|
|
789
|
+
let parsed;
|
|
790
|
+
try {
|
|
791
|
+
parsed = JSON.parse(raw);
|
|
792
|
+
} catch {
|
|
793
|
+
throw new Error(
|
|
794
|
+
`Config file at ${filePath} contains invalid JSON. Please check the file syntax.`
|
|
795
|
+
);
|
|
796
|
+
}
|
|
797
|
+
if (!isRecord2(parsed)) {
|
|
798
|
+
throw new Error(`Config file at ${filePath} must contain a JSON object.`);
|
|
799
|
+
}
|
|
800
|
+
return { parsed, raw };
|
|
801
|
+
}
|
|
802
|
+
function isOldFormat(parsed) {
|
|
803
|
+
return typeof parsed.apiToken === "string" && !parsed.profiles;
|
|
804
|
+
}
|
|
805
|
+
function loadConfig(profileName) {
|
|
745
806
|
migrateFromLegacy();
|
|
746
807
|
const envToken = process.env.CU_API_TOKEN?.trim();
|
|
747
808
|
const envTeamId = process.env.CU_TEAM_ID?.trim();
|
|
748
|
-
|
|
749
|
-
|
|
750
|
-
|
|
809
|
+
if (envToken && envTeamId) {
|
|
810
|
+
if (!envToken.startsWith("pk_")) {
|
|
811
|
+
throw new Error("CU_API_TOKEN must start with pk_.");
|
|
812
|
+
}
|
|
813
|
+
return { apiToken: envToken, teamId: envTeamId };
|
|
814
|
+
}
|
|
751
815
|
const path = configPath();
|
|
752
|
-
if (fs.existsSync(path)) {
|
|
753
|
-
|
|
754
|
-
|
|
755
|
-
|
|
756
|
-
|
|
757
|
-
|
|
816
|
+
if (!fs.existsSync(path)) {
|
|
817
|
+
if (envToken || envTeamId) {
|
|
818
|
+
throw new Error("Both CU_API_TOKEN and CU_TEAM_ID must be set, or run: cup init");
|
|
819
|
+
}
|
|
820
|
+
throw new Error("Config missing required field: apiToken.\nSet CU_API_TOKEN or run: cup init");
|
|
821
|
+
}
|
|
822
|
+
const { parsed } = parseRawConfig(path);
|
|
823
|
+
if (isOldFormat(parsed)) {
|
|
824
|
+
const fileConfig = parseConfigFile(JSON.stringify(parsed), path, true);
|
|
825
|
+
const apiToken2 = envToken ?? fileConfig.apiToken;
|
|
826
|
+
if (!apiToken2) {
|
|
827
|
+
throw new Error("Config missing required field: apiToken.\nSet CU_API_TOKEN or run: cup init");
|
|
828
|
+
}
|
|
829
|
+
if (!apiToken2.startsWith("pk_")) {
|
|
830
|
+
throw new Error("Config apiToken must start with pk_. The configured token does not.");
|
|
831
|
+
}
|
|
832
|
+
const teamId2 = envTeamId ?? fileConfig.teamId;
|
|
833
|
+
if (!teamId2) {
|
|
834
|
+
throw new Error("Config missing required field: teamId.\nSet CU_TEAM_ID or run: cup init");
|
|
835
|
+
}
|
|
836
|
+
migrateToMultiProfile(parsed, path);
|
|
837
|
+
return {
|
|
838
|
+
apiToken: apiToken2,
|
|
839
|
+
teamId: teamId2,
|
|
840
|
+
...fileConfig.sprintFolderId ? { sprintFolderId: fileConfig.sprintFolderId } : {}
|
|
841
|
+
};
|
|
842
|
+
}
|
|
843
|
+
const multi = migrateToMultiProfile(parsed, path);
|
|
844
|
+
const resolvedProfile = profileName ?? process.env.CU_PROFILE?.trim() ?? multi.defaultProfile;
|
|
845
|
+
if (!resolvedProfile) {
|
|
846
|
+
throw new Error("No default profile set. Run: cup profile use <name>");
|
|
758
847
|
}
|
|
759
|
-
const
|
|
848
|
+
const profile = multi.profiles[resolvedProfile];
|
|
849
|
+
if (!profile) {
|
|
850
|
+
const available = Object.keys(multi.profiles).join(", ");
|
|
851
|
+
throw new Error(`Profile "${resolvedProfile}" not found. Available: ${available}`);
|
|
852
|
+
}
|
|
853
|
+
const apiToken = envToken ?? profile.apiToken?.trim();
|
|
760
854
|
if (!apiToken) {
|
|
761
|
-
throw new Error(
|
|
855
|
+
throw new Error(
|
|
856
|
+
`Profile "${resolvedProfile}" missing apiToken. Run: cup profile add ${resolvedProfile}`
|
|
857
|
+
);
|
|
762
858
|
}
|
|
763
859
|
if (!apiToken.startsWith("pk_")) {
|
|
764
860
|
throw new Error("Config apiToken must start with pk_. The configured token does not.");
|
|
765
861
|
}
|
|
766
|
-
const teamId = envTeamId
|
|
862
|
+
const teamId = envTeamId ?? profile.teamId?.trim();
|
|
767
863
|
if (!teamId) {
|
|
768
|
-
throw new Error("
|
|
864
|
+
throw new Error(`Profile "${resolvedProfile}" missing teamId.`);
|
|
865
|
+
}
|
|
866
|
+
return {
|
|
867
|
+
apiToken,
|
|
868
|
+
teamId,
|
|
869
|
+
...profile.sprintFolderId ? { sprintFolderId: profile.sprintFolderId } : {}
|
|
870
|
+
};
|
|
871
|
+
}
|
|
872
|
+
function loadMultiProfileConfig() {
|
|
873
|
+
migrateFromLegacy();
|
|
874
|
+
const path = configPath();
|
|
875
|
+
if (!fs.existsSync(path)) {
|
|
876
|
+
return { defaultProfile: "", profiles: {} };
|
|
877
|
+
}
|
|
878
|
+
let parsed;
|
|
879
|
+
try {
|
|
880
|
+
const raw = fs.readFileSync(path, "utf-8");
|
|
881
|
+
parsed = JSON.parse(raw);
|
|
882
|
+
} catch {
|
|
883
|
+
return { defaultProfile: "", profiles: {} };
|
|
884
|
+
}
|
|
885
|
+
if (!isRecord2(parsed)) return { defaultProfile: "", profiles: {} };
|
|
886
|
+
if (isOldFormat(parsed)) {
|
|
887
|
+
return migrateToMultiProfile(parsed, path);
|
|
769
888
|
}
|
|
770
|
-
return
|
|
889
|
+
return migrateToMultiProfile(parsed, path);
|
|
771
890
|
}
|
|
772
|
-
function
|
|
891
|
+
function saveMultiProfileConfig(config) {
|
|
892
|
+
const dir = configDir();
|
|
893
|
+
if (!fs.existsSync(dir)) {
|
|
894
|
+
fs.mkdirSync(dir, { recursive: true, mode: 448 });
|
|
895
|
+
}
|
|
896
|
+
fs.writeFileSync(join(dir, "config.json"), JSON.stringify(config, null, 2) + "\n", {
|
|
897
|
+
encoding: "utf-8",
|
|
898
|
+
mode: 384
|
|
899
|
+
});
|
|
900
|
+
}
|
|
901
|
+
function addProfile(name, profile) {
|
|
902
|
+
const multi = loadMultiProfileConfig();
|
|
903
|
+
multi.profiles[name] = profile;
|
|
904
|
+
if (!multi.defaultProfile) multi.defaultProfile = name;
|
|
905
|
+
saveMultiProfileConfig(multi);
|
|
906
|
+
}
|
|
907
|
+
function removeProfile(name) {
|
|
908
|
+
const multi = loadMultiProfileConfig();
|
|
909
|
+
if (!multi.profiles[name]) {
|
|
910
|
+
throw new Error(`Profile "${name}" not found.`);
|
|
911
|
+
}
|
|
912
|
+
const keys = Object.keys(multi.profiles);
|
|
913
|
+
if (keys.length <= 1) {
|
|
914
|
+
throw new Error("Cannot remove the last profile.");
|
|
915
|
+
}
|
|
916
|
+
delete multi.profiles[name];
|
|
917
|
+
if (multi.defaultProfile === name) {
|
|
918
|
+
multi.defaultProfile = Object.keys(multi.profiles)[0] ?? "";
|
|
919
|
+
}
|
|
920
|
+
saveMultiProfileConfig(multi);
|
|
921
|
+
}
|
|
922
|
+
function setDefaultProfile(name) {
|
|
923
|
+
const multi = loadMultiProfileConfig();
|
|
924
|
+
if (!multi.profiles[name]) {
|
|
925
|
+
const available = Object.keys(multi.profiles).join(", ");
|
|
926
|
+
throw new Error(`Profile "${name}" not found. Available: ${available}`);
|
|
927
|
+
}
|
|
928
|
+
multi.defaultProfile = name;
|
|
929
|
+
saveMultiProfileConfig(multi);
|
|
930
|
+
}
|
|
931
|
+
function listProfiles() {
|
|
932
|
+
const multi = loadMultiProfileConfig();
|
|
933
|
+
return Object.entries(multi.profiles).map(([name, profile]) => ({
|
|
934
|
+
name,
|
|
935
|
+
isDefault: name === multi.defaultProfile,
|
|
936
|
+
teamId: profile.teamId
|
|
937
|
+
}));
|
|
938
|
+
}
|
|
939
|
+
function loadRawConfig(profileName) {
|
|
773
940
|
migrateFromLegacy();
|
|
774
941
|
const path = configPath();
|
|
775
942
|
if (!fs.existsSync(path)) return {};
|
|
776
|
-
|
|
943
|
+
let parsed;
|
|
944
|
+
try {
|
|
945
|
+
const raw = fs.readFileSync(path, "utf-8");
|
|
946
|
+
parsed = JSON.parse(raw);
|
|
947
|
+
} catch {
|
|
948
|
+
return {};
|
|
949
|
+
}
|
|
950
|
+
if (!isRecord2(parsed)) {
|
|
951
|
+
throw new Error(`Config file at ${path} must contain a JSON object.`);
|
|
952
|
+
}
|
|
953
|
+
if (isOldFormat(parsed)) {
|
|
954
|
+
return parseConfigFile(JSON.stringify(parsed), path, false, true);
|
|
955
|
+
}
|
|
956
|
+
const multi = migrateToMultiProfile(parsed, path);
|
|
957
|
+
const name = profileName || multi.defaultProfile || "default";
|
|
958
|
+
return multi.profiles[name] ?? {};
|
|
777
959
|
}
|
|
778
960
|
function getConfigPath() {
|
|
779
961
|
migrateFromLegacy();
|
|
780
962
|
return configPath();
|
|
781
963
|
}
|
|
782
|
-
function writeConfig(config) {
|
|
783
|
-
const
|
|
784
|
-
|
|
785
|
-
|
|
786
|
-
|
|
787
|
-
const filePath = join(dir, "config.json");
|
|
788
|
-
const apiToken = trimConfigValue(config.apiToken) ?? "";
|
|
789
|
-
const teamId = trimConfigValue(config.teamId) ?? "";
|
|
964
|
+
function writeConfig(config, profileName) {
|
|
965
|
+
const multi = loadMultiProfileConfig();
|
|
966
|
+
const name = profileName || multi.defaultProfile || "default";
|
|
967
|
+
const apiToken = trimConfigValue(config.apiToken) ?? void 0;
|
|
968
|
+
const teamId = trimConfigValue(config.teamId) ?? void 0;
|
|
790
969
|
const sprintFolderId = trimConfigValue(config.sprintFolderId);
|
|
791
970
|
const normalizedConfig = {
|
|
792
971
|
...apiToken ? { apiToken } : {},
|
|
793
972
|
...teamId ? { teamId } : {},
|
|
794
973
|
...sprintFolderId ? { sprintFolderId } : {}
|
|
795
974
|
};
|
|
796
|
-
|
|
797
|
-
|
|
798
|
-
|
|
799
|
-
}
|
|
975
|
+
multi.profiles[name] = {
|
|
976
|
+
...multi.profiles[name],
|
|
977
|
+
...normalizedConfig
|
|
978
|
+
};
|
|
979
|
+
if (!multi.defaultProfile) multi.defaultProfile = name;
|
|
980
|
+
saveMultiProfileConfig(multi);
|
|
800
981
|
}
|
|
801
982
|
|
|
802
983
|
// src/date.ts
|
|
@@ -2255,12 +2436,12 @@ function assertValidKey(key) {
|
|
|
2255
2436
|
throw new Error(`Unknown config key: ${key}. Valid keys: ${[...VALID_KEYS].join(", ")}`);
|
|
2256
2437
|
}
|
|
2257
2438
|
}
|
|
2258
|
-
function getConfigValue(key) {
|
|
2439
|
+
function getConfigValue(key, profileName) {
|
|
2259
2440
|
assertValidKey(key);
|
|
2260
|
-
const raw = loadRawConfig();
|
|
2441
|
+
const raw = loadRawConfig(profileName);
|
|
2261
2442
|
return readStoredString(raw[key]);
|
|
2262
2443
|
}
|
|
2263
|
-
function setConfigValue(key, value) {
|
|
2444
|
+
function setConfigValue(key, value, profileName) {
|
|
2264
2445
|
assertValidKey(key);
|
|
2265
2446
|
const normalizedValue = readStoredString(value);
|
|
2266
2447
|
if (key === "apiToken" && (!normalizedValue || !normalizedValue.startsWith("pk_"))) {
|
|
@@ -2269,7 +2450,7 @@ function setConfigValue(key, value) {
|
|
|
2269
2450
|
if (key === "teamId" && !normalizedValue) {
|
|
2270
2451
|
throw new Error("teamId must be non-empty");
|
|
2271
2452
|
}
|
|
2272
|
-
const raw = loadRawConfig();
|
|
2453
|
+
const raw = loadRawConfig(profileName);
|
|
2273
2454
|
const sprintFolderId = readStoredString(raw.sprintFolderId);
|
|
2274
2455
|
const merged = {
|
|
2275
2456
|
...readStoredString(raw.apiToken) ? { apiToken: readStoredString(raw.apiToken) } : {},
|
|
@@ -2285,7 +2466,7 @@ function setConfigValue(key, value) {
|
|
|
2285
2466
|
} else {
|
|
2286
2467
|
merged[key] = normalizedValue;
|
|
2287
2468
|
}
|
|
2288
|
-
writeConfig(merged);
|
|
2469
|
+
writeConfig(merged, profileName);
|
|
2289
2470
|
}
|
|
2290
2471
|
function configPath2() {
|
|
2291
2472
|
return getConfigPath();
|
|
@@ -2960,6 +3141,13 @@ var commandMetadata = [
|
|
|
2960
3141
|
flags: ["--json"],
|
|
2961
3142
|
quickReference: [{ section: "read", usage: "templates", description: "List task templates" }]
|
|
2962
3143
|
},
|
|
3144
|
+
{
|
|
3145
|
+
name: "profile",
|
|
3146
|
+
description: "Manage profiles",
|
|
3147
|
+
quickReference: [
|
|
3148
|
+
{ section: "configuration", usage: "profile", description: "Manage profiles" }
|
|
3149
|
+
]
|
|
3150
|
+
},
|
|
2963
3151
|
{
|
|
2964
3152
|
name: "config",
|
|
2965
3153
|
description: "Manage CLI configuration",
|
|
@@ -3016,7 +3204,14 @@ function topLevelCommandNames() {
|
|
|
3016
3204
|
}
|
|
3017
3205
|
|
|
3018
3206
|
// src/commands/completion.ts
|
|
3019
|
-
var bashSpecialCaseCommands = /* @__PURE__ */ new Set([
|
|
3207
|
+
var bashSpecialCaseCommands = /* @__PURE__ */ new Set([
|
|
3208
|
+
"checklist",
|
|
3209
|
+
"time",
|
|
3210
|
+
"bulk",
|
|
3211
|
+
"config",
|
|
3212
|
+
"profile",
|
|
3213
|
+
"completion"
|
|
3214
|
+
]);
|
|
3020
3215
|
function escapeSingleQuotes(value) {
|
|
3021
3216
|
return value.replaceAll("'", "'\\''");
|
|
3022
3217
|
}
|
|
@@ -3109,6 +3304,11 @@ ${renderBashCommandCases()}
|
|
|
3109
3304
|
COMPREPLY=($(compgen -W "status" -- "$cur"))
|
|
3110
3305
|
fi
|
|
3111
3306
|
;;
|
|
3307
|
+
profile)
|
|
3308
|
+
if [[ $cword -eq 2 ]]; then
|
|
3309
|
+
COMPREPLY=($(compgen -W "list add remove use" -- "$cur"))
|
|
3310
|
+
fi
|
|
3311
|
+
;;
|
|
3112
3312
|
config)
|
|
3113
3313
|
if [[ $cword -eq 2 ]]; then
|
|
3114
3314
|
COMPREPLY=($(compgen -W "get set path" -- "$cur"))
|
|
@@ -3646,6 +3846,33 @@ ${renderZshTopLevelCommands(name)}
|
|
|
3646
3846
|
'(-c --content)'{-c,--content}'[New page content]:text:' \\
|
|
3647
3847
|
'--json[Force JSON output]'
|
|
3648
3848
|
;;
|
|
3849
|
+
profile)
|
|
3850
|
+
local -a profile_cmds
|
|
3851
|
+
profile_cmds=(
|
|
3852
|
+
'list:List all profiles'
|
|
3853
|
+
'add:Add a new profile'
|
|
3854
|
+
'remove:Remove a profile'
|
|
3855
|
+
'use:Set the default profile'
|
|
3856
|
+
)
|
|
3857
|
+
_arguments -C \\
|
|
3858
|
+
'1:profile command:->profile_cmd' \\
|
|
3859
|
+
'*::profile_arg:->profile_args'
|
|
3860
|
+
case $state in
|
|
3861
|
+
profile_cmd)
|
|
3862
|
+
_describe 'profile command' profile_cmds
|
|
3863
|
+
;;
|
|
3864
|
+
profile_args)
|
|
3865
|
+
case $words[1] in
|
|
3866
|
+
list)
|
|
3867
|
+
_arguments '--json[Force JSON output]'
|
|
3868
|
+
;;
|
|
3869
|
+
add|remove|use)
|
|
3870
|
+
_arguments '1:name:'
|
|
3871
|
+
;;
|
|
3872
|
+
esac
|
|
3873
|
+
;;
|
|
3874
|
+
esac
|
|
3875
|
+
;;
|
|
3649
3876
|
config)
|
|
3650
3877
|
local -a config_cmds
|
|
3651
3878
|
config_cmds=(
|
|
@@ -3726,6 +3953,12 @@ complete -c ${name} -n '__fish_seen_subcommand_from attach' -F
|
|
|
3726
3953
|
complete -c ${name} -n '__fish_seen_subcommand_from bulk; and not __fish_seen_subcommand_from status' -a status -d 'Update status of multiple tasks'
|
|
3727
3954
|
complete -c ${name} -n '__fish_seen_subcommand_from status; and __fish_seen_subcommand_from bulk' -l json -d 'Force JSON output'
|
|
3728
3955
|
|
|
3956
|
+
complete -c ${name} -n '__fish_seen_subcommand_from profile; and not __fish_seen_subcommand_from list add remove use' -a list -d 'List all profiles'
|
|
3957
|
+
complete -c ${name} -n '__fish_seen_subcommand_from profile; and not __fish_seen_subcommand_from list add remove use' -a add -d 'Add a new profile'
|
|
3958
|
+
complete -c ${name} -n '__fish_seen_subcommand_from profile; and not __fish_seen_subcommand_from list add remove use' -a remove -d 'Remove a profile'
|
|
3959
|
+
complete -c ${name} -n '__fish_seen_subcommand_from profile; and not __fish_seen_subcommand_from list add remove use' -a use -d 'Set the default profile'
|
|
3960
|
+
complete -c ${name} -n '__fish_seen_subcommand_from list; and __fish_seen_subcommand_from profile' -l json -d 'Force JSON output'
|
|
3961
|
+
|
|
3729
3962
|
complete -c ${name} -n '__fish_seen_subcommand_from config; and not __fish_seen_subcommand_from get set path' -a get -d 'Print a config value'
|
|
3730
3963
|
complete -c ${name} -n '__fish_seen_subcommand_from config; and not __fish_seen_subcommand_from get set path' -a set -d 'Set a config value'
|
|
3731
3964
|
complete -c ${name} -n '__fish_seen_subcommand_from config; and not __fish_seen_subcommand_from get set path' -a path -d 'Print config file path'
|
|
@@ -4552,7 +4785,10 @@ function parseOptionalNumberOption(value, optionName) {
|
|
|
4552
4785
|
}
|
|
4553
4786
|
function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
4554
4787
|
const program = new Command();
|
|
4555
|
-
program.name(programName).description("ClickUp CLI for AI agents").version(version).allowExcessArguments(false);
|
|
4788
|
+
program.name(programName).description("ClickUp CLI for AI agents").version(version).allowExcessArguments(false).option("-p, --profile <name>", "Use a specific profile");
|
|
4789
|
+
function getProfileName() {
|
|
4790
|
+
return program.opts().profile;
|
|
4791
|
+
}
|
|
4556
4792
|
program.command("init").description(`Set up ${programName} for the first time`).action(
|
|
4557
4793
|
wrapAction(async () => {
|
|
4558
4794
|
await runInitCommand();
|
|
@@ -4560,7 +4796,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4560
4796
|
);
|
|
4561
4797
|
program.command("auth").description("Validate API token and show current user").option("--json", "Force JSON output even in terminal").action(
|
|
4562
4798
|
wrapAction(async (opts) => {
|
|
4563
|
-
const config = loadConfig();
|
|
4799
|
+
const config = loadConfig(getProfileName());
|
|
4564
4800
|
const result = await checkAuth(config);
|
|
4565
4801
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4566
4802
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -4576,7 +4812,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4576
4812
|
'Filter by task type (e.g. "task", "initiative", or custom type name/ID)'
|
|
4577
4813
|
).option("--include-closed", "Include done/closed tasks").option("--json", "Force JSON output even in terminal").action(
|
|
4578
4814
|
wrapAction(async (opts) => {
|
|
4579
|
-
const config = loadConfig();
|
|
4815
|
+
const config = loadConfig(getProfileName());
|
|
4580
4816
|
const tasks = await fetchMyTasks(config, {
|
|
4581
4817
|
typeFilter: opts.type,
|
|
4582
4818
|
statuses: opts.status ? [opts.status] : void 0,
|
|
@@ -4590,7 +4826,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4590
4826
|
);
|
|
4591
4827
|
program.command("task <taskId>").description("Get task details").option("--json", "Force JSON output even in terminal").action(
|
|
4592
4828
|
wrapAction(async (taskId, opts) => {
|
|
4593
|
-
const config = loadConfig();
|
|
4829
|
+
const config = loadConfig(getProfileName());
|
|
4594
4830
|
const result = await getTask(config, taskId);
|
|
4595
4831
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4596
4832
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -4603,7 +4839,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4603
4839
|
);
|
|
4604
4840
|
program.command("update <taskId>").description("Update a task").option("-n, --name <text>", "New task name").option("-d, --description <text>", "New description (markdown supported)").option("-s, --status <status>", 'New status (e.g. "in progress", "done")').option("--priority <level>", "Priority: urgent, high, normal, low (or 1-4)").option("--due-date <date>", "Due date (YYYY-MM-DD)").option("--time-estimate <duration>", 'Time estimate (e.g. "2h", "30m", "1h30m")').option("--assignee <userId>", 'Add assignee by user ID or "me"').option("--parent <taskId>", "Set parent task (makes this a subtask)").option("--json", "Force JSON output even in terminal").action(
|
|
4605
4841
|
wrapAction(async (taskId, opts) => {
|
|
4606
|
-
const config = loadConfig();
|
|
4842
|
+
const config = loadConfig(getProfileName());
|
|
4607
4843
|
if (opts.assignee === "me") {
|
|
4608
4844
|
const client = new ClickUpClient(config);
|
|
4609
4845
|
opts.assignee = String(await resolveAssigneeId(client, "me"));
|
|
@@ -4619,7 +4855,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4619
4855
|
);
|
|
4620
4856
|
program.command("create").description("Create a new task").option("-l, --list <listId>", "Target list ID (auto-detected from --parent if omitted)").requiredOption("-n, --name <name>", "Task name").option("-d, --description <text>", "Task description (markdown supported)").option("-p, --parent <taskId>", "Parent task ID (list auto-detected from parent)").option("-s, --status <status>", "Initial status").option("--priority <level>", "Priority: urgent, high, normal, low (or 1-4)").option("--due-date <date>", "Due date (YYYY-MM-DD)").option("--assignee <userId>", 'Assignee user ID or "me"').option("--tags <tags>", "Comma-separated tag names").option("--custom-item-id <id>", "Custom task type ID (use to create initiatives)").option("--time-estimate <duration>", 'Time estimate (e.g. "2h", "30m", "1h30m")').option("--template <id>", "Create from a task template").option("--json", "Force JSON output even in terminal").action(
|
|
4621
4857
|
wrapAction(async (opts) => {
|
|
4622
|
-
const config = loadConfig();
|
|
4858
|
+
const config = loadConfig(getProfileName());
|
|
4623
4859
|
if (opts.assignee === "me") {
|
|
4624
4860
|
const client = new ClickUpClient(config);
|
|
4625
4861
|
opts.assignee = String(await resolveAssigneeId(client, "me"));
|
|
@@ -4635,21 +4871,21 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4635
4871
|
program.command("sprint").description("List my tasks in the current active sprint (auto-detected)").option("--status <status>", "Filter by status").option("--space <nameOrId>", "Narrow sprint search to a specific space (partial name or ID)").option("--folder <folderId>", "Sprint folder ID (overrides config and auto-detection)").option("--include-closed", "Include done/closed tasks").option("--json", "Force JSON output even in terminal").action(
|
|
4636
4872
|
wrapAction(
|
|
4637
4873
|
async (opts) => {
|
|
4638
|
-
const config = loadConfig();
|
|
4874
|
+
const config = loadConfig(getProfileName());
|
|
4639
4875
|
await runSprintCommand(config, opts);
|
|
4640
4876
|
}
|
|
4641
4877
|
)
|
|
4642
4878
|
);
|
|
4643
4879
|
program.command("sprints").description("List all sprints in sprint folders").option("--space <nameOrId>", "Filter by space (partial name or ID)").option("--json", "Force JSON output even in terminal").action(
|
|
4644
4880
|
wrapAction(async (opts) => {
|
|
4645
|
-
const config = loadConfig();
|
|
4881
|
+
const config = loadConfig(getProfileName());
|
|
4646
4882
|
await listSprints(config, opts);
|
|
4647
4883
|
})
|
|
4648
4884
|
);
|
|
4649
4885
|
program.command("subtasks <taskId>").description("List subtasks of a task or initiative").option("--status <status>", "Filter by status").option("--name <partial>", "Filter by name (case-insensitive contains)").option("--include-closed", "Include closed/done subtasks").option("--json", "Force JSON output even in terminal").action(
|
|
4650
4886
|
wrapAction(
|
|
4651
4887
|
async (taskId, opts) => {
|
|
4652
|
-
const config = loadConfig();
|
|
4888
|
+
const config = loadConfig(getProfileName());
|
|
4653
4889
|
let tasks = await fetchSubtasks(config, taskId, { includeClosed: opts.includeClosed });
|
|
4654
4890
|
if (opts.status) {
|
|
4655
4891
|
const lower = opts.status.toLowerCase();
|
|
@@ -4666,7 +4902,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4666
4902
|
program.command("comment <taskId>").description("Post a comment on a task").requiredOption("-m, --message <text>", "Comment text").option("--notify-all", "Notify all assignees").option("--json", "Force JSON output even in terminal").action(
|
|
4667
4903
|
wrapAction(
|
|
4668
4904
|
async (taskId, opts) => {
|
|
4669
|
-
const config = loadConfig();
|
|
4905
|
+
const config = loadConfig(getProfileName());
|
|
4670
4906
|
const result = await postComment(config, taskId, opts.message, opts.notifyAll);
|
|
4671
4907
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4672
4908
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -4678,7 +4914,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4678
4914
|
);
|
|
4679
4915
|
program.command("comments <taskId>").description("List comments on a task").option("--json", "Force JSON output even in terminal").action(
|
|
4680
4916
|
wrapAction(async (taskId, opts) => {
|
|
4681
|
-
const config = loadConfig();
|
|
4917
|
+
const config = loadConfig(getProfileName());
|
|
4682
4918
|
const comments = await fetchComments(config, taskId);
|
|
4683
4919
|
printComments(comments, opts.json ?? false);
|
|
4684
4920
|
})
|
|
@@ -4686,7 +4922,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4686
4922
|
program.command("comment-edit <commentId>").description("Edit an existing comment").requiredOption("-m, --message <text>", "New comment text").option("--resolved", "Mark comment as resolved").option("--unresolved", "Mark comment as unresolved").option("--json", "Force JSON output even in terminal").action(
|
|
4687
4923
|
wrapAction(
|
|
4688
4924
|
async (commentId, opts) => {
|
|
4689
|
-
const config = loadConfig();
|
|
4925
|
+
const config = loadConfig(getProfileName());
|
|
4690
4926
|
let resolved;
|
|
4691
4927
|
if (opts.resolved) resolved = true;
|
|
4692
4928
|
if (opts.unresolved) resolved = false;
|
|
@@ -4701,7 +4937,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4701
4937
|
);
|
|
4702
4938
|
program.command("comment-delete <commentId>").description("Delete a comment").option("--json", "Force JSON output even in terminal").action(
|
|
4703
4939
|
wrapAction(async (commentId, opts) => {
|
|
4704
|
-
const config = loadConfig();
|
|
4940
|
+
const config = loadConfig(getProfileName());
|
|
4705
4941
|
await deleteComment(config, commentId);
|
|
4706
4942
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4707
4943
|
console.log(JSON.stringify({ success: true, commentId }, null, 2));
|
|
@@ -4712,7 +4948,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4712
4948
|
);
|
|
4713
4949
|
program.command("replies <commentId>").description("List threaded replies on a comment").option("--json", "Force JSON output even in terminal").action(
|
|
4714
4950
|
wrapAction(async (commentId, opts) => {
|
|
4715
|
-
const config = loadConfig();
|
|
4951
|
+
const config = loadConfig(getProfileName());
|
|
4716
4952
|
const replies = await getReplies(config, commentId);
|
|
4717
4953
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4718
4954
|
console.log(JSON.stringify(replies, null, 2));
|
|
@@ -4726,7 +4962,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4726
4962
|
program.command("reply <commentId>").description("Reply to a comment").requiredOption("-m, --message <text>", "Reply text").option("--notify-all", "Notify all assignees").option("--json", "Force JSON output even in terminal").action(
|
|
4727
4963
|
wrapAction(
|
|
4728
4964
|
async (commentId, opts) => {
|
|
4729
|
-
const config = loadConfig();
|
|
4965
|
+
const config = loadConfig(getProfileName());
|
|
4730
4966
|
await createReply(config, commentId, opts.message, opts.notifyAll);
|
|
4731
4967
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4732
4968
|
console.log(JSON.stringify({ success: true, commentId }, null, 2));
|
|
@@ -4738,27 +4974,27 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4738
4974
|
);
|
|
4739
4975
|
program.command("activity <taskId>").description("Show task details and comments combined").option("--json", "Force JSON output even in terminal").action(
|
|
4740
4976
|
wrapAction(async (taskId, opts) => {
|
|
4741
|
-
const config = loadConfig();
|
|
4977
|
+
const config = loadConfig(getProfileName());
|
|
4742
4978
|
const result = await fetchActivity(config, taskId);
|
|
4743
4979
|
printActivity(result, opts.json ?? false);
|
|
4744
4980
|
})
|
|
4745
4981
|
);
|
|
4746
4982
|
program.command("lists <spaceId>").description("List all lists in a space (including lists inside folders)").option("--name <partial>", "Filter by name (case-insensitive contains)").option("--json", "Force JSON output even in terminal").action(
|
|
4747
4983
|
wrapAction(async (spaceId, opts) => {
|
|
4748
|
-
const config = loadConfig();
|
|
4984
|
+
const config = loadConfig(getProfileName());
|
|
4749
4985
|
const lists = await fetchLists(config, spaceId, { name: opts.name });
|
|
4750
4986
|
printLists(lists, opts.json ?? false);
|
|
4751
4987
|
})
|
|
4752
4988
|
);
|
|
4753
4989
|
program.command("spaces").description("List spaces in your workspace").option("--name <partial>", "Filter spaces by name (case-insensitive contains)").option("--my", "Show only spaces where I have assigned tasks").option("--json", "Force JSON output even in terminal").action(
|
|
4754
4990
|
wrapAction(async (opts) => {
|
|
4755
|
-
const config = loadConfig();
|
|
4991
|
+
const config = loadConfig(getProfileName());
|
|
4756
4992
|
await listSpaces(config, opts);
|
|
4757
4993
|
})
|
|
4758
4994
|
);
|
|
4759
4995
|
program.command("inbox").description("Recently updated tasks grouped by time period").option("--include-closed", "Include done/closed tasks").option("--json", "Force JSON output even in terminal").option("--days <n>", "Lookback period in days", "30").action(
|
|
4760
4996
|
wrapAction(async (opts) => {
|
|
4761
|
-
const config = loadConfig();
|
|
4997
|
+
const config = loadConfig(getProfileName());
|
|
4762
4998
|
const days = Number(opts.days ?? 30);
|
|
4763
4999
|
if (!Number.isFinite(days) || days <= 0) {
|
|
4764
5000
|
throw new Error("--days must be a positive number");
|
|
@@ -4769,20 +5005,20 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4769
5005
|
);
|
|
4770
5006
|
program.command("assigned").description("Show all tasks assigned to me, grouped by status").option("--status <status>", "Show only tasks with this status").option("--include-closed", "Include done/closed tasks").option("--json", "Force JSON output even in terminal").action(
|
|
4771
5007
|
wrapAction(async (opts) => {
|
|
4772
|
-
const config = loadConfig();
|
|
5008
|
+
const config = loadConfig(getProfileName());
|
|
4773
5009
|
await runAssignedCommand(config, opts);
|
|
4774
5010
|
})
|
|
4775
5011
|
);
|
|
4776
5012
|
program.command("open <query>").description("Open a task in the browser by ID or name").option("--json", "Output task JSON instead of opening").action(
|
|
4777
5013
|
wrapAction(async (query, opts) => {
|
|
4778
|
-
const config = loadConfig();
|
|
5014
|
+
const config = loadConfig(getProfileName());
|
|
4779
5015
|
await openTask(config, query, opts);
|
|
4780
5016
|
})
|
|
4781
5017
|
);
|
|
4782
5018
|
program.command("search <query>").description("Search my tasks by name").option("--status <status>", "Filter by status").option("--include-closed", "Include done/closed tasks in search").option("--json", "Force JSON output even in terminal").action(
|
|
4783
5019
|
wrapAction(
|
|
4784
5020
|
async (query, opts) => {
|
|
4785
|
-
const config = loadConfig();
|
|
5021
|
+
const config = loadConfig(getProfileName());
|
|
4786
5022
|
const tasks = await searchTasks(config, query, {
|
|
4787
5023
|
status: opts.status,
|
|
4788
5024
|
includeClosed: opts.includeClosed
|
|
@@ -4793,7 +5029,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4793
5029
|
);
|
|
4794
5030
|
program.command("summary").description("Daily standup summary: completed, in-progress, overdue").option("--hours <n>", "Completed-tasks lookback in hours", "24").option("--json", "Force JSON output even in terminal").action(
|
|
4795
5031
|
wrapAction(async (opts) => {
|
|
4796
|
-
const config = loadConfig();
|
|
5032
|
+
const config = loadConfig(getProfileName());
|
|
4797
5033
|
const hours = Number(opts.hours ?? 24);
|
|
4798
5034
|
if (!Number.isFinite(hours) || hours <= 0) {
|
|
4799
5035
|
throw new Error("--hours must be a positive number");
|
|
@@ -4803,14 +5039,14 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4803
5039
|
);
|
|
4804
5040
|
program.command("overdue").description("List tasks that are past their due date").option("--include-closed", "Include done/closed overdue tasks").option("--json", "Force JSON output even in terminal").action(
|
|
4805
5041
|
wrapAction(async (opts) => {
|
|
4806
|
-
const config = loadConfig();
|
|
5042
|
+
const config = loadConfig(getProfileName());
|
|
4807
5043
|
const tasks = await fetchOverdueTasks(config, { includeClosed: opts.includeClosed });
|
|
4808
5044
|
await printTasks(tasks, opts.json ?? false, config);
|
|
4809
5045
|
})
|
|
4810
5046
|
);
|
|
4811
5047
|
program.command("assign <taskId>").description("Assign or unassign users from a task").option("--to <userId>", 'Add assignee (user ID or "me")').option("--remove <userId>", 'Remove assignee (user ID or "me")').option("--json", "Force JSON output even in terminal").action(
|
|
4812
5048
|
wrapAction(async (taskId, opts) => {
|
|
4813
|
-
const config = loadConfig();
|
|
5049
|
+
const config = loadConfig(getProfileName());
|
|
4814
5050
|
const result = await assignTask(config, taskId, opts);
|
|
4815
5051
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4816
5052
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -4821,7 +5057,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4821
5057
|
);
|
|
4822
5058
|
program.command("depend <taskId>").description("Add or remove task dependencies").option("--on <taskId>", "Task that this task depends on (waiting on)").option("--blocks <taskId>", "Task that this task blocks").option("--remove", "Remove the dependency instead of adding it").option("--json", "Force JSON output even in terminal").action(
|
|
4823
5059
|
wrapAction(async (taskId, opts) => {
|
|
4824
|
-
const config = loadConfig();
|
|
5060
|
+
const config = loadConfig(getProfileName());
|
|
4825
5061
|
const message = await manageDependency(config, taskId, opts);
|
|
4826
5062
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4827
5063
|
console.log(
|
|
@@ -4839,7 +5075,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4839
5075
|
program.command("link <taskId> <linksTo>").description("Add or remove a link between two tasks").option("--remove", "Remove the link instead of adding it").option("--json", "Force JSON output even in terminal").action(
|
|
4840
5076
|
wrapAction(
|
|
4841
5077
|
async (taskId, linksTo, opts) => {
|
|
4842
|
-
const config = loadConfig();
|
|
5078
|
+
const config = loadConfig(getProfileName());
|
|
4843
5079
|
const result = await manageTaskLink(config, taskId, linksTo, opts.remove ?? false);
|
|
4844
5080
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4845
5081
|
console.log(
|
|
@@ -4857,7 +5093,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4857
5093
|
);
|
|
4858
5094
|
program.command("attach <taskId> <filePath>").description("Upload a file attachment to a task").option("--json", "Force JSON output even in terminal").action(
|
|
4859
5095
|
wrapAction(async (taskId, filePath, opts) => {
|
|
4860
|
-
const config = loadConfig();
|
|
5096
|
+
const config = loadConfig(getProfileName());
|
|
4861
5097
|
const result = await attachFile(config, taskId, filePath);
|
|
4862
5098
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4863
5099
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -4869,7 +5105,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4869
5105
|
);
|
|
4870
5106
|
program.command("move <taskId>").description("Add or remove a task from a list").option("--to <listId>", "Add task to this list").option("--remove <listId>", "Remove task from this list").option("--json", "Force JSON output even in terminal").action(
|
|
4871
5107
|
wrapAction(async (taskId, opts) => {
|
|
4872
|
-
const config = loadConfig();
|
|
5108
|
+
const config = loadConfig(getProfileName());
|
|
4873
5109
|
const message = await moveTask(config, taskId, opts);
|
|
4874
5110
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4875
5111
|
console.log(
|
|
@@ -4883,7 +5119,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4883
5119
|
program.command("field <taskId>").description("Set or remove a custom field value on a task").option("--set <nameAndValue...>", 'Set field: --set "Field Name" value').option("--remove <fieldName>", "Remove field value by name").option("--json", "Force JSON output even in terminal").action(
|
|
4884
5120
|
wrapAction(
|
|
4885
5121
|
async (taskId, opts) => {
|
|
4886
|
-
const config = loadConfig();
|
|
5122
|
+
const config = loadConfig(getProfileName());
|
|
4887
5123
|
const fieldOpts = {};
|
|
4888
5124
|
if (opts.set) {
|
|
4889
5125
|
if (opts.set.length !== 2) {
|
|
@@ -4911,7 +5147,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4911
5147
|
);
|
|
4912
5148
|
program.command("delete <taskId>").description("Delete a task (requires confirmation)").option("--confirm", "Skip confirmation prompt (required in non-interactive mode)").option("--json", "Force JSON output even in terminal").action(
|
|
4913
5149
|
wrapAction(async (taskId, opts) => {
|
|
4914
|
-
const config = loadConfig();
|
|
5150
|
+
const config = loadConfig(getProfileName());
|
|
4915
5151
|
const result = await deleteTaskCommand(config, taskId, opts);
|
|
4916
5152
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4917
5153
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -4923,7 +5159,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4923
5159
|
program.command("tag <taskId>").description("Add or remove tags from a task").option("--add <tags>", "Comma-separated tag names to add").option("--remove <tags>", "Comma-separated tag names to remove").option("--json", "Force JSON output even in terminal").action(
|
|
4924
5160
|
wrapAction(
|
|
4925
5161
|
async (taskId, opts) => {
|
|
4926
|
-
const config = loadConfig();
|
|
5162
|
+
const config = loadConfig(getProfileName());
|
|
4927
5163
|
const result = await manageTags(config, taskId, opts);
|
|
4928
5164
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4929
5165
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -4939,7 +5175,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4939
5175
|
const checklistCmd = program.command("checklist").description("Manage checklists on a task");
|
|
4940
5176
|
checklistCmd.command("view <taskId>").description("View checklists on a task").option("--json", "Force JSON output even in terminal").action(
|
|
4941
5177
|
wrapAction(async (taskId, opts) => {
|
|
4942
|
-
const config = loadConfig();
|
|
5178
|
+
const config = loadConfig(getProfileName());
|
|
4943
5179
|
const checklists = await viewChecklists(config, taskId);
|
|
4944
5180
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4945
5181
|
console.log(JSON.stringify(checklists, null, 2));
|
|
@@ -4952,7 +5188,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4952
5188
|
);
|
|
4953
5189
|
checklistCmd.command("create <taskId> <name>").description("Create a checklist on a task").option("--json", "Force JSON output even in terminal").action(
|
|
4954
5190
|
wrapAction(async (taskId, name, opts) => {
|
|
4955
|
-
const config = loadConfig();
|
|
5191
|
+
const config = loadConfig(getProfileName());
|
|
4956
5192
|
const result = await createChecklist(config, taskId, name);
|
|
4957
5193
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4958
5194
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -4963,7 +5199,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4963
5199
|
);
|
|
4964
5200
|
checklistCmd.command("delete <checklistId>").description("Delete a checklist").option("--json", "Force JSON output even in terminal").action(
|
|
4965
5201
|
wrapAction(async (checklistId, opts) => {
|
|
4966
|
-
const config = loadConfig();
|
|
5202
|
+
const config = loadConfig(getProfileName());
|
|
4967
5203
|
const result = await deleteChecklist(config, checklistId);
|
|
4968
5204
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4969
5205
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -4974,7 +5210,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4974
5210
|
);
|
|
4975
5211
|
checklistCmd.command("add-item <checklistId> <name>").description("Add an item to a checklist").option("--json", "Force JSON output even in terminal").action(
|
|
4976
5212
|
wrapAction(async (checklistId, name, opts) => {
|
|
4977
|
-
const config = loadConfig();
|
|
5213
|
+
const config = loadConfig(getProfileName());
|
|
4978
5214
|
const result = await addChecklistItem(config, checklistId, name);
|
|
4979
5215
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
4980
5216
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -4986,7 +5222,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
4986
5222
|
checklistCmd.command("edit-item <checklistId> <checklistItemId>").description("Edit a checklist item").option("--name <name>", "New item name").option("--resolved", "Mark item as resolved").option("--unresolved", "Mark item as unresolved").option("--assignee <userId>", 'Assign user by ID (use "null" to unassign)').option("--json", "Force JSON output even in terminal").action(
|
|
4987
5223
|
wrapAction(
|
|
4988
5224
|
async (checklistId, checklistItemId, opts) => {
|
|
4989
|
-
const config = loadConfig();
|
|
5225
|
+
const config = loadConfig(getProfileName());
|
|
4990
5226
|
const updates = {};
|
|
4991
5227
|
if (opts.name) updates.name = opts.name;
|
|
4992
5228
|
if (opts.resolved) updates.resolved = true;
|
|
@@ -5005,7 +5241,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5005
5241
|
);
|
|
5006
5242
|
checklistCmd.command("delete-item <checklistId> <checklistItemId>").description("Delete a checklist item").option("--json", "Force JSON output even in terminal").action(
|
|
5007
5243
|
wrapAction(async (checklistId, checklistItemId, opts) => {
|
|
5008
|
-
const config = loadConfig();
|
|
5244
|
+
const config = loadConfig(getProfileName());
|
|
5009
5245
|
const result = await deleteChecklistItem(config, checklistId, checklistItemId);
|
|
5010
5246
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5011
5247
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -5017,7 +5253,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5017
5253
|
const timeCmd = program.command("time").description("Track time on tasks");
|
|
5018
5254
|
timeCmd.command("start <taskId>").description("Start tracking time on a task").option("-d, --description <text>", "Description for the time entry").option("--json", "Force JSON output even in terminal").action(
|
|
5019
5255
|
wrapAction(async (taskId, opts) => {
|
|
5020
|
-
const config = loadConfig();
|
|
5256
|
+
const config = loadConfig(getProfileName());
|
|
5021
5257
|
const result = await startTimer(config, taskId, opts.description);
|
|
5022
5258
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5023
5259
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -5029,7 +5265,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5029
5265
|
);
|
|
5030
5266
|
timeCmd.command("stop").description("Stop the running timer").option("--json", "Force JSON output even in terminal").action(
|
|
5031
5267
|
wrapAction(async (opts) => {
|
|
5032
|
-
const config = loadConfig();
|
|
5268
|
+
const config = loadConfig(getProfileName());
|
|
5033
5269
|
const result = await stopTimer(config);
|
|
5034
5270
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5035
5271
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -5042,7 +5278,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5042
5278
|
);
|
|
5043
5279
|
timeCmd.command("status").description("Show the currently running timer").option("--json", "Force JSON output even in terminal").action(
|
|
5044
5280
|
wrapAction(async (opts) => {
|
|
5045
|
-
const config = loadConfig();
|
|
5281
|
+
const config = loadConfig(getProfileName());
|
|
5046
5282
|
const result = await timerStatus(config);
|
|
5047
5283
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5048
5284
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -5058,7 +5294,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5058
5294
|
timeCmd.command("log <taskId> <duration>").description('Log a manual time entry (e.g. "2h", "30m", "1h30m")').option("-d, --description <text>", "Description for the time entry").option("--json", "Force JSON output even in terminal").action(
|
|
5059
5295
|
wrapAction(
|
|
5060
5296
|
async (taskId, duration, opts) => {
|
|
5061
|
-
const config = loadConfig();
|
|
5297
|
+
const config = loadConfig(getProfileName());
|
|
5062
5298
|
const result = await logTime(config, taskId, duration, opts.description);
|
|
5063
5299
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5064
5300
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -5070,7 +5306,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5070
5306
|
);
|
|
5071
5307
|
timeCmd.command("list").description("List recent time entries (default: last 7 days)").option("--days <n>", "Number of days to look back", "7").option("--task <taskId>", "Filter by task ID").option("--json", "Force JSON output even in terminal").action(
|
|
5072
5308
|
wrapAction(async (opts) => {
|
|
5073
|
-
const config = loadConfig();
|
|
5309
|
+
const config = loadConfig(getProfileName());
|
|
5074
5310
|
const days = opts.days ? Number(opts.days) : 7;
|
|
5075
5311
|
if (!Number.isFinite(days) || days <= 0) {
|
|
5076
5312
|
throw new Error("--days must be a positive number");
|
|
@@ -5088,7 +5324,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5088
5324
|
timeCmd.command("update <timeEntryId>").description("Update a time entry").option("-d, --description <text>", "New description").option("--duration <duration>", 'New duration (e.g. "2h", "30m")').option("--json", "Force JSON output even in terminal").action(
|
|
5089
5325
|
wrapAction(
|
|
5090
5326
|
async (timeEntryId, opts) => {
|
|
5091
|
-
const config = loadConfig();
|
|
5327
|
+
const config = loadConfig(getProfileName());
|
|
5092
5328
|
const entry = await updateTimeEntry(config, timeEntryId, {
|
|
5093
5329
|
description: opts.description,
|
|
5094
5330
|
duration: opts.duration
|
|
@@ -5105,7 +5341,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5105
5341
|
);
|
|
5106
5342
|
timeCmd.command("delete <timeEntryId>").description("Delete a time entry").option("--json", "Force JSON output even in terminal").action(
|
|
5107
5343
|
wrapAction(async (timeEntryId, opts) => {
|
|
5108
|
-
const config = loadConfig();
|
|
5344
|
+
const config = loadConfig(getProfileName());
|
|
5109
5345
|
await deleteTimeEntry(config, timeEntryId);
|
|
5110
5346
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5111
5347
|
console.log(JSON.stringify({ deleted: timeEntryId }));
|
|
@@ -5116,7 +5352,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5116
5352
|
);
|
|
5117
5353
|
program.command("tags <spaceId>").description("List tags in a space").option("--json", "Force JSON output even in terminal").action(
|
|
5118
5354
|
wrapAction(async (spaceId, opts) => {
|
|
5119
|
-
const config = loadConfig();
|
|
5355
|
+
const config = loadConfig(getProfileName());
|
|
5120
5356
|
const tags = await listSpaceTags(config, spaceId);
|
|
5121
5357
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5122
5358
|
console.log(JSON.stringify(tags, null, 2));
|
|
@@ -5130,7 +5366,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5130
5366
|
program.command("tag-create <spaceId> <name>").description("Create a tag in a space").option("--fg <color>", "Foreground color (hex)").option("--bg <color>", "Background color (hex)").option("--json", "Force JSON output even in terminal").action(
|
|
5131
5367
|
wrapAction(
|
|
5132
5368
|
async (spaceId, name, opts) => {
|
|
5133
|
-
const config = loadConfig();
|
|
5369
|
+
const config = loadConfig(getProfileName());
|
|
5134
5370
|
await createSpaceTag(config, spaceId, name, opts.fg, opts.bg);
|
|
5135
5371
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5136
5372
|
console.log(JSON.stringify({ success: true, spaceId, tag: name }, null, 2));
|
|
@@ -5142,7 +5378,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5142
5378
|
);
|
|
5143
5379
|
program.command("tag-delete <spaceId> <name>").description("Delete a tag from a space").option("--json", "Force JSON output even in terminal").action(
|
|
5144
5380
|
wrapAction(async (spaceId, name, opts) => {
|
|
5145
|
-
const config = loadConfig();
|
|
5381
|
+
const config = loadConfig(getProfileName());
|
|
5146
5382
|
await deleteSpaceTag(config, spaceId, name);
|
|
5147
5383
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5148
5384
|
console.log(JSON.stringify({ success: true, spaceId, tag: name }, null, 2));
|
|
@@ -5153,7 +5389,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5153
5389
|
);
|
|
5154
5390
|
program.command("members").description("List workspace members").option("--json", "Force JSON output even in terminal").action(
|
|
5155
5391
|
wrapAction(async (opts) => {
|
|
5156
|
-
const config = loadConfig();
|
|
5392
|
+
const config = loadConfig(getProfileName());
|
|
5157
5393
|
const members = await listMembers(config);
|
|
5158
5394
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5159
5395
|
console.log(JSON.stringify(members, null, 2));
|
|
@@ -5166,7 +5402,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5166
5402
|
);
|
|
5167
5403
|
program.command("fields <listId>").description("List custom fields for a list").option("--json", "Force JSON output even in terminal").action(
|
|
5168
5404
|
wrapAction(async (listId, opts) => {
|
|
5169
|
-
const config = loadConfig();
|
|
5405
|
+
const config = loadConfig(getProfileName());
|
|
5170
5406
|
const fields = await listFields(config, listId);
|
|
5171
5407
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5172
5408
|
console.log(JSON.stringify(fields, null, 2));
|
|
@@ -5179,7 +5415,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5179
5415
|
);
|
|
5180
5416
|
program.command("duplicate <taskId>").description("Duplicate a task").option("--json", "Force JSON output even in terminal").action(
|
|
5181
5417
|
wrapAction(async (taskId, opts) => {
|
|
5182
|
-
const config = loadConfig();
|
|
5418
|
+
const config = loadConfig(getProfileName());
|
|
5183
5419
|
const result = await duplicateTask(config, taskId);
|
|
5184
5420
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5185
5421
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -5191,7 +5427,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5191
5427
|
const bulkCmd = program.command("bulk").description("Bulk task operations");
|
|
5192
5428
|
bulkCmd.command("status <status> <taskIds...>").description("Update status of multiple tasks").option("--json", "Force JSON output even in terminal").action(
|
|
5193
5429
|
wrapAction(async (status, taskIds, opts) => {
|
|
5194
|
-
const config = loadConfig();
|
|
5430
|
+
const config = loadConfig(getProfileName());
|
|
5195
5431
|
const result = await bulkUpdateStatus(config, taskIds, status);
|
|
5196
5432
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5197
5433
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -5207,7 +5443,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5207
5443
|
);
|
|
5208
5444
|
program.command("goals").description("List goals in your workspace").option("--json", "Force JSON output even in terminal").action(
|
|
5209
5445
|
wrapAction(async (opts) => {
|
|
5210
|
-
const config = loadConfig();
|
|
5446
|
+
const config = loadConfig(getProfileName());
|
|
5211
5447
|
const goals = await listGoals(config);
|
|
5212
5448
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5213
5449
|
console.log(JSON.stringify(goals, null, 2));
|
|
@@ -5221,7 +5457,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5221
5457
|
program.command("goal-create <name>").description("Create a goal").option("-d, --description <text>", "Goal description").option("--color <hex>", "Goal color (hex)").option("--json", "Force JSON output even in terminal").action(
|
|
5222
5458
|
wrapAction(
|
|
5223
5459
|
async (name, opts) => {
|
|
5224
|
-
const config = loadConfig();
|
|
5460
|
+
const config = loadConfig(getProfileName());
|
|
5225
5461
|
const goal = await createGoal(config, name, {
|
|
5226
5462
|
description: opts.description,
|
|
5227
5463
|
color: opts.color
|
|
@@ -5237,7 +5473,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5237
5473
|
program.command("goal-update <goalId>").description("Update a goal").option("-n, --name <text>", "New goal name").option("-d, --description <text>", "New description").option("--color <hex>", "New color (hex)").option("--json", "Force JSON output even in terminal").action(
|
|
5238
5474
|
wrapAction(
|
|
5239
5475
|
async (goalId, opts) => {
|
|
5240
|
-
const config = loadConfig();
|
|
5476
|
+
const config = loadConfig(getProfileName());
|
|
5241
5477
|
const goal = await updateGoal(config, goalId, {
|
|
5242
5478
|
name: opts.name,
|
|
5243
5479
|
description: opts.description,
|
|
@@ -5253,7 +5489,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5253
5489
|
);
|
|
5254
5490
|
program.command("goal-delete <goalId>").description("Delete a goal").option("--json", "Force JSON output even in terminal").action(
|
|
5255
5491
|
wrapAction(async (goalId, opts) => {
|
|
5256
|
-
const config = loadConfig();
|
|
5492
|
+
const config = loadConfig(getProfileName());
|
|
5257
5493
|
await deleteGoal(config, goalId);
|
|
5258
5494
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5259
5495
|
console.log(JSON.stringify({ success: true, goalId }, null, 2));
|
|
@@ -5264,7 +5500,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5264
5500
|
);
|
|
5265
5501
|
program.command("key-results <goalId>").description("List key results for a goal").option("--json", "Force JSON output even in terminal").action(
|
|
5266
5502
|
wrapAction(async (goalId, opts) => {
|
|
5267
|
-
const config = loadConfig();
|
|
5503
|
+
const config = loadConfig(getProfileName());
|
|
5268
5504
|
const krs = await listKeyResults(config, goalId);
|
|
5269
5505
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5270
5506
|
console.log(JSON.stringify(krs, null, 2));
|
|
@@ -5278,7 +5514,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5278
5514
|
program.command("key-result-create <goalId> <name>").description("Create a key result on a goal").option("--type <type>", "Key result type (number or percentage)", "number").option("--target <n>", "Target value", "100").option("--json", "Force JSON output even in terminal").action(
|
|
5279
5515
|
wrapAction(
|
|
5280
5516
|
async (goalId, name, opts) => {
|
|
5281
|
-
const config = loadConfig();
|
|
5517
|
+
const config = loadConfig(getProfileName());
|
|
5282
5518
|
const target = Number(opts.target ?? 100);
|
|
5283
5519
|
if (!Number.isFinite(target) || target <= 0) {
|
|
5284
5520
|
throw new Error("--target must be a positive number");
|
|
@@ -5295,7 +5531,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5295
5531
|
program.command("key-result-update <keyResultId>").description("Update a key result").option("--progress <n>", "Current progress value").option("--note <text>", "Progress note").option("--json", "Force JSON output even in terminal").action(
|
|
5296
5532
|
wrapAction(
|
|
5297
5533
|
async (keyResultId, opts) => {
|
|
5298
|
-
const config = loadConfig();
|
|
5534
|
+
const config = loadConfig(getProfileName());
|
|
5299
5535
|
const updates = {};
|
|
5300
5536
|
if (opts.progress !== void 0) {
|
|
5301
5537
|
const p = Number(opts.progress);
|
|
@@ -5314,7 +5550,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5314
5550
|
);
|
|
5315
5551
|
program.command("key-result-delete <keyResultId>").description("Delete a key result").option("--json", "Force JSON output even in terminal").action(
|
|
5316
5552
|
wrapAction(async (keyResultId, opts) => {
|
|
5317
|
-
const config = loadConfig();
|
|
5553
|
+
const config = loadConfig(getProfileName());
|
|
5318
5554
|
await deleteKeyResult(config, keyResultId);
|
|
5319
5555
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5320
5556
|
console.log(JSON.stringify({ success: true, keyResultId }, null, 2));
|
|
@@ -5325,7 +5561,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5325
5561
|
);
|
|
5326
5562
|
program.command("docs [query]").description("List workspace docs (optionally filter by name)").option("--json", "Force JSON output even in terminal").action(
|
|
5327
5563
|
wrapAction(async (query, opts) => {
|
|
5328
|
-
const config = loadConfig();
|
|
5564
|
+
const config = loadConfig(getProfileName());
|
|
5329
5565
|
const docs = await listDocs(config, query);
|
|
5330
5566
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5331
5567
|
console.log(JSON.stringify(docs, null, 2));
|
|
@@ -5338,7 +5574,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5338
5574
|
);
|
|
5339
5575
|
program.command("doc <docId> [pageId]").description("View a doc (metadata + page tree) or a specific page").option("--json", "Force JSON output even in terminal").action(
|
|
5340
5576
|
wrapAction(async (docId, pageId, opts) => {
|
|
5341
|
-
const config = loadConfig();
|
|
5577
|
+
const config = loadConfig(getProfileName());
|
|
5342
5578
|
if (pageId) {
|
|
5343
5579
|
const page = await getDocPage(config, docId, pageId);
|
|
5344
5580
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
@@ -5362,7 +5598,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5362
5598
|
);
|
|
5363
5599
|
program.command("doc-pages <docId>").description("List all pages in a doc with content").option("--json", "Force JSON output even in terminal").action(
|
|
5364
5600
|
wrapAction(async (docId, opts) => {
|
|
5365
|
-
const config = loadConfig();
|
|
5601
|
+
const config = loadConfig(getProfileName());
|
|
5366
5602
|
const pages = await getAllDocPages(config, docId);
|
|
5367
5603
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5368
5604
|
console.log(JSON.stringify(pages, null, 2));
|
|
@@ -5375,7 +5611,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5375
5611
|
);
|
|
5376
5612
|
program.command("folders <spaceId>").description("List folders in a space (with their lists)").option("--name <partial>", "Filter folders by partial name match").option("--json", "Force JSON output even in terminal").action(
|
|
5377
5613
|
wrapAction(async (spaceId, opts) => {
|
|
5378
|
-
const config = loadConfig();
|
|
5614
|
+
const config = loadConfig(getProfileName());
|
|
5379
5615
|
const folders = await listFolders(config, spaceId, opts.name);
|
|
5380
5616
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5381
5617
|
console.log(JSON.stringify(folders, null, 2));
|
|
@@ -5388,7 +5624,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5388
5624
|
);
|
|
5389
5625
|
program.command("doc-create <title>").description("Create a new doc").option("-c, --content <text>", "Initial content (markdown)").option("--json", "Force JSON output even in terminal").action(
|
|
5390
5626
|
wrapAction(async (title, opts) => {
|
|
5391
|
-
const config = loadConfig();
|
|
5627
|
+
const config = loadConfig(getProfileName());
|
|
5392
5628
|
const result = await createDoc(config, title, opts.content);
|
|
5393
5629
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5394
5630
|
console.log(JSON.stringify(result, null, 2));
|
|
@@ -5400,7 +5636,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5400
5636
|
program.command("doc-page-create <docId> <name>").description("Create a page in a doc").option("-c, --content <text>", "Page content (markdown)").option("--parent-page <pageId>", "Parent page ID for nesting").option("--json", "Force JSON output even in terminal").action(
|
|
5401
5637
|
wrapAction(
|
|
5402
5638
|
async (docId, name, opts) => {
|
|
5403
|
-
const config = loadConfig();
|
|
5639
|
+
const config = loadConfig(getProfileName());
|
|
5404
5640
|
const page = await createDocPage(config, docId, name, opts.content, opts.parentPage);
|
|
5405
5641
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5406
5642
|
console.log(JSON.stringify(page, null, 2));
|
|
@@ -5413,7 +5649,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5413
5649
|
program.command("doc-page-edit <docId> <pageId>").description("Edit a doc page").option("--name <text>", "New page name").option("-c, --content <text>", "New page content (markdown)").option("--json", "Force JSON output even in terminal").action(
|
|
5414
5650
|
wrapAction(
|
|
5415
5651
|
async (docId, pageId, opts) => {
|
|
5416
|
-
const config = loadConfig();
|
|
5652
|
+
const config = loadConfig(getProfileName());
|
|
5417
5653
|
const page = await editDocPage(config, docId, pageId, {
|
|
5418
5654
|
name: opts.name,
|
|
5419
5655
|
content: opts.content
|
|
@@ -5428,7 +5664,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5428
5664
|
);
|
|
5429
5665
|
program.command("doc-delete <docId>").description("Delete a doc").option("--json", "Force JSON output even in terminal").action(
|
|
5430
5666
|
wrapAction(async (docId, opts) => {
|
|
5431
|
-
const config = loadConfig();
|
|
5667
|
+
const config = loadConfig(getProfileName());
|
|
5432
5668
|
await deleteDoc(config, docId);
|
|
5433
5669
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5434
5670
|
console.log(JSON.stringify({ success: true, docId }, null, 2));
|
|
@@ -5439,7 +5675,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5439
5675
|
);
|
|
5440
5676
|
program.command("doc-page-delete <docId> <pageId>").description("Delete a doc page").option("--json", "Force JSON output even in terminal").action(
|
|
5441
5677
|
wrapAction(async (docId, pageId, opts) => {
|
|
5442
|
-
const config = loadConfig();
|
|
5678
|
+
const config = loadConfig(getProfileName());
|
|
5443
5679
|
await deleteDocPage(config, docId, pageId);
|
|
5444
5680
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5445
5681
|
console.log(JSON.stringify({ success: true, docId, pageId }, null, 2));
|
|
@@ -5451,7 +5687,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5451
5687
|
program.command("tag-update <spaceId> <tagName>").description("Update a tag in a space").requiredOption("--name <newName>", "New tag name").option("--fg <color>", "New foreground color (hex)").option("--bg <color>", "New background color (hex)").option("--json", "Force JSON output even in terminal").action(
|
|
5452
5688
|
wrapAction(
|
|
5453
5689
|
async (spaceId, tagName, opts) => {
|
|
5454
|
-
const config = loadConfig();
|
|
5690
|
+
const config = loadConfig(getProfileName());
|
|
5455
5691
|
await updateSpaceTag(config, spaceId, tagName, {
|
|
5456
5692
|
name: opts.name,
|
|
5457
5693
|
fg: opts.fg,
|
|
@@ -5473,7 +5709,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5473
5709
|
);
|
|
5474
5710
|
program.command("task-types").description("List custom task types in your workspace").option("--json", "Force JSON output even in terminal").action(
|
|
5475
5711
|
wrapAction(async (opts) => {
|
|
5476
|
-
const config = loadConfig();
|
|
5712
|
+
const config = loadConfig(getProfileName());
|
|
5477
5713
|
const types = await listTaskTypes(config);
|
|
5478
5714
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5479
5715
|
console.log(JSON.stringify(types, null, 2));
|
|
@@ -5486,7 +5722,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5486
5722
|
);
|
|
5487
5723
|
program.command("templates").description("List task templates in your workspace").option("--json", "Force JSON output even in terminal").action(
|
|
5488
5724
|
wrapAction(async (opts) => {
|
|
5489
|
-
const config = loadConfig();
|
|
5725
|
+
const config = loadConfig(getProfileName());
|
|
5490
5726
|
const templates = await listTemplates(config);
|
|
5491
5727
|
if (shouldOutputJson(opts.json ?? false)) {
|
|
5492
5728
|
console.log(JSON.stringify(templates, null, 2));
|
|
@@ -5497,10 +5733,65 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5497
5733
|
}
|
|
5498
5734
|
})
|
|
5499
5735
|
);
|
|
5736
|
+
const profileCmd = program.command("profile").description("Manage profiles");
|
|
5737
|
+
profileCmd.command("list").description("List all profiles").option("--json", "Force JSON output even in terminal").action(
|
|
5738
|
+
wrapAction(async (opts) => {
|
|
5739
|
+
const profiles = listProfiles();
|
|
5740
|
+
if (shouldOutputJson(opts.json ?? false)) {
|
|
5741
|
+
console.log(JSON.stringify(profiles, null, 2));
|
|
5742
|
+
} else {
|
|
5743
|
+
for (const p of profiles) {
|
|
5744
|
+
const marker = p.isDefault ? " (default)" : "";
|
|
5745
|
+
console.log(`${p.name}${marker}${p.teamId ? ` [team: ${p.teamId}]` : ""}`);
|
|
5746
|
+
}
|
|
5747
|
+
if (profiles.length === 0)
|
|
5748
|
+
console.log("No profiles configured. Run: cup profile add <name>");
|
|
5749
|
+
}
|
|
5750
|
+
})
|
|
5751
|
+
);
|
|
5752
|
+
profileCmd.command("add <name>").description("Add a new profile").action(
|
|
5753
|
+
wrapAction(async (name) => {
|
|
5754
|
+
const { password: password2, select: select3 } = await import("@inquirer/prompts");
|
|
5755
|
+
const apiToken = (await password2({ message: "ClickUp API token (pk_...):" })).trim();
|
|
5756
|
+
if (!apiToken.startsWith("pk_")) throw new Error("Token must start with pk_");
|
|
5757
|
+
const client = new ClickUpClient({ apiToken });
|
|
5758
|
+
const me = await client.getMe();
|
|
5759
|
+
process.stdout.write(`Authenticated as @${me.username}
|
|
5760
|
+
`);
|
|
5761
|
+
const teams = await client.getTeams();
|
|
5762
|
+
if (teams.length === 0) throw new Error("No workspaces found for this token.");
|
|
5763
|
+
let teamId;
|
|
5764
|
+
if (teams.length === 1) {
|
|
5765
|
+
teamId = teams[0].id;
|
|
5766
|
+
process.stdout.write(`Workspace: ${teams[0].name}
|
|
5767
|
+
`);
|
|
5768
|
+
} else {
|
|
5769
|
+
teamId = await select3({
|
|
5770
|
+
message: "Select workspace:",
|
|
5771
|
+
choices: teams.map((t) => ({ name: t.name, value: t.id }))
|
|
5772
|
+
});
|
|
5773
|
+
}
|
|
5774
|
+
addProfile(name, { apiToken, teamId });
|
|
5775
|
+
process.stdout.write(`Profile "${name}" added.
|
|
5776
|
+
`);
|
|
5777
|
+
})
|
|
5778
|
+
);
|
|
5779
|
+
profileCmd.command("remove <name>").description("Remove a profile").action(
|
|
5780
|
+
wrapAction(async (name) => {
|
|
5781
|
+
removeProfile(name);
|
|
5782
|
+
console.log(`Removed profile "${name}"`);
|
|
5783
|
+
})
|
|
5784
|
+
);
|
|
5785
|
+
profileCmd.command("use <name>").description("Set the default profile").action(
|
|
5786
|
+
wrapAction(async (name) => {
|
|
5787
|
+
setDefaultProfile(name);
|
|
5788
|
+
console.log(`Default profile set to "${name}"`);
|
|
5789
|
+
})
|
|
5790
|
+
);
|
|
5500
5791
|
const configCmd = program.command("config").description("Manage CLI configuration");
|
|
5501
5792
|
configCmd.command("get <key>").description("Print a config value").action(
|
|
5502
5793
|
wrapAction(async (key) => {
|
|
5503
|
-
const value = getConfigValue(key);
|
|
5794
|
+
const value = getConfigValue(key, getProfileName());
|
|
5504
5795
|
if (value !== void 0) {
|
|
5505
5796
|
console.log(value);
|
|
5506
5797
|
}
|
|
@@ -5508,7 +5799,7 @@ function buildProgram(programName = basename(process.argv[1] ?? "cup")) {
|
|
|
5508
5799
|
);
|
|
5509
5800
|
configCmd.command("set <key> <value>").description("Set a config value").action(
|
|
5510
5801
|
wrapAction(async (key, value) => {
|
|
5511
|
-
setConfigValue(key, value);
|
|
5802
|
+
setConfigValue(key, value, getProfileName());
|
|
5512
5803
|
})
|
|
5513
5804
|
);
|
|
5514
5805
|
configCmd.command("path").description("Print config file path").action(
|
|
@@ -5533,7 +5824,12 @@ process.on("SIGINT", () => {
|
|
|
5533
5824
|
process.stderr.write("\nInterrupted\n");
|
|
5534
5825
|
process.exit(130);
|
|
5535
5826
|
});
|
|
5536
|
-
var isDirectExecution =
|
|
5827
|
+
var isDirectExecution = false;
|
|
5828
|
+
try {
|
|
5829
|
+
isDirectExecution = process.argv[1] !== void 0 && fileURLToPath(import.meta.url) === realpathSync(resolve(process.argv[1]));
|
|
5830
|
+
} catch {
|
|
5831
|
+
isDirectExecution = false;
|
|
5832
|
+
}
|
|
5537
5833
|
if (isDirectExecution) {
|
|
5538
5834
|
await run();
|
|
5539
5835
|
}
|
package/package.json
CHANGED
|
@@ -9,9 +9,11 @@ Reference for AI agents using the `cup` CLI tool. Covers task management, sprint
|
|
|
9
9
|
|
|
10
10
|
## Setup
|
|
11
11
|
|
|
12
|
-
Config at `~/.config/cup/config.json` with `apiToken` and `teamId`. Optional: `sprintFolderId` to pin sprint detection to a specific folder. Run `cup init` to set up interactively.
|
|
12
|
+
Config at `~/.config/cup/config.json` with named profiles. Each profile has `apiToken` and `teamId`. Optional: `sprintFolderId` to pin sprint detection to a specific folder. Run `cup init` to set up interactively.
|
|
13
13
|
|
|
14
|
-
|
|
14
|
+
Multiple profiles supported - use `cup profile add <name>` to create, `cup profile use <name>` to switch, or `-p <name>` flag for one-off overrides.
|
|
15
|
+
|
|
16
|
+
Environment variables `CU_API_TOKEN` and `CU_TEAM_ID` override config file when both are set. `CU_PROFILE` selects a profile (overridden by `-p` flag).
|
|
15
17
|
|
|
16
18
|
## Output Modes
|
|
17
19
|
|
|
@@ -109,9 +111,20 @@ All commands support `--help` for full flag details. All commands support `--jso
|
|
|
109
111
|
| `cup tag-create <spaceId> <name> [--fg color] [--bg color]` | Create space tag |
|
|
110
112
|
| `cup tag-update <spaceId> <tagName> --name <newName> [--fg c] [--bg c]` | Update space tag |
|
|
111
113
|
| `cup tag-delete <spaceId> <name>` | Delete space tag |
|
|
114
|
+
| `cup profile list [--json]` | List all profiles |
|
|
115
|
+
| `cup profile add <name>` | Add a new profile (interactive) |
|
|
116
|
+
| `cup profile remove <name>` | Remove a profile |
|
|
117
|
+
| `cup profile use <name>` | Set the default profile |
|
|
112
118
|
| `cup config get <key>` / `set <key> <value>` / `path` | Manage config |
|
|
113
119
|
| `cup completion <shell>` | Shell completions (bash/zsh/fish) |
|
|
114
120
|
|
|
121
|
+
## Global Flags
|
|
122
|
+
|
|
123
|
+
| Flag | Description |
|
|
124
|
+
| ------------------- | --------------------------------------------- |
|
|
125
|
+
| `-p, --profile <n>` | Use a specific profile for this command |
|
|
126
|
+
| `--json` | Force JSON output (available on all commands) |
|
|
127
|
+
|
|
115
128
|
## Flags & Conventions
|
|
116
129
|
|
|
117
130
|
| Topic | Detail |
|
|
@@ -218,6 +231,15 @@ cup key-result-create g123 "API coverage" --type percentage --target 80
|
|
|
218
231
|
cup key-result-update kr456 --progress 60 --note "On track"
|
|
219
232
|
```
|
|
220
233
|
|
|
234
|
+
### Profiles
|
|
235
|
+
|
|
236
|
+
```bash
|
|
237
|
+
cup profile add personal # add a profile (interactive)
|
|
238
|
+
cup profile list # list all profiles
|
|
239
|
+
cup profile use personal # switch default
|
|
240
|
+
cup tasks -p work # use specific profile for one command
|
|
241
|
+
```
|
|
242
|
+
|
|
221
243
|
### Standup
|
|
222
244
|
|
|
223
245
|
```bash
|