exponential-cli 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/README.md +226 -0
- package/bin/exponential.js +2 -0
- package/dist/index.d.ts +1 -0
- package/dist/index.js +538 -0
- package/dist/index.js.map +1 -0
- package/package.json +43 -0
package/README.md
ADDED
|
@@ -0,0 +1,226 @@
|
|
|
1
|
+
# Exponential CLI
|
|
2
|
+
|
|
3
|
+
CLI tool to interact with the Exponential productivity app. Pull actions, projects, and workspaces from your Exponential account for use with LLMs and automation.
|
|
4
|
+
|
|
5
|
+
## Installation
|
|
6
|
+
|
|
7
|
+
```bash
|
|
8
|
+
npm install -g exponential-cli
|
|
9
|
+
```
|
|
10
|
+
|
|
11
|
+
Or run directly with npx:
|
|
12
|
+
|
|
13
|
+
```bash
|
|
14
|
+
npx exponential-cli --help
|
|
15
|
+
```
|
|
16
|
+
|
|
17
|
+
## Quick Start
|
|
18
|
+
|
|
19
|
+
### 1. Generate an API Token
|
|
20
|
+
|
|
21
|
+
1. Log into Exponential
|
|
22
|
+
2. Navigate to `/tokens`
|
|
23
|
+
3. Create a new API key with type "JWT"
|
|
24
|
+
4. Copy the generated token
|
|
25
|
+
|
|
26
|
+
### 2. Configure the CLI
|
|
27
|
+
|
|
28
|
+
```bash
|
|
29
|
+
exponential auth login --token <your-jwt-token> --api-url https://app.exponential.so
|
|
30
|
+
```
|
|
31
|
+
|
|
32
|
+
### 3. Verify Authentication
|
|
33
|
+
|
|
34
|
+
```bash
|
|
35
|
+
exponential auth whoami
|
|
36
|
+
```
|
|
37
|
+
|
|
38
|
+
## Commands
|
|
39
|
+
|
|
40
|
+
### Authentication
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
# Login with token
|
|
44
|
+
exponential auth login --token <jwt> --api-url <url>
|
|
45
|
+
|
|
46
|
+
# Check authentication status
|
|
47
|
+
exponential auth whoami
|
|
48
|
+
exponential auth status
|
|
49
|
+
|
|
50
|
+
# Logout
|
|
51
|
+
exponential auth logout
|
|
52
|
+
```
|
|
53
|
+
|
|
54
|
+
### Actions
|
|
55
|
+
|
|
56
|
+
```bash
|
|
57
|
+
# List all active actions
|
|
58
|
+
exponential actions list
|
|
59
|
+
|
|
60
|
+
# List actions for a specific project
|
|
61
|
+
exponential actions list --project <project-id>
|
|
62
|
+
|
|
63
|
+
# List actions with a specific kanban status
|
|
64
|
+
exponential actions list --status IN_PROGRESS
|
|
65
|
+
|
|
66
|
+
# Get today's actions
|
|
67
|
+
exponential actions today
|
|
68
|
+
|
|
69
|
+
# Get actions in a date range
|
|
70
|
+
exponential actions range --start 2024-01-01 --end 2024-01-31
|
|
71
|
+
|
|
72
|
+
# Get kanban board view
|
|
73
|
+
exponential actions kanban --project <project-id>
|
|
74
|
+
```
|
|
75
|
+
|
|
76
|
+
### Projects
|
|
77
|
+
|
|
78
|
+
```bash
|
|
79
|
+
# List all projects
|
|
80
|
+
exponential projects list
|
|
81
|
+
|
|
82
|
+
# List projects in a workspace
|
|
83
|
+
exponential projects list --workspace <workspace-id>
|
|
84
|
+
```
|
|
85
|
+
|
|
86
|
+
### Workspaces
|
|
87
|
+
|
|
88
|
+
```bash
|
|
89
|
+
# List all workspaces
|
|
90
|
+
exponential workspaces list
|
|
91
|
+
|
|
92
|
+
# Set default workspace
|
|
93
|
+
exponential workspaces set-default <workspace-slug>
|
|
94
|
+
```
|
|
95
|
+
|
|
96
|
+
## Output Formats
|
|
97
|
+
|
|
98
|
+
### JSON Output (for LLMs and automation)
|
|
99
|
+
|
|
100
|
+
By default, output is JSON when piped. Force JSON output:
|
|
101
|
+
|
|
102
|
+
```bash
|
|
103
|
+
exponential actions list --json
|
|
104
|
+
```
|
|
105
|
+
|
|
106
|
+
Example output:
|
|
107
|
+
|
|
108
|
+
```json
|
|
109
|
+
{
|
|
110
|
+
"actions": [
|
|
111
|
+
{
|
|
112
|
+
"id": "clx123abc",
|
|
113
|
+
"name": "Fix authentication bug",
|
|
114
|
+
"description": "JWT tokens expiring too early",
|
|
115
|
+
"status": "ACTIVE",
|
|
116
|
+
"priority": "1st Priority",
|
|
117
|
+
"kanbanStatus": "IN_PROGRESS",
|
|
118
|
+
"dueDate": "2024-01-15T00:00:00.000Z",
|
|
119
|
+
"project": {
|
|
120
|
+
"id": "clx456def",
|
|
121
|
+
"name": "Exponential App"
|
|
122
|
+
},
|
|
123
|
+
"assignees": []
|
|
124
|
+
}
|
|
125
|
+
],
|
|
126
|
+
"total": 1,
|
|
127
|
+
"filters": {}
|
|
128
|
+
}
|
|
129
|
+
```
|
|
130
|
+
|
|
131
|
+
### Pretty Output (for humans)
|
|
132
|
+
|
|
133
|
+
Force human-readable output:
|
|
134
|
+
|
|
135
|
+
```bash
|
|
136
|
+
exponential actions list --pretty
|
|
137
|
+
```
|
|
138
|
+
|
|
139
|
+
## LLM Integration
|
|
140
|
+
|
|
141
|
+
### Python Example
|
|
142
|
+
|
|
143
|
+
```python
|
|
144
|
+
import subprocess
|
|
145
|
+
import json
|
|
146
|
+
|
|
147
|
+
def get_exponential_actions(project_id=None):
|
|
148
|
+
cmd = ['exponential', 'actions', 'list', '--json']
|
|
149
|
+
if project_id:
|
|
150
|
+
cmd.extend(['--project', project_id])
|
|
151
|
+
|
|
152
|
+
result = subprocess.run(cmd, capture_output=True, text=True)
|
|
153
|
+
return json.loads(result.stdout)
|
|
154
|
+
|
|
155
|
+
# Get all actions
|
|
156
|
+
actions = get_exponential_actions()
|
|
157
|
+
|
|
158
|
+
# Get actions for a specific project
|
|
159
|
+
project_actions = get_exponential_actions('clx456def')
|
|
160
|
+
```
|
|
161
|
+
|
|
162
|
+
### Shell Example
|
|
163
|
+
|
|
164
|
+
```bash
|
|
165
|
+
# Get actions and pipe to jq
|
|
166
|
+
exponential actions list --json | jq '.actions[] | {name, priority, status: .kanbanStatus}'
|
|
167
|
+
|
|
168
|
+
# Count actions by status
|
|
169
|
+
exponential actions kanban --json | jq '.actions | group_by(.kanbanStatus) | map({status: .[0].kanbanStatus, count: length})'
|
|
170
|
+
```
|
|
171
|
+
|
|
172
|
+
### Claude/LLM Prompt Example
|
|
173
|
+
|
|
174
|
+
```
|
|
175
|
+
I have access to the Exponential CLI. Here are my current actions:
|
|
176
|
+
|
|
177
|
+
$(exponential actions list --json)
|
|
178
|
+
|
|
179
|
+
Based on these actions, what should I work on next considering priority and due dates?
|
|
180
|
+
```
|
|
181
|
+
|
|
182
|
+
## Configuration
|
|
183
|
+
|
|
184
|
+
Configuration is stored in:
|
|
185
|
+
- macOS: `~/Library/Preferences/exponential-cli-nodejs/config.json`
|
|
186
|
+
- Linux: `~/.config/exponential-cli-nodejs/config.json`
|
|
187
|
+
- Windows: `%APPDATA%\exponential-cli-nodejs\config.json`
|
|
188
|
+
|
|
189
|
+
## Kanban Status Values
|
|
190
|
+
|
|
191
|
+
- `BACKLOG` - In backlog
|
|
192
|
+
- `TODO` - Ready to work on
|
|
193
|
+
- `IN_PROGRESS` - Currently being worked on
|
|
194
|
+
- `IN_REVIEW` - In review
|
|
195
|
+
- `DONE` - Completed
|
|
196
|
+
- `CANCELLED` - Cancelled
|
|
197
|
+
|
|
198
|
+
## Priority Values
|
|
199
|
+
|
|
200
|
+
- `1st Priority` through `5th Priority`
|
|
201
|
+
- `Quick` - Quick tasks
|
|
202
|
+
- `Scheduled` - Scheduled tasks
|
|
203
|
+
- `Errand` - Errands
|
|
204
|
+
- `Remember` - Things to remember
|
|
205
|
+
- `Watch` - Items to watch
|
|
206
|
+
- `Someday Maybe` - Future possibilities
|
|
207
|
+
|
|
208
|
+
## Development
|
|
209
|
+
|
|
210
|
+
```bash
|
|
211
|
+
# Install dependencies
|
|
212
|
+
npm install
|
|
213
|
+
|
|
214
|
+
# Build
|
|
215
|
+
npm run build
|
|
216
|
+
|
|
217
|
+
# Run locally
|
|
218
|
+
node bin/exponential.js --help
|
|
219
|
+
|
|
220
|
+
# Link for local testing
|
|
221
|
+
npm link
|
|
222
|
+
```
|
|
223
|
+
|
|
224
|
+
## License
|
|
225
|
+
|
|
226
|
+
MIT
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,538 @@
|
|
|
1
|
+
#!/usr/bin/env node
|
|
2
|
+
|
|
3
|
+
// src/index.ts
|
|
4
|
+
import { Command as Command5 } from "commander";
|
|
5
|
+
|
|
6
|
+
// src/commands/auth.ts
|
|
7
|
+
import { Command } from "commander";
|
|
8
|
+
import chalk2 from "chalk";
|
|
9
|
+
|
|
10
|
+
// src/config/index.ts
|
|
11
|
+
import { createConfigStore } from "exponential-sdk";
|
|
12
|
+
var configStore = createConfigStore({ projectName: "exponential-cli" });
|
|
13
|
+
function getConfig() {
|
|
14
|
+
return configStore.loadConfig();
|
|
15
|
+
}
|
|
16
|
+
function setConfig(values) {
|
|
17
|
+
configStore.saveConfig(values);
|
|
18
|
+
}
|
|
19
|
+
function clearConfig() {
|
|
20
|
+
configStore.clearConfig();
|
|
21
|
+
}
|
|
22
|
+
function isAuthenticated() {
|
|
23
|
+
return configStore.isAuthenticated();
|
|
24
|
+
}
|
|
25
|
+
function getConfigPath() {
|
|
26
|
+
return configStore.getConfigPath();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
// src/client/index.ts
|
|
30
|
+
import { ExponentialClient } from "exponential-sdk";
|
|
31
|
+
import { isTRPCError, TRPCClientError } from "exponential-sdk";
|
|
32
|
+
var clientInstance = null;
|
|
33
|
+
function getClient() {
|
|
34
|
+
if (!isAuthenticated()) {
|
|
35
|
+
throw new Error("Not authenticated. Run: exponential auth login --token <your-jwt> --api-url <url>");
|
|
36
|
+
}
|
|
37
|
+
if (clientInstance) {
|
|
38
|
+
return clientInstance;
|
|
39
|
+
}
|
|
40
|
+
const config = getConfig();
|
|
41
|
+
clientInstance = new ExponentialClient({
|
|
42
|
+
token: config.token,
|
|
43
|
+
apiUrl: config.apiUrl
|
|
44
|
+
});
|
|
45
|
+
return clientInstance;
|
|
46
|
+
}
|
|
47
|
+
function resetClient() {
|
|
48
|
+
clientInstance = null;
|
|
49
|
+
}
|
|
50
|
+
|
|
51
|
+
// src/utils/errors.ts
|
|
52
|
+
import chalk from "chalk";
|
|
53
|
+
var ExponentialError = class extends Error {
|
|
54
|
+
constructor(message, code, suggestion, details) {
|
|
55
|
+
super(message);
|
|
56
|
+
this.code = code;
|
|
57
|
+
this.suggestion = suggestion;
|
|
58
|
+
this.details = details;
|
|
59
|
+
this.name = "ExponentialError";
|
|
60
|
+
}
|
|
61
|
+
};
|
|
62
|
+
function handleError(error, json = false) {
|
|
63
|
+
if (error instanceof ExponentialError) {
|
|
64
|
+
if (json) {
|
|
65
|
+
console.log(JSON.stringify({
|
|
66
|
+
error: {
|
|
67
|
+
code: error.code,
|
|
68
|
+
message: error.message,
|
|
69
|
+
suggestion: error.suggestion
|
|
70
|
+
}
|
|
71
|
+
}, null, 2));
|
|
72
|
+
} else {
|
|
73
|
+
console.error(chalk.red(`Error: ${error.message}`));
|
|
74
|
+
if (error.suggestion) {
|
|
75
|
+
console.error(chalk.yellow(`Suggestion: ${error.suggestion}`));
|
|
76
|
+
}
|
|
77
|
+
}
|
|
78
|
+
process.exit(1);
|
|
79
|
+
}
|
|
80
|
+
if (isTRPCError(error)) {
|
|
81
|
+
const code = error.data?.code ?? "UNKNOWN";
|
|
82
|
+
let message = error.message;
|
|
83
|
+
let suggestion;
|
|
84
|
+
switch (code) {
|
|
85
|
+
case "UNAUTHORIZED":
|
|
86
|
+
message = "Authentication failed. Your token may have expired.";
|
|
87
|
+
suggestion = "Run: exponential auth login --token <new-token> --api-url <url>";
|
|
88
|
+
break;
|
|
89
|
+
case "NOT_FOUND":
|
|
90
|
+
message = "Resource not found";
|
|
91
|
+
break;
|
|
92
|
+
case "FORBIDDEN":
|
|
93
|
+
message = "Access denied";
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
if (json) {
|
|
97
|
+
console.log(JSON.stringify({
|
|
98
|
+
error: {
|
|
99
|
+
code,
|
|
100
|
+
message,
|
|
101
|
+
suggestion
|
|
102
|
+
}
|
|
103
|
+
}, null, 2));
|
|
104
|
+
} else {
|
|
105
|
+
console.error(chalk.red(`Error [${code}]: ${message}`));
|
|
106
|
+
if (suggestion) {
|
|
107
|
+
console.error(chalk.yellow(`Suggestion: ${suggestion}`));
|
|
108
|
+
}
|
|
109
|
+
}
|
|
110
|
+
process.exit(1);
|
|
111
|
+
}
|
|
112
|
+
if (json) {
|
|
113
|
+
console.log(JSON.stringify({
|
|
114
|
+
error: {
|
|
115
|
+
code: "UNKNOWN",
|
|
116
|
+
message: error instanceof Error ? error.message : String(error)
|
|
117
|
+
}
|
|
118
|
+
}, null, 2));
|
|
119
|
+
} else {
|
|
120
|
+
console.error(chalk.red(`Error: ${error instanceof Error ? error.message : String(error)}`));
|
|
121
|
+
}
|
|
122
|
+
process.exit(1);
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
// src/commands/auth.ts
|
|
126
|
+
function createAuthCommand() {
|
|
127
|
+
const auth = new Command("auth").description("Authentication commands");
|
|
128
|
+
auth.command("login").description("Configure CLI with your API token").requiredOption("--token <token>", "JWT token from /tokens page").requiredOption("--api-url <url>", "API URL (e.g., https://app.exponential.so)").action(async (options) => {
|
|
129
|
+
try {
|
|
130
|
+
let apiUrl = options.apiUrl.replace(/\/+$/, "");
|
|
131
|
+
if (!apiUrl.startsWith("http://localhost") && !apiUrl.startsWith("https://")) {
|
|
132
|
+
apiUrl = `https://${apiUrl}`;
|
|
133
|
+
}
|
|
134
|
+
setConfig({
|
|
135
|
+
token: options.token,
|
|
136
|
+
apiUrl
|
|
137
|
+
});
|
|
138
|
+
resetClient();
|
|
139
|
+
console.log(chalk2.gray("Validating token..."));
|
|
140
|
+
const client = getClient();
|
|
141
|
+
await client.workspaces.list();
|
|
142
|
+
console.log(chalk2.green("Successfully authenticated!"));
|
|
143
|
+
console.log(chalk2.gray(`Config saved to: ${getConfigPath()}`));
|
|
144
|
+
} catch (error) {
|
|
145
|
+
clearConfig();
|
|
146
|
+
handleError(error);
|
|
147
|
+
}
|
|
148
|
+
});
|
|
149
|
+
auth.command("logout").description("Remove stored credentials").action(() => {
|
|
150
|
+
clearConfig();
|
|
151
|
+
resetClient();
|
|
152
|
+
console.log(chalk2.green("Successfully logged out."));
|
|
153
|
+
console.log(chalk2.gray(`Config cleared from: ${getConfigPath()}`));
|
|
154
|
+
});
|
|
155
|
+
auth.command("whoami").description("Show current authentication status").action(async () => {
|
|
156
|
+
if (!isAuthenticated()) {
|
|
157
|
+
console.log(chalk2.yellow("Not authenticated."));
|
|
158
|
+
console.log(chalk2.gray("Run: exponential auth login --token <jwt> --api-url <url>"));
|
|
159
|
+
process.exit(1);
|
|
160
|
+
}
|
|
161
|
+
try {
|
|
162
|
+
const config = getConfig();
|
|
163
|
+
const client = getClient();
|
|
164
|
+
const workspaces = await client.workspaces.list();
|
|
165
|
+
console.log(chalk2.green("Authenticated"));
|
|
166
|
+
console.log(chalk2.gray(`API URL: ${config.apiUrl}`));
|
|
167
|
+
console.log(chalk2.gray(`Workspaces: ${workspaces.length}`));
|
|
168
|
+
console.log(chalk2.gray(`Config: ${getConfigPath()}`));
|
|
169
|
+
} catch (error) {
|
|
170
|
+
handleError(error);
|
|
171
|
+
}
|
|
172
|
+
});
|
|
173
|
+
auth.command("status").description("Show detailed authentication status").action(() => {
|
|
174
|
+
const config = getConfig();
|
|
175
|
+
console.log(chalk2.bold("\nAuthentication Status"));
|
|
176
|
+
console.log(chalk2.gray("\u2500".repeat(40)));
|
|
177
|
+
console.log(`Authenticated: ${isAuthenticated() ? chalk2.green("Yes") : chalk2.red("No")}`);
|
|
178
|
+
console.log(`API URL: ${config.apiUrl || chalk2.gray("(not set)")}`);
|
|
179
|
+
console.log(`Token: ${config.token ? chalk2.gray(`${config.token.substring(0, 20)}...`) : chalk2.gray("(not set)")}`);
|
|
180
|
+
console.log(`Config Path: ${getConfigPath()}`);
|
|
181
|
+
console.log();
|
|
182
|
+
});
|
|
183
|
+
return auth;
|
|
184
|
+
}
|
|
185
|
+
|
|
186
|
+
// src/commands/actions.ts
|
|
187
|
+
import { Command as Command2 } from "commander";
|
|
188
|
+
|
|
189
|
+
// src/utils/output.ts
|
|
190
|
+
import chalk3 from "chalk";
|
|
191
|
+
function shouldUseJson(forceJson, forcePretty) {
|
|
192
|
+
if (forceJson) return true;
|
|
193
|
+
if (forcePretty) return false;
|
|
194
|
+
return !process.stdout.isTTY;
|
|
195
|
+
}
|
|
196
|
+
function transformAction(action) {
|
|
197
|
+
return {
|
|
198
|
+
id: action.id,
|
|
199
|
+
name: action.name,
|
|
200
|
+
description: action.description,
|
|
201
|
+
status: action.status,
|
|
202
|
+
priority: action.priority,
|
|
203
|
+
kanbanStatus: action.kanbanStatus,
|
|
204
|
+
dueDate: action.dueDate?.toISOString() ?? null,
|
|
205
|
+
scheduledStart: action.scheduledStart?.toISOString() ?? null,
|
|
206
|
+
scheduledEnd: action.scheduledEnd?.toISOString() ?? null,
|
|
207
|
+
project: action.project ? {
|
|
208
|
+
id: action.project.id,
|
|
209
|
+
name: action.project.name
|
|
210
|
+
} : null,
|
|
211
|
+
workspace: action.workspace ? {
|
|
212
|
+
id: action.workspace.id,
|
|
213
|
+
slug: action.workspace.slug,
|
|
214
|
+
name: action.workspace.name
|
|
215
|
+
} : null,
|
|
216
|
+
assignees: action.assignees?.map((a) => ({
|
|
217
|
+
id: a.user.id,
|
|
218
|
+
name: a.user.name,
|
|
219
|
+
email: a.user.email
|
|
220
|
+
})) ?? [],
|
|
221
|
+
createdAt: action.createdAt?.toISOString() ?? (/* @__PURE__ */ new Date()).toISOString(),
|
|
222
|
+
completedAt: action.completedAt?.toISOString() ?? null
|
|
223
|
+
};
|
|
224
|
+
}
|
|
225
|
+
function transformProject(project) {
|
|
226
|
+
return {
|
|
227
|
+
id: project.id,
|
|
228
|
+
name: project.name,
|
|
229
|
+
description: project.description,
|
|
230
|
+
status: project.status,
|
|
231
|
+
priority: project.priority,
|
|
232
|
+
workspace: project.workspace ? {
|
|
233
|
+
id: project.workspace.id,
|
|
234
|
+
slug: project.workspace.slug,
|
|
235
|
+
name: project.workspace.name
|
|
236
|
+
} : null
|
|
237
|
+
};
|
|
238
|
+
}
|
|
239
|
+
function transformWorkspace(workspace) {
|
|
240
|
+
return {
|
|
241
|
+
id: workspace.id,
|
|
242
|
+
name: workspace.name,
|
|
243
|
+
slug: workspace.slug,
|
|
244
|
+
type: workspace.type
|
|
245
|
+
};
|
|
246
|
+
}
|
|
247
|
+
function outputActionsJson(actions, filters = {}) {
|
|
248
|
+
const output = {
|
|
249
|
+
actions: actions.map(transformAction),
|
|
250
|
+
total: actions.length,
|
|
251
|
+
filters
|
|
252
|
+
};
|
|
253
|
+
console.log(JSON.stringify(output, null, 2));
|
|
254
|
+
}
|
|
255
|
+
function outputActionsPretty(actions) {
|
|
256
|
+
if (actions.length === 0) {
|
|
257
|
+
console.log(chalk3.gray("No actions found."));
|
|
258
|
+
return;
|
|
259
|
+
}
|
|
260
|
+
console.log(chalk3.bold(`
|
|
261
|
+
Actions (${actions.length} total)`));
|
|
262
|
+
console.log(chalk3.gray("\u2500".repeat(50)));
|
|
263
|
+
for (const action of actions) {
|
|
264
|
+
const statusColor = getKanbanStatusColor(action.kanbanStatus);
|
|
265
|
+
const statusBadge = action.kanbanStatus ? chalk3[statusColor](`[${action.kanbanStatus}]`) : chalk3.gray("[NO STATUS]");
|
|
266
|
+
console.log(`
|
|
267
|
+
${statusBadge} ${chalk3.bold(action.name)}`);
|
|
268
|
+
console.log(chalk3.gray(` ID: ${action.id}`));
|
|
269
|
+
if (action.project) {
|
|
270
|
+
console.log(` ${chalk3.cyan("Project:")} ${action.project.name}`);
|
|
271
|
+
}
|
|
272
|
+
console.log(` ${chalk3.magenta("Priority:")} ${action.priority}`);
|
|
273
|
+
if (action.dueDate) {
|
|
274
|
+
const dueDate = new Date(action.dueDate);
|
|
275
|
+
const isOverdue = dueDate < /* @__PURE__ */ new Date();
|
|
276
|
+
const dateStr = formatDate(dueDate);
|
|
277
|
+
console.log(` ${chalk3.yellow("Due:")} ${isOverdue ? chalk3.red(dateStr) : dateStr}`);
|
|
278
|
+
}
|
|
279
|
+
if (action.description) {
|
|
280
|
+
console.log(` ${chalk3.gray("Description:")} ${action.description.substring(0, 100)}${action.description.length > 100 ? "..." : ""}`);
|
|
281
|
+
}
|
|
282
|
+
}
|
|
283
|
+
console.log();
|
|
284
|
+
}
|
|
285
|
+
function outputProjectsJson(projects) {
|
|
286
|
+
const output = {
|
|
287
|
+
projects: projects.map(transformProject),
|
|
288
|
+
total: projects.length
|
|
289
|
+
};
|
|
290
|
+
console.log(JSON.stringify(output, null, 2));
|
|
291
|
+
}
|
|
292
|
+
function outputProjectsPretty(projects) {
|
|
293
|
+
if (projects.length === 0) {
|
|
294
|
+
console.log(chalk3.gray("No projects found."));
|
|
295
|
+
return;
|
|
296
|
+
}
|
|
297
|
+
console.log(chalk3.bold(`
|
|
298
|
+
Projects (${projects.length} total)`));
|
|
299
|
+
console.log(chalk3.gray("\u2500".repeat(50)));
|
|
300
|
+
for (const project of projects) {
|
|
301
|
+
console.log(`
|
|
302
|
+
${chalk3.bold(project.name)}`);
|
|
303
|
+
console.log(chalk3.gray(` ID: ${project.id}`));
|
|
304
|
+
if (project.status) {
|
|
305
|
+
console.log(` ${chalk3.cyan("Status:")} ${project.status}`);
|
|
306
|
+
}
|
|
307
|
+
if (project.priority) {
|
|
308
|
+
console.log(` ${chalk3.magenta("Priority:")} ${project.priority}`);
|
|
309
|
+
}
|
|
310
|
+
if (project.workspace) {
|
|
311
|
+
console.log(` ${chalk3.yellow("Workspace:")} ${project.workspace.name} (${project.workspace.slug})`);
|
|
312
|
+
}
|
|
313
|
+
if (project.description) {
|
|
314
|
+
console.log(` ${chalk3.gray("Description:")} ${project.description.substring(0, 100)}${project.description.length > 100 ? "..." : ""}`);
|
|
315
|
+
}
|
|
316
|
+
}
|
|
317
|
+
console.log();
|
|
318
|
+
}
|
|
319
|
+
function outputWorkspacesJson(workspaces) {
|
|
320
|
+
const output = {
|
|
321
|
+
workspaces: workspaces.map(transformWorkspace),
|
|
322
|
+
total: workspaces.length
|
|
323
|
+
};
|
|
324
|
+
console.log(JSON.stringify(output, null, 2));
|
|
325
|
+
}
|
|
326
|
+
function outputWorkspacesPretty(workspaces) {
|
|
327
|
+
if (workspaces.length === 0) {
|
|
328
|
+
console.log(chalk3.gray("No workspaces found."));
|
|
329
|
+
return;
|
|
330
|
+
}
|
|
331
|
+
console.log(chalk3.bold(`
|
|
332
|
+
Workspaces (${workspaces.length} total)`));
|
|
333
|
+
console.log(chalk3.gray("\u2500".repeat(50)));
|
|
334
|
+
for (const workspace of workspaces) {
|
|
335
|
+
console.log(`
|
|
336
|
+
${chalk3.bold(workspace.name)}`);
|
|
337
|
+
console.log(chalk3.gray(` ID: ${workspace.id}`));
|
|
338
|
+
console.log(` ${chalk3.cyan("Slug:")} ${workspace.slug}`);
|
|
339
|
+
console.log(` ${chalk3.magenta("Type:")} ${workspace.type}`);
|
|
340
|
+
}
|
|
341
|
+
console.log();
|
|
342
|
+
}
|
|
343
|
+
function getKanbanStatusColor(status) {
|
|
344
|
+
switch (status) {
|
|
345
|
+
case "BACKLOG":
|
|
346
|
+
return "gray";
|
|
347
|
+
case "TODO":
|
|
348
|
+
return "blue";
|
|
349
|
+
case "IN_PROGRESS":
|
|
350
|
+
return "yellow";
|
|
351
|
+
case "IN_REVIEW":
|
|
352
|
+
return "cyan";
|
|
353
|
+
case "DONE":
|
|
354
|
+
return "green";
|
|
355
|
+
case "CANCELLED":
|
|
356
|
+
return "red";
|
|
357
|
+
default:
|
|
358
|
+
return "gray";
|
|
359
|
+
}
|
|
360
|
+
}
|
|
361
|
+
function formatDate(date) {
|
|
362
|
+
return date.toLocaleDateString("en-US", {
|
|
363
|
+
year: "numeric",
|
|
364
|
+
month: "short",
|
|
365
|
+
day: "numeric"
|
|
366
|
+
});
|
|
367
|
+
}
|
|
368
|
+
|
|
369
|
+
// src/commands/actions.ts
|
|
370
|
+
function createActionsCommand() {
|
|
371
|
+
const actions = new Command2("actions").description("Manage actions/tasks");
|
|
372
|
+
actions.command("list").description("List all actions").option("--project <id>", "Filter by project ID").option("--status <status>", "Filter by kanban status (BACKLOG, TODO, IN_PROGRESS, IN_REVIEW, DONE)").option("--assignee <id>", "Filter by assignee ID").action(async (options, cmd) => {
|
|
373
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
374
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
375
|
+
try {
|
|
376
|
+
const client = getClient();
|
|
377
|
+
const kanbanStatus = options.status;
|
|
378
|
+
const actions2 = await client.actions.list({
|
|
379
|
+
projectId: options.project,
|
|
380
|
+
status: kanbanStatus,
|
|
381
|
+
assigneeId: options.assignee
|
|
382
|
+
});
|
|
383
|
+
if (useJson) {
|
|
384
|
+
outputActionsJson(actions2, {
|
|
385
|
+
projectId: options.project,
|
|
386
|
+
kanbanStatus: options.status
|
|
387
|
+
});
|
|
388
|
+
} else {
|
|
389
|
+
outputActionsPretty(actions2);
|
|
390
|
+
}
|
|
391
|
+
} catch (error) {
|
|
392
|
+
handleError(error, useJson);
|
|
393
|
+
}
|
|
394
|
+
});
|
|
395
|
+
actions.command("today").description("Get actions due today").option("--workspace <id>", "Filter by workspace ID").action(async (options, cmd) => {
|
|
396
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
397
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
398
|
+
try {
|
|
399
|
+
const client = getClient();
|
|
400
|
+
const actions2 = await client.actions.getToday(options.workspace);
|
|
401
|
+
if (useJson) {
|
|
402
|
+
outputActionsJson(actions2, { workspaceId: options.workspace });
|
|
403
|
+
} else {
|
|
404
|
+
outputActionsPretty(actions2);
|
|
405
|
+
}
|
|
406
|
+
} catch (error) {
|
|
407
|
+
handleError(error, useJson);
|
|
408
|
+
}
|
|
409
|
+
});
|
|
410
|
+
actions.command("range").description("Get actions by date range").requiredOption("--start <date>", "Start date (YYYY-MM-DD)").requiredOption("--end <date>", "End date (YYYY-MM-DD)").option("--workspace <id>", "Filter by workspace ID").action(async (options, cmd) => {
|
|
411
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
412
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
413
|
+
try {
|
|
414
|
+
const startDate = new Date(options.start);
|
|
415
|
+
const endDate = new Date(options.end);
|
|
416
|
+
if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) {
|
|
417
|
+
throw new Error("Invalid date format. Use YYYY-MM-DD");
|
|
418
|
+
}
|
|
419
|
+
const client = getClient();
|
|
420
|
+
const actions2 = await client.actions.getByDateRange(startDate, endDate, options.workspace);
|
|
421
|
+
if (useJson) {
|
|
422
|
+
outputActionsJson(actions2, { workspaceId: options.workspace });
|
|
423
|
+
} else {
|
|
424
|
+
outputActionsPretty(actions2);
|
|
425
|
+
}
|
|
426
|
+
} catch (error) {
|
|
427
|
+
handleError(error, useJson);
|
|
428
|
+
}
|
|
429
|
+
});
|
|
430
|
+
actions.command("kanban").description("Get kanban board actions").option("--project <id>", "Filter by project ID").option("--status <status>", "Filter by kanban status").option("--assignee <id>", "Filter by assignee ID").action(async (options, cmd) => {
|
|
431
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
432
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
433
|
+
try {
|
|
434
|
+
const client = getClient();
|
|
435
|
+
const kanbanStatus = options.status;
|
|
436
|
+
const actions2 = await client.actions.getKanban({
|
|
437
|
+
projectId: options.project,
|
|
438
|
+
status: kanbanStatus,
|
|
439
|
+
assigneeId: options.assignee
|
|
440
|
+
});
|
|
441
|
+
if (useJson) {
|
|
442
|
+
outputActionsJson(actions2, {
|
|
443
|
+
projectId: options.project,
|
|
444
|
+
kanbanStatus: options.status
|
|
445
|
+
});
|
|
446
|
+
} else {
|
|
447
|
+
outputActionsPretty(actions2);
|
|
448
|
+
}
|
|
449
|
+
} catch (error) {
|
|
450
|
+
handleError(error, useJson);
|
|
451
|
+
}
|
|
452
|
+
});
|
|
453
|
+
return actions;
|
|
454
|
+
}
|
|
455
|
+
|
|
456
|
+
// src/commands/projects.ts
|
|
457
|
+
import { Command as Command3 } from "commander";
|
|
458
|
+
function createProjectsCommand() {
|
|
459
|
+
const projects = new Command3("projects").description("Manage projects");
|
|
460
|
+
projects.command("list").description("List all projects").option("--workspace <id>", "Filter by workspace ID").option("--include-actions", "Include actions in output").action(async (options, cmd) => {
|
|
461
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
462
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
463
|
+
try {
|
|
464
|
+
const client = getClient();
|
|
465
|
+
const projects2 = await client.projects.list({
|
|
466
|
+
workspaceId: options.workspace,
|
|
467
|
+
includeActions: options.includeActions
|
|
468
|
+
});
|
|
469
|
+
if (useJson) {
|
|
470
|
+
outputProjectsJson(projects2);
|
|
471
|
+
} else {
|
|
472
|
+
outputProjectsPretty(projects2);
|
|
473
|
+
}
|
|
474
|
+
} catch (error) {
|
|
475
|
+
handleError(error, useJson);
|
|
476
|
+
}
|
|
477
|
+
});
|
|
478
|
+
return projects;
|
|
479
|
+
}
|
|
480
|
+
|
|
481
|
+
// src/commands/workspaces.ts
|
|
482
|
+
import { Command as Command4 } from "commander";
|
|
483
|
+
import chalk4 from "chalk";
|
|
484
|
+
function createWorkspacesCommand() {
|
|
485
|
+
const workspaces = new Command4("workspaces").description("Manage workspaces");
|
|
486
|
+
workspaces.command("list").description("List all workspaces").action(async (_options, cmd) => {
|
|
487
|
+
const globalOpts = cmd.optsWithGlobals();
|
|
488
|
+
const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);
|
|
489
|
+
try {
|
|
490
|
+
const client = getClient();
|
|
491
|
+
const workspaces2 = await client.workspaces.list();
|
|
492
|
+
if (useJson) {
|
|
493
|
+
outputWorkspacesJson(workspaces2);
|
|
494
|
+
} else {
|
|
495
|
+
const config = getConfig();
|
|
496
|
+
outputWorkspacesPretty(workspaces2);
|
|
497
|
+
if (config.defaultWorkspaceSlug) {
|
|
498
|
+
console.log(chalk4.gray(`Default workspace: ${config.defaultWorkspaceSlug}`));
|
|
499
|
+
}
|
|
500
|
+
}
|
|
501
|
+
} catch (error) {
|
|
502
|
+
handleError(error, useJson);
|
|
503
|
+
}
|
|
504
|
+
});
|
|
505
|
+
workspaces.command("set-default <slug>").description("Set the default workspace").action(async (slug) => {
|
|
506
|
+
try {
|
|
507
|
+
const client = getClient();
|
|
508
|
+
const workspaces2 = await client.workspaces.list();
|
|
509
|
+
const workspace = workspaces2.find((w) => w.slug === slug);
|
|
510
|
+
if (!workspace) {
|
|
511
|
+
console.error(chalk4.red(`Workspace with slug "${slug}" not found.`));
|
|
512
|
+
console.log(chalk4.gray("Available workspaces:"));
|
|
513
|
+
workspaces2.forEach((w) => {
|
|
514
|
+
console.log(chalk4.gray(` - ${w.slug} (${w.name})`));
|
|
515
|
+
});
|
|
516
|
+
process.exit(1);
|
|
517
|
+
}
|
|
518
|
+
setConfig({
|
|
519
|
+
defaultWorkspaceId: workspace.id,
|
|
520
|
+
defaultWorkspaceSlug: workspace.slug
|
|
521
|
+
});
|
|
522
|
+
console.log(chalk4.green(`Default workspace set to: ${workspace.name} (${workspace.slug})`));
|
|
523
|
+
} catch (error) {
|
|
524
|
+
handleError(error);
|
|
525
|
+
}
|
|
526
|
+
});
|
|
527
|
+
return workspaces;
|
|
528
|
+
}
|
|
529
|
+
|
|
530
|
+
// src/index.ts
|
|
531
|
+
var program = new Command5();
|
|
532
|
+
program.name("exponential").description("CLI to interact with Exponential productivity app").version("1.0.0").option("--json", "Output as JSON (default when piped)").option("--pretty", "Force pretty-printed output");
|
|
533
|
+
program.addCommand(createAuthCommand());
|
|
534
|
+
program.addCommand(createActionsCommand());
|
|
535
|
+
program.addCommand(createProjectsCommand());
|
|
536
|
+
program.addCommand(createWorkspacesCommand());
|
|
537
|
+
program.parse();
|
|
538
|
+
//# sourceMappingURL=index.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"sources":["../src/index.ts","../src/commands/auth.ts","../src/config/index.ts","../src/client/index.ts","../src/utils/errors.ts","../src/commands/actions.ts","../src/utils/output.ts","../src/commands/projects.ts","../src/commands/workspaces.ts"],"sourcesContent":["#!/usr/bin/env node\nimport { Command } from 'commander';\nimport { createAuthCommand } from './commands/auth.js';\nimport { createActionsCommand } from './commands/actions.js';\nimport { createProjectsCommand } from './commands/projects.js';\nimport { createWorkspacesCommand } from './commands/workspaces.js';\n\nconst program = new Command();\n\nprogram\n .name('exponential')\n .description('CLI to interact with Exponential productivity app')\n .version('1.0.0')\n .option('--json', 'Output as JSON (default when piped)')\n .option('--pretty', 'Force pretty-printed output');\n\n// Add subcommands\nprogram.addCommand(createAuthCommand());\nprogram.addCommand(createActionsCommand());\nprogram.addCommand(createProjectsCommand());\nprogram.addCommand(createWorkspacesCommand());\n\nprogram.parse();\n","import { Command } from 'commander';\nimport chalk from 'chalk';\nimport { getConfig, setConfig, clearConfig, isAuthenticated, getConfigPath } from '../config/index.js';\nimport { getClient, resetClient } from '../client/index.js';\nimport { handleError } from '../utils/errors.js';\n\nexport function createAuthCommand(): Command {\n const auth = new Command('auth')\n .description('Authentication commands');\n\n auth\n .command('login')\n .description('Configure CLI with your API token')\n .requiredOption('--token <token>', 'JWT token from /tokens page')\n .requiredOption('--api-url <url>', 'API URL (e.g., https://app.exponential.so)')\n .action(async (options: { token: string; apiUrl: string }) => {\n try {\n // Normalize API URL (remove trailing slash)\n let apiUrl = options.apiUrl.replace(/\\/+$/, '');\n\n // Ensure HTTPS for non-localhost\n if (!apiUrl.startsWith('http://localhost') && !apiUrl.startsWith('https://')) {\n apiUrl = `https://${apiUrl}`;\n }\n\n // Store the config\n setConfig({\n token: options.token,\n apiUrl: apiUrl,\n });\n\n // Reset client to use new config\n resetClient();\n\n // Validate by trying to list workspaces\n console.log(chalk.gray('Validating token...'));\n const client = getClient();\n await client.workspaces.list();\n\n console.log(chalk.green('Successfully authenticated!'));\n console.log(chalk.gray(`Config saved to: ${getConfigPath()}`));\n } catch (error) {\n // Clear invalid config\n clearConfig();\n handleError(error);\n }\n });\n\n auth\n .command('logout')\n .description('Remove stored credentials')\n .action(() => {\n clearConfig();\n resetClient();\n console.log(chalk.green('Successfully logged out.'));\n console.log(chalk.gray(`Config cleared from: ${getConfigPath()}`));\n });\n\n auth\n .command('whoami')\n .description('Show current authentication status')\n .action(async () => {\n if (!isAuthenticated()) {\n console.log(chalk.yellow('Not authenticated.'));\n console.log(chalk.gray('Run: exponential auth login --token <jwt> --api-url <url>'));\n process.exit(1);\n }\n\n try {\n const config = getConfig();\n const client = getClient();\n\n // Validate token by listing workspaces\n const workspaces = await client.workspaces.list();\n\n console.log(chalk.green('Authenticated'));\n console.log(chalk.gray(`API URL: ${config.apiUrl}`));\n console.log(chalk.gray(`Workspaces: ${(workspaces as unknown[]).length}`));\n console.log(chalk.gray(`Config: ${getConfigPath()}`));\n } catch (error) {\n handleError(error);\n }\n });\n\n auth\n .command('status')\n .description('Show detailed authentication status')\n .action(() => {\n const config = getConfig();\n\n console.log(chalk.bold('\\nAuthentication Status'));\n console.log(chalk.gray('─'.repeat(40)));\n console.log(`Authenticated: ${isAuthenticated() ? chalk.green('Yes') : chalk.red('No')}`);\n console.log(`API URL: ${config.apiUrl || chalk.gray('(not set)')}`);\n console.log(`Token: ${config.token ? chalk.gray(`${config.token.substring(0, 20)}...`) : chalk.gray('(not set)')}`);\n console.log(`Config Path: ${getConfigPath()}`);\n console.log();\n });\n\n return auth;\n}\n","import { createConfigStore } from 'exponential-sdk';\nimport type { ExponentialConfig } from 'exponential-sdk';\n\nconst configStore = createConfigStore({ projectName: 'exponential-cli' });\n\nexport type { ExponentialConfig };\n\nexport function getConfig(): ExponentialConfig {\n return configStore.loadConfig();\n}\n\nexport function setConfig(values: Partial<ExponentialConfig>): void {\n configStore.saveConfig(values);\n}\n\nexport function clearConfig(): void {\n configStore.clearConfig();\n}\n\nexport function isAuthenticated(): boolean {\n return configStore.isAuthenticated();\n}\n\nexport function getConfigPath(): string {\n return configStore.getConfigPath();\n}\n","import { ExponentialClient } from 'exponential-sdk';\nimport { getConfig, isAuthenticated } from '../config/index.js';\n\nlet clientInstance: ExponentialClient | null = null;\n\nexport function getClient() {\n if (!isAuthenticated()) {\n throw new Error('Not authenticated. Run: exponential auth login --token <your-jwt> --api-url <url>');\n }\n\n if (clientInstance) {\n return clientInstance;\n }\n\n const config = getConfig();\n clientInstance = new ExponentialClient({\n token: config.token,\n apiUrl: config.apiUrl,\n });\n\n return clientInstance;\n}\n\nexport function resetClient() {\n clientInstance = null;\n}\n\nexport { isTRPCError, TRPCClientError } from 'exponential-sdk';\n","import chalk from 'chalk';\nimport { isTRPCError } from '../client/index.js';\n\nexport class ExponentialError extends Error {\n constructor(\n message: string,\n public code: string,\n public suggestion?: string,\n public details?: unknown\n ) {\n super(message);\n this.name = 'ExponentialError';\n }\n}\n\nexport function handleError(error: unknown, json: boolean = false): never {\n if (error instanceof ExponentialError) {\n if (json) {\n console.log(JSON.stringify({\n error: {\n code: error.code,\n message: error.message,\n suggestion: error.suggestion,\n },\n }, null, 2));\n } else {\n console.error(chalk.red(`Error: ${error.message}`));\n if (error.suggestion) {\n console.error(chalk.yellow(`Suggestion: ${error.suggestion}`));\n }\n }\n process.exit(1);\n }\n\n if (isTRPCError(error)) {\n const code = error.data?.code ?? 'UNKNOWN';\n let message = error.message;\n let suggestion: string | undefined;\n\n switch (code) {\n case 'UNAUTHORIZED':\n message = 'Authentication failed. Your token may have expired.';\n suggestion = 'Run: exponential auth login --token <new-token> --api-url <url>';\n break;\n case 'NOT_FOUND':\n message = 'Resource not found';\n break;\n case 'FORBIDDEN':\n message = 'Access denied';\n break;\n }\n\n if (json) {\n console.log(JSON.stringify({\n error: {\n code,\n message,\n suggestion,\n },\n }, null, 2));\n } else {\n console.error(chalk.red(`Error [${code}]: ${message}`));\n if (suggestion) {\n console.error(chalk.yellow(`Suggestion: ${suggestion}`));\n }\n }\n process.exit(1);\n }\n\n // Generic error handling\n if (json) {\n console.log(JSON.stringify({\n error: {\n code: 'UNKNOWN',\n message: error instanceof Error ? error.message : String(error),\n },\n }, null, 2));\n } else {\n console.error(chalk.red(`Error: ${error instanceof Error ? error.message : String(error)}`));\n }\n process.exit(1);\n}\n","import { Command } from 'commander';\nimport { getClient } from '../client/index.js';\nimport { handleError } from '../utils/errors.js';\nimport {\n shouldUseJson,\n outputActionsJson,\n outputActionsPretty,\n} from '../utils/output.js';\nimport type { Action, KanbanStatus } from 'exponential-sdk';\n\ninterface GlobalOptions {\n json?: boolean;\n pretty?: boolean;\n workspace?: string;\n}\n\nexport function createActionsCommand(): Command {\n const actions = new Command('actions')\n .description('Manage actions/tasks');\n\n actions\n .command('list')\n .description('List all actions')\n .option('--project <id>', 'Filter by project ID')\n .option('--status <status>', 'Filter by kanban status (BACKLOG, TODO, IN_PROGRESS, IN_REVIEW, DONE)')\n .option('--assignee <id>', 'Filter by assignee ID')\n .action(async (options: { project?: string; status?: string; assignee?: string }, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals() as GlobalOptions;\n const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);\n\n try {\n const client = getClient();\n const kanbanStatus = options.status as KanbanStatus | undefined;\n\n const actions = await client.actions.list({\n projectId: options.project,\n status: kanbanStatus,\n assigneeId: options.assignee,\n });\n\n if (useJson) {\n outputActionsJson(actions, {\n projectId: options.project,\n kanbanStatus: options.status,\n });\n } else {\n outputActionsPretty(actions);\n }\n } catch (error) {\n handleError(error, useJson);\n }\n });\n\n actions\n .command('today')\n .description('Get actions due today')\n .option('--workspace <id>', 'Filter by workspace ID')\n .action(async (options: { workspace?: string }, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals() as GlobalOptions;\n const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);\n\n try {\n const client = getClient();\n const actions = await client.actions.getToday(options.workspace);\n\n if (useJson) {\n outputActionsJson(actions, { workspaceId: options.workspace });\n } else {\n outputActionsPretty(actions);\n }\n } catch (error) {\n handleError(error, useJson);\n }\n });\n\n actions\n .command('range')\n .description('Get actions by date range')\n .requiredOption('--start <date>', 'Start date (YYYY-MM-DD)')\n .requiredOption('--end <date>', 'End date (YYYY-MM-DD)')\n .option('--workspace <id>', 'Filter by workspace ID')\n .action(async (options: { start: string; end: string; workspace?: string }, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals() as GlobalOptions;\n const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);\n\n try {\n const startDate = new Date(options.start);\n const endDate = new Date(options.end);\n\n if (isNaN(startDate.getTime()) || isNaN(endDate.getTime())) {\n throw new Error('Invalid date format. Use YYYY-MM-DD');\n }\n\n const client = getClient();\n const actions = await client.actions.getByDateRange(startDate, endDate, options.workspace);\n\n if (useJson) {\n outputActionsJson(actions, { workspaceId: options.workspace });\n } else {\n outputActionsPretty(actions);\n }\n } catch (error) {\n handleError(error, useJson);\n }\n });\n\n actions\n .command('kanban')\n .description('Get kanban board actions')\n .option('--project <id>', 'Filter by project ID')\n .option('--status <status>', 'Filter by kanban status')\n .option('--assignee <id>', 'Filter by assignee ID')\n .action(async (options: { project?: string; status?: string; assignee?: string }, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals() as GlobalOptions;\n const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);\n\n try {\n const client = getClient();\n const kanbanStatus = options.status as KanbanStatus | undefined;\n\n const actions = await client.actions.getKanban({\n projectId: options.project,\n status: kanbanStatus,\n assigneeId: options.assignee,\n });\n\n if (useJson) {\n outputActionsJson(actions, {\n projectId: options.project,\n kanbanStatus: options.status,\n });\n } else {\n outputActionsPretty(actions);\n }\n } catch (error) {\n handleError(error, useJson);\n }\n });\n\n return actions;\n}\n","import chalk from 'chalk';\nimport type {\n Action,\n ActionOutput,\n ActionsListOutput,\n Project,\n ProjectOutput,\n ProjectsListOutput,\n Workspace,\n WorkspaceOutput,\n WorkspacesListOutput,\n} from 'exponential-sdk';\n\n// Detect if output is being piped\nexport function shouldUseJson(forceJson?: boolean, forcePretty?: boolean): boolean {\n if (forceJson) return true;\n if (forcePretty) return false;\n return !process.stdout.isTTY;\n}\n\n// Transform Action to ActionOutput (serialize dates)\nexport function transformAction(action: Action): ActionOutput {\n return {\n id: action.id,\n name: action.name,\n description: action.description,\n status: action.status,\n priority: action.priority,\n kanbanStatus: action.kanbanStatus,\n dueDate: action.dueDate?.toISOString() ?? null,\n scheduledStart: action.scheduledStart?.toISOString() ?? null,\n scheduledEnd: action.scheduledEnd?.toISOString() ?? null,\n project: action.project ? {\n id: action.project.id,\n name: action.project.name,\n } : null,\n workspace: action.workspace ? {\n id: action.workspace.id,\n slug: action.workspace.slug,\n name: action.workspace.name,\n } : null,\n assignees: action.assignees?.map(a => ({\n id: a.user.id,\n name: a.user.name,\n email: a.user.email,\n })) ?? [],\n createdAt: action.createdAt?.toISOString() ?? new Date().toISOString(),\n completedAt: action.completedAt?.toISOString() ?? null,\n };\n}\n\n// Transform Project to ProjectOutput\nexport function transformProject(project: Project): ProjectOutput {\n return {\n id: project.id,\n name: project.name,\n description: project.description,\n status: project.status,\n priority: project.priority,\n workspace: project.workspace ? {\n id: project.workspace.id,\n slug: project.workspace.slug,\n name: project.workspace.name,\n } : null,\n };\n}\n\n// Transform Workspace to WorkspaceOutput\nexport function transformWorkspace(workspace: Workspace): WorkspaceOutput {\n return {\n id: workspace.id,\n name: workspace.name,\n slug: workspace.slug,\n type: workspace.type,\n };\n}\n\n// Output actions as JSON\nexport function outputActionsJson(actions: Action[], filters: ActionsListOutput['filters'] = {}): void {\n const output: ActionsListOutput = {\n actions: actions.map(transformAction),\n total: actions.length,\n filters,\n };\n console.log(JSON.stringify(output, null, 2));\n}\n\n// Output actions in pretty format\nexport function outputActionsPretty(actions: Action[]): void {\n if (actions.length === 0) {\n console.log(chalk.gray('No actions found.'));\n return;\n }\n\n console.log(chalk.bold(`\\nActions (${actions.length} total)`));\n console.log(chalk.gray('─'.repeat(50)));\n\n for (const action of actions) {\n const statusColor = getKanbanStatusColor(action.kanbanStatus);\n const statusBadge = action.kanbanStatus\n ? chalk[statusColor](`[${action.kanbanStatus}]`)\n : chalk.gray('[NO STATUS]');\n\n console.log(`\\n${statusBadge} ${chalk.bold(action.name)}`);\n console.log(chalk.gray(` ID: ${action.id}`));\n\n if (action.project) {\n console.log(` ${chalk.cyan('Project:')} ${action.project.name}`);\n }\n\n console.log(` ${chalk.magenta('Priority:')} ${action.priority}`);\n\n if (action.dueDate) {\n const dueDate = new Date(action.dueDate);\n const isOverdue = dueDate < new Date();\n const dateStr = formatDate(dueDate);\n console.log(` ${chalk.yellow('Due:')} ${isOverdue ? chalk.red(dateStr) : dateStr}`);\n }\n\n if (action.description) {\n console.log(` ${chalk.gray('Description:')} ${action.description.substring(0, 100)}${action.description.length > 100 ? '...' : ''}`);\n }\n }\n console.log();\n}\n\n// Output projects as JSON\nexport function outputProjectsJson(projects: Project[]): void {\n const output: ProjectsListOutput = {\n projects: projects.map(transformProject),\n total: projects.length,\n };\n console.log(JSON.stringify(output, null, 2));\n}\n\n// Output projects in pretty format\nexport function outputProjectsPretty(projects: Project[]): void {\n if (projects.length === 0) {\n console.log(chalk.gray('No projects found.'));\n return;\n }\n\n console.log(chalk.bold(`\\nProjects (${projects.length} total)`));\n console.log(chalk.gray('─'.repeat(50)));\n\n for (const project of projects) {\n console.log(`\\n${chalk.bold(project.name)}`);\n console.log(chalk.gray(` ID: ${project.id}`));\n\n if (project.status) {\n console.log(` ${chalk.cyan('Status:')} ${project.status}`);\n }\n\n if (project.priority) {\n console.log(` ${chalk.magenta('Priority:')} ${project.priority}`);\n }\n\n if (project.workspace) {\n console.log(` ${chalk.yellow('Workspace:')} ${project.workspace.name} (${project.workspace.slug})`);\n }\n\n if (project.description) {\n console.log(` ${chalk.gray('Description:')} ${project.description.substring(0, 100)}${project.description.length > 100 ? '...' : ''}`);\n }\n }\n console.log();\n}\n\n// Output workspaces as JSON\nexport function outputWorkspacesJson(workspaces: Workspace[]): void {\n const output: WorkspacesListOutput = {\n workspaces: workspaces.map(transformWorkspace),\n total: workspaces.length,\n };\n console.log(JSON.stringify(output, null, 2));\n}\n\n// Output workspaces in pretty format\nexport function outputWorkspacesPretty(workspaces: Workspace[]): void {\n if (workspaces.length === 0) {\n console.log(chalk.gray('No workspaces found.'));\n return;\n }\n\n console.log(chalk.bold(`\\nWorkspaces (${workspaces.length} total)`));\n console.log(chalk.gray('─'.repeat(50)));\n\n for (const workspace of workspaces) {\n console.log(`\\n${chalk.bold(workspace.name)}`);\n console.log(chalk.gray(` ID: ${workspace.id}`));\n console.log(` ${chalk.cyan('Slug:')} ${workspace.slug}`);\n console.log(` ${chalk.magenta('Type:')} ${workspace.type}`);\n }\n console.log();\n}\n\n// Helper functions\nfunction getKanbanStatusColor(status: string | null): 'gray' | 'blue' | 'yellow' | 'cyan' | 'green' | 'red' {\n switch (status) {\n case 'BACKLOG': return 'gray';\n case 'TODO': return 'blue';\n case 'IN_PROGRESS': return 'yellow';\n case 'IN_REVIEW': return 'cyan';\n case 'DONE': return 'green';\n case 'CANCELLED': return 'red';\n default: return 'gray';\n }\n}\n\nfunction formatDate(date: Date): string {\n return date.toLocaleDateString('en-US', {\n year: 'numeric',\n month: 'short',\n day: 'numeric',\n });\n}\n","import { Command } from 'commander';\nimport { getClient } from '../client/index.js';\nimport { handleError } from '../utils/errors.js';\nimport {\n shouldUseJson,\n outputProjectsJson,\n outputProjectsPretty,\n} from '../utils/output.js';\nimport type { Project } from 'exponential-sdk';\n\ninterface GlobalOptions {\n json?: boolean;\n pretty?: boolean;\n workspace?: string;\n}\n\nexport function createProjectsCommand(): Command {\n const projects = new Command('projects')\n .description('Manage projects');\n\n projects\n .command('list')\n .description('List all projects')\n .option('--workspace <id>', 'Filter by workspace ID')\n .option('--include-actions', 'Include actions in output')\n .action(async (options: { workspace?: string; includeActions?: boolean }, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals() as GlobalOptions;\n const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);\n\n try {\n const client = getClient();\n const projects = await client.projects.list({\n workspaceId: options.workspace,\n includeActions: options.includeActions,\n });\n\n if (useJson) {\n outputProjectsJson(projects);\n } else {\n outputProjectsPretty(projects);\n }\n } catch (error) {\n handleError(error, useJson);\n }\n });\n\n return projects;\n}\n","import { Command } from 'commander';\nimport chalk from 'chalk';\nimport { getClient } from '../client/index.js';\nimport { getConfig, setConfig } from '../config/index.js';\nimport { handleError } from '../utils/errors.js';\nimport {\n shouldUseJson,\n outputWorkspacesJson,\n outputWorkspacesPretty,\n} from '../utils/output.js';\nimport type { Workspace } from 'exponential-sdk';\n\ninterface GlobalOptions {\n json?: boolean;\n pretty?: boolean;\n}\n\nexport function createWorkspacesCommand(): Command {\n const workspaces = new Command('workspaces')\n .description('Manage workspaces');\n\n workspaces\n .command('list')\n .description('List all workspaces')\n .action(async (_options: Record<string, never>, cmd: Command) => {\n const globalOpts = cmd.optsWithGlobals() as GlobalOptions;\n const useJson = shouldUseJson(globalOpts.json, globalOpts.pretty);\n\n try {\n const client = getClient();\n const workspaces = await client.workspaces.list();\n\n if (useJson) {\n outputWorkspacesJson(workspaces);\n } else {\n const config = getConfig();\n outputWorkspacesPretty(workspaces);\n\n if (config.defaultWorkspaceSlug) {\n console.log(chalk.gray(`Default workspace: ${config.defaultWorkspaceSlug}`));\n }\n }\n } catch (error) {\n handleError(error, useJson);\n }\n });\n\n workspaces\n .command('set-default <slug>')\n .description('Set the default workspace')\n .action(async (slug: string) => {\n try {\n const client = getClient();\n const workspaces = await client.workspaces.list();\n\n const workspace = workspaces.find((w: Workspace) => w.slug === slug);\n\n if (!workspace) {\n console.error(chalk.red(`Workspace with slug \"${slug}\" not found.`));\n console.log(chalk.gray('Available workspaces:'));\n workspaces.forEach((w: Workspace) => {\n console.log(chalk.gray(` - ${w.slug} (${w.name})`));\n });\n process.exit(1);\n }\n\n setConfig({\n defaultWorkspaceId: workspace.id,\n defaultWorkspaceSlug: workspace.slug,\n });\n\n console.log(chalk.green(`Default workspace set to: ${workspace.name} (${workspace.slug})`));\n } catch (error) {\n handleError(error);\n }\n });\n\n return workspaces;\n}\n"],"mappings":"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","names":["Command","chalk","chalk","Command","chalk","Command","actions","Command","Command","projects","Command","chalk","Command","workspaces","chalk","Command"]}
|
package/package.json
ADDED
|
@@ -0,0 +1,43 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "exponential-cli",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "CLI to interact with Exponential productivity app - pull actions for LLM consumption",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"exponential": "bin/exponential.js"
|
|
8
|
+
},
|
|
9
|
+
"main": "./dist/index.js",
|
|
10
|
+
"types": "./dist/index.d.ts",
|
|
11
|
+
"files": [
|
|
12
|
+
"dist",
|
|
13
|
+
"bin"
|
|
14
|
+
],
|
|
15
|
+
"scripts": {
|
|
16
|
+
"build": "tsup",
|
|
17
|
+
"dev": "tsup --watch",
|
|
18
|
+
"typecheck": "tsc --noEmit",
|
|
19
|
+
"prepublishOnly": "npm run build"
|
|
20
|
+
},
|
|
21
|
+
"engines": {
|
|
22
|
+
"node": ">=18.0.0"
|
|
23
|
+
},
|
|
24
|
+
"keywords": [
|
|
25
|
+
"cli",
|
|
26
|
+
"productivity",
|
|
27
|
+
"actions",
|
|
28
|
+
"tasks",
|
|
29
|
+
"exponential"
|
|
30
|
+
],
|
|
31
|
+
"author": "",
|
|
32
|
+
"license": "MIT",
|
|
33
|
+
"dependencies": {
|
|
34
|
+
"chalk": "^5.3.0",
|
|
35
|
+
"commander": "^12.1.0",
|
|
36
|
+
"exponential-sdk": "^1.0.0"
|
|
37
|
+
},
|
|
38
|
+
"devDependencies": {
|
|
39
|
+
"@types/node": "^20.14.10",
|
|
40
|
+
"tsup": "^8.3.5",
|
|
41
|
+
"typescript": "^5.7.2"
|
|
42
|
+
}
|
|
43
|
+
}
|