@jancellor/ask 1.0.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +93 -0
- package/assets/system-prompt.md +107 -0
- package/dist/agent/agent.js +132 -0
- package/dist/agent/agents-prompt.js +23 -0
- package/dist/agent/config.js +54 -0
- package/dist/agent/execute-tool.js +80 -0
- package/dist/agent/index.js +1 -0
- package/dist/agent/init-prompt.js +11 -0
- package/dist/agent/messages.js +1 -0
- package/dist/agent/openai-subscription-fetch.js +199 -0
- package/dist/agent/paths.js +6 -0
- package/dist/agent/serializer.js +25 -0
- package/dist/agent/session-store.js +80 -0
- package/dist/agent/session.js +87 -0
- package/dist/agent/skills-prompt.js +56 -0
- package/dist/agent/system-prompt.js +11 -0
- package/dist/agent/system-prompt.md +107 -0
- package/dist/agent/tools.js +17 -0
- package/dist/batch/index.js +101 -0
- package/dist/index.js +32 -0
- package/dist/shutdown-manager.js +35 -0
- package/dist/tui/app.js +12 -0
- package/dist/tui/assistant-part-message.js +10 -0
- package/dist/tui/execute-tool-part-message.js +48 -0
- package/dist/tui/generic-tool-part-message.js +28 -0
- package/dist/tui/index.js +18 -0
- package/dist/tui/input.js +115 -0
- package/dist/tui/markdown.js +31 -0
- package/dist/tui/messages.js +86 -0
- package/dist/tui/spinner-message.js +14 -0
- package/dist/tui/tool-part-message.js +9 -0
- package/dist/tui/use-agent.js +27 -0
- package/dist/tui/use-input-state.js +136 -0
- package/dist/tui/user-part-message.js +9 -0
- package/dist/tui/welcome.js +12 -0
- package/package.json +67 -0
|
@@ -0,0 +1,136 @@
|
|
|
1
|
+
import { useState } from 'react';
|
|
2
|
+
export function useInputState() {
|
|
3
|
+
const [state, setState] = useState({ value: '', cursor: 0 });
|
|
4
|
+
const { value, cursor } = state;
|
|
5
|
+
const getWordCursor = (value, cursor, backwards) => {
|
|
6
|
+
const len = value.length;
|
|
7
|
+
const step = backwards ? -1 : 1;
|
|
8
|
+
let i = Math.max(0, Math.min(cursor + Math.min(step, 0), len));
|
|
9
|
+
const isSpace = (index) => /\s/.test(value[index] ?? ' ');
|
|
10
|
+
const shouldMove = (offset, moveOnSpace) => isSpace(i + offset) === moveOnSpace;
|
|
11
|
+
const firstOffset = 0;
|
|
12
|
+
const secondOffset = step < 0 ? -1 : 0;
|
|
13
|
+
const firstMoveOnSpace = step < 0;
|
|
14
|
+
const secondMoveOnSpace = !firstMoveOnSpace;
|
|
15
|
+
while (i > 0 && i < len && shouldMove(firstOffset, firstMoveOnSpace)) {
|
|
16
|
+
i += step;
|
|
17
|
+
}
|
|
18
|
+
while (i > 0 && i < len && shouldMove(secondOffset, secondMoveOnSpace)) {
|
|
19
|
+
i += step;
|
|
20
|
+
}
|
|
21
|
+
return i;
|
|
22
|
+
};
|
|
23
|
+
const moveStart = () => {
|
|
24
|
+
setState((current) => ({ ...current, cursor: 0 }));
|
|
25
|
+
};
|
|
26
|
+
const moveEnd = () => {
|
|
27
|
+
setState((current) => ({ ...current, cursor: current.value.length }));
|
|
28
|
+
};
|
|
29
|
+
const moveLeft = () => {
|
|
30
|
+
setState((current) => ({
|
|
31
|
+
...current,
|
|
32
|
+
cursor: Math.max(0, current.cursor - 1),
|
|
33
|
+
}));
|
|
34
|
+
};
|
|
35
|
+
const moveRight = () => {
|
|
36
|
+
setState((current) => ({
|
|
37
|
+
...current,
|
|
38
|
+
cursor: Math.min(current.value.length, current.cursor + 1),
|
|
39
|
+
}));
|
|
40
|
+
};
|
|
41
|
+
const moveWordLeft = () => {
|
|
42
|
+
setState((current) => ({
|
|
43
|
+
...current,
|
|
44
|
+
cursor: getWordCursor(current.value, current.cursor, true),
|
|
45
|
+
}));
|
|
46
|
+
};
|
|
47
|
+
const moveWordRight = () => {
|
|
48
|
+
setState((current) => ({
|
|
49
|
+
...current,
|
|
50
|
+
cursor: getWordCursor(current.value, current.cursor, false),
|
|
51
|
+
}));
|
|
52
|
+
};
|
|
53
|
+
const deleteBackward = () => {
|
|
54
|
+
setState((current) => {
|
|
55
|
+
if (current.cursor === 0) {
|
|
56
|
+
return current;
|
|
57
|
+
}
|
|
58
|
+
return {
|
|
59
|
+
value: current.value.slice(0, current.cursor - 1) +
|
|
60
|
+
current.value.slice(current.cursor),
|
|
61
|
+
cursor: current.cursor - 1,
|
|
62
|
+
};
|
|
63
|
+
});
|
|
64
|
+
};
|
|
65
|
+
const deleteToStart = () => {
|
|
66
|
+
setState((current) => {
|
|
67
|
+
if (current.cursor === 0) {
|
|
68
|
+
return current;
|
|
69
|
+
}
|
|
70
|
+
return {
|
|
71
|
+
value: current.value.slice(current.cursor),
|
|
72
|
+
cursor: 0,
|
|
73
|
+
};
|
|
74
|
+
});
|
|
75
|
+
};
|
|
76
|
+
const deleteToEnd = () => {
|
|
77
|
+
setState((current) => {
|
|
78
|
+
if (current.cursor >= current.value.length) {
|
|
79
|
+
return current;
|
|
80
|
+
}
|
|
81
|
+
return {
|
|
82
|
+
...current,
|
|
83
|
+
value: current.value.slice(0, current.cursor),
|
|
84
|
+
};
|
|
85
|
+
});
|
|
86
|
+
};
|
|
87
|
+
const deleteWordBackward = () => {
|
|
88
|
+
setState((current) => {
|
|
89
|
+
if (current.cursor === 0) {
|
|
90
|
+
return current;
|
|
91
|
+
}
|
|
92
|
+
const nextCursor = getWordCursor(current.value, current.cursor, true);
|
|
93
|
+
return {
|
|
94
|
+
value: current.value.slice(0, nextCursor) +
|
|
95
|
+
current.value.slice(current.cursor),
|
|
96
|
+
cursor: nextCursor,
|
|
97
|
+
};
|
|
98
|
+
});
|
|
99
|
+
};
|
|
100
|
+
const insertText = (text) => {
|
|
101
|
+
if (!text) {
|
|
102
|
+
return;
|
|
103
|
+
}
|
|
104
|
+
setState((current) => ({
|
|
105
|
+
value: current.value.slice(0, current.cursor) +
|
|
106
|
+
text +
|
|
107
|
+
current.value.slice(current.cursor),
|
|
108
|
+
cursor: current.cursor + text.length,
|
|
109
|
+
}));
|
|
110
|
+
};
|
|
111
|
+
const clear = () => {
|
|
112
|
+
setState({ value: '', cursor: 0 });
|
|
113
|
+
};
|
|
114
|
+
const beforeCursor = value.slice(0, cursor);
|
|
115
|
+
const atCursor = value[cursor] ?? ' ';
|
|
116
|
+
const afterCursor = value.slice(Math.min(cursor + 1, value.length));
|
|
117
|
+
return {
|
|
118
|
+
value,
|
|
119
|
+
cursor,
|
|
120
|
+
beforeCursor,
|
|
121
|
+
atCursor,
|
|
122
|
+
afterCursor,
|
|
123
|
+
moveStart,
|
|
124
|
+
moveEnd,
|
|
125
|
+
moveLeft,
|
|
126
|
+
moveRight,
|
|
127
|
+
moveWordLeft,
|
|
128
|
+
moveWordRight,
|
|
129
|
+
deleteBackward,
|
|
130
|
+
deleteToStart,
|
|
131
|
+
deleteToEnd,
|
|
132
|
+
deleteWordBackward,
|
|
133
|
+
insertText,
|
|
134
|
+
clear,
|
|
135
|
+
};
|
|
136
|
+
}
|
|
@@ -0,0 +1,9 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
import { parseMarkdown } from './markdown.js';
|
|
4
|
+
export function UserPartMessage({ text }) {
|
|
5
|
+
const width = Math.max(10, process.stdout.columns ?? 80);
|
|
6
|
+
const divider = '─'.repeat(width);
|
|
7
|
+
const parsed = parseMarkdown(text);
|
|
8
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { color: "gray", children: divider }), _jsx(Text, { children: parsed }), _jsx(Text, { color: "gray", children: divider }), _jsx(Text, { children: " " })] }));
|
|
9
|
+
}
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import { jsx as _jsx, jsxs as _jsxs } from "react/jsx-runtime";
|
|
2
|
+
import { Box, Text } from 'ink';
|
|
3
|
+
import { homedir } from 'os';
|
|
4
|
+
function shortDir() {
|
|
5
|
+
const cwd = process.cwd();
|
|
6
|
+
const home = homedir();
|
|
7
|
+
return cwd.startsWith(home) ? '~' + cwd.slice(home.length) : cwd;
|
|
8
|
+
}
|
|
9
|
+
export function Welcome({ model, provider }) {
|
|
10
|
+
const dir = shortDir();
|
|
11
|
+
return (_jsxs(Box, { flexDirection: "column", children: [_jsx(Text, { children: " " }), _jsxs(Text, { children: ["Ask ", _jsx(Text, { dimColor: true, children: "\u00B7" }), " ", provider, " ", _jsx(Text, { dimColor: true, children: "\u00B7" }), " ", model, " ", _jsx(Text, { dimColor: true, children: "\u00B7" }), " ", dir] }), _jsx(Text, { children: " " })] }));
|
|
12
|
+
}
|
package/package.json
ADDED
|
@@ -0,0 +1,67 @@
|
|
|
1
|
+
{
|
|
2
|
+
"name": "@jancellor/ask",
|
|
3
|
+
"version": "1.0.0",
|
|
4
|
+
"description": "A minimal coding agent CLI.",
|
|
5
|
+
"main": "dist/index.js",
|
|
6
|
+
"bin": {
|
|
7
|
+
"ask": "./dist/index.js"
|
|
8
|
+
},
|
|
9
|
+
"files": [
|
|
10
|
+
"dist",
|
|
11
|
+
"assets"
|
|
12
|
+
],
|
|
13
|
+
"scripts": {
|
|
14
|
+
"build": "tsc",
|
|
15
|
+
"watch": "tsc --watch",
|
|
16
|
+
"dev": "tsx src/index.ts",
|
|
17
|
+
"prepublishOnly": "npm run build",
|
|
18
|
+
"format": "prettier --write .",
|
|
19
|
+
"format:check": "prettier --check ."
|
|
20
|
+
},
|
|
21
|
+
"keywords": [
|
|
22
|
+
"ai",
|
|
23
|
+
"agent",
|
|
24
|
+
"coding-agent",
|
|
25
|
+
"assistant",
|
|
26
|
+
"cli",
|
|
27
|
+
"terminal",
|
|
28
|
+
"llm"
|
|
29
|
+
],
|
|
30
|
+
"author": "jancellor",
|
|
31
|
+
"license": "MIT",
|
|
32
|
+
"repository": {
|
|
33
|
+
"type": "git",
|
|
34
|
+
"url": "git+https://github.com/jancellor/ask.git"
|
|
35
|
+
},
|
|
36
|
+
"bugs": {
|
|
37
|
+
"url": "https://github.com/jancellor/ask/issues"
|
|
38
|
+
},
|
|
39
|
+
"homepage": "https://github.com/jancellor/ask#readme",
|
|
40
|
+
"publishConfig": {
|
|
41
|
+
"access": "public"
|
|
42
|
+
},
|
|
43
|
+
"engines": {
|
|
44
|
+
"node": ">=20"
|
|
45
|
+
},
|
|
46
|
+
"type": "module",
|
|
47
|
+
"dependencies": {
|
|
48
|
+
"@ai-sdk/openai": "^3.0.29",
|
|
49
|
+
"@ai-sdk/openai-compatible": "^2.0.30",
|
|
50
|
+
"ai": "^6.0.90",
|
|
51
|
+
"commander": "^14.0.3",
|
|
52
|
+
"ink": "^6.7.0",
|
|
53
|
+
"marked": "^15.0.12",
|
|
54
|
+
"marked-terminal": "^7.3.0",
|
|
55
|
+
"react": "^19.2.4",
|
|
56
|
+
"yaml": "^2.8.2",
|
|
57
|
+
"zod": "^4.3.6"
|
|
58
|
+
},
|
|
59
|
+
"devDependencies": {
|
|
60
|
+
"@types/marked-terminal": "^6.1.1",
|
|
61
|
+
"@types/node": "^25.2.3",
|
|
62
|
+
"@types/react": "^19.2.14",
|
|
63
|
+
"prettier": "^3.8.1",
|
|
64
|
+
"tsx": "^4.21.0",
|
|
65
|
+
"typescript": "^5.9.3"
|
|
66
|
+
}
|
|
67
|
+
}
|