@1a35e1/sonar-cli 0.1.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 +422 -0
- package/dist/cli.js +4 -0
- package/dist/commands/account.js +75 -0
- package/dist/commands/config/data/download.js +53 -0
- package/dist/commands/config/data/path.js +11 -0
- package/dist/commands/config/data/sql.js +12 -0
- package/dist/commands/config/data/sync.js +85 -0
- package/dist/commands/config/env.js +15 -0
- package/dist/commands/config/index.js +12 -0
- package/dist/commands/config/nuke.js +19 -0
- package/dist/commands/config/set.js +38 -0
- package/dist/commands/config/setup.js +29 -0
- package/dist/commands/config/skill.js +15 -0
- package/dist/commands/feed.js +172 -0
- package/dist/commands/inbox/archive.js +41 -0
- package/dist/commands/inbox/index.js +92 -0
- package/dist/commands/inbox/later.js +41 -0
- package/dist/commands/inbox/read.js +41 -0
- package/dist/commands/inbox/skip.js +41 -0
- package/dist/commands/index.js +5 -0
- package/dist/commands/ingest/bookmarks.js +31 -0
- package/dist/commands/ingest/index.js +5 -0
- package/dist/commands/ingest/tweets.js +31 -0
- package/dist/commands/interests/create.js +94 -0
- package/dist/commands/interests/index.js +56 -0
- package/dist/commands/interests/match.js +33 -0
- package/dist/commands/interests/update.js +142 -0
- package/dist/commands/monitor.js +81 -0
- package/dist/components/AccountCard.js +6 -0
- package/dist/components/InteractiveSession.js +241 -0
- package/dist/components/InterestCard.js +10 -0
- package/dist/components/RefreshTip.js +5 -0
- package/dist/components/Spinner.js +14 -0
- package/dist/components/Table.js +23 -0
- package/dist/lib/ai.js +160 -0
- package/dist/lib/client.js +33 -0
- package/dist/lib/config.js +74 -0
- package/dist/lib/data-queries.js +61 -0
- package/dist/lib/db.js +73 -0
- package/dist/lib/skill.js +290 -0
- package/dist/types/sonar.js +42 -0
- package/package.json +47 -0
|
@@ -0,0 +1,290 @@
|
|
|
1
|
+
import { writeFileSync, mkdirSync } from 'node:fs';
|
|
2
|
+
import { join, dirname } from 'node:path';
|
|
3
|
+
import { homedir } from 'node:os';
|
|
4
|
+
const SKILL_CONTENT = `---
|
|
5
|
+
name: sonar
|
|
6
|
+
description: Sonar CLI — manage interests, suggestions, indexing jobs, and account config for the Sonar social intelligence platform. Use when the user asks about their Sonar account, wants to create/list interests, check suggestions, trigger indexing, or configure the CLI.
|
|
7
|
+
homepage: https://sonar.sh
|
|
8
|
+
user-invocable: true
|
|
9
|
+
allowed-tools: Bash
|
|
10
|
+
argument-hint: [command and options]
|
|
11
|
+
metadata: {"openclaw":{"emoji":"📡","primaryEnv":"SONAR_API_KEY","requires":{"bins":["sonar"],"env":["SONAR_API_KEY"]}}}
|
|
12
|
+
---
|
|
13
|
+
|
|
14
|
+
# Sonar CLI
|
|
15
|
+
|
|
16
|
+
Sonar is a social intelligence platform. Use the \`sonar\` CLI to manage the user's account.
|
|
17
|
+
|
|
18
|
+
All commands are invoked as: \`sonar <command> [subcommand] [flags]\`
|
|
19
|
+
|
|
20
|
+
---
|
|
21
|
+
|
|
22
|
+
## Account & Config
|
|
23
|
+
|
|
24
|
+
\`\`\`bash
|
|
25
|
+
# Show account info, plan usage, and suggestion counts
|
|
26
|
+
sonar account
|
|
27
|
+
|
|
28
|
+
# Show current CLI config (API URL, vendor, token presence)
|
|
29
|
+
sonar config
|
|
30
|
+
|
|
31
|
+
# Set AI vendor preference for --from-prompt (saved to ~/.sonar/config.json)
|
|
32
|
+
sonar config set vendor openai # or: anthropic
|
|
33
|
+
|
|
34
|
+
# Initialise workspace from environment variables
|
|
35
|
+
# Requires: SONAR_API_KEY
|
|
36
|
+
sonar config setup
|
|
37
|
+
\`\`\`
|
|
38
|
+
|
|
39
|
+
---
|
|
40
|
+
|
|
41
|
+
## Interests
|
|
42
|
+
|
|
43
|
+
Interests are named topic areas with keywords and related topics that drive suggestion matching.
|
|
44
|
+
|
|
45
|
+
\`\`\`bash
|
|
46
|
+
# List all interests
|
|
47
|
+
sonar interests
|
|
48
|
+
|
|
49
|
+
# Create manually
|
|
50
|
+
sonar interests create --name "AI Agents" --description "LLM-based agents and tooling" \\
|
|
51
|
+
--keywords "agents,llm,tools,mcp" --topics "machine learning,AI safety"
|
|
52
|
+
|
|
53
|
+
# Generate fields from a natural language prompt (uses OPENAI_API_KEY or ANTHROPIC_API_KEY)
|
|
54
|
+
sonar interests create --from-prompt "I want to follow the Rust ecosystem and systems programming"
|
|
55
|
+
|
|
56
|
+
# Generate with a specific vendor (overrides config preference)
|
|
57
|
+
sonar interests create --from-prompt "DeFi and crypto protocols" --vendor anthropic
|
|
58
|
+
|
|
59
|
+
# Update an existing interest (full replace)
|
|
60
|
+
sonar interests update --id <id> --name "New Name" --keywords "kw1,kw2"
|
|
61
|
+
|
|
62
|
+
# Add keywords to an existing interest (fetches current, merges, sends full list)
|
|
63
|
+
sonar interests update --id <id> --add-keywords "mcp,a2a,langgraph"
|
|
64
|
+
|
|
65
|
+
# Remove keywords from an existing interest
|
|
66
|
+
sonar interests update --id <id> --remove-keywords "old-term,deprecated-kw"
|
|
67
|
+
|
|
68
|
+
# Add and remove keywords in one shot
|
|
69
|
+
sonar interests update --id <id> --add-keywords "vibe-coding" --remove-keywords "cursor"
|
|
70
|
+
|
|
71
|
+
# Same flags work for related topics
|
|
72
|
+
sonar interests update --id <id> --add-topics "AI safety" --remove-topics "machine learning"
|
|
73
|
+
|
|
74
|
+
# Combine keyword/topic patching with a name change
|
|
75
|
+
sonar interests update --id <id> --name "New Name" --add-keywords "new-kw"
|
|
76
|
+
|
|
77
|
+
# Regenerate all fields from a new prompt (replaces everything)
|
|
78
|
+
sonar interests update --id <id> --from-prompt "Rust and WebAssembly tooling"
|
|
79
|
+
|
|
80
|
+
# Output raw JSON (agent-friendly)
|
|
81
|
+
sonar interests --json
|
|
82
|
+
\`\`\`
|
|
83
|
+
|
|
84
|
+
**AI vendor resolution order:**
|
|
85
|
+
1. \`--vendor\` flag
|
|
86
|
+
2. \`SONAR_AI_VENDOR\` environment variable
|
|
87
|
+
3. \`vendor\` in \`~/.sonar/config.json\` (set via \`sonar config set vendor\`)
|
|
88
|
+
4. Defaults to \`openai\`
|
|
89
|
+
|
|
90
|
+
Required env vars: \`OPENAI_API_KEY\` (OpenAI) or \`ANTHROPIC_API_KEY\` (Anthropic)
|
|
91
|
+
|
|
92
|
+
---
|
|
93
|
+
|
|
94
|
+
## Feed
|
|
95
|
+
|
|
96
|
+
Scored tweet feed from your social network, filtered by interests.
|
|
97
|
+
|
|
98
|
+
\`\`\`bash
|
|
99
|
+
# Show feed (default: last 12h, limit 20, card layout)
|
|
100
|
+
sonar feed
|
|
101
|
+
|
|
102
|
+
# Time window
|
|
103
|
+
sonar feed --hours 24
|
|
104
|
+
sonar feed --days 3
|
|
105
|
+
|
|
106
|
+
# Limit results
|
|
107
|
+
sonar feed --limit 50
|
|
108
|
+
|
|
109
|
+
# Output layout
|
|
110
|
+
sonar feed --render card # default — rich card view
|
|
111
|
+
sonar feed --render table # compact table view
|
|
112
|
+
sonar feed --width 100 # card body width in columns
|
|
113
|
+
|
|
114
|
+
# Raw JSON output (agent-friendly)
|
|
115
|
+
sonar feed --json
|
|
116
|
+
\`\`\`
|
|
117
|
+
|
|
118
|
+
---
|
|
119
|
+
|
|
120
|
+
## Suggestions (inbox)
|
|
121
|
+
|
|
122
|
+
\`\`\`bash
|
|
123
|
+
# List suggestions (default: inbox, limit 20)
|
|
124
|
+
sonar inbox
|
|
125
|
+
|
|
126
|
+
# Filter by status
|
|
127
|
+
sonar inbox --status inbox
|
|
128
|
+
sonar inbox --status later
|
|
129
|
+
sonar inbox --status replied
|
|
130
|
+
sonar inbox --status archived
|
|
131
|
+
|
|
132
|
+
# Change limit
|
|
133
|
+
sonar inbox --limit 50
|
|
134
|
+
|
|
135
|
+
# Update a suggestion's status (positional id replaced with --id flag)
|
|
136
|
+
sonar inbox read --id <id>
|
|
137
|
+
sonar inbox skip --id <id>
|
|
138
|
+
sonar inbox later --id <id>
|
|
139
|
+
sonar inbox archive --id <id>
|
|
140
|
+
|
|
141
|
+
# Raw JSON output
|
|
142
|
+
sonar inbox --json
|
|
143
|
+
\`\`\`
|
|
144
|
+
|
|
145
|
+
---
|
|
146
|
+
|
|
147
|
+
## Ingest
|
|
148
|
+
|
|
149
|
+
Trigger background jobs to ingest data.
|
|
150
|
+
|
|
151
|
+
\`\`\`bash
|
|
152
|
+
# Trigger specific jobs
|
|
153
|
+
sonar ingest tweets # Ingest recent tweets from social graph
|
|
154
|
+
sonar ingest bookmarks # Ingest X bookmarks (requires OAuth token)
|
|
155
|
+
sonar interests match # Match interests against ingested tweets (default: last 24h)
|
|
156
|
+
|
|
157
|
+
# Match tweet window (capped by plan: free=3d, pro=7d, enterprise=14d)
|
|
158
|
+
sonar interests match --days 1 # default
|
|
159
|
+
sonar interests match --days 3 # broader window (free plan max)
|
|
160
|
+
sonar interests match --days 7 # pro plan max
|
|
161
|
+
|
|
162
|
+
# Show current job queue counts (one-shot)
|
|
163
|
+
sonar monitor
|
|
164
|
+
|
|
165
|
+
# Live polling view of job queues
|
|
166
|
+
sonar monitor --watch
|
|
167
|
+
\`\`\`
|
|
168
|
+
|
|
169
|
+
---
|
|
170
|
+
|
|
171
|
+
## Local Data
|
|
172
|
+
|
|
173
|
+
Sync feed, suggestions, and interests to a local SQLite DB (\`~/.sonar/data.db\`) for offline querying.
|
|
174
|
+
|
|
175
|
+
\`\`\`bash
|
|
176
|
+
# Full download — wipes and repopulates ~/.sonar/data.db
|
|
177
|
+
sonar config data download
|
|
178
|
+
|
|
179
|
+
# Incremental sync — upserts records newer than last sync
|
|
180
|
+
sonar config data sync
|
|
181
|
+
|
|
182
|
+
# Open an interactive sqlite3 REPL
|
|
183
|
+
sonar config data sql
|
|
184
|
+
|
|
185
|
+
# Print path to the local DB file
|
|
186
|
+
sonar config data path
|
|
187
|
+
\`\`\`
|
|
188
|
+
|
|
189
|
+
### Schema
|
|
190
|
+
|
|
191
|
+
\`\`\`sql
|
|
192
|
+
-- Core tweet content (shared by feed and suggestions)
|
|
193
|
+
tweets (
|
|
194
|
+
id TEXT PRIMARY KEY, -- Sonar tweet UUID
|
|
195
|
+
xid TEXT, -- Twitter/X tweet ID
|
|
196
|
+
text TEXT,
|
|
197
|
+
created_at TEXT,
|
|
198
|
+
like_count INTEGER,
|
|
199
|
+
retweet_count INTEGER,
|
|
200
|
+
reply_count INTEGER,
|
|
201
|
+
author_username TEXT,
|
|
202
|
+
author_display_name TEXT,
|
|
203
|
+
author_followers_count INTEGER,
|
|
204
|
+
author_following_count INTEGER
|
|
205
|
+
)
|
|
206
|
+
|
|
207
|
+
-- Feed items (scored, keyword-matched tweets)
|
|
208
|
+
feed_items (
|
|
209
|
+
tweet_id TEXT PRIMARY KEY, -- FK → tweets.id
|
|
210
|
+
score REAL,
|
|
211
|
+
matched_keywords TEXT, -- JSON array of strings
|
|
212
|
+
synced_at TEXT
|
|
213
|
+
)
|
|
214
|
+
|
|
215
|
+
-- Inbox suggestions
|
|
216
|
+
suggestions (
|
|
217
|
+
suggestion_id TEXT PRIMARY KEY,
|
|
218
|
+
tweet_id TEXT, -- FK → tweets.id
|
|
219
|
+
score REAL,
|
|
220
|
+
status TEXT, -- INBOX | READ | SKIPPED | LATER | ARCHIVED
|
|
221
|
+
relevance TEXT,
|
|
222
|
+
projects_matched TEXT, -- JSON (count of matched interests)
|
|
223
|
+
metadata TEXT, -- JSON
|
|
224
|
+
synced_at TEXT
|
|
225
|
+
)
|
|
226
|
+
|
|
227
|
+
-- Interests (topics/keywords that drive matching)
|
|
228
|
+
interests (
|
|
229
|
+
id TEXT PRIMARY KEY, -- nanoId
|
|
230
|
+
name TEXT,
|
|
231
|
+
description TEXT,
|
|
232
|
+
keywords TEXT, -- JSON array
|
|
233
|
+
topics TEXT, -- JSON array
|
|
234
|
+
created_at TEXT,
|
|
235
|
+
updated_at TEXT,
|
|
236
|
+
synced_at TEXT
|
|
237
|
+
)
|
|
238
|
+
|
|
239
|
+
-- Internal sync state
|
|
240
|
+
sync_state (
|
|
241
|
+
key TEXT PRIMARY KEY, -- e.g. "last_synced_at"
|
|
242
|
+
value TEXT
|
|
243
|
+
)
|
|
244
|
+
\`\`\`
|
|
245
|
+
|
|
246
|
+
---
|
|
247
|
+
|
|
248
|
+
## Environment Variables
|
|
249
|
+
|
|
250
|
+
| Variable | Purpose |
|
|
251
|
+
|---|---|
|
|
252
|
+
| \`SONAR_API_KEY\` | API key for authentication (overrides config file) |
|
|
253
|
+
| \`SONAR_API_URL\` | Backend URL (default: \`http://localhost:8000/graphql\`) |
|
|
254
|
+
| \`SONAR_AI_VENDOR\` | AI vendor for \`--from-prompt\` (overrides config file) |
|
|
255
|
+
| \`OPENAI_API_KEY\` | Required when vendor is \`openai\` |
|
|
256
|
+
| \`ANTHROPIC_API_KEY\` | Required when vendor is \`anthropic\` |
|
|
257
|
+
|
|
258
|
+
---
|
|
259
|
+
|
|
260
|
+
## Config file
|
|
261
|
+
|
|
262
|
+
Stored at \`~/.sonar/config.json\`:
|
|
263
|
+
|
|
264
|
+
\`\`\`json
|
|
265
|
+
{
|
|
266
|
+
"token": "snr_...",
|
|
267
|
+
"apiUrl": "https://api.sonar.sh/graphql",
|
|
268
|
+
"vendor": "openai"
|
|
269
|
+
}
|
|
270
|
+
\`\`\`
|
|
271
|
+
`;
|
|
272
|
+
const DEFAULT_INSTALL_PATH = join(homedir(), '.claude', 'skills', 'sonar', 'SKILL.md');
|
|
273
|
+
export function writeSkillTo(dest, install) {
|
|
274
|
+
if (install || dest === '--install') {
|
|
275
|
+
const target = DEFAULT_INSTALL_PATH;
|
|
276
|
+
mkdirSync(dirname(target), { recursive: true });
|
|
277
|
+
writeFileSync(target, SKILL_CONTENT, 'utf8');
|
|
278
|
+
process.stdout.write(`SKILL.md written to ${target}\n`);
|
|
279
|
+
process.exit(0);
|
|
280
|
+
}
|
|
281
|
+
if (dest) {
|
|
282
|
+
mkdirSync(dirname(dest), { recursive: true });
|
|
283
|
+
writeFileSync(dest, SKILL_CONTENT, 'utf8');
|
|
284
|
+
process.stdout.write(`SKILL.md written to ${dest}\n`);
|
|
285
|
+
process.exit(0);
|
|
286
|
+
}
|
|
287
|
+
// Default: print to stdout
|
|
288
|
+
process.stdout.write(SKILL_CONTENT);
|
|
289
|
+
process.exit(0);
|
|
290
|
+
}
|
|
@@ -0,0 +1,42 @@
|
|
|
1
|
+
import { print } from 'graphql';
|
|
2
|
+
export var RelevanceLevel;
|
|
3
|
+
(function (RelevanceLevel) {
|
|
4
|
+
RelevanceLevel["High"] = "HIGH";
|
|
5
|
+
RelevanceLevel["Low"] = "LOW";
|
|
6
|
+
RelevanceLevel["Medium"] = "MEDIUM";
|
|
7
|
+
RelevanceLevel["None"] = "NONE";
|
|
8
|
+
})(RelevanceLevel || (RelevanceLevel = {}));
|
|
9
|
+
export var SuggestionStatus;
|
|
10
|
+
(function (SuggestionStatus) {
|
|
11
|
+
SuggestionStatus["Archived"] = "ARCHIVED";
|
|
12
|
+
SuggestionStatus["Inbox"] = "INBOX";
|
|
13
|
+
SuggestionStatus["Later"] = "LATER";
|
|
14
|
+
SuggestionStatus["Read"] = "READ";
|
|
15
|
+
SuggestionStatus["Replied"] = "REPLIED";
|
|
16
|
+
SuggestionStatus["Skipped"] = "SKIPPED";
|
|
17
|
+
})(SuggestionStatus || (SuggestionStatus = {}));
|
|
18
|
+
export const IndexBookmarksDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "mutation", "name": { "kind": "Name", "value": "IndexBookmarks" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "indexBookmarks" } }] } }] };
|
|
19
|
+
export const IndexTweetsDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "mutation", "name": { "kind": "Name", "value": "IndexTweets" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "indexTweets" } }] } }] };
|
|
20
|
+
export const RegenerateSuggestionsDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "mutation", "name": { "kind": "Name", "value": "RegenerateSuggestions" }, "variableDefinitions": [{ "kind": "VariableDefinition", "variable": { "kind": "Variable", "name": { "kind": "Name", "value": "days" } }, "type": { "kind": "NamedType", "name": { "kind": "Name", "value": "Int" } } }], "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "regenerateSuggestions" }, "arguments": [{ "kind": "Argument", "name": { "kind": "Name", "value": "days" }, "value": { "kind": "Variable", "name": { "kind": "Name", "value": "days" } } }] }] } }] };
|
|
21
|
+
export const MonitorStatusDocument = { "kind": "Document", "definitions": [{ "kind": "OperationDefinition", "operation": "query", "name": { "kind": "Name", "value": "MonitorStatus" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "me" }, "selectionSet": { "kind": "SelectionSet", "selections": [{ "kind": "Field", "name": { "kind": "Name", "value": "accountId" } }, { "kind": "Field", "name": { "kind": "Name", "value": "email" } }, { "kind": "Field", "name": { "kind": "Name", "value": "xHandle" } }, { "kind": "Field", "name": { "kind": "Name", "value": "xid" } }, { "kind": "Field", "name": { "kind": "Name", "value": "isPayingCustomer" } }, { "kind": "Field", "name": { "kind": "Name", "value": "indexingAccounts" } }, { "kind": "Field", "name": { "kind": "Name", "value": "indexedTweets" } }, { "kind": "Field", "name": { "kind": "Name", "value": "pendingEmbeddings" } }, { "kind": "Field", "name": { "kind": "Name", "value": "twitterIndexedAt" } }, { "kind": "Field", "name": { "kind": "Name", "value": "refreshedSuggestionsAt" } }] } }] } }] };
|
|
22
|
+
const defaultWrapper = (action, _operationName, _operationType, _variables) => action();
|
|
23
|
+
const IndexBookmarksDocumentString = print(IndexBookmarksDocument);
|
|
24
|
+
const IndexTweetsDocumentString = print(IndexTweetsDocument);
|
|
25
|
+
const RegenerateSuggestionsDocumentString = print(RegenerateSuggestionsDocument);
|
|
26
|
+
const MonitorStatusDocumentString = print(MonitorStatusDocument);
|
|
27
|
+
export function getSdk(client, withWrapper = defaultWrapper) {
|
|
28
|
+
return {
|
|
29
|
+
IndexBookmarks(variables, requestHeaders) {
|
|
30
|
+
return withWrapper((wrappedRequestHeaders) => client.rawRequest(IndexBookmarksDocumentString, variables, { ...requestHeaders, ...wrappedRequestHeaders }), 'IndexBookmarks', 'mutation', variables);
|
|
31
|
+
},
|
|
32
|
+
IndexTweets(variables, requestHeaders) {
|
|
33
|
+
return withWrapper((wrappedRequestHeaders) => client.rawRequest(IndexTweetsDocumentString, variables, { ...requestHeaders, ...wrappedRequestHeaders }), 'IndexTweets', 'mutation', variables);
|
|
34
|
+
},
|
|
35
|
+
RegenerateSuggestions(variables, requestHeaders) {
|
|
36
|
+
return withWrapper((wrappedRequestHeaders) => client.rawRequest(RegenerateSuggestionsDocumentString, variables, { ...requestHeaders, ...wrappedRequestHeaders }), 'RegenerateSuggestions', 'mutation', variables);
|
|
37
|
+
},
|
|
38
|
+
MonitorStatus(variables, requestHeaders) {
|
|
39
|
+
return withWrapper((wrappedRequestHeaders) => client.rawRequest(MonitorStatusDocumentString, variables, { ...requestHeaders, ...wrappedRequestHeaders }), 'MonitorStatus', 'query', variables);
|
|
40
|
+
}
|
|
41
|
+
};
|
|
42
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,47 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@1a35e1/sonar-cli",
|
|
3
|
+
"version": "0.1.0",
|
|
4
|
+
"description": "X/Twitter social graph CLI for signal filtering and curation",
|
|
5
|
+
"type": "module",
|
|
6
|
+
"bin": {
|
|
7
|
+
"sonar": "dist/cli.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"README.md"
|
|
12
|
+
],
|
|
13
|
+
"engines": {
|
|
14
|
+
"node": ">=20"
|
|
15
|
+
},
|
|
16
|
+
"publishConfig": {
|
|
17
|
+
"access": "public"
|
|
18
|
+
},
|
|
19
|
+
"dependencies": {
|
|
20
|
+
"better-sqlite3": "^11",
|
|
21
|
+
"date-fns": "4.1.0",
|
|
22
|
+
"graphql": "^16.12.0",
|
|
23
|
+
"graphql-request": "^7.4.0",
|
|
24
|
+
"ink": "^6",
|
|
25
|
+
"ink-table": "^3.1.0",
|
|
26
|
+
"pastel": "^3.0.0",
|
|
27
|
+
"react": "^19",
|
|
28
|
+
"zod": "^3.25.76"
|
|
29
|
+
},
|
|
30
|
+
"devDependencies": {
|
|
31
|
+
"@graphql-codegen/cli": "^5.0.5",
|
|
32
|
+
"@graphql-codegen/typescript-graphql-request": "^6.4.0",
|
|
33
|
+
"@types/better-sqlite3": "^7",
|
|
34
|
+
"@types/node": "^22",
|
|
35
|
+
"@types/react": "^19",
|
|
36
|
+
"biome": "^0.3.3",
|
|
37
|
+
"ink-link": "^5.0.0",
|
|
38
|
+
"tsx": "^4",
|
|
39
|
+
"typescript": "^5"
|
|
40
|
+
},
|
|
41
|
+
"scripts": {
|
|
42
|
+
"types": "graphql-codegen --config codegen.ts",
|
|
43
|
+
"sonar": "tsx src/cli.ts",
|
|
44
|
+
"build": "tsc",
|
|
45
|
+
"typecheck": "tsc --noEmit"
|
|
46
|
+
}
|
|
47
|
+
}
|