@contextium/cli 0.3.2 → 0.6.7
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 +227 -227
- package/dist/commands/agents.d.ts +3 -0
- package/dist/commands/agents.d.ts.map +1 -0
- package/dist/commands/agents.js +243 -0
- package/dist/commands/agents.js.map +1 -0
- package/dist/commands/cat.d.ts.map +1 -1
- package/dist/commands/cat.js +13 -9
- package/dist/commands/cat.js.map +1 -1
- package/dist/commands/create-library.d.ts +3 -0
- package/dist/commands/create-library.d.ts.map +1 -0
- package/dist/commands/create-library.js +49 -0
- package/dist/commands/create-library.js.map +1 -0
- package/dist/commands/delete-file.d.ts +3 -0
- package/dist/commands/delete-file.d.ts.map +1 -0
- package/dist/commands/delete-file.js +39 -0
- package/dist/commands/delete-file.js.map +1 -0
- package/dist/commands/edit-file.d.ts +3 -0
- package/dist/commands/edit-file.d.ts.map +1 -0
- package/dist/commands/edit-file.js +64 -0
- package/dist/commands/edit-file.js.map +1 -0
- package/dist/commands/files.d.ts.map +1 -1
- package/dist/commands/files.js +5 -4
- package/dist/commands/files.js.map +1 -1
- package/dist/commands/find.d.ts.map +1 -1
- package/dist/commands/find.js +2 -1
- package/dist/commands/find.js.map +1 -1
- package/dist/commands/init.js +2 -2
- package/dist/commands/init.js.map +1 -1
- package/dist/commands/new-file.d.ts +3 -0
- package/dist/commands/new-file.d.ts.map +1 -0
- package/dist/commands/new-file.js +73 -0
- package/dist/commands/new-file.js.map +1 -0
- package/dist/commands/projects.js +6 -6
- package/dist/commands/projects.js.map +1 -1
- package/dist/commands/search.d.ts.map +1 -1
- package/dist/commands/search.js +5 -4
- package/dist/commands/search.js.map +1 -1
- package/dist/commands/setup-claude.js +3 -3
- package/dist/commands/skills.d.ts +3 -0
- package/dist/commands/skills.d.ts.map +1 -0
- package/dist/commands/skills.js +98 -0
- package/dist/commands/skills.js.map +1 -0
- package/dist/commands/status.js +1 -1
- package/dist/commands/status.js.map +1 -1
- package/dist/commands/structure.d.ts +3 -0
- package/dist/commands/structure.d.ts.map +1 -0
- package/dist/commands/structure.js +96 -0
- package/dist/commands/structure.js.map +1 -0
- package/dist/commands/sync.d.ts.map +1 -1
- package/dist/commands/sync.js +7 -5
- package/dist/commands/sync.js.map +1 -1
- package/dist/commands/tags.d.ts.map +1 -1
- package/dist/commands/tags.js +381 -22
- package/dist/commands/tags.js.map +1 -1
- package/dist/commands/update-library.d.ts +3 -0
- package/dist/commands/update-library.d.ts.map +1 -0
- package/dist/commands/update-library.js +69 -0
- package/dist/commands/update-library.js.map +1 -0
- package/dist/commands/versions.d.ts +3 -0
- package/dist/commands/versions.d.ts.map +1 -0
- package/dist/commands/versions.js +48 -0
- package/dist/commands/versions.js.map +1 -0
- package/dist/commands/workflow.js +2 -2
- package/dist/commands/workflow.js.map +1 -1
- package/dist/commands/workflows.d.ts.map +1 -1
- package/dist/commands/workflows.js +400 -17
- package/dist/commands/workflows.js.map +1 -1
- package/dist/commands/workspaces.js +1 -1
- package/dist/commands/workspaces.js.map +1 -1
- package/dist/index.js +59 -17
- package/dist/index.js.map +1 -1
- package/dist/lib/api-client.d.ts +1 -0
- package/dist/lib/api-client.d.ts.map +1 -1
- package/dist/lib/api-client.js +9 -5
- package/dist/lib/api-client.js.map +1 -1
- package/dist/lib/msal.js +18 -18
- package/package.json +58 -58
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAOnC,eAAO,MAAM,WAAW,
|
|
1
|
+
{"version":3,"file":"sync.d.ts","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAOnC,eAAO,MAAM,WAAW,SA6IpB,CAAA"}
|
package/dist/commands/sync.js
CHANGED
|
@@ -6,7 +6,7 @@ import { chalk, ora } from '../lib/output.js';
|
|
|
6
6
|
export const syncCommand = new Command('sync')
|
|
7
7
|
.description('Sync workspace files to local cache')
|
|
8
8
|
.argument('[files...]', 'Specific files to sync')
|
|
9
|
-
.option('--workspace <slug>', 'Specify workspace')
|
|
9
|
+
.option('-w, --workspace <slug>', 'Specify workspace')
|
|
10
10
|
.option('--force', 'Force re-download all files')
|
|
11
11
|
.option('--tag <tags...>', 'Sync only files with these tags')
|
|
12
12
|
.option('--dry-run', 'Show what would be synced')
|
|
@@ -51,8 +51,9 @@ export const syncCommand = new Command('sync')
|
|
|
51
51
|
for (const fileName of files) {
|
|
52
52
|
let found = false;
|
|
53
53
|
for (const project of projects) {
|
|
54
|
-
const { data } = await client.get(`/projects/${project.id}/files`, { params: { search: fileName } });
|
|
55
|
-
const
|
|
54
|
+
const { data: filesData } = await client.get(`/projects/${project.id}/files`, { params: { search: fileName } });
|
|
55
|
+
const files = filesData.data || filesData;
|
|
56
|
+
const file = files.find((f) => f.title === fileName || f.path === fileName);
|
|
56
57
|
if (file) {
|
|
57
58
|
filesToSync.push(file);
|
|
58
59
|
found = true;
|
|
@@ -74,8 +75,9 @@ export const syncCommand = new Command('sync')
|
|
|
74
75
|
params.tags = config.files.tags.join(',');
|
|
75
76
|
}
|
|
76
77
|
for (const project of projects) {
|
|
77
|
-
const { data } = await client.get(`/projects/${project.id}/files`, { params });
|
|
78
|
-
|
|
78
|
+
const { data: filesData } = await client.get(`/projects/${project.id}/files`, { params });
|
|
79
|
+
const files = filesData.data || filesData;
|
|
80
|
+
filesToSync.push(...files);
|
|
79
81
|
}
|
|
80
82
|
}
|
|
81
83
|
if (filesToSync.length === 0) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AACnC,OAAO,EAAE,SAAS,EAAE,MAAM,sBAAsB,CAAA;AAChD,OAAO,EAAE,UAAU,EAAE,MAAM,kBAAkB,CAAA;AAC7C,OAAO,EAAE,KAAK,EAAE,MAAM,iBAAiB,CAAA;AACvC,OAAO,EAAE,KAAK,EAAE,GAAG,EAAE,MAAM,kBAAkB,CAAA;AAG7C,MAAM,CAAC,MAAM,WAAW,GAAG,IAAI,OAAO,CAAC,MAAM,CAAC;KAC3C,WAAW,CAAC,qCAAqC,CAAC;KAClD,QAAQ,CAAC,YAAY,EAAE,wBAAwB,CAAC;KAChD,MAAM,CAAC,
|
|
1
|
+
{"version":3,"file":"sync.js","sourceRoot":"","sources":["../../src/commands/sync.ts"],"names":[],"mappings":"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"}
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"tags.d.ts","sourceRoot":"","sources":["../../src/commands/tags.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;
|
|
1
|
+
{"version":3,"file":"tags.d.ts","sourceRoot":"","sources":["../../src/commands/tags.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAC;AAoBpC,eAAO,MAAM,WAAW,SACmB,CAAC"}
|
package/dist/commands/tags.js
CHANGED
|
@@ -2,25 +2,36 @@ import { Command } from 'commander';
|
|
|
2
2
|
import { ApiClient } from '../lib/api-client.js';
|
|
3
3
|
import { loadConfig } from '../lib/config.js';
|
|
4
4
|
import { chalk, ora } from '../lib/output.js';
|
|
5
|
+
async function resolveWorkspace(client, workspaceName) {
|
|
6
|
+
const { data: workspacesData } = await client.get('/workspaces');
|
|
7
|
+
const workspaces = workspacesData.data || workspacesData;
|
|
8
|
+
const workspace = workspaces.find((w) => w.slug.toLowerCase().trim() === workspaceName.toLowerCase().trim() ||
|
|
9
|
+
w.name.toLowerCase().trim() === workspaceName.toLowerCase().trim());
|
|
10
|
+
if (!workspace) {
|
|
11
|
+
console.log(chalk.dim('Available workspaces:'));
|
|
12
|
+
workspaces.forEach((w) => console.log(chalk.dim(` - ${w.name} (${w.slug})`)));
|
|
13
|
+
throw new Error(`Workspace '${workspaceName}' not found`);
|
|
14
|
+
}
|
|
15
|
+
return workspace;
|
|
16
|
+
}
|
|
5
17
|
export const tagsCommand = new Command('tags')
|
|
6
18
|
.description('Manage tags and tag types');
|
|
7
19
|
// List tag types
|
|
8
20
|
tagsCommand
|
|
9
21
|
.command('types')
|
|
10
22
|
.description('List tag types in a workspace')
|
|
11
|
-
.option('-w, --workspace <id>', 'Workspace
|
|
23
|
+
.option('-w, --workspace <id>', 'Workspace name, slug, or ID')
|
|
12
24
|
.action(async (options) => {
|
|
13
25
|
const spinner = ora('Loading tag types...').start();
|
|
14
26
|
try {
|
|
15
27
|
const config = await loadConfig();
|
|
16
28
|
const client = new ApiClient(config.api_key, config.api_url);
|
|
17
|
-
|
|
18
|
-
|
|
19
|
-
if (!workspaceId) {
|
|
20
|
-
spinner.fail('Error: Workspace ID is required. Use -w flag.');
|
|
29
|
+
if (!options.workspace) {
|
|
30
|
+
spinner.fail('Error: Workspace is required. Use -w flag.');
|
|
21
31
|
process.exit(1);
|
|
22
32
|
}
|
|
23
|
-
const
|
|
33
|
+
const workspace = await resolveWorkspace(client, options.workspace);
|
|
34
|
+
const response = await client.get(`/workspaces/${workspace.id}/tag-types`);
|
|
24
35
|
const tagTypesData = response.data;
|
|
25
36
|
const tagTypes = tagTypesData.data || tagTypesData || [];
|
|
26
37
|
if (tagTypes.length === 0) {
|
|
@@ -54,9 +65,9 @@ tagsCommand
|
|
|
54
65
|
tagsCommand
|
|
55
66
|
.command('create-type')
|
|
56
67
|
.description('Create a new tag type')
|
|
57
|
-
.requiredOption('-w, --workspace <id>', 'Workspace ID')
|
|
68
|
+
.requiredOption('-w, --workspace <id>', 'Workspace name, slug, or ID')
|
|
58
69
|
.requiredOption('-n, --name <name>', 'Type name')
|
|
59
|
-
.
|
|
70
|
+
.option('-s, --slug <slug>', 'Type slug (auto-generated from name if not provided)')
|
|
60
71
|
.option('-c, --color <hex>', 'Hex color code')
|
|
61
72
|
.option('-i, --icon <icon>', 'Icon name')
|
|
62
73
|
.option('-d, --description <text>', 'Description')
|
|
@@ -65,14 +76,16 @@ tagsCommand
|
|
|
65
76
|
try {
|
|
66
77
|
const config = await loadConfig();
|
|
67
78
|
const client = new ApiClient(config.api_key, config.api_url);
|
|
79
|
+
const workspace = await resolveWorkspace(client, options.workspace);
|
|
80
|
+
const slug = options.slug || options.name.toLowerCase().replace(/\s+/g, '-').replace(/[^a-z0-9-]/g, '').replace(/-+/g, '-').replace(/^-|-$/g, '');
|
|
68
81
|
// Validate slug format
|
|
69
|
-
if (!/^[a-z0-9-]+$/.test(
|
|
82
|
+
if (!/^[a-z0-9-]+$/.test(slug)) {
|
|
70
83
|
spinner.fail('Error: Slug must contain only lowercase letters, numbers, and hyphens');
|
|
71
84
|
process.exit(1);
|
|
72
85
|
}
|
|
73
86
|
const data = {
|
|
74
87
|
name: options.name,
|
|
75
|
-
slug
|
|
88
|
+
slug,
|
|
76
89
|
};
|
|
77
90
|
if (options.color)
|
|
78
91
|
data.color = options.color;
|
|
@@ -80,7 +93,7 @@ tagsCommand
|
|
|
80
93
|
data.icon = options.icon;
|
|
81
94
|
if (options.description)
|
|
82
95
|
data.description = options.description;
|
|
83
|
-
const response = await client.post(`/workspaces/${
|
|
96
|
+
const response = await client.post(`/workspaces/${workspace.id}/tag-types`, data);
|
|
84
97
|
const tagTypeData = response.data;
|
|
85
98
|
const tagType = tagTypeData.data || tagTypeData;
|
|
86
99
|
spinner.stop();
|
|
@@ -99,19 +112,19 @@ tagsCommand
|
|
|
99
112
|
tagsCommand
|
|
100
113
|
.command('list')
|
|
101
114
|
.description('List tags in a workspace')
|
|
102
|
-
.option('-w, --workspace <id>', 'Workspace ID')
|
|
115
|
+
.option('-w, --workspace <id>', 'Workspace name, slug, or ID')
|
|
103
116
|
.option('-t, --type <typeId>', 'Filter by tag type ID')
|
|
104
117
|
.action(async (options) => {
|
|
105
118
|
const spinner = ora('Loading tags...').start();
|
|
106
119
|
try {
|
|
107
120
|
const config = await loadConfig();
|
|
108
121
|
const client = new ApiClient(config.api_key, config.api_url);
|
|
109
|
-
|
|
110
|
-
|
|
111
|
-
spinner.fail('Error: Workspace ID is required. Use -w flag.');
|
|
122
|
+
if (!options.workspace) {
|
|
123
|
+
spinner.fail('Error: Workspace is required. Use -w flag.');
|
|
112
124
|
process.exit(1);
|
|
113
125
|
}
|
|
114
|
-
|
|
126
|
+
const workspace = await resolveWorkspace(client, options.workspace);
|
|
127
|
+
let url = `/workspaces/${workspace.id}/tags`;
|
|
115
128
|
if (options.type) {
|
|
116
129
|
url += `?typeId=${options.type}`;
|
|
117
130
|
}
|
|
@@ -155,8 +168,8 @@ tagsCommand
|
|
|
155
168
|
tagsCommand
|
|
156
169
|
.command('create')
|
|
157
170
|
.description('Create a new tag')
|
|
158
|
-
.requiredOption('-w, --workspace <id>', 'Workspace ID')
|
|
159
|
-
.requiredOption('-t, --type <typeId>', 'Tag type ID')
|
|
171
|
+
.requiredOption('-w, --workspace <id>', 'Workspace name, slug, or ID')
|
|
172
|
+
.requiredOption('-t, --type <typeId>', 'Tag type ID or slug')
|
|
160
173
|
.requiredOption('-v, --value <value>', 'Tag value (lowercase, hyphen-separated)')
|
|
161
174
|
.option('-c, --color <hex>', 'Hex color code')
|
|
162
175
|
.action(async (options) => {
|
|
@@ -169,13 +182,28 @@ tagsCommand
|
|
|
169
182
|
spinner.fail('Error: Tag value must contain only lowercase letters, numbers, and hyphens');
|
|
170
183
|
process.exit(1);
|
|
171
184
|
}
|
|
185
|
+
const workspace = await resolveWorkspace(client, options.workspace);
|
|
186
|
+
// Resolve type by slug if not a UUID
|
|
187
|
+
let typeId = options.type;
|
|
188
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
189
|
+
if (!uuidRegex.test(typeId)) {
|
|
190
|
+
const typesResponse = await client.get(`/workspaces/${workspace.id}/tag-types`);
|
|
191
|
+
const typesData = typesResponse.data;
|
|
192
|
+
const types = typesData.data || typesData || [];
|
|
193
|
+
const matchingType = types.find((t) => t.slug === typeId || t.name.toLowerCase() === typeId.toLowerCase());
|
|
194
|
+
if (!matchingType) {
|
|
195
|
+
spinner.fail(`Tag type '${typeId}' not found. Use 'contextium tags types -w ${options.workspace}' to list types.`);
|
|
196
|
+
process.exit(1);
|
|
197
|
+
}
|
|
198
|
+
typeId = matchingType.id;
|
|
199
|
+
}
|
|
172
200
|
const data = {
|
|
173
|
-
typeId
|
|
201
|
+
typeId,
|
|
174
202
|
value: options.value,
|
|
175
203
|
};
|
|
176
204
|
if (options.color)
|
|
177
205
|
data.color = options.color;
|
|
178
|
-
const response = await client.post(`/workspaces/${
|
|
206
|
+
const response = await client.post(`/workspaces/${workspace.id}/tags`, data);
|
|
179
207
|
const tagData = response.data;
|
|
180
208
|
const tag = tagData.data || tagData;
|
|
181
209
|
spinner.stop();
|
|
@@ -190,11 +218,132 @@ tagsCommand
|
|
|
190
218
|
process.exit(1);
|
|
191
219
|
}
|
|
192
220
|
});
|
|
221
|
+
// Apply tag to a file
|
|
222
|
+
tagsCommand
|
|
223
|
+
.command('apply')
|
|
224
|
+
.description('Apply a tag to a file')
|
|
225
|
+
.requiredOption('-w, --workspace <id>', 'Workspace name, slug, or ID')
|
|
226
|
+
.requiredOption('-t, --tag <tagId>', 'Tag ID or slug:value (e.g., "topic:authentication")')
|
|
227
|
+
.requiredOption('-f, --file <fileId>', 'File ID')
|
|
228
|
+
.action(async (options) => {
|
|
229
|
+
const spinner = ora('Applying tag...').start();
|
|
230
|
+
try {
|
|
231
|
+
const config = await loadConfig();
|
|
232
|
+
const client = new ApiClient(config.api_key, config.api_url);
|
|
233
|
+
const workspace = await resolveWorkspace(client, options.workspace);
|
|
234
|
+
// Resolve tag by slug:value if not a UUID
|
|
235
|
+
let tagId = options.tag;
|
|
236
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
237
|
+
if (!uuidRegex.test(tagId)) {
|
|
238
|
+
const tagsResponse = await client.get(`/workspaces/${workspace.id}/tags`);
|
|
239
|
+
const allTags = tagsResponse.data.data || tagsResponse.data || [];
|
|
240
|
+
const [typeSlug, value] = tagId.includes(':') ? tagId.split(':') : [null, tagId];
|
|
241
|
+
const matchingTag = allTags.find((tag) => {
|
|
242
|
+
if (typeSlug)
|
|
243
|
+
return tag.typeSlug === typeSlug && tag.value === value;
|
|
244
|
+
return tag.value === value;
|
|
245
|
+
});
|
|
246
|
+
if (!matchingTag) {
|
|
247
|
+
spinner.fail(`Tag '${tagId}' not found. Use 'contextium tags list -w ${options.workspace}' to see available tags.`);
|
|
248
|
+
process.exit(1);
|
|
249
|
+
}
|
|
250
|
+
tagId = matchingTag.id;
|
|
251
|
+
}
|
|
252
|
+
await client.post(`/tags/${tagId}/apply?workspaceId=${workspace.id}`, { fileId: options.file });
|
|
253
|
+
spinner.stop();
|
|
254
|
+
console.log(chalk.green('\n✓ Tag applied successfully!'));
|
|
255
|
+
}
|
|
256
|
+
catch (error) {
|
|
257
|
+
spinner.fail(`Failed to apply tag: ${error.message}`);
|
|
258
|
+
process.exit(1);
|
|
259
|
+
}
|
|
260
|
+
});
|
|
261
|
+
// Apply tag to multiple files
|
|
262
|
+
tagsCommand
|
|
263
|
+
.command('apply-bulk')
|
|
264
|
+
.description('Apply a tag to multiple files')
|
|
265
|
+
.requiredOption('-w, --workspace <id>', 'Workspace name, slug, or ID')
|
|
266
|
+
.requiredOption('-t, --tag <tagId>', 'Tag ID or slug:value (e.g., "topic:authentication")')
|
|
267
|
+
.requiredOption('-f, --files <fileIds>', 'Comma-separated file IDs')
|
|
268
|
+
.action(async (options) => {
|
|
269
|
+
const fileIds = options.files.split(',').map((f) => f.trim());
|
|
270
|
+
const spinner = ora(`Applying tag to ${fileIds.length} file(s)...`).start();
|
|
271
|
+
try {
|
|
272
|
+
const config = await loadConfig();
|
|
273
|
+
const client = new ApiClient(config.api_key, config.api_url);
|
|
274
|
+
const workspace = await resolveWorkspace(client, options.workspace);
|
|
275
|
+
// Resolve tag by slug:value if not a UUID
|
|
276
|
+
let tagId = options.tag;
|
|
277
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
278
|
+
if (!uuidRegex.test(tagId)) {
|
|
279
|
+
const tagsResponse = await client.get(`/workspaces/${workspace.id}/tags`);
|
|
280
|
+
const allTags = tagsResponse.data.data || tagsResponse.data || [];
|
|
281
|
+
const [typeSlug, value] = tagId.includes(':') ? tagId.split(':') : [null, tagId];
|
|
282
|
+
const matchingTag = allTags.find((tag) => {
|
|
283
|
+
if (typeSlug)
|
|
284
|
+
return tag.typeSlug === typeSlug && tag.value === value;
|
|
285
|
+
return tag.value === value;
|
|
286
|
+
});
|
|
287
|
+
if (!matchingTag) {
|
|
288
|
+
spinner.fail(`Tag '${tagId}' not found.`);
|
|
289
|
+
process.exit(1);
|
|
290
|
+
}
|
|
291
|
+
tagId = matchingTag.id;
|
|
292
|
+
}
|
|
293
|
+
await client.post(`/tags/${tagId}/apply-bulk?workspaceId=${workspace.id}`, { fileIds });
|
|
294
|
+
spinner.stop();
|
|
295
|
+
console.log(chalk.green(`\n✓ Tag applied to ${fileIds.length} file(s) successfully!`));
|
|
296
|
+
}
|
|
297
|
+
catch (error) {
|
|
298
|
+
spinner.fail(`Failed to apply tag: ${error.message}`);
|
|
299
|
+
process.exit(1);
|
|
300
|
+
}
|
|
301
|
+
});
|
|
302
|
+
// Remove tag from a file
|
|
303
|
+
tagsCommand
|
|
304
|
+
.command('remove')
|
|
305
|
+
.description('Remove a tag from a file')
|
|
306
|
+
.requiredOption('-w, --workspace <id>', 'Workspace name, slug, or ID')
|
|
307
|
+
.requiredOption('-t, --tag <tagId>', 'Tag ID or slug:value (e.g., "topic:authentication")')
|
|
308
|
+
.requiredOption('-f, --file <fileId>', 'File ID')
|
|
309
|
+
.action(async (options) => {
|
|
310
|
+
const spinner = ora('Removing tag...').start();
|
|
311
|
+
try {
|
|
312
|
+
const config = await loadConfig();
|
|
313
|
+
const client = new ApiClient(config.api_key, config.api_url);
|
|
314
|
+
const workspace = await resolveWorkspace(client, options.workspace);
|
|
315
|
+
// Resolve tag by slug:value if not a UUID
|
|
316
|
+
let tagId = options.tag;
|
|
317
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
318
|
+
if (!uuidRegex.test(tagId)) {
|
|
319
|
+
const tagsResponse = await client.get(`/workspaces/${workspace.id}/tags`);
|
|
320
|
+
const allTags = tagsResponse.data.data || tagsResponse.data || [];
|
|
321
|
+
const [typeSlug, value] = tagId.includes(':') ? tagId.split(':') : [null, tagId];
|
|
322
|
+
const matchingTag = allTags.find((tag) => {
|
|
323
|
+
if (typeSlug)
|
|
324
|
+
return tag.typeSlug === typeSlug && tag.value === value;
|
|
325
|
+
return tag.value === value;
|
|
326
|
+
});
|
|
327
|
+
if (!matchingTag) {
|
|
328
|
+
spinner.fail(`Tag '${tagId}' not found.`);
|
|
329
|
+
process.exit(1);
|
|
330
|
+
}
|
|
331
|
+
tagId = matchingTag.id;
|
|
332
|
+
}
|
|
333
|
+
await client.post(`/tags/${tagId}/remove?workspaceId=${workspace.id}`, { fileId: options.file });
|
|
334
|
+
spinner.stop();
|
|
335
|
+
console.log(chalk.green('\n✓ Tag removed successfully!'));
|
|
336
|
+
}
|
|
337
|
+
catch (error) {
|
|
338
|
+
spinner.fail(`Failed to remove tag: ${error.message}`);
|
|
339
|
+
process.exit(1);
|
|
340
|
+
}
|
|
341
|
+
});
|
|
193
342
|
// Search files by tags
|
|
194
343
|
tagsCommand
|
|
195
344
|
.command('search')
|
|
196
345
|
.description('Search files by tags')
|
|
197
|
-
.requiredOption('-w, --workspace <id>', 'Workspace ID')
|
|
346
|
+
.requiredOption('-w, --workspace <id>', 'Workspace name, slug, or ID')
|
|
198
347
|
.requiredOption('-t, --tags <tagIds>', 'Comma-separated tag IDs or tag values (e.g., "md" or "file-type:md")')
|
|
199
348
|
.option('-p, --library <libraryId>', 'Filter by context library ID')
|
|
200
349
|
.action(async (options) => {
|
|
@@ -202,7 +351,8 @@ tagsCommand
|
|
|
202
351
|
try {
|
|
203
352
|
const config = await loadConfig();
|
|
204
353
|
const client = new ApiClient(config.api_key, config.api_url);
|
|
205
|
-
const
|
|
354
|
+
const workspace = await resolveWorkspace(client, options.workspace);
|
|
355
|
+
const workspaceId = workspace.id;
|
|
206
356
|
// Parse tag input - support both IDs and slug:value format
|
|
207
357
|
let tagIds = [];
|
|
208
358
|
const tagInput = options.tags.split(',').map((t) => t.trim());
|
|
@@ -295,6 +445,7 @@ tagsCommand
|
|
|
295
445
|
projectFiles.forEach((file) => {
|
|
296
446
|
const sizeKB = file.fileSize ? (file.fileSize / 1024).toFixed(2) : '0';
|
|
297
447
|
console.log(` - ${chalk.white(file.title)}`);
|
|
448
|
+
console.log(` ID: ${chalk.dim(file.id)}`);
|
|
298
449
|
console.log(` Path: ${chalk.dim(file.path || 'N/A')}`);
|
|
299
450
|
console.log(` Size: ${chalk.dim(sizeKB + ' KB')}`);
|
|
300
451
|
console.log('');
|
|
@@ -309,4 +460,212 @@ tagsCommand
|
|
|
309
460
|
process.exit(1);
|
|
310
461
|
}
|
|
311
462
|
});
|
|
463
|
+
// List tags on a file
|
|
464
|
+
tagsCommand
|
|
465
|
+
.command('file-tags')
|
|
466
|
+
.description('List tags applied to a specific file')
|
|
467
|
+
.requiredOption('-w, --workspace <id>', 'Workspace name, slug, or ID')
|
|
468
|
+
.requiredOption('-f, --file <fileId>', 'File ID')
|
|
469
|
+
.action(async (options) => {
|
|
470
|
+
const spinner = ora('Loading file tags...').start();
|
|
471
|
+
try {
|
|
472
|
+
const config = await loadConfig();
|
|
473
|
+
const client = new ApiClient(config.api_key, config.api_url);
|
|
474
|
+
const workspace = await resolveWorkspace(client, options.workspace);
|
|
475
|
+
const response = await client.get(`/files/${options.file}/tags`, {
|
|
476
|
+
params: { workspaceId: workspace.id }
|
|
477
|
+
});
|
|
478
|
+
const tagsData = response.data;
|
|
479
|
+
const tags = tagsData.data || tagsData || [];
|
|
480
|
+
if (tags.length === 0) {
|
|
481
|
+
spinner.stop();
|
|
482
|
+
console.log(chalk.yellow('No tags on this file.'));
|
|
483
|
+
return;
|
|
484
|
+
}
|
|
485
|
+
spinner.stop();
|
|
486
|
+
console.log(chalk.bold(`\n${tags.length} tag(s) on file:\n`));
|
|
487
|
+
tags.forEach((entry) => {
|
|
488
|
+
const tag = entry.tag || entry;
|
|
489
|
+
console.log(` ${chalk.cyan(tag.typeSlug || tag.typeName || 'unknown')}:${tag.value}`);
|
|
490
|
+
console.log(chalk.dim(` ID: ${tag.id} Color: ${tag.color || 'default'}`));
|
|
491
|
+
});
|
|
492
|
+
console.log('');
|
|
493
|
+
}
|
|
494
|
+
catch (error) {
|
|
495
|
+
spinner.fail(`Failed to load file tags: ${error.message}`);
|
|
496
|
+
process.exit(1);
|
|
497
|
+
}
|
|
498
|
+
});
|
|
499
|
+
// Update a tag
|
|
500
|
+
tagsCommand
|
|
501
|
+
.command('update')
|
|
502
|
+
.description('Update an existing tag')
|
|
503
|
+
.requiredOption('-w, --workspace <id>', 'Workspace name, slug, or ID')
|
|
504
|
+
.requiredOption('-t, --tag <tagId>', 'Tag ID or slug:value')
|
|
505
|
+
.option('-v, --value <value>', 'New tag value (lowercase, hyphens)')
|
|
506
|
+
.option('--type <typeId>', 'New tag type ID')
|
|
507
|
+
.option('-c, --color <hex>', 'New hex color code')
|
|
508
|
+
.action(async (options) => {
|
|
509
|
+
const spinner = ora('Updating tag...').start();
|
|
510
|
+
try {
|
|
511
|
+
const config = await loadConfig();
|
|
512
|
+
const client = new ApiClient(config.api_key, config.api_url);
|
|
513
|
+
const workspace = await resolveWorkspace(client, options.workspace);
|
|
514
|
+
// Resolve tag by slug:value if not a UUID
|
|
515
|
+
let tagId = options.tag;
|
|
516
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
517
|
+
if (!uuidRegex.test(tagId)) {
|
|
518
|
+
const tagsResponse = await client.get(`/workspaces/${workspace.id}/tags`);
|
|
519
|
+
const allTags = tagsResponse.data.data || tagsResponse.data || [];
|
|
520
|
+
const [typeSlug, value] = tagId.includes(':') ? tagId.split(':') : [null, tagId];
|
|
521
|
+
const matchingTag = allTags.find((tag) => {
|
|
522
|
+
if (typeSlug)
|
|
523
|
+
return tag.typeSlug === typeSlug && tag.value === value;
|
|
524
|
+
return tag.value === value;
|
|
525
|
+
});
|
|
526
|
+
if (!matchingTag) {
|
|
527
|
+
spinner.fail(`Tag '${tagId}' not found.`);
|
|
528
|
+
process.exit(1);
|
|
529
|
+
}
|
|
530
|
+
tagId = matchingTag.id;
|
|
531
|
+
}
|
|
532
|
+
const data = {};
|
|
533
|
+
if (options.value)
|
|
534
|
+
data.value = options.value;
|
|
535
|
+
if (options.type)
|
|
536
|
+
data.typeId = options.type;
|
|
537
|
+
if (options.color)
|
|
538
|
+
data.color = options.color;
|
|
539
|
+
if (Object.keys(data).length === 0) {
|
|
540
|
+
spinner.fail('No fields to update. Use --value, --type, or --color.');
|
|
541
|
+
process.exit(1);
|
|
542
|
+
}
|
|
543
|
+
const response = await client.put(`/tags/${tagId}?workspaceId=${workspace.id}`, data);
|
|
544
|
+
const tag = response.data.data || response.data;
|
|
545
|
+
spinner.stop();
|
|
546
|
+
console.log(chalk.green('\n✓ Tag updated successfully!'));
|
|
547
|
+
console.log(` Tag: ${tag.typeSlug || ''}:${tag.value}`);
|
|
548
|
+
console.log(` ID: ${tag.id}`);
|
|
549
|
+
if (tag.color)
|
|
550
|
+
console.log(` Color: ${tag.color}`);
|
|
551
|
+
console.log('');
|
|
552
|
+
}
|
|
553
|
+
catch (error) {
|
|
554
|
+
spinner.fail(`Failed to update tag: ${error.message}`);
|
|
555
|
+
process.exit(1);
|
|
556
|
+
}
|
|
557
|
+
});
|
|
558
|
+
// Get tag type by ID
|
|
559
|
+
tagsCommand
|
|
560
|
+
.command('type-get')
|
|
561
|
+
.description('Get a tag type by ID')
|
|
562
|
+
.requiredOption('-w, --workspace <id>', 'Workspace name, slug, or ID')
|
|
563
|
+
.requiredOption('-t, --type <typeId>', 'Tag type ID or slug')
|
|
564
|
+
.action(async (options) => {
|
|
565
|
+
const spinner = ora('Loading tag type...').start();
|
|
566
|
+
try {
|
|
567
|
+
const config = await loadConfig();
|
|
568
|
+
const client = new ApiClient(config.api_key, config.api_url);
|
|
569
|
+
const workspace = await resolveWorkspace(client, options.workspace);
|
|
570
|
+
// Resolve type by slug if not a UUID
|
|
571
|
+
let typeId = options.type;
|
|
572
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
573
|
+
if (!uuidRegex.test(typeId)) {
|
|
574
|
+
const typesResponse = await client.get(`/workspaces/${workspace.id}/tag-types`);
|
|
575
|
+
const types = typesResponse.data.data || typesResponse.data || [];
|
|
576
|
+
const match = types.find((t) => t.slug === typeId || t.name.toLowerCase() === typeId.toLowerCase());
|
|
577
|
+
if (!match) {
|
|
578
|
+
spinner.fail(`Tag type '${typeId}' not found.`);
|
|
579
|
+
process.exit(1);
|
|
580
|
+
}
|
|
581
|
+
typeId = match.id;
|
|
582
|
+
}
|
|
583
|
+
const response = await client.get(`/tag-types/${typeId}`, {
|
|
584
|
+
params: { workspaceId: workspace.id }
|
|
585
|
+
});
|
|
586
|
+
const tagType = response.data.data || response.data;
|
|
587
|
+
spinner.stop();
|
|
588
|
+
console.log(chalk.bold(`\nTag Type: ${tagType.name}\n`));
|
|
589
|
+
console.log(` ID: ${tagType.id}`);
|
|
590
|
+
console.log(` Slug: ${tagType.slug}`);
|
|
591
|
+
console.log(` Color: ${tagType.color || 'default'}`);
|
|
592
|
+
if (tagType.icon)
|
|
593
|
+
console.log(` Icon: ${tagType.icon}`);
|
|
594
|
+
if (tagType.description)
|
|
595
|
+
console.log(` Description: ${tagType.description}`);
|
|
596
|
+
console.log(` System: ${tagType.isSystem ? 'Yes' : 'No'}`);
|
|
597
|
+
console.log(` Display Order: ${tagType.displayOrder}`);
|
|
598
|
+
if (tagType.tagCount !== undefined)
|
|
599
|
+
console.log(` Tag Count: ${tagType.tagCount}`);
|
|
600
|
+
console.log('');
|
|
601
|
+
}
|
|
602
|
+
catch (error) {
|
|
603
|
+
spinner.fail(`Failed to load tag type: ${error.message}`);
|
|
604
|
+
process.exit(1);
|
|
605
|
+
}
|
|
606
|
+
});
|
|
607
|
+
// Update tag type
|
|
608
|
+
tagsCommand
|
|
609
|
+
.command('type-update')
|
|
610
|
+
.description('Update an existing tag type')
|
|
611
|
+
.requiredOption('-w, --workspace <id>', 'Workspace name, slug, or ID')
|
|
612
|
+
.requiredOption('-t, --type <typeId>', 'Tag type ID or slug')
|
|
613
|
+
.option('-n, --name <name>', 'New name')
|
|
614
|
+
.option('-s, --slug <slug>', 'New slug')
|
|
615
|
+
.option('-c, --color <hex>', 'New hex color code')
|
|
616
|
+
.option('-i, --icon <icon>', 'New icon name')
|
|
617
|
+
.option('-d, --description <text>', 'New description')
|
|
618
|
+
.option('--order <number>', 'New display order')
|
|
619
|
+
.action(async (options) => {
|
|
620
|
+
const spinner = ora('Updating tag type...').start();
|
|
621
|
+
try {
|
|
622
|
+
const config = await loadConfig();
|
|
623
|
+
const client = new ApiClient(config.api_key, config.api_url);
|
|
624
|
+
const workspace = await resolveWorkspace(client, options.workspace);
|
|
625
|
+
// Resolve type by slug if not a UUID
|
|
626
|
+
let typeId = options.type;
|
|
627
|
+
const uuidRegex = /^[0-9a-f]{8}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{4}-[0-9a-f]{12}$/i;
|
|
628
|
+
if (!uuidRegex.test(typeId)) {
|
|
629
|
+
const typesResponse = await client.get(`/workspaces/${workspace.id}/tag-types`);
|
|
630
|
+
const types = typesResponse.data.data || typesResponse.data || [];
|
|
631
|
+
const match = types.find((t) => t.slug === typeId || t.name.toLowerCase() === typeId.toLowerCase());
|
|
632
|
+
if (!match) {
|
|
633
|
+
spinner.fail(`Tag type '${typeId}' not found.`);
|
|
634
|
+
process.exit(1);
|
|
635
|
+
}
|
|
636
|
+
typeId = match.id;
|
|
637
|
+
}
|
|
638
|
+
const data = {};
|
|
639
|
+
if (options.name)
|
|
640
|
+
data.name = options.name;
|
|
641
|
+
if (options.slug)
|
|
642
|
+
data.slug = options.slug;
|
|
643
|
+
if (options.color)
|
|
644
|
+
data.color = options.color;
|
|
645
|
+
if (options.icon)
|
|
646
|
+
data.icon = options.icon;
|
|
647
|
+
if (options.description)
|
|
648
|
+
data.description = options.description;
|
|
649
|
+
if (options.order !== undefined)
|
|
650
|
+
data.displayOrder = parseInt(options.order, 10);
|
|
651
|
+
if (Object.keys(data).length === 0) {
|
|
652
|
+
spinner.fail('No fields to update. Use --name, --slug, --color, --icon, --description, or --order.');
|
|
653
|
+
process.exit(1);
|
|
654
|
+
}
|
|
655
|
+
const response = await client.put(`/tag-types/${typeId}?workspaceId=${workspace.id}`, data);
|
|
656
|
+
const tagType = response.data.data || response.data;
|
|
657
|
+
spinner.stop();
|
|
658
|
+
console.log(chalk.green('\n✓ Tag type updated successfully!'));
|
|
659
|
+
console.log(` Name: ${tagType.name}`);
|
|
660
|
+
console.log(` Slug: ${tagType.slug}`);
|
|
661
|
+
console.log(` ID: ${tagType.id}`);
|
|
662
|
+
if (tagType.color)
|
|
663
|
+
console.log(` Color: ${tagType.color}`);
|
|
664
|
+
console.log('');
|
|
665
|
+
}
|
|
666
|
+
catch (error) {
|
|
667
|
+
spinner.fail(`Failed to update tag type: ${error.message}`);
|
|
668
|
+
process.exit(1);
|
|
669
|
+
}
|
|
670
|
+
});
|
|
312
671
|
//# sourceMappingURL=tags.js.map
|