@contextium/cli 0.3.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.
Files changed (86) hide show
  1. package/README.md +227 -0
  2. package/dist/commands/cat.d.ts +3 -0
  3. package/dist/commands/cat.d.ts.map +1 -0
  4. package/dist/commands/cat.js +153 -0
  5. package/dist/commands/cat.js.map +1 -0
  6. package/dist/commands/files.d.ts +3 -0
  7. package/dist/commands/files.d.ts.map +1 -0
  8. package/dist/commands/files.js +121 -0
  9. package/dist/commands/files.js.map +1 -0
  10. package/dist/commands/find.d.ts +3 -0
  11. package/dist/commands/find.d.ts.map +1 -0
  12. package/dist/commands/find.js +119 -0
  13. package/dist/commands/find.js.map +1 -0
  14. package/dist/commands/init.d.ts +3 -0
  15. package/dist/commands/init.d.ts.map +1 -0
  16. package/dist/commands/init.js +157 -0
  17. package/dist/commands/init.js.map +1 -0
  18. package/dist/commands/login.d.ts +3 -0
  19. package/dist/commands/login.d.ts.map +1 -0
  20. package/dist/commands/login.js +44 -0
  21. package/dist/commands/login.js.map +1 -0
  22. package/dist/commands/logout.d.ts +3 -0
  23. package/dist/commands/logout.d.ts.map +1 -0
  24. package/dist/commands/logout.js +22 -0
  25. package/dist/commands/logout.js.map +1 -0
  26. package/dist/commands/projects.d.ts +3 -0
  27. package/dist/commands/projects.d.ts.map +1 -0
  28. package/dist/commands/projects.js +64 -0
  29. package/dist/commands/projects.js.map +1 -0
  30. package/dist/commands/search.d.ts +3 -0
  31. package/dist/commands/search.d.ts.map +1 -0
  32. package/dist/commands/search.js +79 -0
  33. package/dist/commands/search.js.map +1 -0
  34. package/dist/commands/setup-claude.d.ts +3 -0
  35. package/dist/commands/setup-claude.d.ts.map +1 -0
  36. package/dist/commands/setup-claude.js +106 -0
  37. package/dist/commands/setup-claude.js.map +1 -0
  38. package/dist/commands/status.d.ts +3 -0
  39. package/dist/commands/status.d.ts.map +1 -0
  40. package/dist/commands/status.js +103 -0
  41. package/dist/commands/status.js.map +1 -0
  42. package/dist/commands/sync.d.ts +3 -0
  43. package/dist/commands/sync.d.ts.map +1 -0
  44. package/dist/commands/sync.js +118 -0
  45. package/dist/commands/sync.js.map +1 -0
  46. package/dist/commands/tags.d.ts +3 -0
  47. package/dist/commands/tags.d.ts.map +1 -0
  48. package/dist/commands/tags.js +312 -0
  49. package/dist/commands/tags.js.map +1 -0
  50. package/dist/commands/whoami.d.ts +3 -0
  51. package/dist/commands/whoami.d.ts.map +1 -0
  52. package/dist/commands/whoami.js +35 -0
  53. package/dist/commands/whoami.js.map +1 -0
  54. package/dist/commands/workspaces.d.ts +3 -0
  55. package/dist/commands/workspaces.d.ts.map +1 -0
  56. package/dist/commands/workspaces.js +48 -0
  57. package/dist/commands/workspaces.js.map +1 -0
  58. package/dist/index.d.ts +3 -0
  59. package/dist/index.d.ts.map +1 -0
  60. package/dist/index.js +56 -0
  61. package/dist/index.js.map +1 -0
  62. package/dist/lib/api-client.d.ts +11 -0
  63. package/dist/lib/api-client.d.ts.map +1 -0
  64. package/dist/lib/api-client.js +61 -0
  65. package/dist/lib/api-client.js.map +1 -0
  66. package/dist/lib/cache.d.ts +20 -0
  67. package/dist/lib/cache.d.ts.map +1 -0
  68. package/dist/lib/cache.js +79 -0
  69. package/dist/lib/cache.js.map +1 -0
  70. package/dist/lib/config.d.ts +4 -0
  71. package/dist/lib/config.d.ts.map +1 -0
  72. package/dist/lib/config.js +40 -0
  73. package/dist/lib/config.js.map +1 -0
  74. package/dist/lib/msal.d.ts +25 -0
  75. package/dist/lib/msal.d.ts.map +1 -0
  76. package/dist/lib/msal.js +150 -0
  77. package/dist/lib/msal.js.map +1 -0
  78. package/dist/lib/output.d.ts +40 -0
  79. package/dist/lib/output.d.ts.map +1 -0
  80. package/dist/lib/output.js +70 -0
  81. package/dist/lib/output.js.map +1 -0
  82. package/dist/types/index.d.ts +58 -0
  83. package/dist/types/index.d.ts.map +1 -0
  84. package/dist/types/index.js +2 -0
  85. package/dist/types/index.js.map +1 -0
  86. package/package.json +58 -0
package/README.md ADDED
@@ -0,0 +1,227 @@
1
+ # Contextium CLI
2
+
3
+ Command-line interface for Contextium that allows developers to fetch and pipe documentation to external AI tools.
4
+
5
+ ## Installation
6
+
7
+ ```bash
8
+ # Build the CLI
9
+ npm run build
10
+
11
+ # Link for local development
12
+ npm link
13
+ ```
14
+
15
+ ## Setup
16
+
17
+ ### 1. Initialize a Project
18
+
19
+ ```bash
20
+ # Navigate to your project directory
21
+ cd /path/to/your/project
22
+
23
+ # Initialize Contextium with your workspace and project
24
+ contextium init \
25
+ --api-key YOUR_API_KEY \
26
+ --workspace your-workspace-slug \
27
+ --project your-project-slug \
28
+ --api-url http://localhost:3001/api/v1
29
+
30
+ # Or use environment variable for API key
31
+ export CONTEXTIUM_API_KEY=your_api_key
32
+ contextium init --workspace your-workspace-slug --project your-project-slug
33
+ ```
34
+
35
+ This creates:
36
+ - `.contextiumrc` - Configuration file
37
+ - `.contextium-cache/` - Local cache directory
38
+ - Updates `.gitignore` to exclude cache directory
39
+
40
+ ### 2. Sync Files
41
+
42
+ Download all project files to local cache:
43
+
44
+ ```bash
45
+ # Sync all files
46
+ contextium sync
47
+
48
+ # Sync specific files
49
+ contextium sync README.md API_GUIDE.md
50
+
51
+ # Sync files with specific tags
52
+ contextium sync --tag foundation-context --tag always-include
53
+
54
+ # Force re-download all files
55
+ contextium sync --force
56
+
57
+ # Dry run to see what would be synced
58
+ contextium sync --dry-run
59
+ ```
60
+
61
+ ## Usage
62
+
63
+ ### Check Status
64
+
65
+ Check which files are cached and up-to-date:
66
+
67
+ ```bash
68
+ contextium status
69
+ ```
70
+
71
+ Output:
72
+ ```
73
+ Project: My Project
74
+ Project ID: abc-123
75
+ Workspace: my-workspace
76
+
77
+ ✓ README.md v3 (up to date)
78
+ ↓ API_GUIDE.md v2 (v5 available, 3 versions behind)
79
+ ? SETUP.md (not cached)
80
+
81
+ 2 file(s) need update - run 'contextium sync'
82
+ 1 file(s) not cached - run 'contextium sync'
83
+ ```
84
+
85
+ ### Output File Content
86
+
87
+ Output file content to stdout for piping to AI tools:
88
+
89
+ ```bash
90
+ # Output all files
91
+ contextium cat --all
92
+
93
+ # Output specific files
94
+ contextium cat README.md API_GUIDE.md
95
+
96
+ # Output files with specific tags
97
+ contextium cat --tag always-include
98
+
99
+ # Include metadata headers
100
+ contextium cat --all --with-meta
101
+
102
+ # Output as JSON
103
+ contextium cat --all --format json
104
+ ```
105
+
106
+ ### Pipe to External AI Tools
107
+
108
+ The primary use case - pipe documentation to AI tools like Cursor, Claude, or Copilot:
109
+
110
+ ```bash
111
+ # Pipe all documentation to clipboard
112
+ contextium cat --all | pbcopy
113
+
114
+ # Pipe to Cursor
115
+ contextium cat --all | cursor --add-context
116
+
117
+ # Pipe foundation docs to Claude
118
+ contextium cat --tag foundation-context | claude --context
119
+
120
+ # Pipe specific files
121
+ contextium cat README.md API_GUIDE.md | cursor --add-context
122
+ ```
123
+
124
+ ### Search Files
125
+
126
+ Search for files in your project:
127
+
128
+ ```bash
129
+ # Search by filename or content
130
+ contextium search "authentication"
131
+
132
+ # Search with tag filter
133
+ contextium search "api" --tag backend
134
+
135
+ # Limit results
136
+ contextium search "guide" --limit 5
137
+ ```
138
+
139
+ ## Configuration
140
+
141
+ The `.contextiumrc` file contains your project configuration:
142
+
143
+ ```json
144
+ {
145
+ "api_key": "your-api-key",
146
+ "api_url": "http://localhost:3001/api/v1",
147
+ "project_id": "project-uuid",
148
+ "workspace": "workspace-slug",
149
+ "cache": {
150
+ "enabled": true,
151
+ "ttl": 3600,
152
+ "directory": ".contextium-cache",
153
+ "max_size_mb": 100
154
+ },
155
+ "sync": {
156
+ "auto": true,
157
+ "on_command": ["build", "test"],
158
+ "notify_changes": true,
159
+ "interval": 300
160
+ },
161
+ "files": {
162
+ "include": [],
163
+ "exclude": ["DEPRECATED_*.md", "DRAFT_*.md"],
164
+ "tags": ["foundation-context", "always-include"],
165
+ "auto_include_tags": true
166
+ }
167
+ }
168
+ ```
169
+
170
+ ## Workflow Example
171
+
172
+ ```bash
173
+ # 1. Initialize in your project
174
+ cd ~/projects/my-app
175
+ contextium init --workspace my-company --project my-app
176
+
177
+ # 2. Sync all documentation
178
+ contextium sync
179
+
180
+ # 3. Start coding with AI assistance
181
+ # Pipe all relevant docs to your AI tool
182
+ contextium cat --tag always-include | cursor --add-context
183
+
184
+ # 4. Update when docs change
185
+ contextium status # Check for updates
186
+ contextium sync # Download latest versions
187
+ ```
188
+
189
+ ## Cache Management
190
+
191
+ The CLI caches files locally for faster access:
192
+
193
+ - Cache directory: `.contextium-cache/`
194
+ - TTL: 1 hour (configurable)
195
+ - Auto-syncs based on configuration
196
+ - Use `--no-cache` flag to bypass cache
197
+
198
+ ## Development
199
+
200
+ ```bash
201
+ # Build
202
+ npm run build
203
+
204
+ # Watch mode
205
+ npm run dev
206
+
207
+ # Type check
208
+ npm run type-check
209
+ ```
210
+
211
+ ## Architecture
212
+
213
+ The CLI is designed to be a lightweight bridge between your Contextium documentation repository and external AI coding tools:
214
+
215
+ ```
216
+ Your Project
217
+
218
+ Contextium CLI (fetch docs)
219
+
220
+ Local Cache (.contextium-cache/)
221
+
222
+ Pipe to AI Tool (Cursor, Claude, Copilot)
223
+
224
+ AI-assisted Development
225
+ ```
226
+
227
+ For more information, see the [Platform Specification](../../Resources/CONTEXTHUB_PLATFORM_SPEC.md).
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const catCommand: Command;
3
+ //# sourceMappingURL=cat.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cat.d.ts","sourceRoot":"","sources":["../../src/commands/cat.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAOnC,eAAO,MAAM,UAAU,SAkLnB,CAAA"}
@@ -0,0 +1,153 @@
1
+ import { Command } from 'commander';
2
+ import { ApiClient } from '../lib/api-client.js';
3
+ import { loadConfig } from '../lib/config.js';
4
+ import { Cache } from '../lib/cache.js';
5
+ import { chalk } from '../lib/output.js';
6
+ export const catCommand = new Command('cat')
7
+ .description('Output file content to stdout')
8
+ .argument('[files...]', 'File names to output')
9
+ .option('--all', 'Output all files (requires --workspace)')
10
+ .option('--workspace <slug>', 'Specify workspace to search in')
11
+ .option('--tag <tags...>', 'Filter by tags')
12
+ .option('--with-meta', 'Include metadata header')
13
+ .option('--format <format>', 'Output format (text|json)', 'text')
14
+ .option('--no-cache', 'Skip cache')
15
+ .action(async (files, options) => {
16
+ try {
17
+ const config = await loadConfig();
18
+ const client = new ApiClient(config.api_key, config.api_url);
19
+ const cache = new Cache(config.cache);
20
+ // Resolve workspace
21
+ let workspaceId;
22
+ if (options.workspace) {
23
+ const { data: workspacesData } = await client.get('/workspaces');
24
+ const workspaces = workspacesData.data || workspacesData;
25
+ const workspace = workspaces.find((w) => w.slug === options.workspace);
26
+ if (!workspace) {
27
+ console.error(chalk.red(`Error: Workspace '${options.workspace}' not found`));
28
+ process.exit(1);
29
+ }
30
+ workspaceId = workspace.id;
31
+ }
32
+ else if (config.workspace_id) {
33
+ workspaceId = config.workspace_id;
34
+ }
35
+ // For --all and --tag options, workspace is required
36
+ if ((options.all || options.tag) && !workspaceId) {
37
+ console.error(chalk.red('Error: --all and --tag options require a workspace'));
38
+ console.error(chalk.dim('Either set a default workspace or use --workspace <slug>'));
39
+ process.exit(1);
40
+ }
41
+ let filesToFetch = [];
42
+ if (options.all) {
43
+ // Fetch all files from workspace
44
+ const { data: workspacesData } = await client.get('/workspaces');
45
+ const workspaces = workspacesData.data || workspacesData;
46
+ const workspace = workspaces.find((w) => w.id === workspaceId);
47
+ const { data: projectsData } = await client.get(`/workspaces/${workspace.id}/projects`);
48
+ const projects = projectsData.data || projectsData;
49
+ for (const project of projects) {
50
+ const { data } = await client.get(`/projects/${project.id}/files`);
51
+ filesToFetch.push(...data.map((f) => f.title));
52
+ }
53
+ }
54
+ else if (options.tag && options.tag.length > 0) {
55
+ // Fetch by tags from workspace
56
+ const { data: projectsData } = await client.get(`/workspaces/${workspaceId}/projects`);
57
+ const projects = projectsData.data || projectsData;
58
+ for (const project of projects) {
59
+ const { data } = await client.get(`/projects/${project.id}/files`, { params: { tags: options.tag.join(',') } });
60
+ filesToFetch.push(...data.map((f) => f.title));
61
+ }
62
+ }
63
+ else if (files.length > 0) {
64
+ filesToFetch = files;
65
+ }
66
+ else {
67
+ console.error(chalk.red('Error: No files specified'));
68
+ console.error(chalk.dim('Usage: contextium cat <files...> or --all'));
69
+ process.exit(1);
70
+ }
71
+ // Fetch file contents
72
+ const results = [];
73
+ for (const fileName of filesToFetch) {
74
+ // Try cache first
75
+ if (options.cache !== false) {
76
+ const cached = await cache.get(fileName);
77
+ if (cached && cached.content) {
78
+ results.push(cached);
79
+ continue;
80
+ }
81
+ }
82
+ // Search across all workspaces if no default is set
83
+ let file;
84
+ if (workspaceId) {
85
+ // Search in specific workspace
86
+ const { data: projectsData } = await client.get(`/workspaces/${workspaceId}/projects`);
87
+ const projects = projectsData.data || projectsData;
88
+ for (const project of projects) {
89
+ const { data: filesResponse } = await client.get(`/projects/${project.id}/files`, { params: { search: fileName } });
90
+ file = filesResponse.find((f) => f.title === fileName || f.path === fileName);
91
+ if (file)
92
+ break;
93
+ }
94
+ }
95
+ else {
96
+ // Search across all workspaces
97
+ const { data: workspacesData } = await client.get('/workspaces');
98
+ const workspaces = workspacesData.data || workspacesData;
99
+ for (const workspace of workspaces) {
100
+ const { data: projectsData } = await client.get(`/workspaces/${workspace.id}/projects`);
101
+ const projects = projectsData.data || projectsData;
102
+ for (const project of projects) {
103
+ const { data: filesResponse } = await client.get(`/projects/${project.id}/files`, { params: { search: fileName } });
104
+ file = filesResponse.find((f) => f.title === fileName || f.path === fileName);
105
+ if (file)
106
+ break;
107
+ }
108
+ if (file)
109
+ break;
110
+ }
111
+ }
112
+ if (!file) {
113
+ console.error(chalk.yellow(`Warning: File not found: ${fileName}`));
114
+ continue;
115
+ }
116
+ // Get full file content
117
+ const { data: fileData } = await client.get(`/files/${file.id}`);
118
+ results.push(fileData.data || fileData);
119
+ // Cache it
120
+ if (options.cache !== false) {
121
+ await cache.set(fileName, fileData.data || fileData);
122
+ }
123
+ }
124
+ // Output
125
+ if (options.format === 'json') {
126
+ console.log(JSON.stringify(results, null, 2));
127
+ }
128
+ else {
129
+ for (const file of results) {
130
+ if (options.withMeta) {
131
+ console.log(chalk.gray('---'));
132
+ console.log(chalk.gray(`file: ${file.title}`));
133
+ console.log(chalk.gray(`version: ${file.currentVersion}`));
134
+ console.log(chalk.gray(`project_id: ${file.projectId}`));
135
+ console.log(chalk.gray(`last_updated: ${file.updatedAt}`));
136
+ console.log(chalk.gray('---'));
137
+ console.log();
138
+ }
139
+ console.log(file.content);
140
+ if (results.length > 1 && !options.withMeta) {
141
+ console.log();
142
+ console.log(chalk.dim('─'.repeat(60)));
143
+ console.log();
144
+ }
145
+ }
146
+ }
147
+ }
148
+ catch (error) {
149
+ console.error(chalk.red('Error:'), error.message);
150
+ process.exit(1);
151
+ }
152
+ });
153
+ //# sourceMappingURL=cat.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"cat.js","sourceRoot":"","sources":["../../src/commands/cat.ts"],"names":[],"mappings":"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"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const filesCommand: Command;
3
+ //# sourceMappingURL=files.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.d.ts","sourceRoot":"","sources":["../../src/commands/files.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAMnC,eAAO,MAAM,YAAY,SAiJrB,CAAA"}
@@ -0,0 +1,121 @@
1
+ import { Command } from 'commander';
2
+ import { ApiClient } from '../lib/api-client.js';
3
+ import { loadConfig } from '../lib/config.js';
4
+ import { chalk, ora } from '../lib/output.js';
5
+ export const filesCommand = new Command('files')
6
+ .description('List files in a project with pagination')
7
+ .argument('<project>', 'Project name or slug')
8
+ .option('--workspace <slug>', 'Specify workspace (required if project name is ambiguous)')
9
+ .option('--page <number>', 'Page number', '1')
10
+ .option('--limit <number>', 'Items per page', '20')
11
+ .action(async (projectName, options) => {
12
+ const spinner = ora('Loading files...').start();
13
+ try {
14
+ const config = await loadConfig();
15
+ const client = new ApiClient(config.api_key, config.api_url);
16
+ const page = parseInt(options.page);
17
+ const limit = parseInt(options.limit);
18
+ if (page < 1) {
19
+ spinner.fail('Page number must be >= 1');
20
+ process.exit(1);
21
+ }
22
+ // Get workspaces to search
23
+ const { data: workspacesData } = await client.get('/workspaces');
24
+ const workspaces = workspacesData.data || workspacesData;
25
+ let workspacesToSearch = workspaces;
26
+ if (options.workspace) {
27
+ const workspace = workspaces.find((w) => w.slug.toLowerCase() === options.workspace.toLowerCase() ||
28
+ w.name.toLowerCase() === options.workspace.toLowerCase());
29
+ if (!workspace) {
30
+ spinner.fail(`Workspace '${options.workspace}' not found`);
31
+ process.exit(1);
32
+ }
33
+ workspacesToSearch = [workspace];
34
+ }
35
+ // Find project by name or slug (case-insensitive)
36
+ let foundProject = null;
37
+ let foundWorkspace = null;
38
+ const matchingProjects = [];
39
+ for (const workspace of workspacesToSearch) {
40
+ const { data: projectsData } = await client.get(`/workspaces/${workspace.id}/projects`);
41
+ const projects = projectsData.data || projectsData;
42
+ for (const project of projects) {
43
+ if (project.deletedAt)
44
+ continue;
45
+ if (project.slug.toLowerCase().trim() === projectName.toLowerCase().trim() ||
46
+ project.name.toLowerCase().trim() === projectName.toLowerCase().trim()) {
47
+ matchingProjects.push({ project, workspace });
48
+ }
49
+ }
50
+ }
51
+ if (matchingProjects.length === 0) {
52
+ spinner.fail(`Project '${projectName}' not found`);
53
+ process.exit(1);
54
+ }
55
+ if (matchingProjects.length > 1) {
56
+ spinner.fail(`Multiple projects found with name '${projectName}'`);
57
+ console.log();
58
+ console.log(chalk.dim('Please specify a workspace:'));
59
+ matchingProjects.forEach(({ project, workspace }) => {
60
+ console.log(chalk.dim(` - ${project.name} in ${workspace.name} (--workspace ${workspace.slug})`));
61
+ });
62
+ process.exit(1);
63
+ }
64
+ const match = matchingProjects[0];
65
+ foundProject = match.project;
66
+ foundWorkspace = match.workspace;
67
+ // Get files in project
68
+ const { data: filesData } = await client.get(`/projects/${match.project.id}/files`);
69
+ const allFiles = filesData.data || filesData;
70
+ const activeFiles = allFiles.filter((f) => !f.deletedAt);
71
+ if (activeFiles.length === 0) {
72
+ spinner.stop();
73
+ console.log(chalk.yellow(`\nNo files found in project '${foundProject.name}'`));
74
+ return;
75
+ }
76
+ // Sort by updated date (newest first)
77
+ activeFiles.sort((a, b) => new Date(b.updatedAt).getTime() - new Date(a.updatedAt).getTime());
78
+ // Paginate
79
+ const totalFiles = activeFiles.length;
80
+ const totalPages = Math.ceil(totalFiles / limit);
81
+ const startIndex = (page - 1) * limit;
82
+ const endIndex = Math.min(startIndex + limit, totalFiles);
83
+ const pageFiles = activeFiles.slice(startIndex, endIndex);
84
+ spinner.stop();
85
+ console.log(chalk.bold(`\nFiles in '${foundProject.name}' (${foundWorkspace.name}):`));
86
+ console.log(chalk.dim(`Page ${page} of ${totalPages} (${totalFiles} total files)\n`));
87
+ for (let i = 0; i < pageFiles.length; i++) {
88
+ const file = pageFiles[i];
89
+ const itemNumber = startIndex + i + 1;
90
+ const updatedDate = new Date(file.updatedAt);
91
+ const now = new Date();
92
+ const diffMs = now.getTime() - updatedDate.getTime();
93
+ const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
94
+ const diffDays = Math.floor(diffHours / 24);
95
+ let timeAgo;
96
+ if (diffHours < 1)
97
+ timeAgo = 'just now';
98
+ else if (diffHours < 24)
99
+ timeAgo = `${diffHours}h ago`;
100
+ else if (diffDays < 7)
101
+ timeAgo = `${diffDays}d ago`;
102
+ else
103
+ timeAgo = updatedDate.toLocaleDateString();
104
+ console.log(chalk.gray(`${itemNumber}.`), chalk.white(file.title), chalk.dim(`(v${file.currentVersion}, ${timeAgo})`));
105
+ }
106
+ console.log();
107
+ if (totalPages > 1) {
108
+ if (page < totalPages) {
109
+ console.log(chalk.dim(`Next page: contextium files "${projectName}" --page ${page + 1}`));
110
+ }
111
+ if (page > 1) {
112
+ console.log(chalk.dim(`Previous page: contextium files "${projectName}" --page ${page - 1}`));
113
+ }
114
+ }
115
+ }
116
+ catch (error) {
117
+ spinner.fail(`Failed to load files: ${error.message}`);
118
+ process.exit(1);
119
+ }
120
+ });
121
+ //# sourceMappingURL=files.js.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"files.js","sourceRoot":"","sources":["../../src/commands/files.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,GAAG,EAAE,MAAM,kBAAkB,CAAA;AAG7C,MAAM,CAAC,MAAM,YAAY,GAAG,IAAI,OAAO,CAAC,OAAO,CAAC;KAC7C,WAAW,CAAC,yCAAyC,CAAC;KACtD,QAAQ,CAAC,WAAW,EAAE,sBAAsB,CAAC;KAC7C,MAAM,CAAC,oBAAoB,EAAE,2DAA2D,CAAC;KACzF,MAAM,CAAC,iBAAiB,EAAE,aAAa,EAAE,GAAG,CAAC;KAC7C,MAAM,CAAC,kBAAkB,EAAE,gBAAgB,EAAE,IAAI,CAAC;KAClD,MAAM,CAAC,KAAK,EAAE,WAAmB,EAAE,OAAO,EAAE,EAAE;IAC7C,MAAM,OAAO,GAAG,GAAG,CAAC,kBAAkB,CAAC,CAAC,KAAK,EAAE,CAAA;IAE/C,IAAI,CAAC;QACH,MAAM,MAAM,GAAG,MAAM,UAAU,EAAE,CAAA;QACjC,MAAM,MAAM,GAAG,IAAI,SAAS,CAAC,MAAM,CAAC,OAAO,EAAE,MAAM,CAAC,OAAO,CAAC,CAAA;QAE5D,MAAM,IAAI,GAAG,QAAQ,CAAC,OAAO,CAAC,IAAI,CAAC,CAAA;QACnC,MAAM,KAAK,GAAG,QAAQ,CAAC,OAAO,CAAC,KAAK,CAAC,CAAA;QAErC,IAAI,IAAI,GAAG,CAAC,EAAE,CAAC;YACb,OAAO,CAAC,IAAI,CAAC,0BAA0B,CAAC,CAAA;YACxC,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACjB,CAAC;QAED,2BAA2B;QAC3B,MAAM,EAAE,IAAI,EAAE,cAAc,EAAE,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,aAAa,CAAC,CAAA;QAChE,MAAM,UAAU,GAAG,cAAc,CAAC,IAAI,IAAI,cAAc,CAAA;QAExD,IAAI,kBAAkB,GAAG,UAAU,CAAA;QAEnC,IAAI,OAAO,CAAC,SAAS,EAAE,CAAC;YACtB,MAAM,SAAS,GAAG,UAAU,CAAC,IAAI,CAAC,CAAC,CAAM,EAAE,EAAE,CAC3C,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,OAAO,CAAC,SAAS,CAAC,WAAW,EAAE;gBACxD,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,OAAO,CAAC,SAAS,CAAC,WAAW,EAAE,CACzD,CAAA;YAED,IAAI,CAAC,SAAS,EAAE,CAAC;gBACf,OAAO,CAAC,IAAI,CAAC,cAAc,OAAO,CAAC,SAAS,aAAa,CAAC,CAAA;gBAC1D,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;YACjB,CAAC;YAED,kBAAkB,GAAG,CAAC,SAAS,CAAC,CAAA;QAClC,CAAC;QAED,kDAAkD;QAClD,IAAI,YAAY,GAAQ,IAAI,CAAA;QAC5B,IAAI,cAAc,GAAQ,IAAI,CAAA;QAC9B,MAAM,gBAAgB,GAA4C,EAAE,CAAA;QAEpE,KAAK,MAAM,SAAS,IAAI,kBAAkB,EAAE,CAAC;YAC3C,MAAM,EAAE,IAAI,EAAE,YAAY,EAAE,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,eAAe,SAAS,CAAC,EAAE,WAAW,CAAC,CAAA;YACvF,MAAM,QAAQ,GAAG,YAAY,CAAC,IAAI,IAAI,YAAY,CAAA;YAElD,KAAK,MAAM,OAAO,IAAI,QAAQ,EAAE,CAAC;gBAC/B,IAAI,OAAO,CAAC,SAAS;oBAAE,SAAQ;gBAE/B,IACE,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,KAAK,WAAW,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE;oBACtE,OAAO,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,KAAK,WAAW,CAAC,WAAW,EAAE,CAAC,IAAI,EAAE,EACtE,CAAC;oBACD,gBAAgB,CAAC,IAAI,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,CAAC,CAAA;gBAC/C,CAAC;YACH,CAAC;QACH,CAAC;QAED,IAAI,gBAAgB,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAClC,OAAO,CAAC,IAAI,CAAC,YAAY,WAAW,aAAa,CAAC,CAAA;YAClD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACjB,CAAC;QAED,IAAI,gBAAgB,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;YAChC,OAAO,CAAC,IAAI,CAAC,sCAAsC,WAAW,GAAG,CAAC,CAAA;YAClE,OAAO,CAAC,GAAG,EAAE,CAAA;YACb,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,6BAA6B,CAAC,CAAC,CAAA;YACrD,gBAAgB,CAAC,OAAO,CAAC,CAAC,EAAE,OAAO,EAAE,SAAS,EAAE,EAAE,EAAE;gBAClD,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,OAAO,OAAO,CAAC,IAAI,OAAO,SAAS,CAAC,IAAI,iBAAiB,SAAS,CAAC,IAAI,GAAG,CAAC,CAAC,CAAA;YACpG,CAAC,CAAC,CAAA;YACF,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;QACjB,CAAC;QAED,MAAM,KAAK,GAAG,gBAAgB,CAAC,CAAC,CAAE,CAAA;QAClC,YAAY,GAAG,KAAK,CAAC,OAAO,CAAA;QAC5B,cAAc,GAAG,KAAK,CAAC,SAAS,CAAA;QAEhC,uBAAuB;QACvB,MAAM,EAAE,IAAI,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,GAAG,CAAC,aAAa,KAAK,CAAC,OAAO,CAAC,EAAE,QAAQ,CAAC,CAAA;QACnF,MAAM,QAAQ,GAAG,SAAS,CAAC,IAAI,IAAI,SAAS,CAAA;QAC5C,MAAM,WAAW,GAAG,QAAQ,CAAC,MAAM,CAAC,CAAC,CAAO,EAAE,EAAE,CAAC,CAAC,CAAC,CAAC,SAAS,CAAC,CAAA;QAE9D,IAAI,WAAW,CAAC,MAAM,KAAK,CAAC,EAAE,CAAC;YAC7B,OAAO,CAAC,IAAI,EAAE,CAAA;YACd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,MAAM,CAAC,gCAAgC,YAAY,CAAC,IAAI,GAAG,CAAC,CAAC,CAAA;YAC/E,OAAM;QACR,CAAC;QAED,sCAAsC;QACtC,WAAW,CAAC,IAAI,CAAC,CAAC,CAAO,EAAE,CAAO,EAAE,EAAE,CACpC,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,GAAG,IAAI,IAAI,CAAC,CAAC,CAAC,SAAS,CAAC,CAAC,OAAO,EAAE,CAClE,CAAA;QAED,WAAW;QACX,MAAM,UAAU,GAAG,WAAW,CAAC,MAAM,CAAA;QACrC,MAAM,UAAU,GAAG,IAAI,CAAC,IAAI,CAAC,UAAU,GAAG,KAAK,CAAC,CAAA;QAChD,MAAM,UAAU,GAAG,CAAC,IAAI,GAAG,CAAC,CAAC,GAAG,KAAK,CAAA;QACrC,MAAM,QAAQ,GAAG,IAAI,CAAC,GAAG,CAAC,UAAU,GAAG,KAAK,EAAE,UAAU,CAAC,CAAA;QACzD,MAAM,SAAS,GAAG,WAAW,CAAC,KAAK,CAAC,UAAU,EAAE,QAAQ,CAAC,CAAA;QAEzD,OAAO,CAAC,IAAI,EAAE,CAAA;QAEd,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,IAAI,CAAC,eAAe,YAAY,CAAC,IAAI,MAAM,cAAc,CAAC,IAAI,IAAI,CAAC,CAAC,CAAA;QACtF,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,QAAQ,IAAI,OAAO,UAAU,KAAK,UAAU,iBAAiB,CAAC,CAAC,CAAA;QAErF,KAAK,IAAI,CAAC,GAAG,CAAC,EAAE,CAAC,GAAG,SAAS,CAAC,MAAM,EAAE,CAAC,EAAE,EAAE,CAAC;YAC1C,MAAM,IAAI,GAAG,SAAS,CAAC,CAAC,CAAC,CAAA;YACzB,MAAM,UAAU,GAAG,UAAU,GAAG,CAAC,GAAG,CAAC,CAAA;YACrC,MAAM,WAAW,GAAG,IAAI,IAAI,CAAC,IAAI,CAAC,SAAS,CAAC,CAAA;YAC5C,MAAM,GAAG,GAAG,IAAI,IAAI,EAAE,CAAA;YACtB,MAAM,MAAM,GAAG,GAAG,CAAC,OAAO,EAAE,GAAG,WAAW,CAAC,OAAO,EAAE,CAAA;YACpD,MAAM,SAAS,GAAG,IAAI,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,IAAI,GAAG,EAAE,GAAG,EAAE,CAAC,CAAC,CAAA;YACvD,MAAM,QAAQ,GAAG,IAAI,CAAC,KAAK,CAAC,SAAS,GAAG,EAAE,CAAC,CAAA;YAE3C,IAAI,OAAe,CAAA;YACnB,IAAI,SAAS,GAAG,CAAC;gBAAE,OAAO,GAAG,UAAU,CAAA;iBAClC,IAAI,SAAS,GAAG,EAAE;gBAAE,OAAO,GAAG,GAAG,SAAS,OAAO,CAAA;iBACjD,IAAI,QAAQ,GAAG,CAAC;gBAAE,OAAO,GAAG,GAAG,QAAQ,OAAO,CAAA;;gBAC9C,OAAO,GAAG,WAAW,CAAC,kBAAkB,EAAE,CAAA;YAE/C,OAAO,CAAC,GAAG,CACT,KAAK,CAAC,IAAI,CAAC,GAAG,UAAU,GAAG,CAAC,EAC5B,KAAK,CAAC,KAAK,CAAC,IAAI,CAAC,KAAK,CAAC,EACvB,KAAK,CAAC,GAAG,CAAC,KAAK,IAAI,CAAC,cAAc,KAAK,OAAO,GAAG,CAAC,CACnD,CAAA;QACH,CAAC;QAED,OAAO,CAAC,GAAG,EAAE,CAAA;QAEb,IAAI,UAAU,GAAG,CAAC,EAAE,CAAC;YACnB,IAAI,IAAI,GAAG,UAAU,EAAE,CAAC;gBACtB,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,gCAAgC,WAAW,YAAY,IAAI,GAAG,CAAC,EAAE,CAAC,CAAC,CAAA;YAC3F,CAAC;YACD,IAAI,IAAI,GAAG,CAAC,EAAE,CAAC;gBACb,OAAO,CAAC,GAAG,CAAC,KAAK,CAAC,GAAG,CAAC,oCAAoC,WAAW,YAAY,IAAI,GAAG,CAAC,EAAE,CAAC,CAAC,CAAA;YAC/F,CAAC;QACH,CAAC;IACH,CAAC;IAAC,OAAO,KAAU,EAAE,CAAC;QACpB,OAAO,CAAC,IAAI,CAAC,yBAAyB,KAAK,CAAC,OAAO,EAAE,CAAC,CAAA;QACtD,OAAO,CAAC,IAAI,CAAC,CAAC,CAAC,CAAA;IACjB,CAAC;AACH,CAAC,CAAC,CAAA"}
@@ -0,0 +1,3 @@
1
+ import { Command } from 'commander';
2
+ export declare const findCommand: Command;
3
+ //# sourceMappingURL=find.d.ts.map
@@ -0,0 +1 @@
1
+ {"version":3,"file":"find.d.ts","sourceRoot":"","sources":["../../src/commands/find.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,WAAW,CAAA;AAMnC,eAAO,MAAM,WAAW,SA0IpB,CAAA"}
@@ -0,0 +1,119 @@
1
+ import { Command } from 'commander';
2
+ import { ApiClient } from '../lib/api-client.js';
3
+ import { loadConfig } from '../lib/config.js';
4
+ import { chalk, ora } from '../lib/output.js';
5
+ export const findCommand = new Command('find')
6
+ .description('Find files by name (partial match, no extension needed)')
7
+ .argument('<filename>', 'File name or partial name to search for')
8
+ .option('--workspace <slug>', 'Limit search to specific workspace')
9
+ .action(async (filename, options) => {
10
+ const spinner = ora('Searching for files...').start();
11
+ try {
12
+ const config = await loadConfig();
13
+ const client = new ApiClient(config.api_key, config.api_url);
14
+ // Normalize search query (lowercase, trim)
15
+ const searchQuery = filename.toLowerCase().trim();
16
+ // Get workspaces to search
17
+ const { data: workspacesData } = await client.get('/workspaces');
18
+ const workspaces = workspacesData.data || workspacesData;
19
+ let workspacesToSearch = workspaces;
20
+ if (options.workspace) {
21
+ const workspace = workspaces.find((w) => w.slug.toLowerCase() === options.workspace.toLowerCase() ||
22
+ w.name.toLowerCase() === options.workspace.toLowerCase());
23
+ if (!workspace) {
24
+ spinner.fail(`Workspace '${options.workspace}' not found`);
25
+ process.exit(1);
26
+ }
27
+ workspacesToSearch = [workspace];
28
+ }
29
+ // Search for files across all workspaces/projects
30
+ const matchingFiles = [];
31
+ for (const workspace of workspacesToSearch) {
32
+ const { data: projectsData } = await client.get(`/workspaces/${workspace.id}/projects`);
33
+ const projects = projectsData.data || projectsData;
34
+ for (const project of projects) {
35
+ if (project.deletedAt)
36
+ continue;
37
+ const { data: filesData } = await client.get(`/projects/${project.id}/files`);
38
+ const files = filesData.data || filesData;
39
+ for (const file of files) {
40
+ if (file.deletedAt)
41
+ continue;
42
+ // Smart matching: case-insensitive, partial match on title or path
43
+ const fileTitle = file.title.toLowerCase();
44
+ const filePath = file.path.toLowerCase();
45
+ // Remove extension from file title for matching
46
+ const titleWithoutExt = fileTitle.replace(/\.[^/.]+$/, '');
47
+ if (fileTitle.includes(searchQuery) ||
48
+ titleWithoutExt.includes(searchQuery) ||
49
+ filePath.includes(searchQuery)) {
50
+ matchingFiles.push({ file, project, workspace });
51
+ }
52
+ }
53
+ }
54
+ }
55
+ spinner.stop();
56
+ if (matchingFiles.length === 0) {
57
+ console.log(chalk.yellow(`\nNo files found matching '${filename}'`));
58
+ return;
59
+ }
60
+ // Sort by relevance (exact match first, then by updated date)
61
+ matchingFiles.sort((a, b) => {
62
+ const aTitle = a.file.title.toLowerCase();
63
+ const bTitle = b.file.title.toLowerCase();
64
+ const aTitleNoExt = aTitle.replace(/\.[^/.]+$/, '');
65
+ const bTitleNoExt = bTitle.replace(/\.[^/.]+$/, '');
66
+ // Exact matches first
67
+ if (aTitleNoExt === searchQuery && bTitleNoExt !== searchQuery)
68
+ return -1;
69
+ if (bTitleNoExt === searchQuery && aTitleNoExt !== searchQuery)
70
+ return 1;
71
+ // Then by starts with
72
+ if (aTitleNoExt.startsWith(searchQuery) && !bTitleNoExt.startsWith(searchQuery))
73
+ return -1;
74
+ if (bTitleNoExt.startsWith(searchQuery) && !aTitleNoExt.startsWith(searchQuery))
75
+ return 1;
76
+ // Then by updated date (newest first)
77
+ return new Date(b.file.updatedAt).getTime() - new Date(a.file.updatedAt).getTime();
78
+ });
79
+ const matchText = matchingFiles.length === 1 ? 'match' : 'matches';
80
+ console.log(chalk.bold(`\nFound ${matchingFiles.length} ${matchText}:\n`));
81
+ for (let i = 0; i < matchingFiles.length; i++) {
82
+ const match = matchingFiles[i];
83
+ const { file, project, workspace } = match;
84
+ // Format time ago
85
+ const updatedDate = new Date(file.updatedAt);
86
+ const now = new Date();
87
+ const diffMs = now.getTime() - updatedDate.getTime();
88
+ const diffHours = Math.floor(diffMs / (1000 * 60 * 60));
89
+ const diffDays = Math.floor(diffHours / 24);
90
+ let timeAgo;
91
+ if (diffHours < 1)
92
+ timeAgo = 'just now';
93
+ else if (diffHours < 24)
94
+ timeAgo = `${diffHours} hour${diffHours === 1 ? '' : 's'} ago`;
95
+ else if (diffDays < 7)
96
+ timeAgo = `${diffDays} day${diffDays === 1 ? '' : 's'} ago`;
97
+ else
98
+ timeAgo = updatedDate.toLocaleDateString();
99
+ if (i > 0)
100
+ console.log();
101
+ console.log(chalk.white(`${i + 1}. ${file.title}`));
102
+ console.log(chalk.dim(` Project: ${project.name}`));
103
+ console.log(chalk.dim(` Workspace: ${workspace.name}`));
104
+ console.log(chalk.dim(` Version: v${file.currentVersion}`));
105
+ console.log(chalk.dim(` Updated: ${timeAgo}`));
106
+ }
107
+ console.log();
108
+ if (matchingFiles.length === 1) {
109
+ const { file } = matchingFiles[0];
110
+ console.log(chalk.dim(`To view this file, run:`));
111
+ console.log(chalk.white(` contextium cat "${file.title}"`));
112
+ }
113
+ }
114
+ catch (error) {
115
+ spinner.fail(`Search failed: ${error.message}`);
116
+ process.exit(1);
117
+ }
118
+ });
119
+ //# sourceMappingURL=find.js.map