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