@orderful/droid 0.39.0 → 0.40.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/CHANGELOG.md +18 -0
- package/bun.lock +73 -0
- package/dist/bin/droid.js +900 -386
- package/dist/commands/integrations.d.ts +10 -0
- package/dist/commands/integrations.d.ts.map +1 -0
- package/dist/commands/tui/components/IntegrationsDetails.d.ts +6 -0
- package/dist/commands/tui/components/IntegrationsDetails.d.ts.map +1 -0
- package/dist/commands/tui/components/Markdown.d.ts.map +1 -1
- package/dist/commands/tui/types.d.ts +1 -1
- package/dist/commands/tui/types.d.ts.map +1 -1
- package/dist/commands/tui.d.ts.map +1 -1
- package/dist/index.js +29 -1
- package/dist/integrations/slack/index.d.ts +42 -0
- package/dist/integrations/slack/index.d.ts.map +1 -0
- package/dist/integrations/slack/index.ts +148 -0
- package/dist/integrations/slack/references/setup.md +53 -0
- package/dist/lib/config.d.ts.map +1 -1
- package/dist/lib/types.d.ts +9 -0
- package/dist/lib/types.d.ts.map +1 -1
- package/dist/tools/status-update/.claude-plugin/plugin.json +1 -1
- package/dist/tools/status-update/TOOL.yaml +2 -6
- package/dist/tools/status-update/skills/status-update/SKILL.md +14 -26
- package/dist/tools/tech-design/skills/tech-design/SKILL.md +47 -10
- package/dist/tools/tech-design/skills/tech-design/references/draft.md +8 -0
- package/dist/tools/tech-design/skills/tech-design/references/publish.md +164 -48
- package/dist/tools/tech-design/skills/tech-design/references/summary-template.md +94 -0
- package/package.json +2 -1
- package/scripts/build.ts +4 -0
- package/src/bin/droid.ts +27 -13
- package/src/commands/integrations.ts +434 -0
- package/src/commands/tui/components/IntegrationsDetails.tsx +95 -0
- package/src/commands/tui/components/Markdown.tsx +68 -3
- package/src/commands/tui/types.ts +1 -1
- package/src/commands/tui.tsx +81 -1
- package/src/integrations/slack/index.ts +148 -0
- package/src/integrations/slack/references/setup.md +53 -0
- package/src/lib/config.ts +49 -1
- package/src/lib/types.ts +11 -0
- package/src/tools/status-update/.claude-plugin/plugin.json +1 -1
- package/src/tools/status-update/TOOL.yaml +2 -6
- package/src/tools/status-update/skills/status-update/SKILL.md +14 -26
- package/src/tools/tech-design/skills/tech-design/SKILL.md +47 -10
- package/src/tools/tech-design/skills/tech-design/references/draft.md +8 -0
- package/src/tools/tech-design/skills/tech-design/references/publish.md +164 -48
- package/src/tools/tech-design/skills/tech-design/references/summary-template.md +94 -0
- package/dist/commands/auth.d.ts +0 -3
- package/dist/commands/auth.d.ts.map +0 -1
- package/dist/lib/secrets.d.ts +0 -7
- package/dist/lib/secrets.d.ts.map +0 -1
- package/src/commands/auth.ts +0 -150
- package/src/lib/secrets.ts +0 -12
package/dist/bin/droid.js
CHANGED
|
@@ -1,4 +1,10 @@
|
|
|
1
1
|
#!/usr/bin/env node
|
|
2
|
+
var __require = /* @__PURE__ */ ((x) => typeof require !== "undefined" ? require : typeof Proxy !== "undefined" ? new Proxy(x, {
|
|
3
|
+
get: (a, b) => (typeof require !== "undefined" ? require : a)[b]
|
|
4
|
+
}) : x)(function(x) {
|
|
5
|
+
if (typeof require !== "undefined") return require.apply(this, arguments);
|
|
6
|
+
throw Error('Dynamic require of "' + x + '" is not supported');
|
|
7
|
+
});
|
|
2
8
|
|
|
3
9
|
// src/bin/droid.ts
|
|
4
10
|
import { program } from "commander";
|
|
@@ -123,6 +129,33 @@ function migrateToolConfigs(config) {
|
|
|
123
129
|
return false;
|
|
124
130
|
}
|
|
125
131
|
}
|
|
132
|
+
function migrateIntegrations(config) {
|
|
133
|
+
if (config.migrations?.integrations_consolidated) {
|
|
134
|
+
return false;
|
|
135
|
+
}
|
|
136
|
+
const statusUpdateConfig = config.tools?.["status-update"];
|
|
137
|
+
if (statusUpdateConfig && "default_crosspost_channel" in statusUpdateConfig) {
|
|
138
|
+
const channel = statusUpdateConfig.default_crosspost_channel;
|
|
139
|
+
if (!config.integrations) {
|
|
140
|
+
config.integrations = {};
|
|
141
|
+
}
|
|
142
|
+
if (!config.integrations.slack) {
|
|
143
|
+
config.integrations.slack = {};
|
|
144
|
+
}
|
|
145
|
+
if (!config.integrations.slack.crosspost_channel && channel) {
|
|
146
|
+
config.integrations.slack.crosspost_channel = channel;
|
|
147
|
+
}
|
|
148
|
+
delete statusUpdateConfig.default_crosspost_channel;
|
|
149
|
+
if (Object.keys(statusUpdateConfig).length === 0) {
|
|
150
|
+
delete config.tools["status-update"];
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
if (!config.migrations) {
|
|
154
|
+
config.migrations = {};
|
|
155
|
+
}
|
|
156
|
+
config.migrations.integrations_consolidated = true;
|
|
157
|
+
return true;
|
|
158
|
+
}
|
|
126
159
|
function ensureConfigDir() {
|
|
127
160
|
if (!existsSync(CONFIG_DIR)) {
|
|
128
161
|
mkdirSync(CONFIG_DIR, { recursive: true });
|
|
@@ -142,7 +175,8 @@ function loadConfig() {
|
|
|
142
175
|
const needsLegacyMigration = "ai_tool" in rawConfig && !("platform" in rawConfig);
|
|
143
176
|
const config = migrateConfig(rawConfig);
|
|
144
177
|
const needsToolMigration = migrateToolConfigs(config);
|
|
145
|
-
|
|
178
|
+
const needsIntegrationsMigration = migrateIntegrations(config);
|
|
179
|
+
if (needsLegacyMigration || needsToolMigration || needsIntegrationsMigration) {
|
|
146
180
|
saveConfig(config);
|
|
147
181
|
}
|
|
148
182
|
return config;
|
|
@@ -2502,8 +2536,12 @@ async function updateCommand(tool, options) {
|
|
|
2502
2536
|
}
|
|
2503
2537
|
|
|
2504
2538
|
// src/commands/tui.tsx
|
|
2505
|
-
import { render, Box as
|
|
2539
|
+
import { render, Box as Box16, Text as Text17, useInput as useInput9, useApp as useApp2 } from "ink";
|
|
2506
2540
|
import { useState as useState10, useEffect } from "react";
|
|
2541
|
+
import { readFileSync as readFileSync9 } from "fs";
|
|
2542
|
+
import { spawnSync as spawnSync3 } from "child_process";
|
|
2543
|
+
import { join as join11, dirname as dirname7 } from "path";
|
|
2544
|
+
import { fileURLToPath as fileURLToPath5 } from "url";
|
|
2507
2545
|
|
|
2508
2546
|
// src/commands/tui/constants.ts
|
|
2509
2547
|
var colors = {
|
|
@@ -2786,9 +2824,78 @@ function SettingsDetails({
|
|
|
2786
2824
|
] });
|
|
2787
2825
|
}
|
|
2788
2826
|
|
|
2789
|
-
// src/commands/tui/components/
|
|
2827
|
+
// src/commands/tui/components/IntegrationsDetails.tsx
|
|
2790
2828
|
import { Box as Box6, Text as Text6 } from "ink";
|
|
2791
2829
|
import { jsx as jsx6, jsxs as jsxs6 } from "react/jsx-runtime";
|
|
2830
|
+
function IntegrationsDetails({
|
|
2831
|
+
isFocused,
|
|
2832
|
+
selectedAction
|
|
2833
|
+
}) {
|
|
2834
|
+
const hasToken = !!process.env.SLACK_USER_TOKEN;
|
|
2835
|
+
const hasClientId = !!process.env.SLACK_CLIENT_ID;
|
|
2836
|
+
const hasClientSecret = !!process.env.SLACK_CLIENT_SECRET;
|
|
2837
|
+
const isConnected = hasToken;
|
|
2838
|
+
const canSetup = hasClientId && hasClientSecret;
|
|
2839
|
+
const guideActionIndex = canSetup && !isConnected ? 1 : 0;
|
|
2840
|
+
return /* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", paddingLeft: 2, flexGrow: 1, children: [
|
|
2841
|
+
/* @__PURE__ */ jsx6(Text6, { color: colors.text, bold: true, children: "Slack" }),
|
|
2842
|
+
/* @__PURE__ */ jsxs6(Box6, { flexDirection: "column", marginTop: 1, children: [
|
|
2843
|
+
/* @__PURE__ */ jsx6(Text6, { color: colors.textDim, bold: true, children: "Credentials" }),
|
|
2844
|
+
/* @__PURE__ */ jsxs6(Text6, { children: [
|
|
2845
|
+
/* @__PURE__ */ jsx6(Text6, { color: colors.textDim, children: " SLACK_CLIENT_ID " }),
|
|
2846
|
+
/* @__PURE__ */ jsx6(Text6, { color: hasClientId ? colors.success : "#fbbf24", children: hasClientId ? "\u2713" : "\u2717" })
|
|
2847
|
+
] }),
|
|
2848
|
+
/* @__PURE__ */ jsxs6(Text6, { children: [
|
|
2849
|
+
/* @__PURE__ */ jsx6(Text6, { color: colors.textDim, children: " SLACK_CLIENT_SECRET " }),
|
|
2850
|
+
/* @__PURE__ */ jsx6(Text6, { color: hasClientSecret ? colors.success : "#fbbf24", children: hasClientSecret ? "\u2713" : "\u2717" })
|
|
2851
|
+
] }),
|
|
2852
|
+
/* @__PURE__ */ jsxs6(Text6, { children: [
|
|
2853
|
+
/* @__PURE__ */ jsx6(Text6, { color: colors.textDim, children: " SLACK_USER_TOKEN " }),
|
|
2854
|
+
/* @__PURE__ */ jsx6(Text6, { color: hasToken ? colors.success : "#fbbf24", children: hasToken ? "\u2713" : "\u2717" })
|
|
2855
|
+
] })
|
|
2856
|
+
] }),
|
|
2857
|
+
/* @__PURE__ */ jsx6(Box6, { flexDirection: "column", marginTop: 1, children: /* @__PURE__ */ jsx6(Text6, { children: isConnected ? /* @__PURE__ */ jsx6(Text6, { color: colors.success, children: "Connected" }) : hasClientId && hasClientSecret ? /* @__PURE__ */ jsx6(Text6, { color: "#fbbf24", children: "Ready to connect" }) : /* @__PURE__ */ jsx6(Text6, { color: "#fbbf24", children: "Not configured" }) }) }),
|
|
2858
|
+
!isConnected && !canSetup && /* @__PURE__ */ jsx6(Box6, { marginTop: 1, children: /* @__PURE__ */ jsx6(Text6, { color: colors.textDim, children: "Add SLACK_CLIENT_ID and SLACK_CLIENT_SECRET to your shell rc first" }) }),
|
|
2859
|
+
isFocused && /* @__PURE__ */ jsxs6(Box6, { marginTop: 2, flexDirection: "row", gap: 2, children: [
|
|
2860
|
+
canSetup && !isConnected && /* @__PURE__ */ jsxs6(
|
|
2861
|
+
Text6,
|
|
2862
|
+
{
|
|
2863
|
+
backgroundColor: selectedAction === 0 ? colors.primary : void 0,
|
|
2864
|
+
color: selectedAction === 0 ? "#ffffff" : colors.textDim,
|
|
2865
|
+
bold: selectedAction === 0,
|
|
2866
|
+
children: [
|
|
2867
|
+
" ",
|
|
2868
|
+
"Run Setup",
|
|
2869
|
+
" "
|
|
2870
|
+
]
|
|
2871
|
+
}
|
|
2872
|
+
),
|
|
2873
|
+
/* @__PURE__ */ jsxs6(
|
|
2874
|
+
Text6,
|
|
2875
|
+
{
|
|
2876
|
+
backgroundColor: selectedAction === guideActionIndex ? colors.primary : void 0,
|
|
2877
|
+
color: selectedAction === guideActionIndex ? "#ffffff" : colors.textDim,
|
|
2878
|
+
bold: selectedAction === guideActionIndex,
|
|
2879
|
+
children: [
|
|
2880
|
+
" ",
|
|
2881
|
+
"Setup Guide",
|
|
2882
|
+
" "
|
|
2883
|
+
]
|
|
2884
|
+
}
|
|
2885
|
+
)
|
|
2886
|
+
] }),
|
|
2887
|
+
isFocused && /* @__PURE__ */ jsx6(Box6, { marginTop: 1, children: /* @__PURE__ */ jsxs6(Text6, { color: colors.textDim, children: [
|
|
2888
|
+
"enter confirm ",
|
|
2889
|
+
"\xB7",
|
|
2890
|
+
" esc back"
|
|
2891
|
+
] }) }),
|
|
2892
|
+
!isFocused && /* @__PURE__ */ jsx6(Box6, { marginTop: 2, children: /* @__PURE__ */ jsx6(Text6, { color: colors.textDim, children: "press enter for options" }) })
|
|
2893
|
+
] });
|
|
2894
|
+
}
|
|
2895
|
+
|
|
2896
|
+
// src/commands/tui/components/PlatformBadges.tsx
|
|
2897
|
+
import { Box as Box7, Text as Text7 } from "ink";
|
|
2898
|
+
import { jsx as jsx7, jsxs as jsxs7 } from "react/jsx-runtime";
|
|
2792
2899
|
var PLATFORM_INFO = {
|
|
2793
2900
|
["claude-code" /* ClaudeCode */]: { color: "#da7756", label: "Claude" },
|
|
2794
2901
|
["cursor" /* Cursor */]: { color: "#22d3ee", label: "Cursor" },
|
|
@@ -2801,19 +2908,19 @@ function PlatformBadges({
|
|
|
2801
2908
|
}) {
|
|
2802
2909
|
const active = detected.filter((p) => !ignored.includes(p));
|
|
2803
2910
|
if (active.length === 0) {
|
|
2804
|
-
return /* @__PURE__ */
|
|
2911
|
+
return /* @__PURE__ */ jsx7(Text7, { color: "#6a6a6a", children: "No platforms detected" });
|
|
2805
2912
|
}
|
|
2806
|
-
return /* @__PURE__ */
|
|
2913
|
+
return /* @__PURE__ */ jsx7(Box7, { children: active.map((p, i) => {
|
|
2807
2914
|
const info = PLATFORM_INFO[p];
|
|
2808
|
-
return /* @__PURE__ */
|
|
2809
|
-
/* @__PURE__ */
|
|
2810
|
-
i < active.length - 1 && /* @__PURE__ */
|
|
2915
|
+
return /* @__PURE__ */ jsxs7(Text7, { children: [
|
|
2916
|
+
/* @__PURE__ */ jsx7(Text7, { color: info.color, children: info.label }),
|
|
2917
|
+
i < active.length - 1 && /* @__PURE__ */ jsx7(Text7, { color: "#6a6a6a", children: " \xB7 " })
|
|
2811
2918
|
] }, p);
|
|
2812
2919
|
}) });
|
|
2813
2920
|
}
|
|
2814
2921
|
|
|
2815
2922
|
// src/commands/tui/views/WelcomeScreen.tsx
|
|
2816
|
-
import { Box as
|
|
2923
|
+
import { Box as Box8, Text as Text8, useInput } from "ink";
|
|
2817
2924
|
import { useState, useMemo } from "react";
|
|
2818
2925
|
|
|
2819
2926
|
// src/lib/quotes.ts
|
|
@@ -2834,7 +2941,7 @@ function getRandomQuote() {
|
|
|
2834
2941
|
}
|
|
2835
2942
|
|
|
2836
2943
|
// src/commands/tui/views/WelcomeScreen.tsx
|
|
2837
|
-
import { Fragment, jsx as
|
|
2944
|
+
import { Fragment, jsx as jsx8, jsxs as jsxs8 } from "react/jsx-runtime";
|
|
2838
2945
|
function WelcomeScreen({ onContinue, onUpdate, onAlways, onExit, updateInfo, isUpdating }) {
|
|
2839
2946
|
const [selectedButton, setSelectedButton] = useState(0);
|
|
2840
2947
|
const welcomeQuote = useMemo(() => getRandomQuote(), []);
|
|
@@ -2869,8 +2976,8 @@ function WelcomeScreen({ onContinue, onUpdate, onAlways, onExit, updateInfo, isU
|
|
|
2869
2976
|
}
|
|
2870
2977
|
});
|
|
2871
2978
|
const hasUpdate = updateInfo.hasUpdate && updateInfo.latestVersion;
|
|
2872
|
-
return /* @__PURE__ */
|
|
2873
|
-
|
|
2979
|
+
return /* @__PURE__ */ jsx8(Box8, { flexDirection: "column", alignItems: "center", justifyContent: "center", height: 18, children: /* @__PURE__ */ jsxs8(
|
|
2980
|
+
Box8,
|
|
2874
2981
|
{
|
|
2875
2982
|
flexDirection: "column",
|
|
2876
2983
|
alignItems: "center",
|
|
@@ -2879,42 +2986,42 @@ function WelcomeScreen({ onContinue, onUpdate, onAlways, onExit, updateInfo, isU
|
|
|
2879
2986
|
paddingX: 4,
|
|
2880
2987
|
paddingY: 1,
|
|
2881
2988
|
children: [
|
|
2882
|
-
/* @__PURE__ */
|
|
2883
|
-
/* @__PURE__ */
|
|
2884
|
-
/* @__PURE__ */
|
|
2885
|
-
/* @__PURE__ */
|
|
2886
|
-
/* @__PURE__ */
|
|
2989
|
+
/* @__PURE__ */ jsxs8(Box8, { flexDirection: "column", children: [
|
|
2990
|
+
/* @__PURE__ */ jsxs8(Text8, { children: [
|
|
2991
|
+
/* @__PURE__ */ jsx8(Text8, { color: colors.textDim, children: "\u2554\u2550\u2550\u2550\u2550\u2550\u2557 " }),
|
|
2992
|
+
/* @__PURE__ */ jsx8(Text8, { color: colors.text, children: "droid" }),
|
|
2993
|
+
/* @__PURE__ */ jsxs8(Text8, { color: colors.textDim, children: [
|
|
2887
2994
|
" v",
|
|
2888
2995
|
updateInfo.currentVersion
|
|
2889
2996
|
] })
|
|
2890
2997
|
] }),
|
|
2891
|
-
/* @__PURE__ */
|
|
2892
|
-
/* @__PURE__ */
|
|
2893
|
-
/* @__PURE__ */
|
|
2894
|
-
/* @__PURE__ */
|
|
2895
|
-
/* @__PURE__ */
|
|
2896
|
-
/* @__PURE__ */
|
|
2897
|
-
/* @__PURE__ */
|
|
2998
|
+
/* @__PURE__ */ jsxs8(Text8, { children: [
|
|
2999
|
+
/* @__PURE__ */ jsx8(Text8, { color: colors.textDim, children: "\u2551 " }),
|
|
3000
|
+
/* @__PURE__ */ jsx8(Text8, { color: hasUpdate ? "#eab308" : colors.primary, children: "\u25CF" }),
|
|
3001
|
+
/* @__PURE__ */ jsx8(Text8, { color: colors.textDim, children: " " }),
|
|
3002
|
+
/* @__PURE__ */ jsx8(Text8, { color: hasUpdate ? "#eab308" : colors.primary, children: "\u25CF" }),
|
|
3003
|
+
/* @__PURE__ */ jsx8(Text8, { color: colors.textDim, children: " \u2551 " }),
|
|
3004
|
+
/* @__PURE__ */ jsx8(Text8, { color: colors.textMuted, children: "Droid, teaching your AI new tricks" })
|
|
2898
3005
|
] }),
|
|
2899
|
-
/* @__PURE__ */
|
|
2900
|
-
/* @__PURE__ */
|
|
2901
|
-
/* @__PURE__ */
|
|
3006
|
+
/* @__PURE__ */ jsxs8(Text8, { children: [
|
|
3007
|
+
/* @__PURE__ */ jsx8(Text8, { color: colors.textDim, children: "\u255A\u2550\u2566\u2550\u2566\u2550\u255D " }),
|
|
3008
|
+
/* @__PURE__ */ jsx8(Text8, { color: colors.textDim, children: "github.com/Orderful/droid" })
|
|
2902
3009
|
] })
|
|
2903
3010
|
] }),
|
|
2904
|
-
hasUpdate ? /* @__PURE__ */
|
|
2905
|
-
/* @__PURE__ */
|
|
2906
|
-
/* @__PURE__ */
|
|
2907
|
-
/* @__PURE__ */
|
|
3011
|
+
hasUpdate ? /* @__PURE__ */ jsxs8(Fragment, { children: [
|
|
3012
|
+
/* @__PURE__ */ jsxs8(Box8, { marginTop: 2, marginBottom: 1, flexDirection: "column", alignItems: "center", children: [
|
|
3013
|
+
/* @__PURE__ */ jsx8(Text8, { color: "#eab308", italic: true, children: '"The odds of functioning optimally without this' }),
|
|
3014
|
+
/* @__PURE__ */ jsx8(Text8, { color: "#eab308", italic: true, children: 'update are approximately 3,720 to 1."' })
|
|
2908
3015
|
] }),
|
|
2909
|
-
/* @__PURE__ */
|
|
3016
|
+
/* @__PURE__ */ jsx8(Box8, { marginBottom: 1, children: /* @__PURE__ */ jsxs8(Text8, { color: colors.textMuted, children: [
|
|
2910
3017
|
"v",
|
|
2911
3018
|
updateInfo.currentVersion,
|
|
2912
3019
|
" \u2192 v",
|
|
2913
3020
|
updateInfo.latestVersion
|
|
2914
3021
|
] }) }),
|
|
2915
|
-
isUpdating ? /* @__PURE__ */
|
|
2916
|
-
/* @__PURE__ */
|
|
2917
|
-
|
|
3022
|
+
isUpdating ? /* @__PURE__ */ jsx8(Text8, { color: "#eab308", children: "Updating..." }) : /* @__PURE__ */ jsxs8(Box8, { flexDirection: "row", children: [
|
|
3023
|
+
/* @__PURE__ */ jsxs8(
|
|
3024
|
+
Text8,
|
|
2918
3025
|
{
|
|
2919
3026
|
backgroundColor: selectedButton === 0 ? "#eab308" : colors.bgSelected,
|
|
2920
3027
|
color: selectedButton === 0 ? "#000000" : colors.textMuted,
|
|
@@ -2926,9 +3033,9 @@ function WelcomeScreen({ onContinue, onUpdate, onAlways, onExit, updateInfo, isU
|
|
|
2926
3033
|
]
|
|
2927
3034
|
}
|
|
2928
3035
|
),
|
|
2929
|
-
/* @__PURE__ */
|
|
2930
|
-
/* @__PURE__ */
|
|
2931
|
-
|
|
3036
|
+
/* @__PURE__ */ jsx8(Text8, { children: " " }),
|
|
3037
|
+
/* @__PURE__ */ jsxs8(
|
|
3038
|
+
Text8,
|
|
2932
3039
|
{
|
|
2933
3040
|
backgroundColor: selectedButton === 1 ? "#eab308" : colors.bgSelected,
|
|
2934
3041
|
color: selectedButton === 1 ? "#000000" : colors.textMuted,
|
|
@@ -2940,9 +3047,9 @@ function WelcomeScreen({ onContinue, onUpdate, onAlways, onExit, updateInfo, isU
|
|
|
2940
3047
|
]
|
|
2941
3048
|
}
|
|
2942
3049
|
),
|
|
2943
|
-
/* @__PURE__ */
|
|
2944
|
-
/* @__PURE__ */
|
|
2945
|
-
|
|
3050
|
+
/* @__PURE__ */ jsx8(Text8, { children: " " }),
|
|
3051
|
+
/* @__PURE__ */ jsxs8(
|
|
3052
|
+
Text8,
|
|
2946
3053
|
{
|
|
2947
3054
|
backgroundColor: selectedButton === 2 ? colors.bgSelected : void 0,
|
|
2948
3055
|
color: selectedButton === 2 ? colors.text : colors.textMuted,
|
|
@@ -2955,10 +3062,10 @@ function WelcomeScreen({ onContinue, onUpdate, onAlways, onExit, updateInfo, isU
|
|
|
2955
3062
|
}
|
|
2956
3063
|
)
|
|
2957
3064
|
] }),
|
|
2958
|
-
/* @__PURE__ */
|
|
2959
|
-
] }) : /* @__PURE__ */
|
|
2960
|
-
/* @__PURE__ */
|
|
2961
|
-
/* @__PURE__ */
|
|
3065
|
+
/* @__PURE__ */ jsx8(Box8, { marginTop: 1, children: /* @__PURE__ */ jsx8(Text8, { color: colors.textDim, children: '\u2190\u2192 select \xB7 enter \xB7 "Always" enables auto-update' }) })
|
|
3066
|
+
] }) : /* @__PURE__ */ jsxs8(Fragment, { children: [
|
|
3067
|
+
/* @__PURE__ */ jsx8(Box8, { marginTop: 2, marginBottom: 1, children: /* @__PURE__ */ jsx8(Text8, { backgroundColor: colors.primary, color: "#ffffff", bold: true, children: ` ${welcomeQuote} ` }) }),
|
|
3068
|
+
/* @__PURE__ */ jsx8(Text8, { color: colors.textDim, children: "press enter" })
|
|
2962
3069
|
] })
|
|
2963
3070
|
]
|
|
2964
3071
|
}
|
|
@@ -2966,9 +3073,9 @@ function WelcomeScreen({ onContinue, onUpdate, onAlways, onExit, updateInfo, isU
|
|
|
2966
3073
|
}
|
|
2967
3074
|
|
|
2968
3075
|
// src/commands/tui/views/ToolUpdatePrompt.tsx
|
|
2969
|
-
import { Box as
|
|
3076
|
+
import { Box as Box9, Text as Text9, useInput as useInput2 } from "ink";
|
|
2970
3077
|
import { useState as useState2 } from "react";
|
|
2971
|
-
import { jsx as
|
|
3078
|
+
import { jsx as jsx9, jsxs as jsxs9 } from "react/jsx-runtime";
|
|
2972
3079
|
function ToolUpdatePrompt({ toolUpdates, onUpdateAll, onAlways, onSkip, isUpdating }) {
|
|
2973
3080
|
const [selectedButton, setSelectedButton] = useState2(0);
|
|
2974
3081
|
useInput2((input, key) => {
|
|
@@ -2997,8 +3104,8 @@ function ToolUpdatePrompt({ toolUpdates, onUpdateAll, onAlways, onSkip, isUpdati
|
|
|
2997
3104
|
{ label: "Always", action: onAlways },
|
|
2998
3105
|
{ label: "Skip", action: onSkip }
|
|
2999
3106
|
];
|
|
3000
|
-
return /* @__PURE__ */
|
|
3001
|
-
|
|
3107
|
+
return /* @__PURE__ */ jsx9(Box9, { flexDirection: "column", alignItems: "center", justifyContent: "center", height: 18, children: /* @__PURE__ */ jsxs9(
|
|
3108
|
+
Box9,
|
|
3002
3109
|
{
|
|
3003
3110
|
flexDirection: "column",
|
|
3004
3111
|
alignItems: "center",
|
|
@@ -3007,46 +3114,46 @@ function ToolUpdatePrompt({ toolUpdates, onUpdateAll, onAlways, onSkip, isUpdati
|
|
|
3007
3114
|
paddingX: 4,
|
|
3008
3115
|
paddingY: 1,
|
|
3009
3116
|
children: [
|
|
3010
|
-
/* @__PURE__ */
|
|
3011
|
-
/* @__PURE__ */
|
|
3012
|
-
/* @__PURE__ */
|
|
3013
|
-
/* @__PURE__ */
|
|
3117
|
+
/* @__PURE__ */ jsxs9(Box9, { flexDirection: "column", children: [
|
|
3118
|
+
/* @__PURE__ */ jsxs9(Text9, { children: [
|
|
3119
|
+
/* @__PURE__ */ jsx9(Text9, { color: colors.textDim, children: "\u2554\u2550\u2550\u2550\u2550\u2550\u2557 " }),
|
|
3120
|
+
/* @__PURE__ */ jsx9(Text9, { color: colors.text, children: "Tool Updates" })
|
|
3014
3121
|
] }),
|
|
3015
|
-
/* @__PURE__ */
|
|
3016
|
-
/* @__PURE__ */
|
|
3017
|
-
/* @__PURE__ */
|
|
3018
|
-
/* @__PURE__ */
|
|
3019
|
-
/* @__PURE__ */
|
|
3020
|
-
/* @__PURE__ */
|
|
3021
|
-
/* @__PURE__ */
|
|
3122
|
+
/* @__PURE__ */ jsxs9(Text9, { children: [
|
|
3123
|
+
/* @__PURE__ */ jsx9(Text9, { color: colors.textDim, children: "\u2551 " }),
|
|
3124
|
+
/* @__PURE__ */ jsx9(Text9, { color: colors.primary, children: "\u25CF" }),
|
|
3125
|
+
/* @__PURE__ */ jsx9(Text9, { color: colors.textDim, children: " " }),
|
|
3126
|
+
/* @__PURE__ */ jsx9(Text9, { color: colors.primary, children: "\u25CF" }),
|
|
3127
|
+
/* @__PURE__ */ jsx9(Text9, { color: colors.textDim, children: " \u2551 " }),
|
|
3128
|
+
/* @__PURE__ */ jsxs9(Text9, { color: colors.textMuted, children: [
|
|
3022
3129
|
toolUpdates.length,
|
|
3023
3130
|
" tool",
|
|
3024
3131
|
toolUpdates.length > 1 ? "s have" : " has",
|
|
3025
3132
|
" updates available"
|
|
3026
3133
|
] })
|
|
3027
3134
|
] }),
|
|
3028
|
-
/* @__PURE__ */
|
|
3135
|
+
/* @__PURE__ */ jsx9(Text9, { children: /* @__PURE__ */ jsx9(Text9, { color: colors.textDim, children: "\u255A\u2550\u2566\u2550\u2566\u2550\u255D" }) })
|
|
3029
3136
|
] }),
|
|
3030
|
-
/* @__PURE__ */
|
|
3031
|
-
toolUpdates.slice(0, 5).map((tool) => /* @__PURE__ */
|
|
3032
|
-
/* @__PURE__ */
|
|
3137
|
+
/* @__PURE__ */ jsxs9(Box9, { marginTop: 1, marginBottom: 1, flexDirection: "column", children: [
|
|
3138
|
+
toolUpdates.slice(0, 5).map((tool) => /* @__PURE__ */ jsxs9(Text9, { color: colors.textMuted, children: [
|
|
3139
|
+
/* @__PURE__ */ jsx9(Text9, { color: colors.primary, children: "\u2191" }),
|
|
3033
3140
|
" ",
|
|
3034
3141
|
tool.name,
|
|
3035
|
-
/* @__PURE__ */
|
|
3142
|
+
/* @__PURE__ */ jsxs9(Text9, { color: colors.textDim, children: [
|
|
3036
3143
|
" ",
|
|
3037
3144
|
tool.installedVersion,
|
|
3038
3145
|
" \u2192 ",
|
|
3039
3146
|
tool.bundledVersion
|
|
3040
3147
|
] })
|
|
3041
3148
|
] }, tool.name)),
|
|
3042
|
-
toolUpdates.length > 5 && /* @__PURE__ */
|
|
3149
|
+
toolUpdates.length > 5 && /* @__PURE__ */ jsxs9(Text9, { color: colors.textDim, children: [
|
|
3043
3150
|
"...and ",
|
|
3044
3151
|
toolUpdates.length - 5,
|
|
3045
3152
|
" more"
|
|
3046
3153
|
] })
|
|
3047
3154
|
] }),
|
|
3048
|
-
isUpdating ? /* @__PURE__ */
|
|
3049
|
-
|
|
3155
|
+
isUpdating ? /* @__PURE__ */ jsx9(Text9, { color: colors.primary, children: "Updating tools..." }) : /* @__PURE__ */ jsx9(Box9, { flexDirection: "row", children: buttons.map((button, index) => /* @__PURE__ */ jsxs9(
|
|
3156
|
+
Text9,
|
|
3050
3157
|
{
|
|
3051
3158
|
backgroundColor: selectedButton === index ? colors.primary : colors.bgSelected,
|
|
3052
3159
|
color: selectedButton === index ? "#000000" : colors.textMuted,
|
|
@@ -3059,17 +3166,17 @@ function ToolUpdatePrompt({ toolUpdates, onUpdateAll, onAlways, onSkip, isUpdati
|
|
|
3059
3166
|
},
|
|
3060
3167
|
button.label
|
|
3061
3168
|
)) }),
|
|
3062
|
-
/* @__PURE__ */
|
|
3169
|
+
/* @__PURE__ */ jsx9(Box9, { marginTop: 1, children: /* @__PURE__ */ jsx9(Text9, { color: colors.textDim, children: '\u2190\u2192 select \xB7 enter \xB7 "Always" enables auto-update' }) })
|
|
3063
3170
|
]
|
|
3064
3171
|
}
|
|
3065
3172
|
) });
|
|
3066
3173
|
}
|
|
3067
3174
|
|
|
3068
3175
|
// src/commands/tui/views/SetupScreen.tsx
|
|
3069
|
-
import { Box as
|
|
3176
|
+
import { Box as Box10, Text as Text10, useInput as useInput3 } from "ink";
|
|
3070
3177
|
import TextInput from "ink-text-input";
|
|
3071
3178
|
import { useState as useState3 } from "react";
|
|
3072
|
-
import { jsx as
|
|
3179
|
+
import { jsx as jsx10, jsxs as jsxs10 } from "react/jsx-runtime";
|
|
3073
3180
|
var PLATFORM_LABELS3 = {
|
|
3074
3181
|
["claude-code" /* ClaudeCode */]: "Claude Code",
|
|
3075
3182
|
["cursor" /* Cursor */]: "Cursor",
|
|
@@ -3147,14 +3254,14 @@ function SetupScreen({ onComplete, onSkip, initialConfig, detectedPlatforms }) {
|
|
|
3147
3254
|
}
|
|
3148
3255
|
}
|
|
3149
3256
|
}, { isActive: step !== "user_mention" });
|
|
3150
|
-
const renderHeader = () => /* @__PURE__ */
|
|
3151
|
-
/* @__PURE__ */
|
|
3152
|
-
/* @__PURE__ */
|
|
3153
|
-
/* @__PURE__ */
|
|
3154
|
-
/* @__PURE__ */
|
|
3155
|
-
/* @__PURE__ */
|
|
3156
|
-
/* @__PURE__ */
|
|
3157
|
-
/* @__PURE__ */
|
|
3257
|
+
const renderHeader = () => /* @__PURE__ */ jsx10(Box10, { flexDirection: "column", marginBottom: 1, children: /* @__PURE__ */ jsxs10(Text10, { children: [
|
|
3258
|
+
/* @__PURE__ */ jsx10(Text10, { color: colors.textDim, children: "[" }),
|
|
3259
|
+
/* @__PURE__ */ jsx10(Text10, { color: colors.primary, children: "\u25CF" }),
|
|
3260
|
+
/* @__PURE__ */ jsx10(Text10, { color: colors.textDim, children: " " }),
|
|
3261
|
+
/* @__PURE__ */ jsx10(Text10, { color: colors.primary, children: "\u25CF" }),
|
|
3262
|
+
/* @__PURE__ */ jsx10(Text10, { color: colors.textDim, children: "] " }),
|
|
3263
|
+
/* @__PURE__ */ jsx10(Text10, { color: colors.text, bold: true, children: "droid setup" }),
|
|
3264
|
+
/* @__PURE__ */ jsxs10(Text10, { color: colors.textDim, children: [
|
|
3158
3265
|
" \xB7 Step ",
|
|
3159
3266
|
Math.min(stepIndex + 1, totalSteps),
|
|
3160
3267
|
" of ",
|
|
@@ -3162,12 +3269,12 @@ function SetupScreen({ onComplete, onSkip, initialConfig, detectedPlatforms }) {
|
|
|
3162
3269
|
] })
|
|
3163
3270
|
] }) });
|
|
3164
3271
|
if (step === "user_mention") {
|
|
3165
|
-
return /* @__PURE__ */
|
|
3272
|
+
return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", padding: 1, children: [
|
|
3166
3273
|
renderHeader(),
|
|
3167
|
-
/* @__PURE__ */
|
|
3168
|
-
/* @__PURE__ */
|
|
3169
|
-
/* @__PURE__ */
|
|
3170
|
-
/* @__PURE__ */
|
|
3274
|
+
/* @__PURE__ */ jsx10(Text10, { color: colors.text, children: "What @mention should be used for you?" }),
|
|
3275
|
+
/* @__PURE__ */ jsxs10(Box10, { marginTop: 1, children: [
|
|
3276
|
+
/* @__PURE__ */ jsx10(Text10, { color: colors.textDim, children: "> " }),
|
|
3277
|
+
/* @__PURE__ */ jsx10(
|
|
3171
3278
|
TextInput,
|
|
3172
3279
|
{
|
|
3173
3280
|
value: userMention,
|
|
@@ -3177,42 +3284,42 @@ function SetupScreen({ onComplete, onSkip, initialConfig, detectedPlatforms }) {
|
|
|
3177
3284
|
}
|
|
3178
3285
|
)
|
|
3179
3286
|
] }),
|
|
3180
|
-
error && /* @__PURE__ */
|
|
3181
|
-
/* @__PURE__ */
|
|
3287
|
+
error && /* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx10(Text10, { color: colors.error, children: error }) }),
|
|
3288
|
+
/* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx10(Text10, { color: colors.textDim, children: "enter next \xB7 esc back" }) })
|
|
3182
3289
|
] });
|
|
3183
3290
|
}
|
|
3184
3291
|
if (step === "auto_update") {
|
|
3185
|
-
return /* @__PURE__ */
|
|
3292
|
+
return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", padding: 1, children: [
|
|
3186
3293
|
renderHeader(),
|
|
3187
|
-
/* @__PURE__ */
|
|
3188
|
-
/* @__PURE__ */
|
|
3189
|
-
/* @__PURE__ */
|
|
3190
|
-
/* @__PURE__ */
|
|
3294
|
+
/* @__PURE__ */ jsx10(Text10, { color: colors.text, children: "Configure auto-update behaviour" }),
|
|
3295
|
+
/* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", marginTop: 1, children: [
|
|
3296
|
+
/* @__PURE__ */ jsx10(Box10, { children: /* @__PURE__ */ jsxs10(Text10, { children: [
|
|
3297
|
+
/* @__PURE__ */ jsxs10(Text10, { color: colors.textDim, children: [
|
|
3191
3298
|
autoUpdateSelectedIndex === 0 ? ">" : " ",
|
|
3192
3299
|
" "
|
|
3193
3300
|
] }),
|
|
3194
|
-
/* @__PURE__ */
|
|
3301
|
+
/* @__PURE__ */ jsxs10(Text10, { color: autoUpdateSelectedIndex === 0 ? colors.text : colors.textMuted, children: [
|
|
3195
3302
|
"[",
|
|
3196
3303
|
autoUpdateTools ? "x" : " ",
|
|
3197
3304
|
"] Auto-update tools"
|
|
3198
3305
|
] })
|
|
3199
3306
|
] }) }),
|
|
3200
|
-
/* @__PURE__ */
|
|
3201
|
-
/* @__PURE__ */
|
|
3202
|
-
/* @__PURE__ */
|
|
3307
|
+
/* @__PURE__ */ jsx10(Text10, { color: colors.textDim, children: " Update tools automatically when droid starts" }),
|
|
3308
|
+
/* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsxs10(Text10, { children: [
|
|
3309
|
+
/* @__PURE__ */ jsxs10(Text10, { color: colors.textDim, children: [
|
|
3203
3310
|
autoUpdateSelectedIndex === 1 ? ">" : " ",
|
|
3204
3311
|
" "
|
|
3205
3312
|
] }),
|
|
3206
|
-
/* @__PURE__ */
|
|
3313
|
+
/* @__PURE__ */ jsxs10(Text10, { color: autoUpdateSelectedIndex === 1 ? colors.text : colors.textMuted, children: [
|
|
3207
3314
|
"[",
|
|
3208
3315
|
autoUpdateApp ? "x" : " ",
|
|
3209
3316
|
"] Auto-update app"
|
|
3210
3317
|
] })
|
|
3211
3318
|
] }) }),
|
|
3212
|
-
/* @__PURE__ */
|
|
3319
|
+
/* @__PURE__ */ jsx10(Text10, { color: colors.textDim, children: " Update droid automatically when a new version is available" })
|
|
3213
3320
|
] }),
|
|
3214
|
-
/* @__PURE__ */
|
|
3215
|
-
|
|
3321
|
+
/* @__PURE__ */ jsx10(Box10, { marginTop: 2, children: /* @__PURE__ */ jsxs10(
|
|
3322
|
+
Text10,
|
|
3216
3323
|
{
|
|
3217
3324
|
backgroundColor: autoUpdateSelectedIndex === 2 ? colors.primary : colors.bgSelected,
|
|
3218
3325
|
color: autoUpdateSelectedIndex === 2 ? "#ffffff" : colors.textMuted,
|
|
@@ -3224,80 +3331,126 @@ function SetupScreen({ onComplete, onSkip, initialConfig, detectedPlatforms }) {
|
|
|
3224
3331
|
]
|
|
3225
3332
|
}
|
|
3226
3333
|
) }),
|
|
3227
|
-
/* @__PURE__ */
|
|
3334
|
+
/* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx10(Text10, { color: colors.textDim, children: "\u2191\u2193 select \xB7 enter toggle/next \xB7 esc back" }) })
|
|
3228
3335
|
] });
|
|
3229
3336
|
}
|
|
3230
3337
|
const platformsText = detectedPlatforms.length > 0 ? detectedPlatforms.map((p) => PLATFORM_LABELS3[p]).join(", ") : "None detected";
|
|
3231
|
-
return /* @__PURE__ */
|
|
3338
|
+
return /* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", padding: 1, children: [
|
|
3232
3339
|
renderHeader(),
|
|
3233
|
-
/* @__PURE__ */
|
|
3234
|
-
/* @__PURE__ */
|
|
3235
|
-
/* @__PURE__ */
|
|
3236
|
-
/* @__PURE__ */
|
|
3237
|
-
/* @__PURE__ */
|
|
3340
|
+
/* @__PURE__ */ jsx10(Text10, { color: colors.text, bold: true, children: "Review your settings" }),
|
|
3341
|
+
/* @__PURE__ */ jsxs10(Box10, { flexDirection: "column", marginTop: 1, children: [
|
|
3342
|
+
/* @__PURE__ */ jsxs10(Text10, { children: [
|
|
3343
|
+
/* @__PURE__ */ jsx10(Text10, { color: colors.textDim, children: "Platforms: " }),
|
|
3344
|
+
/* @__PURE__ */ jsx10(Text10, { color: colors.text, children: platformsText })
|
|
3238
3345
|
] }),
|
|
3239
|
-
/* @__PURE__ */
|
|
3240
|
-
/* @__PURE__ */
|
|
3241
|
-
/* @__PURE__ */
|
|
3346
|
+
/* @__PURE__ */ jsxs10(Text10, { children: [
|
|
3347
|
+
/* @__PURE__ */ jsx10(Text10, { color: colors.textDim, children: "Your @mention: " }),
|
|
3348
|
+
/* @__PURE__ */ jsx10(Text10, { color: colors.text, children: userMention })
|
|
3242
3349
|
] }),
|
|
3243
|
-
/* @__PURE__ */
|
|
3244
|
-
/* @__PURE__ */
|
|
3245
|
-
/* @__PURE__ */
|
|
3350
|
+
/* @__PURE__ */ jsxs10(Text10, { children: [
|
|
3351
|
+
/* @__PURE__ */ jsx10(Text10, { color: colors.textDim, children: "Auto-update tools: " }),
|
|
3352
|
+
/* @__PURE__ */ jsx10(Text10, { color: colors.text, children: autoUpdateTools ? "enabled" : "disabled" })
|
|
3246
3353
|
] }),
|
|
3247
|
-
/* @__PURE__ */
|
|
3248
|
-
/* @__PURE__ */
|
|
3249
|
-
/* @__PURE__ */
|
|
3354
|
+
/* @__PURE__ */ jsxs10(Text10, { children: [
|
|
3355
|
+
/* @__PURE__ */ jsx10(Text10, { color: colors.textDim, children: "Auto-update app: " }),
|
|
3356
|
+
/* @__PURE__ */ jsx10(Text10, { color: colors.text, children: autoUpdateApp ? "enabled" : "disabled" })
|
|
3250
3357
|
] })
|
|
3251
3358
|
] }),
|
|
3252
|
-
/* @__PURE__ */
|
|
3359
|
+
/* @__PURE__ */ jsx10(Box10, { marginTop: 2, children: /* @__PURE__ */ jsxs10(Text10, { backgroundColor: colors.primary, color: "#ffffff", bold: true, children: [
|
|
3253
3360
|
" ",
|
|
3254
3361
|
"Save",
|
|
3255
3362
|
" "
|
|
3256
3363
|
] }) }),
|
|
3257
|
-
/* @__PURE__ */
|
|
3364
|
+
/* @__PURE__ */ jsx10(Box10, { marginTop: 1, children: /* @__PURE__ */ jsx10(Text10, { color: colors.textDim, children: "enter save \xB7 esc back" }) })
|
|
3258
3365
|
] });
|
|
3259
3366
|
}
|
|
3260
3367
|
|
|
3261
3368
|
// src/commands/tui/views/ReadmeViewer.tsx
|
|
3262
|
-
import { Box as
|
|
3369
|
+
import { Box as Box11, Text as Text12, useInput as useInput4 } from "ink";
|
|
3263
3370
|
import { useState as useState4, useMemo as useMemo2 } from "react";
|
|
3264
3371
|
|
|
3265
3372
|
// src/commands/tui/components/Markdown.tsx
|
|
3266
|
-
import { Text as
|
|
3267
|
-
import { jsx as
|
|
3373
|
+
import { Text as Text11 } from "ink";
|
|
3374
|
+
import { jsx as jsx11 } from "react/jsx-runtime";
|
|
3375
|
+
function renderInline(text, baseColor) {
|
|
3376
|
+
const parts = [];
|
|
3377
|
+
let remaining = text;
|
|
3378
|
+
let key = 0;
|
|
3379
|
+
while (remaining.length > 0) {
|
|
3380
|
+
const boldMatch = remaining.match(/^(.*?)\*\*(.+?)\*\*(.*)/s);
|
|
3381
|
+
if (boldMatch) {
|
|
3382
|
+
if (boldMatch[1]) {
|
|
3383
|
+
parts.push(...renderInlineSimple(boldMatch[1], baseColor, key));
|
|
3384
|
+
key += boldMatch[1].length;
|
|
3385
|
+
}
|
|
3386
|
+
parts.push(/* @__PURE__ */ jsx11(Text11, { color: baseColor, bold: true, children: boldMatch[2] }, key++));
|
|
3387
|
+
remaining = boldMatch[3];
|
|
3388
|
+
continue;
|
|
3389
|
+
}
|
|
3390
|
+
const codeMatch = remaining.match(/^(.*?)`(.+?)`(.*)/s);
|
|
3391
|
+
if (codeMatch) {
|
|
3392
|
+
if (codeMatch[1]) {
|
|
3393
|
+
parts.push(...renderInlineSimple(codeMatch[1], baseColor, key));
|
|
3394
|
+
key += codeMatch[1].length;
|
|
3395
|
+
}
|
|
3396
|
+
parts.push(/* @__PURE__ */ jsx11(Text11, { color: "#a5d6ff", children: codeMatch[2] }, key++));
|
|
3397
|
+
remaining = codeMatch[3];
|
|
3398
|
+
continue;
|
|
3399
|
+
}
|
|
3400
|
+
const italicMatch = remaining.match(/^(.*?)\*(.+?)\*(.*)/s);
|
|
3401
|
+
if (italicMatch) {
|
|
3402
|
+
if (italicMatch[1]) {
|
|
3403
|
+
parts.push(...renderInlineSimple(italicMatch[1], baseColor, key));
|
|
3404
|
+
key += italicMatch[1].length;
|
|
3405
|
+
}
|
|
3406
|
+
parts.push(/* @__PURE__ */ jsx11(Text11, { color: baseColor, italic: true, children: italicMatch[2] }, key++));
|
|
3407
|
+
remaining = italicMatch[3];
|
|
3408
|
+
continue;
|
|
3409
|
+
}
|
|
3410
|
+
parts.push(/* @__PURE__ */ jsx11(Text11, { color: baseColor, children: remaining }, key));
|
|
3411
|
+
break;
|
|
3412
|
+
}
|
|
3413
|
+
return parts;
|
|
3414
|
+
}
|
|
3415
|
+
function renderInlineSimple(text, color, startKey) {
|
|
3416
|
+
return [/* @__PURE__ */ jsx11(Text11, { color, children: text }, startKey)];
|
|
3417
|
+
}
|
|
3268
3418
|
function MarkdownLine({ line, inCodeBlock }) {
|
|
3269
3419
|
if (inCodeBlock) {
|
|
3270
|
-
return /* @__PURE__ */
|
|
3420
|
+
return /* @__PURE__ */ jsx11(Text11, { color: "#a5d6ff", children: line || " " });
|
|
3271
3421
|
}
|
|
3272
3422
|
if (line.startsWith("```")) {
|
|
3273
|
-
return /* @__PURE__ */
|
|
3423
|
+
return /* @__PURE__ */ jsx11(Text11, { color: colors.textDim, children: line });
|
|
3274
3424
|
}
|
|
3275
3425
|
if (line.startsWith("# ")) {
|
|
3276
|
-
return /* @__PURE__ */
|
|
3426
|
+
return /* @__PURE__ */ jsx11(Text11, { color: colors.text, bold: true, children: line.slice(2) });
|
|
3277
3427
|
}
|
|
3278
3428
|
if (line.startsWith("## ")) {
|
|
3279
|
-
return /* @__PURE__ */
|
|
3429
|
+
return /* @__PURE__ */ jsx11(Text11, { color: colors.text, bold: true, children: line.slice(3) });
|
|
3280
3430
|
}
|
|
3281
3431
|
if (line.startsWith("### ")) {
|
|
3282
|
-
return /* @__PURE__ */
|
|
3432
|
+
return /* @__PURE__ */ jsx11(Text11, { color: "#c9d1d9", bold: true, children: line.slice(4) });
|
|
3283
3433
|
}
|
|
3284
3434
|
if (line === "---") {
|
|
3285
|
-
return /* @__PURE__ */
|
|
3435
|
+
return /* @__PURE__ */ jsx11(Text11, { color: colors.textDim, children: line });
|
|
3436
|
+
}
|
|
3437
|
+
if (line.match(/^[\s]*\d+\.\s/)) {
|
|
3438
|
+
return /* @__PURE__ */ jsx11(Text11, { children: renderInline(line, colors.textMuted) });
|
|
3286
3439
|
}
|
|
3287
3440
|
if (line.match(/^[\s]*[-*]\s/)) {
|
|
3288
|
-
return /* @__PURE__ */
|
|
3441
|
+
return /* @__PURE__ */ jsx11(Text11, { children: renderInline(line, colors.textMuted) });
|
|
3289
3442
|
}
|
|
3290
3443
|
if (line.startsWith(">")) {
|
|
3291
|
-
return /* @__PURE__ */
|
|
3444
|
+
return /* @__PURE__ */ jsx11(Text11, { color: "#8b949e", italic: true, children: line });
|
|
3292
3445
|
}
|
|
3293
3446
|
if (line.includes("|")) {
|
|
3294
|
-
return /* @__PURE__ */
|
|
3447
|
+
return /* @__PURE__ */ jsx11(Text11, { color: colors.textMuted, children: line });
|
|
3295
3448
|
}
|
|
3296
|
-
return /* @__PURE__ */
|
|
3449
|
+
return /* @__PURE__ */ jsx11(Text11, { children: renderInline(line || " ", colors.textMuted) });
|
|
3297
3450
|
}
|
|
3298
3451
|
|
|
3299
3452
|
// src/commands/tui/views/ReadmeViewer.tsx
|
|
3300
|
-
import { jsx as
|
|
3453
|
+
import { jsx as jsx12, jsxs as jsxs11 } from "react/jsx-runtime";
|
|
3301
3454
|
function ReadmeViewer({ title, content, onClose }) {
|
|
3302
3455
|
const [scrollOffset, setScrollOffset] = useState4(0);
|
|
3303
3456
|
const lines = useMemo2(() => content.split("\n"), [content]);
|
|
@@ -3340,30 +3493,30 @@ function ReadmeViewer({ title, content, onClose }) {
|
|
|
3340
3493
|
const showBottomIndicator = endIndex < lines.length;
|
|
3341
3494
|
const actualContentLines = contentLines - (showBottomIndicator ? 1 : 0);
|
|
3342
3495
|
const visibleLines = lines.slice(scrollOffset, scrollOffset + actualContentLines);
|
|
3343
|
-
return /* @__PURE__ */
|
|
3344
|
-
/* @__PURE__ */
|
|
3345
|
-
/* @__PURE__ */
|
|
3346
|
-
/* @__PURE__ */
|
|
3496
|
+
return /* @__PURE__ */ jsxs11(Box11, { flexDirection: "column", padding: 1, children: [
|
|
3497
|
+
/* @__PURE__ */ jsxs11(Box11, { marginBottom: 1, children: [
|
|
3498
|
+
/* @__PURE__ */ jsx12(Text12, { color: colors.text, bold: true, children: title }),
|
|
3499
|
+
/* @__PURE__ */ jsxs11(Text12, { color: colors.textDim, children: [
|
|
3347
3500
|
" \xB7 ",
|
|
3348
3501
|
lines.length,
|
|
3349
3502
|
" lines"
|
|
3350
3503
|
] })
|
|
3351
3504
|
] }),
|
|
3352
|
-
/* @__PURE__ */
|
|
3353
|
-
|
|
3505
|
+
/* @__PURE__ */ jsxs11(
|
|
3506
|
+
Box11,
|
|
3354
3507
|
{
|
|
3355
3508
|
flexDirection: "column",
|
|
3356
3509
|
borderStyle: "single",
|
|
3357
3510
|
borderColor: colors.border,
|
|
3358
3511
|
paddingX: 1,
|
|
3359
3512
|
children: [
|
|
3360
|
-
showTopIndicator && /* @__PURE__ */
|
|
3513
|
+
showTopIndicator && /* @__PURE__ */ jsxs11(Text12, { color: colors.textDim, children: [
|
|
3361
3514
|
"\u2191 ",
|
|
3362
3515
|
scrollOffset,
|
|
3363
3516
|
" more lines"
|
|
3364
3517
|
] }),
|
|
3365
|
-
visibleLines.map((line, i) => /* @__PURE__ */
|
|
3366
|
-
showBottomIndicator && /* @__PURE__ */
|
|
3518
|
+
visibleLines.map((line, i) => /* @__PURE__ */ jsx12(MarkdownLine, { line, inCodeBlock: lineStates[scrollOffset + i] }, scrollOffset + i)),
|
|
3519
|
+
showBottomIndicator && /* @__PURE__ */ jsxs11(Text12, { color: colors.textDim, children: [
|
|
3367
3520
|
"\u2193 ",
|
|
3368
3521
|
lines.length - scrollOffset - actualContentLines,
|
|
3369
3522
|
" more lines"
|
|
@@ -3371,16 +3524,16 @@ function ReadmeViewer({ title, content, onClose }) {
|
|
|
3371
3524
|
]
|
|
3372
3525
|
}
|
|
3373
3526
|
),
|
|
3374
|
-
/* @__PURE__ */
|
|
3527
|
+
/* @__PURE__ */ jsx12(Box11, { marginTop: 1, children: /* @__PURE__ */ jsx12(Text12, { color: colors.textDim, children: "\u2191\u2193 scroll \xB7 space/pgdn page \xB7 esc back" }) })
|
|
3375
3528
|
] });
|
|
3376
3529
|
}
|
|
3377
3530
|
|
|
3378
3531
|
// src/commands/tui/views/ToolExplorer.tsx
|
|
3379
|
-
import { Box as
|
|
3532
|
+
import { Box as Box12, Text as Text13, useInput as useInput5 } from "ink";
|
|
3380
3533
|
import { useState as useState5, useMemo as useMemo3 } from "react";
|
|
3381
3534
|
import { existsSync as existsSync9, readFileSync as readFileSync8 } from "fs";
|
|
3382
3535
|
import { join as join10 } from "path";
|
|
3383
|
-
import { jsx as
|
|
3536
|
+
import { jsx as jsx13, jsxs as jsxs12 } from "react/jsx-runtime";
|
|
3384
3537
|
function ToolExplorer({ tool, onViewSource, onClose }) {
|
|
3385
3538
|
const [selectedIndex, setSelectedIndex] = useState5(0);
|
|
3386
3539
|
const items = useMemo3(() => {
|
|
@@ -3439,23 +3592,23 @@ function ToolExplorer({ tool, onViewSource, onClose }) {
|
|
|
3439
3592
|
const commandItems = items.filter((i) => i.type === "command");
|
|
3440
3593
|
const agentItems = items.filter((i) => i.type === "agent");
|
|
3441
3594
|
const getItemIndex = (item) => items.indexOf(item);
|
|
3442
|
-
return /* @__PURE__ */
|
|
3443
|
-
/* @__PURE__ */
|
|
3444
|
-
/* @__PURE__ */
|
|
3445
|
-
/* @__PURE__ */
|
|
3446
|
-
/* @__PURE__ */
|
|
3447
|
-
/* @__PURE__ */
|
|
3448
|
-
/* @__PURE__ */
|
|
3449
|
-
/* @__PURE__ */
|
|
3595
|
+
return /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", padding: 1, children: [
|
|
3596
|
+
/* @__PURE__ */ jsx13(Box12, { marginBottom: 1, children: /* @__PURE__ */ jsxs12(Text13, { children: [
|
|
3597
|
+
/* @__PURE__ */ jsx13(Text13, { color: colors.textDim, children: "[" }),
|
|
3598
|
+
/* @__PURE__ */ jsx13(Text13, { color: colors.primary, children: "\u25CF" }),
|
|
3599
|
+
/* @__PURE__ */ jsx13(Text13, { color: colors.textDim, children: " " }),
|
|
3600
|
+
/* @__PURE__ */ jsx13(Text13, { color: colors.primary, children: "\u25CF" }),
|
|
3601
|
+
/* @__PURE__ */ jsx13(Text13, { color: colors.textDim, children: "] " }),
|
|
3602
|
+
/* @__PURE__ */ jsx13(Text13, { color: colors.text, bold: true, children: tool.name })
|
|
3450
3603
|
] }) }),
|
|
3451
|
-
/* @__PURE__ */
|
|
3452
|
-
skillItems.length > 0 && /* @__PURE__ */
|
|
3453
|
-
/* @__PURE__ */
|
|
3454
|
-
/* @__PURE__ */
|
|
3604
|
+
/* @__PURE__ */ jsx13(Box12, { marginBottom: 1, children: /* @__PURE__ */ jsx13(Text13, { color: colors.textMuted, children: tool.description }) }),
|
|
3605
|
+
skillItems.length > 0 && /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", marginBottom: 1, children: [
|
|
3606
|
+
/* @__PURE__ */ jsx13(Text13, { color: colors.skill, bold: true, children: "Skills" }),
|
|
3607
|
+
/* @__PURE__ */ jsx13(Box12, { flexDirection: "row", flexWrap: "wrap", marginTop: 1, children: skillItems.map((item) => {
|
|
3455
3608
|
const idx = getItemIndex(item);
|
|
3456
3609
|
const isSelected = selectedIndex === idx;
|
|
3457
|
-
return /* @__PURE__ */
|
|
3458
|
-
|
|
3610
|
+
return /* @__PURE__ */ jsx13(Box12, { marginRight: 1, marginBottom: 1, children: /* @__PURE__ */ jsx13(
|
|
3611
|
+
Text13,
|
|
3459
3612
|
{
|
|
3460
3613
|
backgroundColor: isSelected ? colors.skill : colors.bgSelected,
|
|
3461
3614
|
color: isSelected ? "#000000" : colors.skill,
|
|
@@ -3465,13 +3618,13 @@ function ToolExplorer({ tool, onViewSource, onClose }) {
|
|
|
3465
3618
|
) }, item.name);
|
|
3466
3619
|
}) })
|
|
3467
3620
|
] }),
|
|
3468
|
-
commandItems.length > 0 && /* @__PURE__ */
|
|
3469
|
-
/* @__PURE__ */
|
|
3470
|
-
/* @__PURE__ */
|
|
3621
|
+
commandItems.length > 0 && /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", marginBottom: 1, children: [
|
|
3622
|
+
/* @__PURE__ */ jsx13(Text13, { color: colors.command, bold: true, children: "Commands" }),
|
|
3623
|
+
/* @__PURE__ */ jsx13(Box12, { flexDirection: "row", flexWrap: "wrap", marginTop: 1, children: commandItems.map((item) => {
|
|
3471
3624
|
const idx = getItemIndex(item);
|
|
3472
3625
|
const isSelected = selectedIndex === idx;
|
|
3473
|
-
return /* @__PURE__ */
|
|
3474
|
-
|
|
3626
|
+
return /* @__PURE__ */ jsx13(Box12, { marginRight: 1, marginBottom: 1, children: /* @__PURE__ */ jsx13(
|
|
3627
|
+
Text13,
|
|
3475
3628
|
{
|
|
3476
3629
|
backgroundColor: isSelected ? colors.command : colors.bgSelected,
|
|
3477
3630
|
color: isSelected ? "#000000" : colors.command,
|
|
@@ -3481,13 +3634,13 @@ function ToolExplorer({ tool, onViewSource, onClose }) {
|
|
|
3481
3634
|
) }, item.name);
|
|
3482
3635
|
}) })
|
|
3483
3636
|
] }),
|
|
3484
|
-
agentItems.length > 0 && /* @__PURE__ */
|
|
3485
|
-
/* @__PURE__ */
|
|
3486
|
-
/* @__PURE__ */
|
|
3637
|
+
agentItems.length > 0 && /* @__PURE__ */ jsxs12(Box12, { flexDirection: "column", marginBottom: 1, children: [
|
|
3638
|
+
/* @__PURE__ */ jsx13(Text13, { color: colors.agent, bold: true, children: "Agents" }),
|
|
3639
|
+
/* @__PURE__ */ jsx13(Box12, { flexDirection: "row", flexWrap: "wrap", marginTop: 1, children: agentItems.map((item) => {
|
|
3487
3640
|
const idx = getItemIndex(item);
|
|
3488
3641
|
const isSelected = selectedIndex === idx;
|
|
3489
|
-
return /* @__PURE__ */
|
|
3490
|
-
|
|
3642
|
+
return /* @__PURE__ */ jsx13(Box12, { marginRight: 1, marginBottom: 1, children: /* @__PURE__ */ jsx13(
|
|
3643
|
+
Text13,
|
|
3491
3644
|
{
|
|
3492
3645
|
backgroundColor: isSelected ? colors.agent : colors.bgSelected,
|
|
3493
3646
|
color: isSelected ? "#000000" : colors.agent,
|
|
@@ -3497,15 +3650,15 @@ function ToolExplorer({ tool, onViewSource, onClose }) {
|
|
|
3497
3650
|
) }, item.name);
|
|
3498
3651
|
}) })
|
|
3499
3652
|
] }),
|
|
3500
|
-
/* @__PURE__ */
|
|
3653
|
+
/* @__PURE__ */ jsx13(Box12, { marginTop: 1, children: /* @__PURE__ */ jsx13(Text13, { color: colors.textDim, children: "\u2190\u2192 navigate \xB7 enter view source \xB7 esc back" }) })
|
|
3501
3654
|
] });
|
|
3502
3655
|
}
|
|
3503
3656
|
|
|
3504
3657
|
// src/commands/tui/views/SkillConfigScreen.tsx
|
|
3505
|
-
import { Box as
|
|
3658
|
+
import { Box as Box13, Text as Text14, useInput as useInput6 } from "ink";
|
|
3506
3659
|
import TextInput2 from "ink-text-input";
|
|
3507
3660
|
import { useState as useState6, useMemo as useMemo4 } from "react";
|
|
3508
|
-
import { jsx as
|
|
3661
|
+
import { jsx as jsx14, jsxs as jsxs13 } from "react/jsx-runtime";
|
|
3509
3662
|
function SkillConfigScreen({ skill, onComplete, onCancel }) {
|
|
3510
3663
|
const configSchema = skill.config_schema || {};
|
|
3511
3664
|
const configKeys = Object.keys(configSchema);
|
|
@@ -3605,20 +3758,20 @@ function SkillConfigScreen({ skill, onComplete, onCancel }) {
|
|
|
3605
3758
|
}
|
|
3606
3759
|
}, { isActive: editingField === null && editingSelect === null });
|
|
3607
3760
|
if (configKeys.length === 0) {
|
|
3608
|
-
return /* @__PURE__ */
|
|
3609
|
-
/* @__PURE__ */
|
|
3610
|
-
/* @__PURE__ */
|
|
3611
|
-
/* @__PURE__ */
|
|
3612
|
-
/* @__PURE__ */
|
|
3613
|
-
/* @__PURE__ */
|
|
3614
|
-
/* @__PURE__ */
|
|
3615
|
-
/* @__PURE__ */
|
|
3761
|
+
return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", padding: 1, children: [
|
|
3762
|
+
/* @__PURE__ */ jsx14(Box13, { marginBottom: 1, children: /* @__PURE__ */ jsxs13(Text14, { children: [
|
|
3763
|
+
/* @__PURE__ */ jsx14(Text14, { color: colors.textDim, children: "[" }),
|
|
3764
|
+
/* @__PURE__ */ jsx14(Text14, { color: colors.primary, children: "\u25CF" }),
|
|
3765
|
+
/* @__PURE__ */ jsx14(Text14, { color: colors.textDim, children: " " }),
|
|
3766
|
+
/* @__PURE__ */ jsx14(Text14, { color: colors.primary, children: "\u25CF" }),
|
|
3767
|
+
/* @__PURE__ */ jsx14(Text14, { color: colors.textDim, children: "] " }),
|
|
3768
|
+
/* @__PURE__ */ jsxs13(Text14, { color: colors.text, bold: true, children: [
|
|
3616
3769
|
"configure ",
|
|
3617
3770
|
skill.name
|
|
3618
3771
|
] })
|
|
3619
3772
|
] }) }),
|
|
3620
|
-
/* @__PURE__ */
|
|
3621
|
-
/* @__PURE__ */
|
|
3773
|
+
/* @__PURE__ */ jsx14(Text14, { color: colors.textMuted, children: "This skill has no configuration options." }),
|
|
3774
|
+
/* @__PURE__ */ jsx14(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text14, { color: colors.textDim, children: "esc to go back" }) })
|
|
3622
3775
|
] });
|
|
3623
3776
|
}
|
|
3624
3777
|
const visibleEndIndex = Math.min(scrollOffset + MAX_VISIBLE_CONFIG_ITEMS, totalItems);
|
|
@@ -3626,20 +3779,20 @@ function SkillConfigScreen({ skill, onComplete, onCancel }) {
|
|
|
3626
3779
|
const showSaveButton = visibleEndIndex > configKeys.length || scrollOffset + MAX_VISIBLE_CONFIG_ITEMS > configKeys.length;
|
|
3627
3780
|
const showTopIndicator = scrollOffset > 0;
|
|
3628
3781
|
const showBottomIndicator = scrollOffset + MAX_VISIBLE_CONFIG_ITEMS < totalItems;
|
|
3629
|
-
return /* @__PURE__ */
|
|
3630
|
-
/* @__PURE__ */
|
|
3631
|
-
/* @__PURE__ */
|
|
3632
|
-
/* @__PURE__ */
|
|
3633
|
-
/* @__PURE__ */
|
|
3634
|
-
/* @__PURE__ */
|
|
3635
|
-
/* @__PURE__ */
|
|
3636
|
-
/* @__PURE__ */
|
|
3782
|
+
return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", padding: 1, children: [
|
|
3783
|
+
/* @__PURE__ */ jsx14(Box13, { marginBottom: 1, children: /* @__PURE__ */ jsxs13(Text14, { children: [
|
|
3784
|
+
/* @__PURE__ */ jsx14(Text14, { color: colors.textDim, children: "[" }),
|
|
3785
|
+
/* @__PURE__ */ jsx14(Text14, { color: colors.primary, children: "\u25CF" }),
|
|
3786
|
+
/* @__PURE__ */ jsx14(Text14, { color: colors.textDim, children: " " }),
|
|
3787
|
+
/* @__PURE__ */ jsx14(Text14, { color: colors.primary, children: "\u25CF" }),
|
|
3788
|
+
/* @__PURE__ */ jsx14(Text14, { color: colors.textDim, children: "] " }),
|
|
3789
|
+
/* @__PURE__ */ jsxs13(Text14, { color: colors.text, bold: true, children: [
|
|
3637
3790
|
"configure ",
|
|
3638
3791
|
skill.name
|
|
3639
3792
|
] })
|
|
3640
3793
|
] }) }),
|
|
3641
|
-
/* @__PURE__ */
|
|
3642
|
-
showTopIndicator && /* @__PURE__ */
|
|
3794
|
+
/* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", children: [
|
|
3795
|
+
showTopIndicator && /* @__PURE__ */ jsx14(Box13, { marginBottom: 1, children: /* @__PURE__ */ jsxs13(Text14, { color: colors.textDim, children: [
|
|
3643
3796
|
" \u2191 ",
|
|
3644
3797
|
scrollOffset,
|
|
3645
3798
|
" more"
|
|
@@ -3649,33 +3802,33 @@ function SkillConfigScreen({ skill, onComplete, onCancel }) {
|
|
|
3649
3802
|
const option = configSchema[configKey];
|
|
3650
3803
|
const isSelected = selectedIndex === actualIndex;
|
|
3651
3804
|
const isEditing = editingField === configKey;
|
|
3652
|
-
return /* @__PURE__ */
|
|
3653
|
-
/* @__PURE__ */
|
|
3654
|
-
/* @__PURE__ */
|
|
3805
|
+
return /* @__PURE__ */ jsxs13(Box13, { flexDirection: "column", marginBottom: 1, children: [
|
|
3806
|
+
/* @__PURE__ */ jsxs13(Text14, { children: [
|
|
3807
|
+
/* @__PURE__ */ jsxs13(Text14, { color: colors.textDim, children: [
|
|
3655
3808
|
isSelected ? ">" : " ",
|
|
3656
3809
|
" "
|
|
3657
3810
|
] }),
|
|
3658
|
-
/* @__PURE__ */
|
|
3811
|
+
/* @__PURE__ */ jsx14(Text14, { color: isSelected ? colors.text : colors.textMuted, children: configKey })
|
|
3659
3812
|
] }),
|
|
3660
|
-
/* @__PURE__ */
|
|
3813
|
+
/* @__PURE__ */ jsxs13(Text14, { color: colors.textDim, children: [
|
|
3661
3814
|
" ",
|
|
3662
3815
|
option.description
|
|
3663
3816
|
] }),
|
|
3664
|
-
/* @__PURE__ */
|
|
3665
|
-
/* @__PURE__ */
|
|
3666
|
-
option.type === "boolean" /* Boolean */ ? /* @__PURE__ */
|
|
3817
|
+
/* @__PURE__ */ jsxs13(Box13, { children: [
|
|
3818
|
+
/* @__PURE__ */ jsx14(Text14, { color: colors.textDim, children: " " }),
|
|
3819
|
+
option.type === "boolean" /* Boolean */ ? /* @__PURE__ */ jsxs13(Text14, { color: colors.text, children: [
|
|
3667
3820
|
"[",
|
|
3668
3821
|
values[configKey] ? "x" : " ",
|
|
3669
3822
|
"] ",
|
|
3670
3823
|
values[configKey] ? "enabled" : "disabled"
|
|
3671
|
-
] }) : option.type === "select" /* Select */ && option.options ? /* @__PURE__ */
|
|
3824
|
+
] }) : option.type === "select" /* Select */ && option.options ? /* @__PURE__ */ jsx14(Text14, { color: colors.text, children: option.options.map((opt, i) => {
|
|
3672
3825
|
const isCurrentValue = String(values[configKey]) === opt;
|
|
3673
3826
|
const isEditingThis = editingSelect === configKey;
|
|
3674
3827
|
const isHighlighted = isEditingThis && selectOptionIndex === i;
|
|
3675
|
-
return /* @__PURE__ */
|
|
3676
|
-
i > 0 && /* @__PURE__ */
|
|
3677
|
-
/* @__PURE__ */
|
|
3678
|
-
|
|
3828
|
+
return /* @__PURE__ */ jsxs13(Text14, { children: [
|
|
3829
|
+
i > 0 && /* @__PURE__ */ jsx14(Text14, { color: colors.textDim, children: " \xB7 " }),
|
|
3830
|
+
/* @__PURE__ */ jsx14(
|
|
3831
|
+
Text14,
|
|
3679
3832
|
{
|
|
3680
3833
|
color: isHighlighted ? "#ffffff" : isCurrentValue ? colors.primary : colors.textMuted,
|
|
3681
3834
|
backgroundColor: isHighlighted ? colors.primary : void 0,
|
|
@@ -3683,9 +3836,9 @@ function SkillConfigScreen({ skill, onComplete, onCancel }) {
|
|
|
3683
3836
|
}
|
|
3684
3837
|
)
|
|
3685
3838
|
] }, opt);
|
|
3686
|
-
}) }) : isEditing ? /* @__PURE__ */
|
|
3687
|
-
/* @__PURE__ */
|
|
3688
|
-
/* @__PURE__ */
|
|
3839
|
+
}) }) : isEditing ? /* @__PURE__ */ jsxs13(Box13, { children: [
|
|
3840
|
+
/* @__PURE__ */ jsx14(Text14, { color: colors.textDim, children: "> " }),
|
|
3841
|
+
/* @__PURE__ */ jsx14(
|
|
3689
3842
|
TextInput2,
|
|
3690
3843
|
{
|
|
3691
3844
|
value: editValue,
|
|
@@ -3693,17 +3846,17 @@ function SkillConfigScreen({ skill, onComplete, onCancel }) {
|
|
|
3693
3846
|
onSubmit: handleSubmitEdit
|
|
3694
3847
|
}
|
|
3695
3848
|
)
|
|
3696
|
-
] }) : /* @__PURE__ */
|
|
3849
|
+
] }) : /* @__PURE__ */ jsx14(Text14, { color: colors.text, children: String(values[configKey]) || "(not set)" })
|
|
3697
3850
|
] })
|
|
3698
3851
|
] }, configKey);
|
|
3699
3852
|
}),
|
|
3700
|
-
showSaveButton && /* @__PURE__ */
|
|
3701
|
-
/* @__PURE__ */
|
|
3853
|
+
showSaveButton && /* @__PURE__ */ jsx14(Box13, { marginTop: 1, children: /* @__PURE__ */ jsxs13(Text14, { children: [
|
|
3854
|
+
/* @__PURE__ */ jsxs13(Text14, { color: colors.textDim, children: [
|
|
3702
3855
|
selectedIndex === configKeys.length ? ">" : " ",
|
|
3703
3856
|
" "
|
|
3704
3857
|
] }),
|
|
3705
|
-
/* @__PURE__ */
|
|
3706
|
-
|
|
3858
|
+
/* @__PURE__ */ jsxs13(
|
|
3859
|
+
Text14,
|
|
3707
3860
|
{
|
|
3708
3861
|
backgroundColor: selectedIndex === configKeys.length ? colors.primary : void 0,
|
|
3709
3862
|
color: selectedIndex === configKeys.length ? "#ffffff" : colors.textMuted,
|
|
@@ -3716,21 +3869,21 @@ function SkillConfigScreen({ skill, onComplete, onCancel }) {
|
|
|
3716
3869
|
}
|
|
3717
3870
|
)
|
|
3718
3871
|
] }) }),
|
|
3719
|
-
showBottomIndicator && /* @__PURE__ */
|
|
3872
|
+
showBottomIndicator && /* @__PURE__ */ jsx14(Box13, { marginTop: 1, children: /* @__PURE__ */ jsxs13(Text14, { color: colors.textDim, children: [
|
|
3720
3873
|
" \u2193 ",
|
|
3721
3874
|
totalItems - scrollOffset - MAX_VISIBLE_CONFIG_ITEMS,
|
|
3722
3875
|
" more"
|
|
3723
3876
|
] }) })
|
|
3724
3877
|
] }),
|
|
3725
|
-
/* @__PURE__ */
|
|
3878
|
+
/* @__PURE__ */ jsx14(Box13, { marginTop: 1, children: /* @__PURE__ */ jsx14(Text14, { color: colors.textDim, children: editingField ? "enter save \xB7 esc cancel" : editingSelect ? "\u2190\u2192 choose \xB7 enter select \xB7 esc cancel" : "\u2191\u2193 select \xB7 enter toggle/edit \xB7 esc back" }) })
|
|
3726
3879
|
] });
|
|
3727
3880
|
}
|
|
3728
3881
|
|
|
3729
3882
|
// src/commands/tui/views/ReposManagementScreen.tsx
|
|
3730
|
-
import { Box as
|
|
3883
|
+
import { Box as Box14, Text as Text15, useInput as useInput7 } from "ink";
|
|
3731
3884
|
import TextInput3 from "ink-text-input";
|
|
3732
3885
|
import { useState as useState7 } from "react";
|
|
3733
|
-
import { jsx as
|
|
3886
|
+
import { jsx as jsx15, jsxs as jsxs14 } from "react/jsx-runtime";
|
|
3734
3887
|
function ReposManagementScreen({ onComplete: _onComplete, onCancel }) {
|
|
3735
3888
|
const [repos2, setRepos] = useState7(() => getRepos());
|
|
3736
3889
|
const [selectedIndex, setSelectedIndex] = useState7(0);
|
|
@@ -3818,11 +3971,11 @@ function ReposManagementScreen({ onComplete: _onComplete, onCancel }) {
|
|
|
3818
3971
|
}
|
|
3819
3972
|
}, { isActive: screen === "confirm-delete" });
|
|
3820
3973
|
if (screen === "add-name") {
|
|
3821
|
-
return /* @__PURE__ */
|
|
3822
|
-
/* @__PURE__ */
|
|
3823
|
-
/* @__PURE__ */
|
|
3824
|
-
/* @__PURE__ */
|
|
3825
|
-
/* @__PURE__ */
|
|
3974
|
+
return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", padding: 2, children: [
|
|
3975
|
+
/* @__PURE__ */ jsx15(Text15, { color: colors.text, bold: true, children: "Add Repository" }),
|
|
3976
|
+
/* @__PURE__ */ jsxs14(Box14, { marginTop: 1, children: [
|
|
3977
|
+
/* @__PURE__ */ jsx15(Text15, { color: colors.textDim, children: "Repository name: " }),
|
|
3978
|
+
/* @__PURE__ */ jsx15(
|
|
3826
3979
|
TextInput3,
|
|
3827
3980
|
{
|
|
3828
3981
|
value: newRepoName,
|
|
@@ -3835,23 +3988,23 @@ function ReposManagementScreen({ onComplete: _onComplete, onCancel }) {
|
|
|
3835
3988
|
}
|
|
3836
3989
|
)
|
|
3837
3990
|
] }),
|
|
3838
|
-
/* @__PURE__ */
|
|
3991
|
+
/* @__PURE__ */ jsx15(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx15(Text15, { color: colors.textDim, children: "esc cancel" }) })
|
|
3839
3992
|
] });
|
|
3840
3993
|
}
|
|
3841
3994
|
if (screen === "add-path") {
|
|
3842
|
-
return /* @__PURE__ */
|
|
3843
|
-
/* @__PURE__ */
|
|
3844
|
-
/* @__PURE__ */
|
|
3845
|
-
/* @__PURE__ */
|
|
3846
|
-
/* @__PURE__ */
|
|
3995
|
+
return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", padding: 2, children: [
|
|
3996
|
+
/* @__PURE__ */ jsx15(Text15, { color: colors.text, bold: true, children: "Add Repository" }),
|
|
3997
|
+
/* @__PURE__ */ jsxs14(Box14, { marginTop: 1, children: [
|
|
3998
|
+
/* @__PURE__ */ jsx15(Text15, { color: colors.textDim, children: "Name: " }),
|
|
3999
|
+
/* @__PURE__ */ jsx15(Text15, { color: colors.text, children: newRepoName })
|
|
3847
4000
|
] }),
|
|
3848
|
-
/* @__PURE__ */
|
|
3849
|
-
/* @__PURE__ */
|
|
4001
|
+
/* @__PURE__ */ jsxs14(Box14, { marginTop: 1, children: [
|
|
4002
|
+
/* @__PURE__ */ jsxs14(Text15, { color: colors.textDim, children: [
|
|
3850
4003
|
"Path (e.g., ~/src/github.com/",
|
|
3851
4004
|
newRepoName,
|
|
3852
4005
|
"): "
|
|
3853
4006
|
] }),
|
|
3854
|
-
/* @__PURE__ */
|
|
4007
|
+
/* @__PURE__ */ jsx15(
|
|
3855
4008
|
TextInput3,
|
|
3856
4009
|
{
|
|
3857
4010
|
value: newRepoPath,
|
|
@@ -3865,23 +4018,23 @@ function ReposManagementScreen({ onComplete: _onComplete, onCancel }) {
|
|
|
3865
4018
|
}
|
|
3866
4019
|
)
|
|
3867
4020
|
] }),
|
|
3868
|
-
/* @__PURE__ */
|
|
4021
|
+
/* @__PURE__ */ jsx15(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx15(Text15, { color: colors.textDim, children: "esc back" }) })
|
|
3869
4022
|
] });
|
|
3870
4023
|
}
|
|
3871
4024
|
if (screen === "add-desc") {
|
|
3872
|
-
return /* @__PURE__ */
|
|
3873
|
-
/* @__PURE__ */
|
|
3874
|
-
/* @__PURE__ */
|
|
3875
|
-
/* @__PURE__ */
|
|
3876
|
-
/* @__PURE__ */
|
|
4025
|
+
return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", padding: 2, children: [
|
|
4026
|
+
/* @__PURE__ */ jsx15(Text15, { color: colors.text, bold: true, children: "Add Repository" }),
|
|
4027
|
+
/* @__PURE__ */ jsxs14(Box14, { marginTop: 1, children: [
|
|
4028
|
+
/* @__PURE__ */ jsx15(Text15, { color: colors.textDim, children: "Name: " }),
|
|
4029
|
+
/* @__PURE__ */ jsx15(Text15, { color: colors.text, children: newRepoName })
|
|
3877
4030
|
] }),
|
|
3878
|
-
/* @__PURE__ */
|
|
3879
|
-
/* @__PURE__ */
|
|
3880
|
-
/* @__PURE__ */
|
|
4031
|
+
/* @__PURE__ */ jsxs14(Box14, { marginTop: 1, children: [
|
|
4032
|
+
/* @__PURE__ */ jsx15(Text15, { color: colors.textDim, children: "Path: " }),
|
|
4033
|
+
/* @__PURE__ */ jsx15(Text15, { color: colors.text, children: newRepoPath })
|
|
3881
4034
|
] }),
|
|
3882
|
-
/* @__PURE__ */
|
|
3883
|
-
/* @__PURE__ */
|
|
3884
|
-
/* @__PURE__ */
|
|
4035
|
+
/* @__PURE__ */ jsxs14(Box14, { marginTop: 1, children: [
|
|
4036
|
+
/* @__PURE__ */ jsx15(Text15, { color: colors.textDim, children: "Description (optional): " }),
|
|
4037
|
+
/* @__PURE__ */ jsx15(
|
|
3885
4038
|
TextInput3,
|
|
3886
4039
|
{
|
|
3887
4040
|
value: newRepoDesc,
|
|
@@ -3890,28 +4043,28 @@ function ReposManagementScreen({ onComplete: _onComplete, onCancel }) {
|
|
|
3890
4043
|
}
|
|
3891
4044
|
)
|
|
3892
4045
|
] }),
|
|
3893
|
-
/* @__PURE__ */
|
|
4046
|
+
/* @__PURE__ */ jsx15(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx15(Text15, { color: colors.textDim, children: "enter save \xB7 esc back" }) })
|
|
3894
4047
|
] });
|
|
3895
4048
|
}
|
|
3896
4049
|
if (screen === "confirm-delete" && repoToDelete) {
|
|
3897
4050
|
const repo = repos2.find((r) => r.name === repoToDelete);
|
|
3898
|
-
return /* @__PURE__ */
|
|
3899
|
-
/* @__PURE__ */
|
|
3900
|
-
/* @__PURE__ */
|
|
3901
|
-
/* @__PURE__ */
|
|
3902
|
-
/* @__PURE__ */
|
|
4051
|
+
return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", padding: 2, children: [
|
|
4052
|
+
/* @__PURE__ */ jsx15(Text15, { color: colors.text, bold: true, children: "Remove Repository" }),
|
|
4053
|
+
/* @__PURE__ */ jsxs14(Box14, { marginTop: 1, flexDirection: "column", children: [
|
|
4054
|
+
/* @__PURE__ */ jsx15(Text15, { color: colors.text, children: repo?.name }),
|
|
4055
|
+
/* @__PURE__ */ jsx15(Text15, { color: colors.textDim, children: repo?.path })
|
|
3903
4056
|
] }),
|
|
3904
|
-
/* @__PURE__ */
|
|
3905
|
-
/* @__PURE__ */
|
|
4057
|
+
/* @__PURE__ */ jsx15(Box14, { marginTop: 2, children: /* @__PURE__ */ jsx15(Text15, { color: colors.error, children: "Remove this repository from the registry?" }) }),
|
|
4058
|
+
/* @__PURE__ */ jsx15(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx15(Text15, { color: colors.textDim, children: "y yes \xB7 n no" }) })
|
|
3906
4059
|
] });
|
|
3907
4060
|
}
|
|
3908
|
-
return /* @__PURE__ */
|
|
3909
|
-
/* @__PURE__ */
|
|
3910
|
-
message && /* @__PURE__ */
|
|
3911
|
-
/* @__PURE__ */
|
|
3912
|
-
repos2.length === 0 ? /* @__PURE__ */
|
|
3913
|
-
/* @__PURE__ */
|
|
3914
|
-
|
|
4061
|
+
return /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", padding: 2, children: [
|
|
4062
|
+
/* @__PURE__ */ jsx15(Text15, { color: colors.text, bold: true, children: "Manage Repositories" }),
|
|
4063
|
+
message && /* @__PURE__ */ jsx15(Box14, { marginTop: 1, children: /* @__PURE__ */ jsx15(Text15, { color: message.type === "success" ? colors.success : colors.error, children: message.text }) }),
|
|
4064
|
+
/* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", marginTop: 1, children: [
|
|
4065
|
+
repos2.length === 0 ? /* @__PURE__ */ jsx15(Box14, { marginY: 1, children: /* @__PURE__ */ jsx15(Text15, { color: colors.textDim, children: "No repos configured" }) }) : repos2.map((repo, index) => /* @__PURE__ */ jsxs14(Box14, { flexDirection: "column", marginTop: index > 0 ? 1 : 0, children: [
|
|
4066
|
+
/* @__PURE__ */ jsx15(Box14, { children: /* @__PURE__ */ jsxs14(
|
|
4067
|
+
Text15,
|
|
3915
4068
|
{
|
|
3916
4069
|
color: selectedIndex === index ? colors.primary : colors.text,
|
|
3917
4070
|
bold: selectedIndex === index,
|
|
@@ -3921,11 +4074,11 @@ function ReposManagementScreen({ onComplete: _onComplete, onCancel }) {
|
|
|
3921
4074
|
]
|
|
3922
4075
|
}
|
|
3923
4076
|
) }),
|
|
3924
|
-
/* @__PURE__ */
|
|
3925
|
-
repo.description && /* @__PURE__ */
|
|
4077
|
+
/* @__PURE__ */ jsx15(Box14, { paddingLeft: 2, children: /* @__PURE__ */ jsx15(Text15, { color: colors.textDim, children: repo.path }) }),
|
|
4078
|
+
repo.description && /* @__PURE__ */ jsx15(Box14, { paddingLeft: 2, children: /* @__PURE__ */ jsx15(Text15, { color: colors.textDim, children: repo.description }) })
|
|
3926
4079
|
] }, repo.name)),
|
|
3927
|
-
/* @__PURE__ */
|
|
3928
|
-
|
|
4080
|
+
/* @__PURE__ */ jsx15(Box14, { marginTop: repos2.length > 0 ? 2 : 0, children: /* @__PURE__ */ jsxs14(
|
|
4081
|
+
Text15,
|
|
3929
4082
|
{
|
|
3930
4083
|
color: selectedIndex === repos2.length ? colors.primary : colors.textDim,
|
|
3931
4084
|
bold: selectedIndex === repos2.length,
|
|
@@ -3936,13 +4089,13 @@ function ReposManagementScreen({ onComplete: _onComplete, onCancel }) {
|
|
|
3936
4089
|
}
|
|
3937
4090
|
) })
|
|
3938
4091
|
] }),
|
|
3939
|
-
/* @__PURE__ */
|
|
4092
|
+
/* @__PURE__ */ jsx15(Box14, { marginTop: 2, children: /* @__PURE__ */ jsx15(Text15, { color: colors.textDim, children: repos2.length > 0 && selectedIndex < repos2.length ? "enter remove \xB7 esc back" : "\u2191\u2193 navigate \xB7 enter select \xB7 esc back" }) })
|
|
3940
4093
|
] });
|
|
3941
4094
|
}
|
|
3942
4095
|
|
|
3943
4096
|
// src/commands/tui/views/ReposViewerScreen.tsx
|
|
3944
|
-
import { Box as
|
|
3945
|
-
import { jsx as
|
|
4097
|
+
import { Box as Box15, Text as Text16, useInput as useInput8 } from "ink";
|
|
4098
|
+
import { jsx as jsx16, jsxs as jsxs15 } from "react/jsx-runtime";
|
|
3946
4099
|
function ReposViewerScreen({ onClose }) {
|
|
3947
4100
|
const repos2 = getRepos();
|
|
3948
4101
|
useInput8((input, key) => {
|
|
@@ -3950,17 +4103,17 @@ function ReposViewerScreen({ onClose }) {
|
|
|
3950
4103
|
onClose();
|
|
3951
4104
|
}
|
|
3952
4105
|
});
|
|
3953
|
-
return /* @__PURE__ */
|
|
3954
|
-
/* @__PURE__ */
|
|
3955
|
-
repos2.length === 0 ? /* @__PURE__ */
|
|
3956
|
-
/* @__PURE__ */
|
|
3957
|
-
/* @__PURE__ */
|
|
4106
|
+
return /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", padding: 2, children: [
|
|
4107
|
+
/* @__PURE__ */ jsx16(Text16, { color: colors.text, bold: true, children: "Repositories" }),
|
|
4108
|
+
repos2.length === 0 ? /* @__PURE__ */ jsx16(Box15, { marginTop: 1, children: /* @__PURE__ */ jsx16(Text16, { color: colors.textDim, children: "No repos configured" }) }) : /* @__PURE__ */ jsx16(Box15, { flexDirection: "column", marginTop: 1, children: repos2.map((repo, index) => /* @__PURE__ */ jsxs15(Box15, { flexDirection: "column", marginTop: index > 0 ? 2 : 0, children: [
|
|
4109
|
+
/* @__PURE__ */ jsx16(Text16, { color: colors.text, bold: true, children: repo.name }),
|
|
4110
|
+
/* @__PURE__ */ jsx16(Box15, { marginTop: 0, children: /* @__PURE__ */ jsxs15(Text16, { color: colors.textDim, children: [
|
|
3958
4111
|
"Path: ",
|
|
3959
4112
|
repo.path
|
|
3960
4113
|
] }) }),
|
|
3961
|
-
repo.description && /* @__PURE__ */
|
|
4114
|
+
repo.description && /* @__PURE__ */ jsx16(Box15, { marginTop: 0, children: /* @__PURE__ */ jsx16(Text16, { color: colors.textDim, children: repo.description }) })
|
|
3962
4115
|
] }, repo.name)) }),
|
|
3963
|
-
/* @__PURE__ */
|
|
4116
|
+
/* @__PURE__ */ jsx16(Box15, { marginTop: 2, children: /* @__PURE__ */ jsx16(Text16, { color: colors.textDim, children: "esc back" }) })
|
|
3964
4117
|
] });
|
|
3965
4118
|
}
|
|
3966
4119
|
|
|
@@ -4097,12 +4250,23 @@ function useToolUpdates({ onUpdateComplete }) {
|
|
|
4097
4250
|
}
|
|
4098
4251
|
|
|
4099
4252
|
// src/commands/tui.tsx
|
|
4100
|
-
import { Fragment as Fragment2, jsx as
|
|
4253
|
+
import { Fragment as Fragment2, jsx as jsx17, jsxs as jsxs16 } from "react/jsx-runtime";
|
|
4101
4254
|
var exitMessage = null;
|
|
4255
|
+
var exitCommand = null;
|
|
4256
|
+
var __tui_dirname = dirname7(fileURLToPath5(import.meta.url));
|
|
4257
|
+
var INTEGRATIONS_DIR = join11(__tui_dirname, "../integrations");
|
|
4258
|
+
function loadIntegrationReference(integration, filename) {
|
|
4259
|
+
try {
|
|
4260
|
+
return readFileSync9(join11(INTEGRATIONS_DIR, integration, "references", filename), "utf-8");
|
|
4261
|
+
} catch {
|
|
4262
|
+
return null;
|
|
4263
|
+
}
|
|
4264
|
+
}
|
|
4102
4265
|
function App() {
|
|
4103
4266
|
const { exit } = useApp2();
|
|
4104
4267
|
const tabs = [
|
|
4105
4268
|
{ id: "tools", label: "Tools" },
|
|
4269
|
+
{ id: "integrations", label: "Integrations" },
|
|
4106
4270
|
{ id: "settings", label: "Settings" }
|
|
4107
4271
|
];
|
|
4108
4272
|
const [activeTab, setActiveTab] = useState10("tools");
|
|
@@ -4217,7 +4381,7 @@ function App() {
|
|
|
4217
4381
|
setSelectedAction(0);
|
|
4218
4382
|
}
|
|
4219
4383
|
if (key.downArrow) {
|
|
4220
|
-
const maxIndex = activeTab === "tools" ? tools.length - 1 : 0;
|
|
4384
|
+
const maxIndex = activeTab === "tools" ? tools.length - 1 : activeTab === "integrations" ? 0 : 0;
|
|
4221
4385
|
setSelectedIndex((prev) => {
|
|
4222
4386
|
const newIndex = Math.min(maxIndex, prev + 1);
|
|
4223
4387
|
if (newIndex >= scrollOffset + MAX_VISIBLE_ITEMS) {
|
|
@@ -4230,6 +4394,8 @@ function App() {
|
|
|
4230
4394
|
if (key.return) {
|
|
4231
4395
|
if (activeTab === "tools" && tools.length > 0) {
|
|
4232
4396
|
setView("detail");
|
|
4397
|
+
} else if (activeTab === "integrations") {
|
|
4398
|
+
setView("detail");
|
|
4233
4399
|
} else if (activeTab === "settings") {
|
|
4234
4400
|
setView("detail");
|
|
4235
4401
|
}
|
|
@@ -4239,6 +4405,37 @@ function App() {
|
|
|
4239
4405
|
setView("menu");
|
|
4240
4406
|
setSelectedAction(0);
|
|
4241
4407
|
}
|
|
4408
|
+
if (activeTab === "integrations") {
|
|
4409
|
+
const hasClientCreds = !!process.env.SLACK_CLIENT_ID && !!process.env.SLACK_CLIENT_SECRET;
|
|
4410
|
+
const canRunSetup = hasClientCreds && !process.env.SLACK_USER_TOKEN;
|
|
4411
|
+
const intActions = [
|
|
4412
|
+
...canRunSetup ? [{ id: "setup" }] : [],
|
|
4413
|
+
{ id: "guide" }
|
|
4414
|
+
];
|
|
4415
|
+
const maxIntAction = intActions.length - 1;
|
|
4416
|
+
if (key.leftArrow) {
|
|
4417
|
+
setSelectedAction((prev) => Math.max(0, prev - 1));
|
|
4418
|
+
}
|
|
4419
|
+
if (key.rightArrow) {
|
|
4420
|
+
setSelectedAction((prev) => Math.min(maxIntAction, prev + 1));
|
|
4421
|
+
}
|
|
4422
|
+
if (key.return) {
|
|
4423
|
+
const actionId = intActions[selectedAction]?.id;
|
|
4424
|
+
if (actionId === "setup") {
|
|
4425
|
+
exitCommand = ["droid", "integrations", "setup", "slack"];
|
|
4426
|
+
exit();
|
|
4427
|
+
} else if (actionId === "guide") {
|
|
4428
|
+
const content = loadIntegrationReference("slack", "setup.md");
|
|
4429
|
+
if (content) {
|
|
4430
|
+
setPreviousView("detail");
|
|
4431
|
+
setReadmeContent({ title: "Slack Integration Setup", content });
|
|
4432
|
+
setView("readme");
|
|
4433
|
+
} else {
|
|
4434
|
+
setMessage({ text: "Could not load setup guide", type: "error" });
|
|
4435
|
+
}
|
|
4436
|
+
}
|
|
4437
|
+
}
|
|
4438
|
+
}
|
|
4242
4439
|
if (activeTab === "settings") {
|
|
4243
4440
|
if (key.leftArrow) {
|
|
4244
4441
|
setSelectedAction((prev) => Math.max(0, prev - 1));
|
|
@@ -4340,7 +4537,7 @@ function App() {
|
|
|
4340
4537
|
(s) => s.name === (selectedTool.includes.skills.find((sk) => sk.required)?.name || selectedTool.name)
|
|
4341
4538
|
) : null;
|
|
4342
4539
|
if (view === "welcome") {
|
|
4343
|
-
return /* @__PURE__ */
|
|
4540
|
+
return /* @__PURE__ */ jsx17(
|
|
4344
4541
|
WelcomeScreen,
|
|
4345
4542
|
{
|
|
4346
4543
|
updateInfo,
|
|
@@ -4353,7 +4550,7 @@ function App() {
|
|
|
4353
4550
|
);
|
|
4354
4551
|
}
|
|
4355
4552
|
if (view === "tool-updates" && toolUpdates.length > 0) {
|
|
4356
|
-
return /* @__PURE__ */
|
|
4553
|
+
return /* @__PURE__ */ jsx17(
|
|
4357
4554
|
ToolUpdatePrompt,
|
|
4358
4555
|
{
|
|
4359
4556
|
toolUpdates,
|
|
@@ -4365,7 +4562,7 @@ function App() {
|
|
|
4365
4562
|
);
|
|
4366
4563
|
}
|
|
4367
4564
|
if (view === "setup") {
|
|
4368
|
-
return /* @__PURE__ */
|
|
4565
|
+
return /* @__PURE__ */ jsx17(
|
|
4369
4566
|
SetupScreen,
|
|
4370
4567
|
{
|
|
4371
4568
|
onComplete: () => {
|
|
@@ -4382,7 +4579,7 @@ function App() {
|
|
|
4382
4579
|
);
|
|
4383
4580
|
}
|
|
4384
4581
|
if (view === "readme" && readmeContent) {
|
|
4385
|
-
return /* @__PURE__ */
|
|
4582
|
+
return /* @__PURE__ */ jsx17(
|
|
4386
4583
|
ReadmeViewer,
|
|
4387
4584
|
{
|
|
4388
4585
|
title: readmeContent.title,
|
|
@@ -4395,7 +4592,7 @@ function App() {
|
|
|
4395
4592
|
);
|
|
4396
4593
|
}
|
|
4397
4594
|
if (view === "explorer" && selectedTool) {
|
|
4398
|
-
return /* @__PURE__ */
|
|
4595
|
+
return /* @__PURE__ */ jsx17(
|
|
4399
4596
|
ToolExplorer,
|
|
4400
4597
|
{
|
|
4401
4598
|
tool: selectedTool,
|
|
@@ -4411,7 +4608,7 @@ function App() {
|
|
|
4411
4608
|
);
|
|
4412
4609
|
}
|
|
4413
4610
|
if (view === "configure" && selectedSkillForConfig) {
|
|
4414
|
-
return /* @__PURE__ */
|
|
4611
|
+
return /* @__PURE__ */ jsx17(
|
|
4415
4612
|
SkillConfigScreen,
|
|
4416
4613
|
{
|
|
4417
4614
|
skill: selectedSkillForConfig,
|
|
@@ -4429,7 +4626,7 @@ function App() {
|
|
|
4429
4626
|
);
|
|
4430
4627
|
}
|
|
4431
4628
|
if (view === "view-repos") {
|
|
4432
|
-
return /* @__PURE__ */
|
|
4629
|
+
return /* @__PURE__ */ jsx17(
|
|
4433
4630
|
ReposViewerScreen,
|
|
4434
4631
|
{
|
|
4435
4632
|
onClose: () => {
|
|
@@ -4439,7 +4636,7 @@ function App() {
|
|
|
4439
4636
|
);
|
|
4440
4637
|
}
|
|
4441
4638
|
if (view === "repos") {
|
|
4442
|
-
return /* @__PURE__ */
|
|
4639
|
+
return /* @__PURE__ */ jsx17(
|
|
4443
4640
|
ReposManagementScreen,
|
|
4444
4641
|
{
|
|
4445
4642
|
onComplete: () => {
|
|
@@ -4455,43 +4652,43 @@ function App() {
|
|
|
4455
4652
|
}
|
|
4456
4653
|
);
|
|
4457
4654
|
}
|
|
4458
|
-
return /* @__PURE__ */
|
|
4459
|
-
/* @__PURE__ */
|
|
4460
|
-
|
|
4655
|
+
return /* @__PURE__ */ jsxs16(Box16, { flexDirection: "row", padding: 1, children: [
|
|
4656
|
+
/* @__PURE__ */ jsxs16(
|
|
4657
|
+
Box16,
|
|
4461
4658
|
{
|
|
4462
4659
|
flexDirection: "column",
|
|
4463
4660
|
width: 44,
|
|
4464
4661
|
borderStyle: "single",
|
|
4465
4662
|
borderColor: colors.border,
|
|
4466
4663
|
children: [
|
|
4467
|
-
/* @__PURE__ */
|
|
4468
|
-
/* @__PURE__ */
|
|
4469
|
-
/* @__PURE__ */
|
|
4470
|
-
/* @__PURE__ */
|
|
4471
|
-
/* @__PURE__ */
|
|
4472
|
-
/* @__PURE__ */
|
|
4473
|
-
/* @__PURE__ */
|
|
4474
|
-
/* @__PURE__ */
|
|
4664
|
+
/* @__PURE__ */ jsx17(Box16, { paddingX: 1, children: /* @__PURE__ */ jsxs16(Text17, { children: [
|
|
4665
|
+
/* @__PURE__ */ jsx17(Text17, { color: colors.textDim, children: "[" }),
|
|
4666
|
+
/* @__PURE__ */ jsx17(Text17, { color: colors.primary, children: "\u25CF" }),
|
|
4667
|
+
/* @__PURE__ */ jsx17(Text17, { color: colors.textDim, children: " " }),
|
|
4668
|
+
/* @__PURE__ */ jsx17(Text17, { color: colors.primary, children: "\u25CF" }),
|
|
4669
|
+
/* @__PURE__ */ jsx17(Text17, { color: colors.textDim, children: "] " }),
|
|
4670
|
+
/* @__PURE__ */ jsx17(Text17, { color: colors.textMuted, children: "droid" }),
|
|
4671
|
+
/* @__PURE__ */ jsxs16(Text17, { color: colors.textDim, children: [
|
|
4475
4672
|
" v",
|
|
4476
4673
|
getVersion()
|
|
4477
4674
|
] })
|
|
4478
4675
|
] }) }),
|
|
4479
|
-
/* @__PURE__ */
|
|
4676
|
+
/* @__PURE__ */ jsx17(Box16, { paddingX: 1, children: /* @__PURE__ */ jsx17(
|
|
4480
4677
|
PlatformBadges,
|
|
4481
4678
|
{
|
|
4482
4679
|
detected: detectedPlatforms,
|
|
4483
4680
|
ignored: loadConfig().ignored_platforms ?? []
|
|
4484
4681
|
}
|
|
4485
4682
|
) }),
|
|
4486
|
-
/* @__PURE__ */
|
|
4487
|
-
/* @__PURE__ */
|
|
4488
|
-
activeTab === "tools" && /* @__PURE__ */
|
|
4489
|
-
scrollOffset > 0 && /* @__PURE__ */
|
|
4683
|
+
/* @__PURE__ */ jsx17(Box16, { paddingX: 1, marginTop: 1, children: /* @__PURE__ */ jsx17(TabBar, { tabs, activeTab }) }),
|
|
4684
|
+
/* @__PURE__ */ jsxs16(Box16, { flexDirection: "column", marginTop: 1, children: [
|
|
4685
|
+
activeTab === "tools" && /* @__PURE__ */ jsxs16(Fragment2, { children: [
|
|
4686
|
+
scrollOffset > 0 && /* @__PURE__ */ jsx17(Box16, { paddingX: 1, children: /* @__PURE__ */ jsxs16(Text17, { color: colors.textDim, children: [
|
|
4490
4687
|
"\u2191 ",
|
|
4491
4688
|
scrollOffset,
|
|
4492
4689
|
" more"
|
|
4493
4690
|
] }) }),
|
|
4494
|
-
tools.slice(scrollOffset, scrollOffset + MAX_VISIBLE_ITEMS).map((tool, index) => /* @__PURE__ */
|
|
4691
|
+
tools.slice(scrollOffset, scrollOffset + MAX_VISIBLE_ITEMS).map((tool, index) => /* @__PURE__ */ jsx17(
|
|
4495
4692
|
ToolItem,
|
|
4496
4693
|
{
|
|
4497
4694
|
tool,
|
|
@@ -4501,30 +4698,35 @@ function App() {
|
|
|
4501
4698
|
},
|
|
4502
4699
|
tool.name
|
|
4503
4700
|
)),
|
|
4504
|
-
scrollOffset + MAX_VISIBLE_ITEMS < tools.length && /* @__PURE__ */
|
|
4701
|
+
scrollOffset + MAX_VISIBLE_ITEMS < tools.length && /* @__PURE__ */ jsx17(Box16, { paddingX: 1, children: /* @__PURE__ */ jsxs16(Text17, { color: colors.textDim, children: [
|
|
4505
4702
|
"\u2193 ",
|
|
4506
4703
|
tools.length - scrollOffset - MAX_VISIBLE_ITEMS,
|
|
4507
4704
|
" more"
|
|
4508
4705
|
] }) }),
|
|
4509
|
-
tools.length > MAX_VISIBLE_ITEMS && /* @__PURE__ */
|
|
4706
|
+
tools.length > MAX_VISIBLE_ITEMS && /* @__PURE__ */ jsx17(Box16, { paddingX: 1, marginTop: 1, children: /* @__PURE__ */ jsxs16(Text17, { color: colors.textDim, children: [
|
|
4510
4707
|
tools.length,
|
|
4511
4708
|
" tools total"
|
|
4512
4709
|
] }) })
|
|
4513
4710
|
] }),
|
|
4514
|
-
activeTab === "
|
|
4711
|
+
activeTab === "integrations" && /* @__PURE__ */ jsx17(Box16, { paddingX: 1, children: /* @__PURE__ */ jsxs16(Text17, { children: [
|
|
4712
|
+
selectedIndex === 0 ? /* @__PURE__ */ jsx17(Text17, { color: colors.primary, children: ">" }) : /* @__PURE__ */ jsx17(Text17, { children: " " }),
|
|
4713
|
+
/* @__PURE__ */ jsx17(Text17, { children: " Slack" }),
|
|
4714
|
+
process.env.SLACK_USER_TOKEN ? /* @__PURE__ */ jsx17(Text17, { color: colors.success, children: " \u2713" }) : /* @__PURE__ */ jsx17(Text17, { color: colors.textDim, children: " \u2717" })
|
|
4715
|
+
] }) }),
|
|
4716
|
+
activeTab === "settings" && /* @__PURE__ */ jsx17(Box16, { paddingX: 1, children: /* @__PURE__ */ jsx17(Text17, { color: colors.textDim, children: "View and edit config" }) })
|
|
4515
4717
|
] }),
|
|
4516
|
-
message && /* @__PURE__ */
|
|
4517
|
-
|
|
4718
|
+
message && /* @__PURE__ */ jsx17(Box16, { paddingX: 1, marginTop: 1, children: /* @__PURE__ */ jsx17(
|
|
4719
|
+
Text17,
|
|
4518
4720
|
{
|
|
4519
4721
|
color: message.type === "success" ? colors.success : colors.error,
|
|
4520
4722
|
children: message.text
|
|
4521
4723
|
}
|
|
4522
4724
|
) }),
|
|
4523
|
-
/* @__PURE__ */
|
|
4725
|
+
/* @__PURE__ */ jsx17(Box16, { paddingX: 1, marginTop: 1, children: /* @__PURE__ */ jsx17(Text17, { color: colors.textDim, children: view === "menu" ? "\u2190\u2192 \u2191\u2193 enter q" : "\u2190\u2192 enter esc q" }) })
|
|
4524
4726
|
]
|
|
4525
4727
|
}
|
|
4526
4728
|
),
|
|
4527
|
-
activeTab === "tools" && /* @__PURE__ */
|
|
4729
|
+
activeTab === "tools" && /* @__PURE__ */ jsx17(
|
|
4528
4730
|
ToolDetails,
|
|
4529
4731
|
{
|
|
4530
4732
|
tool: selectedTool,
|
|
@@ -4532,7 +4734,14 @@ function App() {
|
|
|
4532
4734
|
selectedAction
|
|
4533
4735
|
}
|
|
4534
4736
|
),
|
|
4535
|
-
activeTab === "
|
|
4737
|
+
activeTab === "integrations" && /* @__PURE__ */ jsx17(
|
|
4738
|
+
IntegrationsDetails,
|
|
4739
|
+
{
|
|
4740
|
+
isFocused: view === "detail",
|
|
4741
|
+
selectedAction
|
|
4742
|
+
}
|
|
4743
|
+
),
|
|
4744
|
+
activeTab === "settings" && /* @__PURE__ */ jsx17(
|
|
4536
4745
|
SettingsDetails,
|
|
4537
4746
|
{
|
|
4538
4747
|
isFocused: view === "detail",
|
|
@@ -4546,9 +4755,15 @@ function App() {
|
|
|
4546
4755
|
async function tuiCommand() {
|
|
4547
4756
|
process.stdout.write("\x1B[?1049h");
|
|
4548
4757
|
process.stdout.write("\x1B[H");
|
|
4549
|
-
const { waitUntilExit } = render(/* @__PURE__ */
|
|
4758
|
+
const { waitUntilExit } = render(/* @__PURE__ */ jsx17(App, {}));
|
|
4550
4759
|
await waitUntilExit();
|
|
4551
4760
|
process.stdout.write("\x1B[?1049l");
|
|
4761
|
+
if (exitCommand) {
|
|
4762
|
+
const [cmd, ...args] = exitCommand;
|
|
4763
|
+
exitCommand = null;
|
|
4764
|
+
spawnSync3(cmd, args, { stdio: "inherit" });
|
|
4765
|
+
return;
|
|
4766
|
+
}
|
|
4552
4767
|
if (exitMessage) {
|
|
4553
4768
|
console.log(exitMessage);
|
|
4554
4769
|
exitMessage = null;
|
|
@@ -4559,7 +4774,7 @@ async function tuiCommand() {
|
|
|
4559
4774
|
import chalk9 from "chalk";
|
|
4560
4775
|
import { spawn } from "child_process";
|
|
4561
4776
|
import { existsSync as existsSync10 } from "fs";
|
|
4562
|
-
import { join as
|
|
4777
|
+
import { join as join12 } from "path";
|
|
4563
4778
|
function getRuntime(toolPath) {
|
|
4564
4779
|
if (toolPath.endsWith(".ts") || toolPath.endsWith(".js")) {
|
|
4565
4780
|
return { cmd: "bun", args: ["run", toolPath] };
|
|
@@ -4572,12 +4787,12 @@ function getRuntime(toolPath) {
|
|
|
4572
4787
|
async function execCommand(tool, script, args) {
|
|
4573
4788
|
const config = loadConfig();
|
|
4574
4789
|
const skillsPath = getSkillsPath(config.platform);
|
|
4575
|
-
const toolDir =
|
|
4790
|
+
const toolDir = join12(skillsPath, tool);
|
|
4576
4791
|
if (!existsSync10(toolDir)) {
|
|
4577
4792
|
console.error(chalk9.red(`Tool '${tool}' not found at ${toolDir}`));
|
|
4578
4793
|
process.exit(1);
|
|
4579
4794
|
}
|
|
4580
|
-
const scriptsDir =
|
|
4795
|
+
const scriptsDir = join12(toolDir, "scripts");
|
|
4581
4796
|
if (!existsSync10(scriptsDir)) {
|
|
4582
4797
|
console.error(chalk9.red(`No scripts directory in tool '${tool}'`));
|
|
4583
4798
|
process.exit(1);
|
|
@@ -4585,7 +4800,7 @@ async function execCommand(tool, script, args) {
|
|
|
4585
4800
|
const extensions = [".ts", ".js", ".py"];
|
|
4586
4801
|
let scriptPath = null;
|
|
4587
4802
|
for (const ext of extensions) {
|
|
4588
|
-
const candidate =
|
|
4803
|
+
const candidate = join12(scriptsDir, script + ext);
|
|
4589
4804
|
if (existsSync10(candidate)) {
|
|
4590
4805
|
scriptPath = candidate;
|
|
4591
4806
|
break;
|
|
@@ -4748,30 +4963,249 @@ async function reposGetCommand(name) {
|
|
|
4748
4963
|
console.log(JSON.stringify(repo, null, 2));
|
|
4749
4964
|
}
|
|
4750
4965
|
|
|
4751
|
-
// src/commands/
|
|
4966
|
+
// src/commands/integrations.ts
|
|
4752
4967
|
import inquirer5 from "inquirer";
|
|
4753
4968
|
import chalk11 from "chalk";
|
|
4754
4969
|
import { execSync as execSync6 } from "child_process";
|
|
4970
|
+
import { createServer } from "https";
|
|
4971
|
+
import { readFileSync as readFileSync10 } from "fs";
|
|
4972
|
+
import { join as join13 } from "path";
|
|
4755
4973
|
|
|
4756
|
-
// src/
|
|
4974
|
+
// src/integrations/slack/index.ts
|
|
4975
|
+
import { WebClient } from "@slack/web-api";
|
|
4976
|
+
function getSlackToken() {
|
|
4977
|
+
return process.env.SLACK_USER_TOKEN;
|
|
4978
|
+
}
|
|
4757
4979
|
function hasSlackToken() {
|
|
4758
4980
|
return !!process.env.SLACK_USER_TOKEN;
|
|
4759
4981
|
}
|
|
4982
|
+
async function postMessage(params) {
|
|
4983
|
+
const token = getSlackToken();
|
|
4984
|
+
if (!token) {
|
|
4985
|
+
return { ok: false, error: "SLACK_USER_TOKEN not set. Run: droid integrations setup slack" };
|
|
4986
|
+
}
|
|
4987
|
+
const client = new WebClient(token);
|
|
4988
|
+
try {
|
|
4989
|
+
const result = await client.chat.postMessage({
|
|
4990
|
+
channel: params.channel,
|
|
4991
|
+
text: params.text,
|
|
4992
|
+
unfurl_links: params.unfurl_links
|
|
4993
|
+
});
|
|
4994
|
+
return {
|
|
4995
|
+
ok: result.ok ?? false,
|
|
4996
|
+
ts: result.ts,
|
|
4997
|
+
channel: result.channel
|
|
4998
|
+
};
|
|
4999
|
+
} catch (error) {
|
|
5000
|
+
return {
|
|
5001
|
+
ok: false,
|
|
5002
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
5003
|
+
};
|
|
5004
|
+
}
|
|
5005
|
+
}
|
|
5006
|
+
async function editCanvas(params) {
|
|
5007
|
+
const token = getSlackToken();
|
|
5008
|
+
if (!token) {
|
|
5009
|
+
return { ok: false, error: "SLACK_USER_TOKEN not set. Run: droid integrations setup slack" };
|
|
5010
|
+
}
|
|
5011
|
+
const client = new WebClient(token);
|
|
5012
|
+
try {
|
|
5013
|
+
const result = await client.canvases.edit({
|
|
5014
|
+
canvas_id: params.canvas_id,
|
|
5015
|
+
// eslint-disable-next-line @typescript-eslint/no-explicit-any
|
|
5016
|
+
changes: params.changes
|
|
5017
|
+
});
|
|
5018
|
+
return { ok: result.ok ?? false };
|
|
5019
|
+
} catch (error) {
|
|
5020
|
+
return {
|
|
5021
|
+
ok: false,
|
|
5022
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
5023
|
+
};
|
|
5024
|
+
}
|
|
5025
|
+
}
|
|
5026
|
+
async function exchangeOAuthCode(clientId, clientSecret, code, redirectUri) {
|
|
5027
|
+
try {
|
|
5028
|
+
const client = new WebClient();
|
|
5029
|
+
const result = await client.oauth.v2.access({
|
|
5030
|
+
client_id: clientId,
|
|
5031
|
+
client_secret: clientSecret,
|
|
5032
|
+
code,
|
|
5033
|
+
redirect_uri: redirectUri
|
|
5034
|
+
});
|
|
5035
|
+
if (!result.ok) {
|
|
5036
|
+
return { ok: false, error: String(result.error ?? "Unknown error") };
|
|
5037
|
+
}
|
|
5038
|
+
const token = result.authed_user?.access_token;
|
|
5039
|
+
if (!token) {
|
|
5040
|
+
return { ok: false, error: "No user token in response" };
|
|
5041
|
+
}
|
|
5042
|
+
return { ok: true, token };
|
|
5043
|
+
} catch (error) {
|
|
5044
|
+
return {
|
|
5045
|
+
ok: false,
|
|
5046
|
+
error: error instanceof Error ? error.message : "Unknown error"
|
|
5047
|
+
};
|
|
5048
|
+
}
|
|
5049
|
+
}
|
|
4760
5050
|
|
|
4761
|
-
// src/commands/
|
|
5051
|
+
// src/commands/integrations.ts
|
|
4762
5052
|
var SLACK_SCOPES = "chat:write,canvases:write";
|
|
4763
|
-
var
|
|
4764
|
-
|
|
5053
|
+
var CALLBACK_PORT = 9876;
|
|
5054
|
+
var REDIRECT_URI = `https://localhost:${CALLBACK_PORT}/callback`;
|
|
5055
|
+
function getShellInfo() {
|
|
4765
5056
|
const shell = process.env.SHELL || "/bin/zsh";
|
|
4766
|
-
if (shell.includes("
|
|
4767
|
-
|
|
4768
|
-
|
|
4769
|
-
return "~/.
|
|
5057
|
+
if (shell.includes("fish")) {
|
|
5058
|
+
return { rcPath: "~/.config/fish/config.fish", isFish: true };
|
|
5059
|
+
}
|
|
5060
|
+
if (shell.includes("zsh")) return { rcPath: "~/.zshrc", isFish: false };
|
|
5061
|
+
if (shell.includes("bash")) return { rcPath: "~/.bashrc", isFish: false };
|
|
5062
|
+
return { rcPath: "~/.profile", isFish: false };
|
|
5063
|
+
}
|
|
5064
|
+
function expandHome(path) {
|
|
5065
|
+
if (path.startsWith("~/")) {
|
|
5066
|
+
return path.replace("~", process.env.HOME || "");
|
|
5067
|
+
}
|
|
5068
|
+
return path;
|
|
5069
|
+
}
|
|
5070
|
+
function buildExportLine(key, value, isFish) {
|
|
5071
|
+
if (isFish) {
|
|
5072
|
+
return `set -gx ${key} "${value}"`;
|
|
5073
|
+
}
|
|
5074
|
+
return `export ${key}="${value}"`;
|
|
5075
|
+
}
|
|
5076
|
+
var SUCCESS_HTML = `<!DOCTYPE html>
|
|
5077
|
+
<html>
|
|
5078
|
+
<head>
|
|
5079
|
+
<title>Droid - Slack Connected</title>
|
|
5080
|
+
<style>
|
|
5081
|
+
body { font-family: -apple-system, system-ui, sans-serif; display: flex; justify-content: center; align-items: center; min-height: 100vh; margin: 0; background: #1a1a2e; colour: #eee; }
|
|
5082
|
+
.card { text-align: center; padding: 3rem; border-radius: 12px; background: #16213e; box-shadow: 0 4px 24px rgba(0,0,0,0.3); }
|
|
5083
|
+
h1 { color: #4ecca3; margin-bottom: 0.5rem; }
|
|
5084
|
+
p { color: #a0a0b0; }
|
|
5085
|
+
</style>
|
|
5086
|
+
</head>
|
|
5087
|
+
<body>
|
|
5088
|
+
<div class="card">
|
|
5089
|
+
<h1>Connected!</h1>
|
|
5090
|
+
<p>Slack is now linked to Droid. You can close this tab.</p>
|
|
5091
|
+
</div>
|
|
5092
|
+
</body>
|
|
5093
|
+
</html>`;
|
|
5094
|
+
var CERT_DIR = join13(process.env.HOME || "", ".droid", "certs");
|
|
5095
|
+
var CERT_KEY_PATH = join13(CERT_DIR, "localhost-key.pem");
|
|
5096
|
+
var CERT_PATH = join13(CERT_DIR, "localhost.pem");
|
|
5097
|
+
function getOrCreateCert() {
|
|
5098
|
+
try {
|
|
5099
|
+
const key = readFileSync10(CERT_KEY_PATH, "utf-8");
|
|
5100
|
+
const cert = readFileSync10(CERT_PATH, "utf-8");
|
|
5101
|
+
if (key && cert) return { key, cert };
|
|
5102
|
+
} catch {
|
|
5103
|
+
}
|
|
5104
|
+
const { mkdirSync: mkdirSync7 } = __require("fs");
|
|
5105
|
+
mkdirSync7(CERT_DIR, { recursive: true });
|
|
5106
|
+
execSync6(
|
|
5107
|
+
`openssl req -x509 -newkey rsa:2048 -keyout "${CERT_KEY_PATH}" -out "${CERT_PATH}" -days 365 -nodes -subj "/CN=localhost" -addext "subjectAltName=DNS:localhost,IP:127.0.0.1" 2>/dev/null`,
|
|
5108
|
+
{ stdio: "ignore" }
|
|
5109
|
+
);
|
|
5110
|
+
return {
|
|
5111
|
+
key: readFileSync10(CERT_KEY_PATH, "utf-8"),
|
|
5112
|
+
cert: readFileSync10(CERT_PATH, "utf-8")
|
|
5113
|
+
};
|
|
5114
|
+
}
|
|
5115
|
+
function trustCertInKeychain() {
|
|
5116
|
+
try {
|
|
5117
|
+
execSync6(
|
|
5118
|
+
`security add-trusted-cert -p ssl -r trustRoot -k ~/Library/Keychains/login.keychain-db "${CERT_PATH}"`,
|
|
5119
|
+
{ stdio: "pipe" }
|
|
5120
|
+
);
|
|
5121
|
+
return true;
|
|
5122
|
+
} catch {
|
|
5123
|
+
return false;
|
|
5124
|
+
}
|
|
5125
|
+
}
|
|
5126
|
+
function waitForCallback() {
|
|
5127
|
+
const { key, cert } = getOrCreateCert();
|
|
5128
|
+
return new Promise((resolve, reject) => {
|
|
5129
|
+
const server = createServer({ key, cert }, (req, res) => {
|
|
5130
|
+
const url = new URL(req.url || "", `https://localhost:${CALLBACK_PORT}`);
|
|
5131
|
+
if (url.pathname === "/callback") {
|
|
5132
|
+
const code = url.searchParams.get("code");
|
|
5133
|
+
const error = url.searchParams.get("error");
|
|
5134
|
+
if (error) {
|
|
5135
|
+
clearTimeout(timeout);
|
|
5136
|
+
res.writeHead(400, { "Content-Type": "text/html" });
|
|
5137
|
+
res.end(`<h1>Error</h1><p>${error}</p>`);
|
|
5138
|
+
server.close();
|
|
5139
|
+
reject(new Error(`Slack authorization denied: ${error}`));
|
|
5140
|
+
return;
|
|
5141
|
+
}
|
|
5142
|
+
if (code) {
|
|
5143
|
+
clearTimeout(timeout);
|
|
5144
|
+
res.writeHead(200, { "Content-Type": "text/html" });
|
|
5145
|
+
res.end(SUCCESS_HTML);
|
|
5146
|
+
server.close();
|
|
5147
|
+
resolve(code);
|
|
5148
|
+
return;
|
|
5149
|
+
}
|
|
5150
|
+
clearTimeout(timeout);
|
|
5151
|
+
res.writeHead(400, { "Content-Type": "text/plain" });
|
|
5152
|
+
res.end("Missing code parameter");
|
|
5153
|
+
server.close();
|
|
5154
|
+
reject(new Error("No code in callback"));
|
|
5155
|
+
}
|
|
5156
|
+
});
|
|
5157
|
+
server.listen(CALLBACK_PORT, () => {
|
|
5158
|
+
});
|
|
5159
|
+
server.on("error", (err) => {
|
|
5160
|
+
clearTimeout(timeout);
|
|
5161
|
+
reject(new Error(`Could not start callback server on port ${CALLBACK_PORT}: ${err.message}`));
|
|
5162
|
+
});
|
|
5163
|
+
const timeout = setTimeout(() => {
|
|
5164
|
+
server.close();
|
|
5165
|
+
reject(new Error("Timed out waiting for Slack authorization (2 minutes)"));
|
|
5166
|
+
}, 12e4);
|
|
5167
|
+
});
|
|
4770
5168
|
}
|
|
4771
|
-
|
|
4772
|
-
|
|
5169
|
+
function writeTokenToShellRc(key, value) {
|
|
5170
|
+
const { rcPath, isFish } = getShellInfo();
|
|
5171
|
+
const exportLine = buildExportLine(key, value, isFish);
|
|
5172
|
+
const fullPath = expandHome(rcPath);
|
|
5173
|
+
try {
|
|
5174
|
+
const { readFileSync: readFs, appendFileSync: appendFileSync2 } = __require("fs");
|
|
5175
|
+
const existing = readFs(fullPath, "utf-8");
|
|
5176
|
+
if (existing.includes(`${key}=`) || existing.includes(`${key} "`)) {
|
|
5177
|
+
const lines = existing.split("\n");
|
|
5178
|
+
const pattern = isFish ? new RegExp(`^set\\s+-gx\\s+${key}\\s+`) : new RegExp(`^export\\s+${key}=`);
|
|
5179
|
+
let replaced = false;
|
|
5180
|
+
const updated = lines.map((line) => {
|
|
5181
|
+
if (pattern.test(line) && !replaced) {
|
|
5182
|
+
replaced = true;
|
|
5183
|
+
return exportLine;
|
|
5184
|
+
}
|
|
5185
|
+
return line;
|
|
5186
|
+
});
|
|
5187
|
+
if (replaced) {
|
|
5188
|
+
const { writeFileSync: writeFileSync6 } = __require("fs");
|
|
5189
|
+
writeFileSync6(fullPath, updated.join("\n"), "utf-8");
|
|
5190
|
+
} else {
|
|
5191
|
+
appendFileSync2(fullPath, `
|
|
5192
|
+
${exportLine}
|
|
5193
|
+
`, "utf-8");
|
|
5194
|
+
}
|
|
5195
|
+
} else {
|
|
5196
|
+
appendFileSync2(fullPath, `
|
|
5197
|
+
${exportLine}
|
|
5198
|
+
`, "utf-8");
|
|
5199
|
+
}
|
|
5200
|
+
return true;
|
|
5201
|
+
} catch {
|
|
5202
|
+
return false;
|
|
5203
|
+
}
|
|
5204
|
+
}
|
|
5205
|
+
async function integrationsSetupSlackCommand() {
|
|
5206
|
+
console.log(chalk11.bold("\nSlack Integration Setup\n"));
|
|
4773
5207
|
if (hasSlackToken()) {
|
|
4774
|
-
console.log(chalk11.green("
|
|
5208
|
+
console.log(chalk11.green(" SLACK_USER_TOKEN is already set in your environment\n"));
|
|
4775
5209
|
const { reauth } = await inquirer5.prompt([
|
|
4776
5210
|
{
|
|
4777
5211
|
type: "confirm",
|
|
@@ -4788,93 +5222,170 @@ async function authSlackCommand() {
|
|
|
4788
5222
|
const clientId = process.env.SLACK_CLIENT_ID;
|
|
4789
5223
|
const clientSecret = process.env.SLACK_CLIENT_SECRET;
|
|
4790
5224
|
if (!clientId || !clientSecret) {
|
|
4791
|
-
const
|
|
4792
|
-
console.log(chalk11.yellow("Missing Slack app credentials.\n"));
|
|
4793
|
-
console.log(chalk11.gray('Get Client ID and Client Secret from 1Password ("Droid Slack App")'));
|
|
4794
|
-
console.log(chalk11.gray(`and add to your ${
|
|
5225
|
+
const { rcPath: rcPath2 } = getShellInfo();
|
|
5226
|
+
console.log(chalk11.yellow(" Missing Slack app credentials.\n"));
|
|
5227
|
+
console.log(chalk11.gray(' Get Client ID and Client Secret from 1Password ("Droid Slack App")'));
|
|
5228
|
+
console.log(chalk11.gray(` and add to your ${rcPath2}:
|
|
4795
5229
|
`));
|
|
4796
|
-
console.log(chalk11.white('
|
|
4797
|
-
console.log(chalk11.white('
|
|
4798
|
-
console.log(chalk11.gray("Then reload and run this again:\n"));
|
|
4799
|
-
console.log(chalk11.white(`
|
|
5230
|
+
console.log(chalk11.white(' export SLACK_CLIENT_ID="your-client-id"'));
|
|
5231
|
+
console.log(chalk11.white(' export SLACK_CLIENT_SECRET="your-client-secret"\n'));
|
|
5232
|
+
console.log(chalk11.gray(" Then reload and run this again:\n"));
|
|
5233
|
+
console.log(chalk11.white(` source ${rcPath2} && droid integrations setup slack
|
|
4800
5234
|
`));
|
|
4801
5235
|
return;
|
|
4802
5236
|
}
|
|
5237
|
+
console.log(chalk11.gray(" Checking credentials...") + chalk11.green(" SLACK_CLIENT_ID found"));
|
|
4803
5238
|
const authorizeUrl = `https://slack.com/oauth/v2/authorize?client_id=${clientId}&user_scope=${SLACK_SCOPES}&redirect_uri=${encodeURIComponent(REDIRECT_URI)}`;
|
|
4804
|
-
|
|
4805
|
-
|
|
4806
|
-
|
|
4807
|
-
|
|
4808
|
-
|
|
4809
|
-
|
|
4810
|
-
|
|
4811
|
-
|
|
4812
|
-
|
|
4813
|
-
|
|
4814
|
-
|
|
4815
|
-
|
|
4816
|
-
|
|
5239
|
+
getOrCreateCert();
|
|
5240
|
+
const certTrusted = getConfigValue("integrations.slack.cert_trusted");
|
|
5241
|
+
if (!certTrusted) {
|
|
5242
|
+
console.log(chalk11.gray(" The OAuth callback uses a local HTTPS certificate."));
|
|
5243
|
+
const { trust } = await inquirer5.prompt([
|
|
5244
|
+
{
|
|
5245
|
+
type: "confirm",
|
|
5246
|
+
name: "trust",
|
|
5247
|
+
message: "Trust the local certificate? (avoids browser warnings)",
|
|
5248
|
+
default: true
|
|
5249
|
+
}
|
|
5250
|
+
]);
|
|
5251
|
+
if (trust) {
|
|
5252
|
+
console.log(chalk11.gray(" Adding certificate to Keychain (you may be prompted for your password)..."));
|
|
5253
|
+
if (trustCertInKeychain()) {
|
|
5254
|
+
console.log(chalk11.green(" Certificate trusted."));
|
|
5255
|
+
setConfigValue("integrations.slack.cert_trusted", true);
|
|
5256
|
+
} else {
|
|
5257
|
+
console.log(chalk11.yellow(" Could not trust certificate \u2014 you may see a browser warning."));
|
|
5258
|
+
}
|
|
4817
5259
|
}
|
|
4818
|
-
|
|
4819
|
-
|
|
5260
|
+
console.log("");
|
|
5261
|
+
}
|
|
5262
|
+
console.log(chalk11.gray(" Opening browser for Slack authorisation..."));
|
|
5263
|
+
const callbackPromise = waitForCallback();
|
|
4820
5264
|
try {
|
|
4821
|
-
|
|
4822
|
-
|
|
4823
|
-
|
|
4824
|
-
|
|
4825
|
-
|
|
4826
|
-
|
|
4827
|
-
|
|
4828
|
-
|
|
4829
|
-
|
|
4830
|
-
|
|
4831
|
-
|
|
5265
|
+
execSync6(`open "${authorizeUrl}"`, { stdio: "ignore" });
|
|
5266
|
+
} catch {
|
|
5267
|
+
console.log(chalk11.gray("\n Could not open browser. Open this URL manually:\n"));
|
|
5268
|
+
console.log(chalk11.cyan(` ${authorizeUrl}
|
|
5269
|
+
`));
|
|
5270
|
+
}
|
|
5271
|
+
console.log(chalk11.gray(" Waiting for callback..."));
|
|
5272
|
+
let code;
|
|
5273
|
+
try {
|
|
5274
|
+
code = await callbackPromise;
|
|
5275
|
+
} catch (error) {
|
|
5276
|
+
console.log(chalk11.red(`
|
|
5277
|
+
${error instanceof Error ? error.message : "Failed to receive callback"}`));
|
|
5278
|
+
return;
|
|
5279
|
+
}
|
|
5280
|
+
console.log(chalk11.green(" Authorisation received"));
|
|
5281
|
+
const result = await exchangeOAuthCode(clientId, clientSecret, code, REDIRECT_URI);
|
|
5282
|
+
if (!result.ok || !result.token) {
|
|
5283
|
+
console.log(chalk11.red(`
|
|
5284
|
+
Slack API error: ${result.error}`));
|
|
5285
|
+
if (result.error === "invalid_code") {
|
|
5286
|
+
console.log(chalk11.gray(" The code may have expired. Try again."));
|
|
4832
5287
|
}
|
|
4833
|
-
|
|
4834
|
-
|
|
4835
|
-
|
|
4836
|
-
|
|
4837
|
-
|
|
5288
|
+
return;
|
|
5289
|
+
}
|
|
5290
|
+
console.log(chalk11.green(" Token exchanged successfully"));
|
|
5291
|
+
const { rcPath } = getShellInfo();
|
|
5292
|
+
const { writeToRc } = await inquirer5.prompt([
|
|
5293
|
+
{
|
|
5294
|
+
type: "confirm",
|
|
5295
|
+
name: "writeToRc",
|
|
5296
|
+
message: `Write SLACK_USER_TOKEN to ${rcPath}?`,
|
|
5297
|
+
default: true
|
|
4838
5298
|
}
|
|
4839
|
-
|
|
4840
|
-
|
|
4841
|
-
|
|
4842
|
-
|
|
4843
|
-
`
|
|
4844
|
-
|
|
5299
|
+
]);
|
|
5300
|
+
if (writeToRc) {
|
|
5301
|
+
const written = writeTokenToShellRc("SLACK_USER_TOKEN", result.token);
|
|
5302
|
+
if (written) {
|
|
5303
|
+
console.log(chalk11.green(`
|
|
5304
|
+
Token saved to ${rcPath}`));
|
|
5305
|
+
console.log(chalk11.gray(" Source your shell or open a new tab to use it."));
|
|
5306
|
+
} else {
|
|
5307
|
+
console.log(chalk11.yellow(`
|
|
5308
|
+
Could not write to ${rcPath}. Add manually:
|
|
4845
5309
|
`));
|
|
4846
|
-
|
|
4847
|
-
|
|
5310
|
+
const { isFish } = getShellInfo();
|
|
5311
|
+
console.log(chalk11.white(` ${buildExportLine("SLACK_USER_TOKEN", result.token, isFish)}
|
|
4848
5312
|
`));
|
|
4849
|
-
} catch (error) {
|
|
4850
|
-
console.log(chalk11.red("\u2717 Failed to exchange code for token"));
|
|
4851
|
-
if (error instanceof Error) {
|
|
4852
|
-
console.log(chalk11.gray(` ${error.message}`));
|
|
4853
5313
|
}
|
|
5314
|
+
} else {
|
|
5315
|
+
const { isFish } = getShellInfo();
|
|
5316
|
+
console.log(chalk11.yellow("\n Add to your shell config manually:\n"));
|
|
5317
|
+
console.log(chalk11.white(` ${buildExportLine("SLACK_USER_TOKEN", result.token, isFish)}
|
|
5318
|
+
`));
|
|
4854
5319
|
}
|
|
5320
|
+
setConfigValue("integrations.slack.configured", true);
|
|
5321
|
+
console.log(chalk11.green("\n Slack integration configured!\n"));
|
|
4855
5322
|
}
|
|
4856
|
-
async function
|
|
4857
|
-
console.log(chalk11.bold("\
|
|
5323
|
+
async function integrationsStatusCommand() {
|
|
5324
|
+
console.log(chalk11.bold("\nIntegrations Status\n"));
|
|
5325
|
+
console.log(chalk11.bold(" Slack"));
|
|
5326
|
+
const configured = getConfigValue("integrations.slack.configured");
|
|
4858
5327
|
const clientId = process.env.SLACK_CLIENT_ID;
|
|
4859
5328
|
const clientSecret = process.env.SLACK_CLIENT_SECRET;
|
|
4860
5329
|
const hasCredentials = clientId && clientSecret;
|
|
4861
5330
|
if (hasCredentials) {
|
|
4862
|
-
console.log(chalk11.green("
|
|
5331
|
+
console.log(chalk11.green(" App credentials configured"));
|
|
4863
5332
|
} else {
|
|
4864
|
-
console.log(chalk11.yellow("
|
|
4865
|
-
console.log(chalk11.gray("
|
|
5333
|
+
console.log(chalk11.yellow(" App credentials missing"));
|
|
5334
|
+
console.log(chalk11.gray(" Run: droid integrations setup slack"));
|
|
4866
5335
|
}
|
|
4867
5336
|
if (hasSlackToken()) {
|
|
4868
5337
|
const token = process.env.SLACK_USER_TOKEN;
|
|
4869
5338
|
const masked = token.slice(0, 10) + "..." + token.slice(-4);
|
|
4870
|
-
console.log(chalk11.green("
|
|
4871
|
-
console.log(chalk11.gray(`
|
|
5339
|
+
console.log(chalk11.green(" User token configured"));
|
|
5340
|
+
console.log(chalk11.gray(` Token: ${masked}`));
|
|
4872
5341
|
} else {
|
|
4873
|
-
console.log(chalk11.yellow("
|
|
5342
|
+
console.log(chalk11.yellow(" User token missing"));
|
|
4874
5343
|
if (hasCredentials) {
|
|
4875
|
-
console.log(chalk11.gray("
|
|
5344
|
+
console.log(chalk11.gray(" Run: droid integrations setup slack"));
|
|
4876
5345
|
}
|
|
4877
5346
|
}
|
|
5347
|
+
if (configured) {
|
|
5348
|
+
console.log(chalk11.green(" Status: configured"));
|
|
5349
|
+
} else {
|
|
5350
|
+
console.log(chalk11.yellow(" Status: not configured"));
|
|
5351
|
+
}
|
|
5352
|
+
console.log("");
|
|
5353
|
+
}
|
|
5354
|
+
async function slackPostCommand(options) {
|
|
5355
|
+
let input;
|
|
5356
|
+
try {
|
|
5357
|
+
input = readFileSync10(0, "utf-8").trim();
|
|
5358
|
+
} catch {
|
|
5359
|
+
console.log(JSON.stringify({ ok: false, error: "Failed to read from stdin. Pipe JSON payload via stdin." }));
|
|
5360
|
+
process.exit(1);
|
|
5361
|
+
}
|
|
5362
|
+
if (!input) {
|
|
5363
|
+
console.log(JSON.stringify({ ok: false, error: "Empty stdin. Pipe JSON payload via stdin." }));
|
|
5364
|
+
process.exit(1);
|
|
5365
|
+
}
|
|
5366
|
+
let payload;
|
|
5367
|
+
try {
|
|
5368
|
+
payload = JSON.parse(input);
|
|
5369
|
+
} catch {
|
|
5370
|
+
console.log(JSON.stringify({ ok: false, error: "Invalid JSON on stdin." }));
|
|
5371
|
+
process.exit(1);
|
|
5372
|
+
}
|
|
5373
|
+
if (options.canvas) {
|
|
5374
|
+
const result = await editCanvas({
|
|
5375
|
+
canvas_id: payload.canvas_id,
|
|
5376
|
+
changes: payload.changes
|
|
5377
|
+
});
|
|
5378
|
+
console.log(JSON.stringify(result));
|
|
5379
|
+
if (!result.ok) process.exit(1);
|
|
5380
|
+
} else {
|
|
5381
|
+
const result = await postMessage({
|
|
5382
|
+
channel: payload.channel,
|
|
5383
|
+
text: payload.text,
|
|
5384
|
+
unfurl_links: payload.unfurl_links
|
|
5385
|
+
});
|
|
5386
|
+
console.log(JSON.stringify(result));
|
|
5387
|
+
if (!result.ok) process.exit(1);
|
|
5388
|
+
}
|
|
4878
5389
|
}
|
|
4879
5390
|
|
|
4880
5391
|
// src/bin/droid.ts
|
|
@@ -4896,10 +5407,13 @@ program.command("uninstall <tool>").description("Uninstall a tool").action(unins
|
|
|
4896
5407
|
program.command("update").description("Update droid and installed tools").option("--tools", "Only update tools").option("--cli", "Only update the CLI").argument("[tool]", "Update a specific tool").action(updateCommand);
|
|
4897
5408
|
program.command("tui").description("Launch interactive TUI dashboard").action(tuiCommand);
|
|
4898
5409
|
program.command("exec <tool> <script>").description("Execute a tool script").argument("[args...]", "Arguments to pass to the script").allowUnknownOption().action(execCommand);
|
|
4899
|
-
var
|
|
4900
|
-
|
|
4901
|
-
|
|
4902
|
-
|
|
5410
|
+
var integrations = program.command("integrations").description("Manage external service integrations");
|
|
5411
|
+
var integrationsSetup = integrations.command("setup").description("Set up an integration");
|
|
5412
|
+
integrationsSetup.command("slack").description("Set up Slack integration").action(integrationsSetupSlackCommand);
|
|
5413
|
+
integrations.command("status").description("Show integration status").action(integrationsStatusCommand);
|
|
5414
|
+
var integrationsSlack = integrations.command("slack").description("Slack integration commands");
|
|
5415
|
+
integrationsSlack.command("post").description("Post a message or edit a canvas (JSON from stdin)").option("--canvas", "Edit a canvas instead of posting a message").action((options) => slackPostCommand(options));
|
|
5416
|
+
integrations.action(integrationsStatusCommand);
|
|
4903
5417
|
if (configExists()) {
|
|
4904
5418
|
const config = loadConfig();
|
|
4905
5419
|
const newPlatforms = syncNewPlatforms(config);
|