termcast 1.4.1 → 1.6.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/build.d.ts.map +1 -1
- package/dist/build.js +30 -12
- package/dist/build.js.map +1 -1
- package/dist/cli.js +0 -40
- package/dist/cli.js.map +1 -1
- package/dist/compile.d.ts.map +1 -1
- package/dist/compile.js +7 -1
- package/dist/compile.js.map +1 -1
- package/dist/components/bar-graph.d.ts +23 -8
- package/dist/components/bar-graph.d.ts.map +1 -1
- package/dist/components/bar-graph.js +84 -40
- package/dist/components/bar-graph.js.map +1 -1
- package/dist/components/dotted-line-graph.d.ts +86 -0
- package/dist/components/dotted-line-graph.d.ts.map +1 -0
- package/dist/components/dotted-line-graph.js +260 -0
- package/dist/components/dotted-line-graph.js.map +1 -0
- package/dist/components/extension-preferences.d.ts.map +1 -1
- package/dist/components/extension-preferences.js +1 -10
- package/dist/components/extension-preferences.js.map +1 -1
- package/dist/components/graph.d.ts.map +1 -1
- package/dist/components/graph.js +7 -1
- package/dist/components/graph.js.map +1 -1
- package/dist/components/histogram.d.ts +42 -0
- package/dist/components/histogram.d.ts.map +1 -0
- package/dist/components/histogram.js +115 -0
- package/dist/components/histogram.js.map +1 -0
- package/dist/components/horizontal-bar-graph.d.ts +47 -0
- package/dist/components/horizontal-bar-graph.d.ts.map +1 -0
- package/dist/components/horizontal-bar-graph.js +137 -0
- package/dist/components/horizontal-bar-graph.js.map +1 -0
- package/dist/components/list.d.ts +9 -0
- package/dist/components/list.d.ts.map +1 -1
- package/dist/components/list.js +84 -21
- package/dist/components/list.js.map +1 -1
- package/dist/examples/bar-graph-weekly.js +2 -2
- package/dist/examples/bar-graph-weekly.js.map +1 -1
- package/dist/examples/charts-showcase-barchart.d.ts +2 -0
- package/dist/examples/charts-showcase-barchart.d.ts.map +1 -0
- package/dist/examples/charts-showcase-barchart.js +10 -0
- package/dist/examples/charts-showcase-barchart.js.map +1 -0
- package/dist/examples/charts-showcase-bargraph.d.ts +2 -0
- package/dist/examples/charts-showcase-bargraph.d.ts.map +1 -0
- package/dist/examples/charts-showcase-bargraph.js +60 -0
- package/dist/examples/charts-showcase-bargraph.js.map +1 -0
- package/dist/examples/charts-showcase-candle.d.ts +2 -0
- package/dist/examples/charts-showcase-candle.d.ts.map +1 -0
- package/dist/examples/charts-showcase-candle.js +30 -0
- package/dist/examples/charts-showcase-candle.js.map +1 -0
- package/dist/examples/charts-showcase-graph.d.ts +2 -0
- package/dist/examples/charts-showcase-graph.d.ts.map +1 -0
- package/dist/examples/charts-showcase-graph.js +33 -0
- package/dist/examples/charts-showcase-graph.js.map +1 -0
- package/dist/examples/charts-showcase-heatmap.d.ts +2 -0
- package/dist/examples/charts-showcase-heatmap.d.ts.map +1 -0
- package/dist/examples/charts-showcase-heatmap.js +36 -0
- package/dist/examples/charts-showcase-heatmap.js.map +1 -0
- package/dist/examples/charts-showcase-mixed.d.ts +2 -0
- package/dist/examples/charts-showcase-mixed.d.ts.map +1 -0
- package/dist/examples/charts-showcase-mixed.js +30 -0
- package/dist/examples/charts-showcase-mixed.js.map +1 -0
- package/dist/examples/charts-showcase-progress.d.ts +2 -0
- package/dist/examples/charts-showcase-progress.d.ts.map +1 -0
- package/dist/examples/charts-showcase-progress.js +10 -0
- package/dist/examples/charts-showcase-progress.js.map +1 -0
- package/dist/examples/graph-multi-series.js +1 -1
- package/dist/examples/graph-multi-series.js.map +1 -1
- package/dist/examples/horizontal-bar-graph-weekly.d.ts +2 -0
- package/dist/examples/horizontal-bar-graph-weekly.d.ts.map +1 -0
- package/dist/examples/horizontal-bar-graph-weekly.js +67 -0
- package/dist/examples/horizontal-bar-graph-weekly.js.map +1 -0
- package/dist/examples/list-detail-height-ratchet.d.ts +2 -0
- package/dist/examples/list-detail-height-ratchet.d.ts.map +1 -0
- package/dist/examples/list-detail-height-ratchet.js +26 -0
- package/dist/examples/list-detail-height-ratchet.js.map +1 -0
- package/dist/examples/simple-dotted-line-graph.d.ts +2 -0
- package/dist/examples/simple-dotted-line-graph.d.ts.map +1 -0
- package/dist/examples/simple-dotted-line-graph.js +39 -0
- package/dist/examples/simple-dotted-line-graph.js.map +1 -0
- package/dist/examples/simple-histogram.d.ts +2 -0
- package/dist/examples/simple-histogram.d.ts.map +1 -0
- package/dist/examples/simple-histogram.js +47 -0
- package/dist/examples/simple-histogram.js.map +1 -0
- package/dist/extensions/dev.d.ts.map +1 -1
- package/dist/extensions/dev.js +1 -0
- package/dist/extensions/dev.js.map +1 -1
- package/dist/globals.js +8 -0
- package/dist/globals.js.map +1 -1
- package/dist/index.d.ts +6 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/index.js.map +1 -1
- package/dist/package-json.d.ts +2 -0
- package/dist/package-json.d.ts.map +1 -1
- package/dist/package-json.js +20 -17
- package/dist/package-json.js.map +1 -1
- package/dist/platform/node/sqlite.d.ts +6 -5
- package/dist/platform/node/sqlite.d.ts.map +1 -1
- package/dist/platform/node/sqlite.js +30 -14
- package/dist/platform/node/sqlite.js.map +1 -1
- package/dist/profiler.d.ts +2 -0
- package/dist/profiler.d.ts.map +1 -0
- package/dist/profiler.js +390 -0
- package/dist/profiler.js.map +1 -0
- package/dist/theme.d.ts.map +1 -1
- package/dist/theme.js +11 -9
- package/dist/theme.js.map +1 -1
- package/dist/utils/run-command.d.ts.map +1 -1
- package/dist/utils/run-command.js +8 -19
- package/dist/utils/run-command.js.map +1 -1
- package/dist/utils.d.ts +1 -19
- package/dist/utils.d.ts.map +1 -1
- package/dist/utils.js +1 -100
- package/dist/utils.js.map +1 -1
- package/package.json +18 -21
- package/src/build.tsx +38 -15
- package/src/cli.tsx +3 -40
- package/src/compile.tsx +9 -1
- package/src/compile.vitest.tsx +8 -8
- package/src/components/bar-graph.tsx +217 -111
- package/src/components/dotted-line-graph.tsx +407 -0
- package/src/components/extension-preferences.tsx +2 -12
- package/src/components/graph.tsx +5 -1
- package/src/components/histogram.tsx +228 -0
- package/src/components/horizontal-bar-graph.tsx +279 -0
- package/src/components/list.tsx +112 -26
- package/src/examples/action-shortcut.vitest.tsx +20 -20
- package/src/examples/actions-context.vitest.tsx +2 -2
- package/src/examples/bar-graph-weekly.tsx +2 -2
- package/src/examples/bar-graph-weekly.vitest.tsx +103 -102
- package/src/examples/charts-showcase-bargraph.tsx +103 -0
- package/src/examples/detail-metadata-showcase.vitest.tsx +12 -12
- package/src/examples/form-basic.vitest.tsx +11 -11
- package/src/examples/form-dropdown.vitest.tsx +11 -11
- package/src/examples/form-scroll.vitest.tsx +1 -1
- package/src/examples/form-tagpicker.vitest.tsx +11 -11
- package/src/examples/github.vitest.tsx +22 -31
- package/src/examples/graph-bar-chart.vitest.tsx +36 -36
- package/src/examples/graph-multi-series.tsx +1 -1
- package/src/examples/graph-polymarket.vitest.tsx +24 -24
- package/src/examples/graph-row.vitest.tsx +14 -14
- package/src/examples/graph-styles.vitest.tsx +77 -77
- package/src/examples/horizontal-bar-graph-weekly.tsx +138 -0
- package/src/examples/horizontal-bar-graph-weekly.vitest.tsx +164 -0
- package/src/examples/list-detail-height-ratchet.tsx +48 -0
- package/src/examples/list-detail-height-ratchet.vitest.tsx +161 -0
- package/src/examples/list-detail-metadata.vitest.tsx +51 -51
- package/src/examples/list-dropdown-default.vitest.tsx +27 -27
- package/src/examples/list-fetch-data.vitest.tsx +3 -3
- package/src/examples/list-loading-empty-view.vitest.tsx +1 -1
- package/src/examples/list-no-actions.vitest.tsx +3 -3
- package/src/examples/list-scrollbox.vitest.tsx +6 -6
- package/src/examples/list-spacing-mode.vitest.tsx +1 -1
- package/src/examples/list-with-detail.vitest.tsx +55 -55
- package/src/examples/list-with-dropdown.vitest.tsx +6 -6
- package/src/examples/list-with-sections.vitest.tsx +20 -20
- package/src/examples/list-with-toast.vitest.tsx +4 -4
- package/src/examples/simple-candle-chart.vitest.tsx +61 -59
- package/src/examples/simple-dotted-line-graph.tsx +53 -0
- package/src/examples/simple-dotted-line-graph.vitest.tsx +62 -0
- package/src/examples/simple-grid.vitest.tsx +4 -4
- package/src/examples/simple-heatmap.vitest.tsx +9 -9
- package/src/examples/simple-histogram.tsx +90 -0
- package/src/examples/simple-navigation.vitest.tsx +25 -25
- package/src/examples/simple-progress-bar.vitest.tsx +7 -7
- package/src/examples/swift-extension.vitest.tsx +5 -5
- package/src/examples/toast-action.vitest.tsx +4 -4
- package/src/extensions/dev.tsx +2 -1
- package/src/extensions/dev.vitest.tsx +17 -17
- package/src/globals.ts +9 -0
- package/src/index.tsx +21 -0
- package/src/package-json.tsx +24 -23
- package/src/platform/node/sqlite.ts +29 -13
- package/src/profiler.tsx +487 -0
- package/src/theme.tsx +11 -10
- package/src/utils/run-command.tsx +10 -19
- package/src/utils.tsx +0 -163
- package/src/examples/store.tsx +0 -4
- package/src/examples/store.vitest.tsx +0 -78
- package/src/extensions/home.tsx +0 -227
- package/src/extensions/store.tsx +0 -375
package/src/utils.tsx
CHANGED
|
@@ -13,10 +13,6 @@ import {
|
|
|
13
13
|
readFileSync,
|
|
14
14
|
ensureDir,
|
|
15
15
|
execCommand,
|
|
16
|
-
readdirSync,
|
|
17
|
-
rmSync,
|
|
18
|
-
mkdirSync,
|
|
19
|
-
cpSync,
|
|
20
16
|
} from '#platform/runtime'
|
|
21
17
|
import {
|
|
22
18
|
parsePackageJson,
|
|
@@ -317,90 +313,11 @@ export function captureException(exception: unknown): void {
|
|
|
317
313
|
console.error('[captureException] Exception captured:', exception)
|
|
318
314
|
}
|
|
319
315
|
|
|
320
|
-
export function getExtensionPath(extensionName: string): string {
|
|
321
|
-
const storeDir = getStoreDirectory()
|
|
322
|
-
return joinPath(storeDir, extensionName)
|
|
323
|
-
}
|
|
324
|
-
|
|
325
|
-
export function getExtensionPackageJsonPath(extensionName: string): string {
|
|
326
|
-
return joinPath(getExtensionPath(extensionName), 'package.json')
|
|
327
|
-
}
|
|
328
|
-
|
|
329
|
-
export function getExtensionPackageJson(
|
|
330
|
-
extensionName: string,
|
|
331
|
-
): RaycastPackageJson | null {
|
|
332
|
-
const packageJsonPath = getExtensionPackageJsonPath(extensionName)
|
|
333
|
-
|
|
334
|
-
if (!fileExists(packageJsonPath)) {
|
|
335
|
-
return null
|
|
336
|
-
}
|
|
337
|
-
|
|
338
|
-
try {
|
|
339
|
-
return parsePackageJson({ packageJsonPath })
|
|
340
|
-
} catch (error) {
|
|
341
|
-
console.error(`Failed to parse package.json for ${extensionName}:`, error)
|
|
342
|
-
return null
|
|
343
|
-
}
|
|
344
|
-
}
|
|
345
|
-
|
|
346
316
|
export interface ExtensionPreferencesInfo {
|
|
347
317
|
hasPreferences: boolean
|
|
348
318
|
hasRequiredPreferences: boolean
|
|
349
319
|
}
|
|
350
320
|
|
|
351
|
-
export function checkExtensionPreferences(
|
|
352
|
-
extensionName: string,
|
|
353
|
-
): ExtensionPreferencesInfo {
|
|
354
|
-
const packageJson = getExtensionPackageJson(extensionName)
|
|
355
|
-
|
|
356
|
-
if (!packageJson) {
|
|
357
|
-
return { hasPreferences: false, hasRequiredPreferences: false }
|
|
358
|
-
}
|
|
359
|
-
|
|
360
|
-
// Check for extension-wide preferences
|
|
361
|
-
const hasExtensionPreferences =
|
|
362
|
-
packageJson.preferences && packageJson.preferences.length > 0
|
|
363
|
-
|
|
364
|
-
// Check if any command has preferences
|
|
365
|
-
const commandsWithPreferences = (packageJson.commands || []).filter(
|
|
366
|
-
(cmd) => cmd.preferences && cmd.preferences.length > 0,
|
|
367
|
-
)
|
|
368
|
-
|
|
369
|
-
const hasPreferences =
|
|
370
|
-
hasExtensionPreferences || commandsWithPreferences.length > 0
|
|
371
|
-
|
|
372
|
-
// Check for required extension-wide preferences
|
|
373
|
-
const requiredExtensionPrefs = (packageJson.preferences || []).filter(
|
|
374
|
-
(pref) => pref.required,
|
|
375
|
-
)
|
|
376
|
-
|
|
377
|
-
// Check if any command has required preferences
|
|
378
|
-
const commandsWithRequiredPrefs = (packageJson.commands || []).filter(
|
|
379
|
-
(cmd) => {
|
|
380
|
-
const requiredPrefs = (cmd.preferences || []).filter(
|
|
381
|
-
(pref) => pref.required,
|
|
382
|
-
)
|
|
383
|
-
return requiredPrefs.length > 0
|
|
384
|
-
},
|
|
385
|
-
)
|
|
386
|
-
|
|
387
|
-
const hasRequiredPreferences =
|
|
388
|
-
requiredExtensionPrefs.length > 0 || commandsWithRequiredPrefs.length > 0
|
|
389
|
-
|
|
390
|
-
return { hasPreferences, hasRequiredPreferences }
|
|
391
|
-
}
|
|
392
|
-
|
|
393
|
-
// Store management types
|
|
394
|
-
interface BundledCommand extends CommandWithFile {
|
|
395
|
-
bundledPath: string
|
|
396
|
-
}
|
|
397
|
-
|
|
398
|
-
interface StoredExtension {
|
|
399
|
-
name: string
|
|
400
|
-
packageJsonPath: string
|
|
401
|
-
commands: BundledCommand[]
|
|
402
|
-
}
|
|
403
|
-
|
|
404
321
|
export function resolveCommandPath({
|
|
405
322
|
commandName,
|
|
406
323
|
dir,
|
|
@@ -425,87 +342,7 @@ export function resolveCommandPath({
|
|
|
425
342
|
return ''
|
|
426
343
|
}
|
|
427
344
|
|
|
428
|
-
export function getStoreDirectory(): string {
|
|
429
|
-
const homeDir = homedir()
|
|
430
|
-
const storeDir = joinPath(homeDir, '.termcast', 'store')
|
|
431
|
-
|
|
432
|
-
// Ensure store directory exists
|
|
433
|
-
ensureDir(storeDir)
|
|
434
|
-
|
|
435
|
-
return storeDir
|
|
436
|
-
}
|
|
437
|
-
|
|
438
|
-
export function installExtension({
|
|
439
|
-
extensionName,
|
|
440
|
-
extensionSourcePath,
|
|
441
|
-
}: {
|
|
442
|
-
extensionName: string
|
|
443
|
-
extensionSourcePath: string
|
|
444
|
-
}): void {
|
|
445
|
-
const storeDir = getStoreDirectory()
|
|
446
|
-
const extensionDir = joinPath(storeDir, extensionName)
|
|
447
|
-
|
|
448
|
-
if (fileExists(extensionDir)) {
|
|
449
|
-
rmSync(extensionDir)
|
|
450
|
-
}
|
|
451
|
-
|
|
452
|
-
mkdirSync(extensionDir)
|
|
453
|
-
cpSync(extensionSourcePath, extensionDir)
|
|
454
|
-
|
|
455
|
-
logger.log(`Extension '${extensionName}' installed to ${extensionDir}`)
|
|
456
|
-
}
|
|
457
|
-
|
|
458
|
-
export function getStoredExtensions(): StoredExtension[] {
|
|
459
|
-
const storeDir = getStoreDirectory()
|
|
460
|
-
const extensions: StoredExtension[] = []
|
|
461
345
|
|
|
462
|
-
if (!fileExists(storeDir)) {
|
|
463
|
-
return extensions
|
|
464
|
-
}
|
|
465
|
-
|
|
466
|
-
const entries = readdirSync(storeDir)
|
|
467
|
-
|
|
468
|
-
for (const entry of entries) {
|
|
469
|
-
if (!entry.isDirectory()) continue
|
|
470
|
-
|
|
471
|
-
const extensionDir = joinPath(storeDir, entry.name)
|
|
472
|
-
const packageJsonPath = joinPath(extensionDir, 'package.json')
|
|
473
|
-
|
|
474
|
-
if (!fileExists(packageJsonPath)) {
|
|
475
|
-
logger.log(`Skipping ${entry.name}: no package.json found`)
|
|
476
|
-
continue
|
|
477
|
-
}
|
|
478
|
-
|
|
479
|
-
try {
|
|
480
|
-
const commandsData = getCommandsWithFiles({ packageJsonPath })
|
|
481
|
-
|
|
482
|
-
// Map commands to bundled commands using the resolver
|
|
483
|
-
const bundledCommands: BundledCommand[] = commandsData.commands.map(
|
|
484
|
-
(command) => {
|
|
485
|
-
const bundledPath = resolveCommandPath({
|
|
486
|
-
commandName: command.name,
|
|
487
|
-
dir: extensionDir,
|
|
488
|
-
})
|
|
489
|
-
|
|
490
|
-
return {
|
|
491
|
-
...command,
|
|
492
|
-
bundledPath,
|
|
493
|
-
}
|
|
494
|
-
},
|
|
495
|
-
)
|
|
496
|
-
|
|
497
|
-
extensions.push({
|
|
498
|
-
name: entry.name,
|
|
499
|
-
packageJsonPath,
|
|
500
|
-
commands: bundledCommands,
|
|
501
|
-
})
|
|
502
|
-
} catch (error: any) {
|
|
503
|
-
logger.error(`Failed to load extension ${entry.name}:`, error.message)
|
|
504
|
-
}
|
|
505
|
-
}
|
|
506
|
-
|
|
507
|
-
return extensions
|
|
508
|
-
}
|
|
509
346
|
|
|
510
347
|
export type ParseExecOutputHandler<T = any> = (args: { stdout: string }) => T
|
|
511
348
|
|
package/src/examples/store.tsx
DELETED
|
@@ -1,78 +0,0 @@
|
|
|
1
|
-
import { test, expect, afterEach, beforeEach } from 'vitest'
|
|
2
|
-
import { launchTerminal, Session } from 'tuistory/src'
|
|
3
|
-
|
|
4
|
-
let session: Session
|
|
5
|
-
|
|
6
|
-
beforeEach(async () => {
|
|
7
|
-
session = await launchTerminal({
|
|
8
|
-
command: 'bun',
|
|
9
|
-
args: ['src/examples/store.tsx'],
|
|
10
|
-
cols: 80,
|
|
11
|
-
rows: 30,
|
|
12
|
-
})
|
|
13
|
-
})
|
|
14
|
-
|
|
15
|
-
afterEach(() => {
|
|
16
|
-
session?.close()
|
|
17
|
-
})
|
|
18
|
-
|
|
19
|
-
test('Store extension - searching for spiceblow shows Database', async () => {
|
|
20
|
-
// Wait for store interface to load
|
|
21
|
-
const initialOutput = await session.text({
|
|
22
|
-
waitFor: (text) => {
|
|
23
|
-
// Wait until we see the store title
|
|
24
|
-
return text.includes('Store - Install Extensions')
|
|
25
|
-
},
|
|
26
|
-
timeout: 15000,
|
|
27
|
-
})
|
|
28
|
-
|
|
29
|
-
// Verify the store interface loads
|
|
30
|
-
expect(initialOutput).toContain('Store - Install Extensions')
|
|
31
|
-
|
|
32
|
-
// Type "spiceblow" in the search bar
|
|
33
|
-
await session.type('spiceblow')
|
|
34
|
-
|
|
35
|
-
// Get the output after search, waiting for Database to appear
|
|
36
|
-
// This will automatically wait for the API request to complete and results to show
|
|
37
|
-
const afterSearchOutput = await session.text({
|
|
38
|
-
waitFor: (text) => {
|
|
39
|
-
return text.includes('Search, update, insert')
|
|
40
|
-
},
|
|
41
|
-
timeout: 15000,
|
|
42
|
-
})
|
|
43
|
-
|
|
44
|
-
// Store the snapshot after searching for spiceblow
|
|
45
|
-
expect(afterSearchOutput).toMatchInlineSnapshot(`
|
|
46
|
-
"
|
|
47
|
-
|
|
48
|
-
|
|
49
|
-
Store - Install Extensions ───────────────────────────────────────────────
|
|
50
|
-
|
|
51
|
-
> spiceblow
|
|
52
|
-
|
|
53
|
-
›Spiceblow - Sql Database Management Search, update, insert and delete rows
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
59
|
-
|
|
60
|
-
|
|
61
|
-
↵ view details ↑↓ navigate ^k actions :vim powered by termcast.app
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
69
|
-
|
|
70
|
-
|
|
71
|
-
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
"
|
|
77
|
-
`)
|
|
78
|
-
}, 30000)
|
package/src/extensions/home.tsx
DELETED
|
@@ -1,227 +0,0 @@
|
|
|
1
|
-
import fs from 'node:fs'
|
|
2
|
-
import path from 'node:path'
|
|
3
|
-
import React from 'react'
|
|
4
|
-
import { List, logger, useStore, renderWithProviders } from 'termcast'
|
|
5
|
-
import { Action, ActionPanel } from 'termcast'
|
|
6
|
-
import { useNavigation } from 'termcast/src/internal/navigation'
|
|
7
|
-
import { showToast, Toast } from 'termcast/src/apis/toast'
|
|
8
|
-
import { Icon } from 'termcast'
|
|
9
|
-
import { getStoredExtensions } from '../utils'
|
|
10
|
-
import Store from './store'
|
|
11
|
-
import { ExtensionPreferences } from '../components/extension-preferences'
|
|
12
|
-
import { runCommand, clearCommandArguments } from '../utils/run-command'
|
|
13
|
-
import '../globals'
|
|
14
|
-
|
|
15
|
-
interface ExtensionCommand {
|
|
16
|
-
extensionName: string
|
|
17
|
-
extensionTitle: string
|
|
18
|
-
extensionDir?: string
|
|
19
|
-
command: any
|
|
20
|
-
bundledPath?: string
|
|
21
|
-
loadComponent?: () => Promise<(props: any) => any>
|
|
22
|
-
packageJson?: any
|
|
23
|
-
}
|
|
24
|
-
|
|
25
|
-
// Built-in extensions available globally
|
|
26
|
-
const builtinExtensions: ExtensionCommand[] = [
|
|
27
|
-
{
|
|
28
|
-
extensionName: 'termcast-store',
|
|
29
|
-
extensionTitle: 'Termcast Store',
|
|
30
|
-
command: {
|
|
31
|
-
name: 'store',
|
|
32
|
-
title: 'Store - Install Extensions',
|
|
33
|
-
description: 'Browse and install extensions from the Raycast Store',
|
|
34
|
-
mode: 'view',
|
|
35
|
-
icon: 'Store',
|
|
36
|
-
},
|
|
37
|
-
loadComponent: async () => Store,
|
|
38
|
-
},
|
|
39
|
-
]
|
|
40
|
-
|
|
41
|
-
function ExtensionsList({
|
|
42
|
-
allCommands,
|
|
43
|
-
initialSearchQuery = '',
|
|
44
|
-
}: {
|
|
45
|
-
allCommands: ExtensionCommand[]
|
|
46
|
-
initialSearchQuery?: string
|
|
47
|
-
}): any {
|
|
48
|
-
const { push, replace } = useNavigation()
|
|
49
|
-
const [searchText, setSearchText] = React.useState(initialSearchQuery)
|
|
50
|
-
|
|
51
|
-
const handleCommandSelect = async (item: ExtensionCommand) => {
|
|
52
|
-
clearCommandArguments()
|
|
53
|
-
|
|
54
|
-
try {
|
|
55
|
-
await runCommand({
|
|
56
|
-
command: item.command,
|
|
57
|
-
extensionName: item.extensionName,
|
|
58
|
-
packageJson: item.packageJson,
|
|
59
|
-
bundledPath: item.bundledPath,
|
|
60
|
-
loadComponent: item.loadComponent,
|
|
61
|
-
push,
|
|
62
|
-
replace,
|
|
63
|
-
})
|
|
64
|
-
} catch (error: any) {
|
|
65
|
-
await showToast({
|
|
66
|
-
style: Toast.Style.Failure,
|
|
67
|
-
title: 'Failed to load command',
|
|
68
|
-
message: error.message || String(error),
|
|
69
|
-
})
|
|
70
|
-
}
|
|
71
|
-
}
|
|
72
|
-
|
|
73
|
-
// Group commands by extension
|
|
74
|
-
const groupedByExtension = allCommands.reduce(
|
|
75
|
-
(acc, cmd) => {
|
|
76
|
-
if (!acc[cmd.extensionName]) {
|
|
77
|
-
acc[cmd.extensionName] = {
|
|
78
|
-
title: cmd.extensionTitle,
|
|
79
|
-
commands: [],
|
|
80
|
-
}
|
|
81
|
-
}
|
|
82
|
-
acc[cmd.extensionName].commands.push(cmd)
|
|
83
|
-
return acc
|
|
84
|
-
},
|
|
85
|
-
{} as Record<string, { title: string; commands: ExtensionCommand[] }>,
|
|
86
|
-
)
|
|
87
|
-
|
|
88
|
-
return (
|
|
89
|
-
<List
|
|
90
|
-
navigationTitle='Installed Extensions'
|
|
91
|
-
searchBarPlaceholder='Search commands...'
|
|
92
|
-
filtering={true}
|
|
93
|
-
onSearchTextChange={setSearchText}
|
|
94
|
-
searchText={searchText}
|
|
95
|
-
>
|
|
96
|
-
{Object.entries(groupedByExtension).map(
|
|
97
|
-
([extensionName, { title, commands }]) => (
|
|
98
|
-
<List.Section key={extensionName} title={title}>
|
|
99
|
-
{commands.map((item) => (
|
|
100
|
-
<List.Item
|
|
101
|
-
key={`${item.extensionName}-${item.command.name}`}
|
|
102
|
-
id={`${item.extensionName}-${item.command.name}`}
|
|
103
|
-
title={item.command.title}
|
|
104
|
-
subtitle={item.command.description}
|
|
105
|
-
icon={
|
|
106
|
-
item.command.icon
|
|
107
|
-
? Icon[item.command.icon as keyof typeof Icon]
|
|
108
|
-
: undefined
|
|
109
|
-
}
|
|
110
|
-
accessories={
|
|
111
|
-
item.command.mode ? [{ text: item.command.mode }] : []
|
|
112
|
-
}
|
|
113
|
-
keywords={[
|
|
114
|
-
...(item.command.keywords || []),
|
|
115
|
-
item.extensionName,
|
|
116
|
-
]}
|
|
117
|
-
actions={
|
|
118
|
-
<ActionPanel>
|
|
119
|
-
<Action
|
|
120
|
-
title='Run Command'
|
|
121
|
-
onAction={() => {
|
|
122
|
-
handleCommandSelect(item)
|
|
123
|
-
}}
|
|
124
|
-
/>
|
|
125
|
-
<Action
|
|
126
|
-
title='Configure Extension'
|
|
127
|
-
onAction={() => {
|
|
128
|
-
push(
|
|
129
|
-
<ExtensionPreferences
|
|
130
|
-
extensionName={item.extensionName}
|
|
131
|
-
onSubmit={() => {
|
|
132
|
-
handleCommandSelect(item)
|
|
133
|
-
}}
|
|
134
|
-
/>,
|
|
135
|
-
)
|
|
136
|
-
}}
|
|
137
|
-
/>
|
|
138
|
-
<Action
|
|
139
|
-
title='Configure Command'
|
|
140
|
-
onAction={() => {
|
|
141
|
-
push(
|
|
142
|
-
<ExtensionPreferences
|
|
143
|
-
extensionName={item.extensionName}
|
|
144
|
-
commandName={item.command.name}
|
|
145
|
-
onSubmit={() => {
|
|
146
|
-
handleCommandSelect(item)
|
|
147
|
-
}}
|
|
148
|
-
/>,
|
|
149
|
-
)
|
|
150
|
-
}}
|
|
151
|
-
/>
|
|
152
|
-
{item.bundledPath && (
|
|
153
|
-
<Action.CopyToClipboard
|
|
154
|
-
content={item.bundledPath}
|
|
155
|
-
title='Copy Bundle Path'
|
|
156
|
-
/>
|
|
157
|
-
)}
|
|
158
|
-
<Action.CopyToClipboard
|
|
159
|
-
content={JSON.stringify(item.command, null, 2)}
|
|
160
|
-
title='Copy Command Info'
|
|
161
|
-
/>
|
|
162
|
-
</ActionPanel>
|
|
163
|
-
}
|
|
164
|
-
/>
|
|
165
|
-
))}
|
|
166
|
-
</List.Section>
|
|
167
|
-
),
|
|
168
|
-
)}
|
|
169
|
-
|
|
170
|
-
{allCommands.length === 0 && (
|
|
171
|
-
<List.Section title='No Commands'>
|
|
172
|
-
<List.Item
|
|
173
|
-
title='No extensions installed'
|
|
174
|
-
subtitle='Use "termcast build" to install an extension'
|
|
175
|
-
/>
|
|
176
|
-
</List.Section>
|
|
177
|
-
)}
|
|
178
|
-
</List>
|
|
179
|
-
)
|
|
180
|
-
}
|
|
181
|
-
|
|
182
|
-
export async function runHomeCommand(): Promise<void> {
|
|
183
|
-
logger.log(`preparing to render the home command component`)
|
|
184
|
-
await renderWithProviders(<Home />, { extensionName: 'termcast-home' })
|
|
185
|
-
logger.log(`rendered home command component`)
|
|
186
|
-
}
|
|
187
|
-
|
|
188
|
-
export default function Home({
|
|
189
|
-
initialSearchQuery = '',
|
|
190
|
-
key,
|
|
191
|
-
}: {
|
|
192
|
-
initialSearchQuery?: string
|
|
193
|
-
key?: React.Key
|
|
194
|
-
}): any {
|
|
195
|
-
const storedExtensions = getStoredExtensions()
|
|
196
|
-
|
|
197
|
-
const allCommands: ExtensionCommand[] = []
|
|
198
|
-
|
|
199
|
-
allCommands.push(...builtinExtensions)
|
|
200
|
-
|
|
201
|
-
for (const extension of storedExtensions) {
|
|
202
|
-
const packageJson = JSON.parse(
|
|
203
|
-
fs.readFileSync(extension.packageJsonPath, 'utf-8'),
|
|
204
|
-
)
|
|
205
|
-
const extensionPath = path.dirname(extension.packageJsonPath)
|
|
206
|
-
|
|
207
|
-
for (const command of extension.commands) {
|
|
208
|
-
if (command.bundledPath) {
|
|
209
|
-
allCommands.push({
|
|
210
|
-
extensionName: extension.name,
|
|
211
|
-
extensionTitle: packageJson.title || extension.name,
|
|
212
|
-
extensionDir: extensionPath,
|
|
213
|
-
command,
|
|
214
|
-
bundledPath: command.bundledPath,
|
|
215
|
-
packageJson,
|
|
216
|
-
})
|
|
217
|
-
}
|
|
218
|
-
}
|
|
219
|
-
}
|
|
220
|
-
|
|
221
|
-
return (
|
|
222
|
-
<ExtensionsList
|
|
223
|
-
allCommands={allCommands}
|
|
224
|
-
initialSearchQuery={initialSearchQuery}
|
|
225
|
-
/>
|
|
226
|
-
)
|
|
227
|
-
}
|