wave-code 0.18.5 → 0.18.6

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.
@@ -1 +1 @@
1
- {"version":3,"file":"MarketplaceAddForm.d.ts","sourceRoot":"","sources":["../../src/components/MarketplaceAddForm.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAqB,MAAM,OAAO,CAAC;AAW1C,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAiGtC,CAAC"}
1
+ {"version":3,"file":"MarketplaceAddForm.d.ts","sourceRoot":"","sources":["../../src/components/MarketplaceAddForm.tsx"],"names":[],"mappings":"AAAA,OAAO,KAAgC,MAAM,OAAO,CAAC;AASrD,eAAO,MAAM,kBAAkB,EAAE,KAAK,CAAC,EAqFtC,CAAC"}
@@ -1,66 +1,41 @@
1
1
  import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
2
- import { useReducer } from "react";
2
+ import { useReducer, useEffect } from "react";
3
3
  import { Box, Text, useInput } from "ink";
4
4
  import { usePluginManagerContext } from "../contexts/PluginManagerContext.js";
5
- import { marketplaceAddFormReducer } from "../reducers/marketplaceAddFormReducer.js";
6
- const SCOPES = [
7
- { value: "user", label: "user" },
8
- { value: "project", label: "project" },
9
- { value: "local", label: "local" },
10
- ];
5
+ import { marketplaceAddFormReducer, SCOPES, } from "../reducers/marketplaceAddFormReducer.js";
11
6
  export const MarketplaceAddForm = () => {
12
- const { state, actions } = usePluginManagerContext();
13
- const [{ source, scopeIndex, step }, dispatch] = useReducer(marketplaceAddFormReducer, { source: "", scopeIndex: 0, step: "source" });
14
- useInput((input, key) => {
15
- if (key.escape) {
16
- if (step === "scope") {
17
- dispatch({ type: "BACK_TO_SOURCE" });
18
- }
19
- else {
20
- actions.setView("MARKETPLACES");
21
- }
22
- }
23
- else if (state.isLoading) {
7
+ const { state: ctxState, actions } = usePluginManagerContext();
8
+ const [state, dispatch] = useReducer(marketplaceAddFormReducer, {
9
+ source: "",
10
+ scopeIndex: 0,
11
+ step: "source",
12
+ pendingAction: null,
13
+ });
14
+ // Handle side effects from reducer decisions
15
+ useEffect(() => {
16
+ if (!state.pendingAction)
24
17
  return;
18
+ if (state.pendingAction.type === "submit") {
19
+ actions.addMarketplace(state.pendingAction.source, state.pendingAction.scope);
25
20
  }
26
- else if (step === "source" && key.return) {
27
- if (source.trim()) {
28
- dispatch({ type: "SET_STEP", step: "scope" });
29
- }
30
- }
31
- else if (step === "source" && (key.backspace || key.delete)) {
32
- dispatch({ type: "DELETE_CHAR" });
33
- }
34
- else if (step === "source" &&
35
- input &&
36
- !key.ctrl &&
37
- !key.meta &&
38
- !("alt" in key && key.alt)) {
39
- dispatch({ type: "INSERT_CHAR", text: input });
40
- }
41
- else if (step === "scope") {
42
- if (key.upArrow) {
43
- dispatch({
44
- type: "SET_SCOPE_INDEX",
45
- index: Math.max(0, scopeIndex - 1),
46
- });
47
- }
48
- else if (key.downArrow) {
49
- dispatch({
50
- type: "SET_SCOPE_INDEX",
51
- index: Math.min(SCOPES.length - 1, scopeIndex + 1),
52
- });
53
- }
54
- else if (key.return) {
55
- const scope = SCOPES[scopeIndex].value;
56
- actions.addMarketplace(source.trim(), scope);
57
- }
21
+ else if (state.pendingAction.type === "cancel") {
22
+ actions.setView("MARKETPLACES");
58
23
  }
24
+ dispatch({ type: "CLEAR_PENDING_ACTION" });
25
+ }, [state.pendingAction, actions]);
26
+ useInput((input, key) => {
27
+ dispatch({
28
+ type: "HANDLE_KEY",
29
+ key,
30
+ input,
31
+ isLoading: ctxState.isLoading,
32
+ });
59
33
  });
34
+ const { source, scopeIndex, step } = state;
60
35
  if (step === "source") {
61
- return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: "Step 1/2: Enter marketplace source" }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { children: "Source: " }), _jsx(Text, { color: "yellow", children: source }), !state.isLoading && _jsx(Text, { color: "yellow", children: "_" })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Enter to continue, Esc to cancel" }) })] }));
36
+ return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: "Step 1/2: Enter marketplace source" }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { children: "Source: " }), _jsx(Text, { color: "yellow", children: source }), !ctxState.isLoading && _jsx(Text, { color: "yellow", children: "_" })] }), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: "Enter to continue, Esc to cancel" }) })] }));
62
37
  }
63
- return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: "Step 2/2: Select scope" }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "Source: " }), _jsx(Text, { dimColor: true, children: source })] }), _jsx(Box, { marginTop: 1, flexDirection: "column", children: SCOPES.map((s, i) => (_jsxs(Text, { color: i === scopeIndex ? "yellow" : "dim", children: [i === scopeIndex ? "> " : " ", s.label] }, s.value))) }), state.isLoading && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "yellow", children: "Adding marketplace..." }) })), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: state.isLoading
38
+ return (_jsxs(Box, { flexDirection: "column", padding: 1, children: [_jsx(Text, { bold: true, color: "cyan", children: "Step 2/2: Select scope" }), _jsxs(Box, { marginTop: 1, children: [_jsx(Text, { dimColor: true, children: "Source: " }), _jsx(Text, { dimColor: true, children: source })] }), _jsx(Box, { marginTop: 1, flexDirection: "column", children: SCOPES.map((s, i) => (_jsxs(Text, { color: i === scopeIndex ? "yellow" : "dim", children: [i === scopeIndex ? "> " : " ", s] }, s))) }), ctxState.isLoading && (_jsx(Box, { marginTop: 1, children: _jsx(Text, { color: "yellow", children: "Adding marketplace..." }) })), _jsx(Box, { marginTop: 1, children: _jsx(Text, { dimColor: true, children: ctxState.isLoading
64
39
  ? "Please wait..."
65
40
  : "Enter to confirm, \u2191/\u2193 to navigate, Esc to go back" }) })] }));
66
41
  };
@@ -1,24 +1,25 @@
1
+ import { Key } from "ink";
2
+ export declare const SCOPES: readonly ["user", "project", "local"];
3
+ export type Scope = (typeof SCOPES)[number];
1
4
  export interface MarketplaceAddFormState {
2
5
  source: string;
3
6
  scopeIndex: number;
4
7
  step: "source" | "scope";
8
+ pendingAction: {
9
+ type: "submit";
10
+ source: string;
11
+ scope: Scope;
12
+ } | {
13
+ type: "cancel";
14
+ } | null;
5
15
  }
6
16
  export type MarketplaceAddFormAction = {
7
- type: "SET_SOURCE";
8
- source: string;
9
- } | {
10
- type: "SET_SCOPE_INDEX";
11
- index: number;
12
- } | {
13
- type: "SET_STEP";
14
- step: "source" | "scope";
15
- } | {
16
- type: "INSERT_CHAR";
17
- text: string;
18
- } | {
19
- type: "DELETE_CHAR";
17
+ type: "HANDLE_KEY";
18
+ key: Key;
19
+ input: string;
20
+ isLoading: boolean;
20
21
  } | {
21
- type: "BACK_TO_SOURCE";
22
+ type: "CLEAR_PENDING_ACTION";
22
23
  };
23
24
  export declare function marketplaceAddFormReducer(state: MarketplaceAddFormState, action: MarketplaceAddFormAction): MarketplaceAddFormState;
24
25
  //# sourceMappingURL=marketplaceAddFormReducer.d.ts.map
@@ -1 +1 @@
1
- {"version":3,"file":"marketplaceAddFormReducer.d.ts","sourceRoot":"","sources":["../../src/reducers/marketplaceAddFormReducer.ts"],"names":[],"mappings":"AAAA,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC;CAC1B;AAED,MAAM,MAAM,wBAAwB,GAChC;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,MAAM,EAAE,MAAM,CAAA;CAAE,GACtC;IAAE,IAAI,EAAE,iBAAiB,CAAC;IAAC,KAAK,EAAE,MAAM,CAAA;CAAE,GAC1C;IAAE,IAAI,EAAE,UAAU,CAAC;IAAC,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAA;CAAE,GAC9C;IAAE,IAAI,EAAE,aAAa,CAAC;IAAC,IAAI,EAAE,MAAM,CAAA;CAAE,GACrC;IAAE,IAAI,EAAE,aAAa,CAAA;CAAE,GACvB;IAAE,IAAI,EAAE,gBAAgB,CAAA;CAAE,CAAC;AAE/B,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,uBAAuB,EAC9B,MAAM,EAAE,wBAAwB,GAC/B,uBAAuB,CAiBzB"}
1
+ {"version":3,"file":"marketplaceAddFormReducer.d.ts","sourceRoot":"","sources":["../../src/reducers/marketplaceAddFormReducer.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,GAAG,EAAE,MAAM,KAAK,CAAC;AAE1B,eAAO,MAAM,MAAM,uCAAwC,CAAC;AAC5D,MAAM,MAAM,KAAK,GAAG,CAAC,OAAO,MAAM,CAAC,CAAC,MAAM,CAAC,CAAC;AAE5C,MAAM,WAAW,uBAAuB;IACtC,MAAM,EAAE,MAAM,CAAC;IACf,UAAU,EAAE,MAAM,CAAC;IACnB,IAAI,EAAE,QAAQ,GAAG,OAAO,CAAC;IACzB,aAAa,EACT;QAAE,IAAI,EAAE,QAAQ,CAAC;QAAC,MAAM,EAAE,MAAM,CAAC;QAAC,KAAK,EAAE,KAAK,CAAA;KAAE,GAChD;QAAE,IAAI,EAAE,QAAQ,CAAA;KAAE,GAClB,IAAI,CAAC;CACV;AAED,MAAM,MAAM,wBAAwB,GAChC;IAAE,IAAI,EAAE,YAAY,CAAC;IAAC,GAAG,EAAE,GAAG,CAAC;IAAC,KAAK,EAAE,MAAM,CAAC;IAAC,SAAS,EAAE,OAAO,CAAA;CAAE,GACnE;IAAE,IAAI,EAAE,sBAAsB,CAAA;CAAE,CAAC;AAErC,wBAAgB,yBAAyB,CACvC,KAAK,EAAE,uBAAuB,EAC9B,MAAM,EAAE,wBAAwB,GAC/B,uBAAuB,CA2DzB"}
@@ -1,17 +1,57 @@
1
+ export const SCOPES = ["user", "project", "local"];
1
2
  export function marketplaceAddFormReducer(state, action) {
2
3
  switch (action.type) {
3
- case "SET_SOURCE":
4
- return { ...state, source: action.source };
5
- case "SET_SCOPE_INDEX":
6
- return { ...state, scopeIndex: action.index };
7
- case "SET_STEP":
8
- return { ...state, step: action.step };
9
- case "INSERT_CHAR":
10
- return { ...state, source: state.source + action.text };
11
- case "DELETE_CHAR":
12
- return { ...state, source: state.source.slice(0, -1) };
13
- case "BACK_TO_SOURCE":
14
- return { ...state, step: "source" };
4
+ case "HANDLE_KEY": {
5
+ const { key, input, isLoading } = action;
6
+ // Escape always works, even during loading
7
+ if (key.escape) {
8
+ if (state.step === "scope") {
9
+ return { ...state, step: "source" };
10
+ }
11
+ return { ...state, pendingAction: { type: "cancel" } };
12
+ }
13
+ // Ignore all other input during loading
14
+ if (isLoading)
15
+ return state;
16
+ if (state.step === "source") {
17
+ if (key.return) {
18
+ if (state.source.trim()) {
19
+ return { ...state, step: "scope" };
20
+ }
21
+ return state;
22
+ }
23
+ if (key.backspace || key.delete) {
24
+ return { ...state, source: state.source.slice(0, -1) };
25
+ }
26
+ if (input && !key.ctrl && !key.meta && !("alt" in key && key.alt)) {
27
+ return { ...state, source: state.source + input };
28
+ }
29
+ return state;
30
+ }
31
+ // step === "scope"
32
+ if (key.upArrow) {
33
+ return { ...state, scopeIndex: Math.max(0, state.scopeIndex - 1) };
34
+ }
35
+ if (key.downArrow) {
36
+ return {
37
+ ...state,
38
+ scopeIndex: Math.min(SCOPES.length - 1, state.scopeIndex + 1),
39
+ };
40
+ }
41
+ if (key.return) {
42
+ return {
43
+ ...state,
44
+ pendingAction: {
45
+ type: "submit",
46
+ source: state.source.trim(),
47
+ scope: SCOPES[state.scopeIndex],
48
+ },
49
+ };
50
+ }
51
+ return state;
52
+ }
53
+ case "CLEAR_PENDING_ACTION":
54
+ return { ...state, pendingAction: null };
15
55
  default:
16
56
  return state;
17
57
  }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "wave-code",
3
- "version": "0.18.5",
3
+ "version": "0.18.6",
4
4
  "description": "CLI-based code assistant powered by AI, built with React and Ink",
5
5
  "repository": {
6
6
  "type": "git",
@@ -42,7 +42,7 @@
42
42
  "semver": "^7.7.4",
43
43
  "yargs": "^17.7.2",
44
44
  "zod": "^3.23.8",
45
- "wave-agent-sdk": "0.18.5"
45
+ "wave-agent-sdk": "0.18.6"
46
46
  },
47
47
  "devDependencies": {
48
48
  "@types/react": "^19.1.8",
@@ -1,62 +1,48 @@
1
- import React, { useReducer } from "react";
1
+ import React, { useReducer, useEffect } from "react";
2
2
  import { Box, Text, useInput } from "ink";
3
3
  import { usePluginManagerContext } from "../contexts/PluginManagerContext.js";
4
- import { marketplaceAddFormReducer } from "../reducers/marketplaceAddFormReducer.js";
5
-
6
- const SCOPES = [
7
- { value: "user" as const, label: "user" },
8
- { value: "project" as const, label: "project" },
9
- { value: "local" as const, label: "local" },
10
- ];
4
+ import {
5
+ marketplaceAddFormReducer,
6
+ SCOPES,
7
+ type MarketplaceAddFormState,
8
+ } from "../reducers/marketplaceAddFormReducer.js";
11
9
 
12
10
  export const MarketplaceAddForm: React.FC = () => {
13
- const { state, actions } = usePluginManagerContext();
14
- const [{ source, scopeIndex, step }, dispatch] = useReducer(
15
- marketplaceAddFormReducer,
16
- { source: "", scopeIndex: 0, step: "source" },
17
- );
11
+ const { state: ctxState, actions } = usePluginManagerContext();
12
+ const [state, dispatch] = useReducer(marketplaceAddFormReducer, {
13
+ source: "",
14
+ scopeIndex: 0,
15
+ step: "source",
16
+ pendingAction: null,
17
+ } as MarketplaceAddFormState);
18
18
 
19
- useInput((input, key) => {
20
- if (key.escape) {
21
- if (step === "scope") {
22
- dispatch({ type: "BACK_TO_SOURCE" });
23
- } else {
24
- actions.setView("MARKETPLACES");
25
- }
26
- } else if (state.isLoading) {
27
- return;
28
- } else if (step === "source" && key.return) {
29
- if (source.trim()) {
30
- dispatch({ type: "SET_STEP", step: "scope" });
31
- }
32
- } else if (step === "source" && (key.backspace || key.delete)) {
33
- dispatch({ type: "DELETE_CHAR" });
34
- } else if (
35
- step === "source" &&
36
- input &&
37
- !key.ctrl &&
38
- !key.meta &&
39
- !("alt" in key && key.alt)
40
- ) {
41
- dispatch({ type: "INSERT_CHAR", text: input });
42
- } else if (step === "scope") {
43
- if (key.upArrow) {
44
- dispatch({
45
- type: "SET_SCOPE_INDEX",
46
- index: Math.max(0, scopeIndex - 1),
47
- });
48
- } else if (key.downArrow) {
49
- dispatch({
50
- type: "SET_SCOPE_INDEX",
51
- index: Math.min(SCOPES.length - 1, scopeIndex + 1),
52
- });
53
- } else if (key.return) {
54
- const scope = SCOPES[scopeIndex].value;
55
- actions.addMarketplace(source.trim(), scope);
56
- }
19
+ // Handle side effects from reducer decisions
20
+ useEffect(() => {
21
+ if (!state.pendingAction) return;
22
+
23
+ if (state.pendingAction.type === "submit") {
24
+ actions.addMarketplace(
25
+ state.pendingAction.source,
26
+ state.pendingAction.scope,
27
+ );
28
+ } else if (state.pendingAction.type === "cancel") {
29
+ actions.setView("MARKETPLACES");
57
30
  }
31
+
32
+ dispatch({ type: "CLEAR_PENDING_ACTION" });
33
+ }, [state.pendingAction, actions]);
34
+
35
+ useInput((input, key) => {
36
+ dispatch({
37
+ type: "HANDLE_KEY",
38
+ key,
39
+ input,
40
+ isLoading: ctxState.isLoading,
41
+ });
58
42
  });
59
43
 
44
+ const { source, scopeIndex, step } = state;
45
+
60
46
  if (step === "source") {
61
47
  return (
62
48
  <Box flexDirection="column" padding={1}>
@@ -66,7 +52,7 @@ export const MarketplaceAddForm: React.FC = () => {
66
52
  <Box marginTop={1}>
67
53
  <Text>Source: </Text>
68
54
  <Text color="yellow">{source}</Text>
69
- {!state.isLoading && <Text color="yellow">_</Text>}
55
+ {!ctxState.isLoading && <Text color="yellow">_</Text>}
70
56
  </Box>
71
57
  <Box marginTop={1}>
72
58
  <Text dimColor>Enter to continue, Esc to cancel</Text>
@@ -86,20 +72,20 @@ export const MarketplaceAddForm: React.FC = () => {
86
72
  </Box>
87
73
  <Box marginTop={1} flexDirection="column">
88
74
  {SCOPES.map((s, i) => (
89
- <Text key={s.value} color={i === scopeIndex ? "yellow" : "dim"}>
75
+ <Text key={s} color={i === scopeIndex ? "yellow" : "dim"}>
90
76
  {i === scopeIndex ? "> " : " "}
91
- {s.label}
77
+ {s}
92
78
  </Text>
93
79
  ))}
94
80
  </Box>
95
- {state.isLoading && (
81
+ {ctxState.isLoading && (
96
82
  <Box marginTop={1}>
97
83
  <Text color="yellow">Adding marketplace...</Text>
98
84
  </Box>
99
85
  )}
100
86
  <Box marginTop={1}>
101
87
  <Text dimColor>
102
- {state.isLoading
88
+ {ctxState.isLoading
103
89
  ? "Please wait..."
104
90
  : "Enter to confirm, \u2191/\u2193 to navigate, Esc to go back"}
105
91
  </Text>
@@ -1,34 +1,81 @@
1
+ import { Key } from "ink";
2
+
3
+ export const SCOPES = ["user", "project", "local"] as const;
4
+ export type Scope = (typeof SCOPES)[number];
5
+
1
6
  export interface MarketplaceAddFormState {
2
7
  source: string;
3
8
  scopeIndex: number;
4
9
  step: "source" | "scope";
10
+ pendingAction:
11
+ | { type: "submit"; source: string; scope: Scope }
12
+ | { type: "cancel" }
13
+ | null;
5
14
  }
6
15
 
7
16
  export type MarketplaceAddFormAction =
8
- | { type: "SET_SOURCE"; source: string }
9
- | { type: "SET_SCOPE_INDEX"; index: number }
10
- | { type: "SET_STEP"; step: "source" | "scope" }
11
- | { type: "INSERT_CHAR"; text: string }
12
- | { type: "DELETE_CHAR" }
13
- | { type: "BACK_TO_SOURCE" };
17
+ | { type: "HANDLE_KEY"; key: Key; input: string; isLoading: boolean }
18
+ | { type: "CLEAR_PENDING_ACTION" };
14
19
 
15
20
  export function marketplaceAddFormReducer(
16
21
  state: MarketplaceAddFormState,
17
22
  action: MarketplaceAddFormAction,
18
23
  ): MarketplaceAddFormState {
19
24
  switch (action.type) {
20
- case "SET_SOURCE":
21
- return { ...state, source: action.source };
22
- case "SET_SCOPE_INDEX":
23
- return { ...state, scopeIndex: action.index };
24
- case "SET_STEP":
25
- return { ...state, step: action.step };
26
- case "INSERT_CHAR":
27
- return { ...state, source: state.source + action.text };
28
- case "DELETE_CHAR":
29
- return { ...state, source: state.source.slice(0, -1) };
30
- case "BACK_TO_SOURCE":
31
- return { ...state, step: "source" };
25
+ case "HANDLE_KEY": {
26
+ const { key, input, isLoading } = action;
27
+
28
+ // Escape always works, even during loading
29
+ if (key.escape) {
30
+ if (state.step === "scope") {
31
+ return { ...state, step: "source" };
32
+ }
33
+ return { ...state, pendingAction: { type: "cancel" } };
34
+ }
35
+
36
+ // Ignore all other input during loading
37
+ if (isLoading) return state;
38
+
39
+ if (state.step === "source") {
40
+ if (key.return) {
41
+ if (state.source.trim()) {
42
+ return { ...state, step: "scope" };
43
+ }
44
+ return state;
45
+ }
46
+ if (key.backspace || key.delete) {
47
+ return { ...state, source: state.source.slice(0, -1) };
48
+ }
49
+ if (input && !key.ctrl && !key.meta && !("alt" in key && key.alt)) {
50
+ return { ...state, source: state.source + input };
51
+ }
52
+ return state;
53
+ }
54
+
55
+ // step === "scope"
56
+ if (key.upArrow) {
57
+ return { ...state, scopeIndex: Math.max(0, state.scopeIndex - 1) };
58
+ }
59
+ if (key.downArrow) {
60
+ return {
61
+ ...state,
62
+ scopeIndex: Math.min(SCOPES.length - 1, state.scopeIndex + 1),
63
+ };
64
+ }
65
+ if (key.return) {
66
+ return {
67
+ ...state,
68
+ pendingAction: {
69
+ type: "submit",
70
+ source: state.source.trim(),
71
+ scope: SCOPES[state.scopeIndex],
72
+ },
73
+ };
74
+ }
75
+ return state;
76
+ }
77
+ case "CLEAR_PENDING_ACTION":
78
+ return { ...state, pendingAction: null };
32
79
  default:
33
80
  return state;
34
81
  }