@opencoven/coven-code 0.0.4 → 0.0.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.
Files changed (115) hide show
  1. package/README.md +29 -130
  2. package/bin/coven-code +26 -0
  3. package/install.js +117 -0
  4. package/package.json +26 -23
  5. package/bin/coven-code-sdk.mjs +0 -12
  6. package/bin/coven-code.mjs +0 -19
  7. package/docs/CLI.md +0 -256
  8. package/docs/CONFIGURATION.md +0 -107
  9. package/docs/DEMO.md +0 -453
  10. package/docs/DEVELOPMENT.md +0 -104
  11. package/docs/DOGFOOD-PROTOCOL.md +0 -263
  12. package/docs/MCP-SKILLS-PLUGINS.md +0 -127
  13. package/docs/README.md +0 -39
  14. package/docs/RELEASE.md +0 -33
  15. package/docs/SDK.md +0 -107
  16. package/docs/superpowers/plans/2026-05-25-coven-code-panel-tui.md +0 -904
  17. package/docs/superpowers/plans/2026-05-25-coven-code-rebrand.md +0 -670
  18. package/docs/superpowers/specs/2026-05-25-coven-code-panel-tui-design.md +0 -235
  19. package/docs/superpowers/specs/2026-05-26-slash-first-tui-review.md +0 -63
  20. package/src/agent/fixture.mjs +0 -95
  21. package/src/agent/lane.mjs +0 -136
  22. package/src/cli/dispatch.mjs +0 -66
  23. package/src/cli/execute.mjs +0 -452
  24. package/src/cli/help.mjs +0 -58
  25. package/src/cli/interactive-core.mjs +0 -28
  26. package/src/cli/interactive-io.mjs +0 -101
  27. package/src/cli/interactive-slash.mjs +0 -184
  28. package/src/cli/notifications.mjs +0 -13
  29. package/src/cli/parse.mjs +0 -83
  30. package/src/cli/reasoning.mjs +0 -45
  31. package/src/cli/refs.mjs +0 -162
  32. package/src/cli/repl.mjs +0 -60
  33. package/src/cli/slash-commands.mjs +0 -375
  34. package/src/cli/stream-json.mjs +0 -225
  35. package/src/cli/tui-actions.mjs +0 -72
  36. package/src/cli/tui-blessed.mjs +0 -198
  37. package/src/cli/tui-keys.mjs +0 -80
  38. package/src/cli/tui-lane.mjs +0 -73
  39. package/src/cli/tui-render.mjs +0 -169
  40. package/src/cli/tui-submit.mjs +0 -82
  41. package/src/cli/tui.mjs +0 -174
  42. package/src/commands/agents.mjs +0 -53
  43. package/src/commands/config.mjs +0 -27
  44. package/src/commands/ide.mjs +0 -17
  45. package/src/commands/login.mjs +0 -84
  46. package/src/commands/mcp.mjs +0 -176
  47. package/src/commands/permissions-eval.mjs +0 -122
  48. package/src/commands/permissions-rules.mjs +0 -53
  49. package/src/commands/permissions-text.mjs +0 -112
  50. package/src/commands/permissions.mjs +0 -62
  51. package/src/commands/plugins.mjs +0 -86
  52. package/src/commands/review.mjs +0 -74
  53. package/src/commands/skill.mjs +0 -23
  54. package/src/commands/threads.mjs +0 -165
  55. package/src/commands/tools.mjs +0 -77
  56. package/src/commands/update.mjs +0 -31
  57. package/src/commands/usage.mjs +0 -34
  58. package/src/constants.mjs +0 -52
  59. package/src/main.mjs +0 -87
  60. package/src/mcp/discover.mjs +0 -154
  61. package/src/mcp/local.mjs +0 -55
  62. package/src/mcp/parsers.mjs +0 -46
  63. package/src/mcp/permissions.mjs +0 -52
  64. package/src/mcp/probe.mjs +0 -85
  65. package/src/mcp/registry.mjs +0 -96
  66. package/src/mcp/remote-oauth.mjs +0 -55
  67. package/src/mcp/remote-session.mjs +0 -54
  68. package/src/mcp/remote-sse.mjs +0 -82
  69. package/src/mcp/remote.mjs +0 -74
  70. package/src/plugins/api.mjs +0 -187
  71. package/src/plugins/configuration.mjs +0 -124
  72. package/src/plugins/discover.mjs +0 -84
  73. package/src/plugins/helpers.mjs +0 -187
  74. package/src/plugins/subsystems.mjs +0 -198
  75. package/src/plugins/validators.mjs +0 -142
  76. package/src/sdk-execute.mjs +0 -82
  77. package/src/sdk-install.mjs +0 -187
  78. package/src/sdk-settings.mjs +0 -88
  79. package/src/sdk.mjs +0 -163
  80. package/src/settings/load.mjs +0 -134
  81. package/src/settings/paths.mjs +0 -101
  82. package/src/skills/builtin/building-skills/SKILL.md +0 -20
  83. package/src/skills/discover.mjs +0 -95
  84. package/src/threads/store.mjs +0 -176
  85. package/src/tools/builtin/bash.mjs +0 -110
  86. package/src/tools/builtin/create-file.mjs +0 -66
  87. package/src/tools/builtin/edit-file.mjs +0 -76
  88. package/src/tools/builtin/finder.mjs +0 -73
  89. package/src/tools/builtin/glob.mjs +0 -74
  90. package/src/tools/builtin/grep.mjs +0 -82
  91. package/src/tools/builtin/index.mjs +0 -83
  92. package/src/tools/builtin/librarian.mjs +0 -97
  93. package/src/tools/builtin/look-at.mjs +0 -92
  94. package/src/tools/builtin/mcp.mjs +0 -51
  95. package/src/tools/builtin/mermaid.mjs +0 -59
  96. package/src/tools/builtin/oracle.mjs +0 -56
  97. package/src/tools/builtin/painter.mjs +0 -81
  98. package/src/tools/builtin/plugin-tool.mjs +0 -53
  99. package/src/tools/builtin/read-mcp-resource.mjs +0 -63
  100. package/src/tools/builtin/read-web-page.mjs +0 -72
  101. package/src/tools/builtin/read.mjs +0 -59
  102. package/src/tools/builtin/runtime-content.mjs +0 -31
  103. package/src/tools/builtin/runtime-decisions.mjs +0 -115
  104. package/src/tools/builtin/runtime.mjs +0 -85
  105. package/src/tools/builtin/task.mjs +0 -63
  106. package/src/tools/builtin/toolbox-tool.mjs +0 -57
  107. package/src/tools/builtin/undo-edit.mjs +0 -97
  108. package/src/tools/builtin/web-search.mjs +0 -128
  109. package/src/tools/toolbox.mjs +0 -273
  110. package/src/util/fs.mjs +0 -13
  111. package/src/util/glob.mjs +0 -46
  112. package/src/util/html.mjs +0 -21
  113. package/src/util/media.mjs +0 -13
  114. package/src/util/shell.mjs +0 -24
  115. package/src/util/table.mjs +0 -11
@@ -1,128 +0,0 @@
1
- import { resolvePermissionDecision } from '../../commands/permissions.mjs';
2
- import { runPluginEventHandlers } from '../../plugins/discover.mjs';
3
- import { decodeHtmlText } from '../../util/html.mjs';
4
- import { isToolDisabled } from '../toolbox.mjs';
5
- import {
6
- applyToolCallDecision,
7
- createToolUseID,
8
- permissionDeniedOutput,
9
- pluginTextToolRunResult,
10
- pluginToolCallEvent,
11
- pluginToolResultEvent,
12
- pluginToolUseBlock,
13
- toolCallDecisionToolRun,
14
- validateToolCallDecision,
15
- } from './runtime.mjs';
16
-
17
- export const TOOL_NAME = 'web_search';
18
-
19
- export async function executePromptWebSearchToolRequest(request, parsed = {}, plugins = { handlers: {} }, threadId = '') {
20
- if (isToolDisabled(TOOL_NAME, 'built-in', parsed)) return { output: `Tool disabled: ${TOOL_NAME}` };
21
- request = { ...request, flags: normalizeWebSearchInput(request.flags) };
22
- if (!request.flags.query) return { output: 'web_search requires --query' };
23
- const toolUseID = createToolUseID();
24
- const callDecision = await runPluginEventHandlers(
25
- plugins.handlers['tool.call'],
26
- pluginToolCallEvent(TOOL_NAME, request.flags, threadId, toolUseID),
27
- validateToolCallDecision,
28
- );
29
- const callResult = applyToolCallDecision(TOOL_NAME, request, callDecision);
30
- if (callResult.output) return toolCallDecisionToolRun(TOOL_NAME, request.flags, toolUseID, callResult);
31
- request = { ...callResult.request, flags: normalizeWebSearchInput(callResult.request.flags) };
32
- const decision = resolvePermissionDecision(TOOL_NAME, request.flags, parsed, { threadId });
33
- if (!parsed.dangerouslyAllowAll && decision.action !== 'allow') {
34
- return {
35
- output: permissionDeniedOutput(TOOL_NAME, decision),
36
- permissionDenials: [{ tool: TOOL_NAME, action: decision.action, reason: 'permission' }],
37
- };
38
- }
39
- const output = await searchWebBuiltin(request.flags.query, request.flags.limit);
40
- const resultDecision = await runPluginEventHandlers(
41
- plugins.handlers['tool.result'],
42
- pluginToolResultEvent(TOOL_NAME, request.flags, 'done', output, threadId, toolUseID),
43
- );
44
- return {
45
- ...pluginTextToolRunResult(resultDecision, output),
46
- toolUse: pluginToolUseBlock(TOOL_NAME, request.flags, toolUseID),
47
- };
48
- }
49
-
50
- function normalizeWebSearchInput(input = {}) {
51
- const query = input.query ?? input.q ?? input.search;
52
- const limit = Number.parseInt(String(input.limit ?? input.count ?? 5), 10);
53
- return {
54
- ...input,
55
- query: query ? String(query) : '',
56
- limit: Number.isFinite(limit) && limit > 0 ? Math.min(limit, 10) : 5,
57
- };
58
- }
59
-
60
- async function searchWebBuiltin(query, limit = 5) {
61
- const fixture = webSearchFixtureResults(limit);
62
- if (fixture) return formatWebSearchResults(fixture, query);
63
-
64
- try {
65
- const url = `https://html.duckduckgo.com/html/?${new URLSearchParams({ q: query }).toString()}`;
66
- const response = await fetch(url, {
67
- headers: { 'user-agent': 'coven-code/0.0.0' },
68
- });
69
- if (!response.ok) return `Web search failed for ${query}: HTTP ${response.status}`;
70
- const results = parseDuckDuckGoHtml(await response.text()).slice(0, limit);
71
- return formatWebSearchResults(results, query);
72
- } catch (error) {
73
- return `Web search failed for ${query}: ${error.message}`;
74
- }
75
- }
76
-
77
- function webSearchFixtureResults(limit) {
78
- const fixtureJson = process.env.COVEN_CODE_WEB_SEARCH_RESULTS_JSON;
79
- if (!fixtureJson) return undefined;
80
- try {
81
- const parsed = JSON.parse(fixtureJson);
82
- return Array.isArray(parsed) ? parsed.slice(0, limit) : [];
83
- } catch {
84
- return [];
85
- }
86
- }
87
-
88
- function parseDuckDuckGoHtml(html) {
89
- const blocks = html.match(/<div[^>]+class="[^"]*result[^"]*"[\s\S]*?(?=<div[^>]+class="[^"]*result[^"]*"|<\/body>)/g) ?? [];
90
- return blocks
91
- .map((block) => {
92
- const link = block.match(/<a[^>]+class="[^"]*result__a[^"]*"[^>]+href="([^"]+)"[^>]*>([\s\S]*?)<\/a>/);
93
- if (!link) return undefined;
94
- const snippet = block.match(/<a[^>]+class="[^"]*result__snippet[^"]*"[^>]*>([\s\S]*?)<\/a>/)
95
- ?? block.match(/<div[^>]+class="[^"]*result__snippet[^"]*"[^>]*>([\s\S]*?)<\/div>/);
96
- return {
97
- title: cleanHtmlText(link[2]),
98
- url: cleanDuckDuckGoUrl(decodeHtmlText(link[1])),
99
- snippet: snippet ? cleanHtmlText(snippet[1]) : '',
100
- };
101
- })
102
- .filter(Boolean);
103
- }
104
-
105
- function cleanDuckDuckGoUrl(url) {
106
- try {
107
- const parsed = new URL(url);
108
- const redirected = parsed.searchParams.get('uddg');
109
- return redirected ? decodeURIComponent(redirected) : url;
110
- } catch {
111
- return url;
112
- }
113
- }
114
-
115
- function cleanHtmlText(value = '') {
116
- return decodeHtmlText(value.replace(/<[^>]+>/g, ' ').replace(/\s+/g, ' ').trim());
117
- }
118
-
119
- function formatWebSearchResults(results = [], query = '') {
120
- if (results.length === 0) return `No web search results found for ${query}`;
121
- return results
122
- .map((result, index) => [
123
- `${index + 1}. ${result.title ?? 'Untitled'}`,
124
- result.url ?? '',
125
- result.snippet ?? '',
126
- ].filter(Boolean).join('\n'))
127
- .join('\n\n');
128
- }
@@ -1,273 +0,0 @@
1
- import { spawnSync } from 'node:child_process';
2
- import { randomUUID } from 'node:crypto';
3
- import { existsSync, readdirSync, statSync } from 'node:fs';
4
- import path from 'node:path';
5
- import { BUILTIN_TOOLS } from '../constants.mjs';
6
- import { toolsDirs } from '../settings/paths.mjs';
7
- import { readEffectiveSettings } from '../settings/load.mjs';
8
- import { globMatch } from '../util/glob.mjs';
9
-
10
- export function listToolboxTools(parsed = {}) {
11
- const seen = new Set();
12
- const tools = [];
13
- for (const dir of toolsDirs(parsed)) {
14
- if (!existsSync(dir)) continue;
15
- for (const entry of readdirSync(dir)) {
16
- const filePath = path.join(dir, entry);
17
- if (!statSync(filePath).isFile()) continue;
18
- const name = `tb__${path.basename(filePath)}`;
19
- if (seen.has(name)) continue;
20
- seen.add(name);
21
- const schema = describeToolboxTool(filePath);
22
- tools.push({ name, path: filePath, description: schema.description, schema });
23
- }
24
- }
25
- return tools;
26
- }
27
-
28
- export function isToolDisabled(name, kind, parsed = {}) {
29
- const settings = readEffectiveSettings(parsed);
30
- const enabled = settings['covenCode.tools.enable'];
31
- if (Array.isArray(enabled) && !enabled.some((pattern) => typeof pattern === 'string' && globMatch(pattern, name))) {
32
- return true;
33
- }
34
- const disabled = settings['covenCode.tools.disable'];
35
- if (!Array.isArray(disabled)) return false;
36
- return disabled.some((pattern) => {
37
- if (typeof pattern !== 'string') return false;
38
- if (pattern.startsWith('builtin:')) {
39
- return kind === 'built-in' && globMatch(pattern.slice('builtin:'.length), name);
40
- }
41
- return globMatch(pattern, name);
42
- });
43
- }
44
-
45
- export function toolKindForName(name) {
46
- if (BUILTIN_TOOLS.some(([builtinName]) => builtinName === name)) return 'built-in';
47
- if (name.startsWith('tb__')) return 'toolbox';
48
- if (name.startsWith('mcp__')) return 'local-mcp';
49
- return '';
50
- }
51
-
52
- function describeToolboxTool(filePath) {
53
- const result = spawnSync(filePath, {
54
- env: { ...process.env, TOOLBOX_ACTION: 'describe', AGENT: 'coven-code' },
55
- encoding: 'utf8',
56
- shell: false,
57
- });
58
- return parseToolboxDescription(result.stdout, filePath);
59
- }
60
-
61
- function parseToolboxDescription(stdout, filePath) {
62
- try {
63
- const parsed = JSON.parse(stdout);
64
- return {
65
- format: 'json',
66
- description: parsed.description || `Toolbox tool at ${filePath}`,
67
- input: normalizeToolboxInputSchema(parsed.input ?? parsed.args ?? parsed.inputSchema ?? parsed.schema),
68
- raw: parsed,
69
- };
70
- } catch {
71
- // Fall through to the documented text format.
72
- }
73
-
74
- const lines = stdout.split(/\r?\n/).filter(Boolean);
75
- const description = lines
76
- .filter((line) => line.startsWith('description: '))
77
- .map((line) => line.replace('description: ', '').trim())
78
- .join('\n');
79
- const input = lines
80
- .filter((line) => !line.startsWith('name: ') && !line.startsWith('description: '))
81
- .map((line) => {
82
- const match = line.match(/^([^:]+):\s*(.*)$/);
83
- return match ? parseTextParameter(match[1], match[2]) : undefined;
84
- })
85
- .filter(Boolean);
86
- return {
87
- format: 'text',
88
- description: description || `Toolbox tool at ${filePath}`,
89
- input,
90
- raw: stdout,
91
- };
92
- }
93
-
94
- function parseTextParameter(name, definition = '') {
95
- const [first = '', ...rest] = definition.trim().split(/\s+/);
96
- const knownTypes = new Set(['string', 'number', 'integer', 'boolean', 'array', 'object']);
97
- if (!first || first.toLowerCase() === 'optional') {
98
- return { name, type: 'string', description: ['optional', ...rest].filter(Boolean).join(' ') };
99
- }
100
- const optionalSuffix = first.endsWith('?');
101
- const type = optionalSuffix ? first.slice(0, -1) : first;
102
- if (knownTypes.has(type)) {
103
- return { name, type, description: optionalText(rest.join(' '), optionalSuffix) };
104
- }
105
- return { name, type: 'string', description: definition.trim() };
106
- }
107
-
108
- function optionalText(description, optional) {
109
- if (!optional) return description.replace(/^\(optional\)\s*/i, 'optional ');
110
- return description.toLowerCase().startsWith('optional') ? description : `optional ${description}`.trim();
111
- }
112
-
113
- function normalizeToolboxInputSchema(input = {}) {
114
- if (Array.isArray(input)) return input;
115
- if (input?.type === 'object' && input.properties && typeof input.properties === 'object') {
116
- return Object.entries(input.properties).map(([name, value]) => ({
117
- name,
118
- type: schemaTypeName(value),
119
- description: value?.description || '',
120
- }));
121
- }
122
- return Object.entries(input).map(([name, value]) => ({
123
- name,
124
- type: compactArgType(value),
125
- description: compactArgDescription(value),
126
- }));
127
- }
128
-
129
- function compactArgType(value) {
130
- if (Array.isArray(value)) return value[0] || 'string';
131
- return value?.type || 'string';
132
- }
133
-
134
- function compactArgDescription(value) {
135
- if (Array.isArray(value)) return value[1] || '';
136
- return value?.description || '';
137
- }
138
-
139
- function schemaTypeName(value = {}) {
140
- const type = value.type || 'string';
141
- if (type === 'array' && value.items?.type) return `array<${value.items.type}>`;
142
- return type;
143
- }
144
-
145
- export function printToolboxSchema(tool) {
146
- console.log(`# ${tool.name} (toolbox: ${tool.path})`);
147
- console.log('');
148
- console.log(tool.schema.description);
149
- if (tool.schema.input.length === 0) return;
150
- console.log('');
151
- console.log('# Schema');
152
- console.log('');
153
- for (const input of tool.schema.input) {
154
- const suffix = input.description ? `: ${input.description}` : '';
155
- console.log(`- ${input.name} (${input.type})${suffix}`);
156
- }
157
- }
158
-
159
- export function parseToolUseArgs(args) {
160
- const result = {
161
- toolName: '',
162
- flags: {},
163
- onlyOutput: false,
164
- threadId: `T-${randomUUID()}`,
165
- };
166
-
167
- for (let index = 0; index < args.length; index += 1) {
168
- const token = args[index];
169
- if (token === '--only' && args[index + 1] === 'output') {
170
- result.onlyOutput = true;
171
- index += 1;
172
- continue;
173
- }
174
- if (token === '--thread') {
175
- result.threadId = args[index + 1] ?? result.threadId;
176
- index += 1;
177
- continue;
178
- }
179
- if (token.startsWith('--')) {
180
- const key = token.slice(2);
181
- const value = args[index + 1] && !args[index + 1].startsWith('--') ? args[index + 1] : true;
182
- if (value !== true) index += 1;
183
- result.flags[key] = value;
184
- continue;
185
- }
186
- if (!result.toolName) result.toolName = token;
187
- }
188
-
189
- return result;
190
- }
191
-
192
- function formatToolboxInput(tool, flags, stdin) {
193
- if (stdin.length > 0) return stdin;
194
- if (Object.keys(flags).length === 0) return '';
195
- if (tool.schema.format === 'text') {
196
- return Object.entries(flags).map(([key, value]) => `${key}: ${value}`).join('\n') + '\n';
197
- }
198
- return `${JSON.stringify(flags)}\n`;
199
- }
200
-
201
- export function normalizeToolName(name = '') {
202
- return name.startsWith('tb__') ? name : `tb__${name}`;
203
- }
204
-
205
- export function toolboxTemplate(shell, name) {
206
- if (shell === 'js') return javascriptToolboxTemplate(name);
207
- return `#!/usr/bin/env ${shell}
208
- set -euo pipefail
209
-
210
- if [ "\${TOOLBOX_ACTION:-describe}" = "describe" ]; then
211
- cat <<'EOF'
212
- name: ${name}
213
- description: ${name.replaceAll('_', ' ')} toolbox tool
214
- input: string optional Input passed to the tool
215
- EOF
216
- exit 0
217
- fi
218
-
219
- input="$(cat || true)"
220
- if [ -n "$input" ]; then
221
- printf '%s\\n' "$input"
222
- else
223
- printf '${name} executed\\n'
224
- fi
225
- `;
226
- }
227
-
228
- function javascriptToolboxTemplate(name) {
229
- return `#!/usr/bin/env bun
230
- const action = process.env.TOOLBOX_ACTION ?? 'describe';
231
-
232
- if (action === 'describe') showDescription();
233
- else if (action === 'execute') execute();
234
- else {
235
- console.error(\`Unknown action: \${action}\`);
236
- process.exit(1);
237
- }
238
-
239
- function showDescription() {
240
- process.stdout.write([
241
- 'name: ${name}',
242
- 'description: ${name.replaceAll('_', ' ')} toolbox tool',
243
- 'input: string optional Input passed to the tool',
244
- ].join('\\n'));
245
- process.stdout.write('\\n');
246
- }
247
-
248
- async function execute() {
249
- const input = await new Response(Bun.stdin).text();
250
- if (input.trim()) {
251
- process.stdout.write(input.endsWith('\\n') ? input : \`\${input}\\n\`);
252
- } else {
253
- process.stdout.write('${name} executed\\n');
254
- }
255
- }
256
- `;
257
- }
258
-
259
- export function executeToolboxTool(tool, flags, stdin, threadId) {
260
- const input = formatToolboxInput(tool, flags, stdin);
261
- return spawnSync(tool.path, {
262
- input,
263
- env: {
264
- ...process.env,
265
- TOOLBOX_ACTION: 'execute',
266
- AGENT: 'coven-code',
267
- COVEN_CODE_THREAD_ID: threadId,
268
- AGENT_THREAD_ID: threadId,
269
- },
270
- encoding: 'utf8',
271
- shell: false,
272
- });
273
- }
package/src/util/fs.mjs DELETED
@@ -1,13 +0,0 @@
1
- import { existsSync } from 'node:fs';
2
-
3
- export function emitJson(value) {
4
- process.stdout.write(`${JSON.stringify(value)}\n`);
5
- }
6
-
7
- export function displayCwd(cwd = process.cwd()) {
8
- return String(cwd).replace(/^\/private\/var\//, '/var/');
9
- }
10
-
11
- export function addIfExists(files, filePath) {
12
- if (existsSync(filePath)) files.push(filePath);
13
- }
package/src/util/glob.mjs DELETED
@@ -1,46 +0,0 @@
1
- import { existsSync, readdirSync, statSync } from 'node:fs';
2
- import path from 'node:path';
3
-
4
- export function globMatch(pattern, value) {
5
- const re = new RegExp(`^${String(pattern).split('*').map(escapeRegex).join('.*')}$`);
6
- return re.test(value);
7
- }
8
-
9
- export function escapeRegex(value) {
10
- return value.replace(/[|\\{}()[\]^$+?.]/g, '\\$&');
11
- }
12
-
13
- export function hasGlob(rawPath) {
14
- return /[*?]/.test(rawPath);
15
- }
16
-
17
- export function globToRegex(pattern) {
18
- let source = '';
19
- for (let index = 0; index < pattern.length; index += 1) {
20
- const char = pattern[index];
21
- const next = pattern[index + 1];
22
- if (char === '*' && next === '*') {
23
- source += '.*';
24
- index += 1;
25
- } else if (char === '*') {
26
- source += `[^${escapeRegex(path.sep)}]*`;
27
- } else if (char === '?') {
28
- source += `[^${escapeRegex(path.sep)}]`;
29
- } else {
30
- source += escapeRegex(char);
31
- }
32
- }
33
- return new RegExp(`^${source}$`);
34
- }
35
-
36
- export function walkFiles(dir) {
37
- if (!existsSync(dir) || !statSync(dir).isDirectory()) return [];
38
- const files = [];
39
- for (const entry of readdirSync(dir)) {
40
- const filePath = path.join(dir, entry);
41
- const stat = statSync(filePath);
42
- if (stat.isDirectory()) files.push(...walkFiles(filePath));
43
- else if (stat.isFile()) files.push(filePath);
44
- }
45
- return files;
46
- }
package/src/util/html.mjs DELETED
@@ -1,21 +0,0 @@
1
- export function decodeHtmlText(value = '') {
2
- return value
3
- .replace(new RegExp('&' + 'a' + 'mp;', 'g'), '&')
4
- .replace(/&quot;/g, '"')
5
- .replace(/&#39;/g, "'")
6
- .replace(/&lt;/g, '<')
7
- .replace(/&gt;/g, '>');
8
- }
9
-
10
- export function htmlToText(html) {
11
- return decodeHtmlText(html
12
- .replace(/<script[\s\S]*?<\/script>/gi, '')
13
- .replace(/<style[\s\S]*?<\/style>/gi, '')
14
- .replace(/<\/(?:h[1-6]|p|div|main|article|section|li|tr)>/gi, '\n')
15
- .replace(/<br\s*\/?>/gi, '\n')
16
- .replace(/<[^>]+>/g, ' ')
17
- .replace(/[ \t]+/g, ' ')
18
- .replace(/\n\s+/g, '\n')
19
- .replace(/\n{3,}/g, '\n\n')
20
- .trim());
21
- }
@@ -1,13 +0,0 @@
1
- export function detectImageMediaType(raw) {
2
- if (raw.subarray(0, 8).equals(Buffer.from([0x89, 0x50, 0x4e, 0x47, 0x0d, 0x0a, 0x1a, 0x0a]))) return 'image/png';
3
- if (raw[0] === 0xff && raw[1] === 0xd8 && raw[2] === 0xff) return 'image/jpeg';
4
- const header = raw.subarray(0, 12).toString('ascii');
5
- if (header.startsWith('GIF87a') || header.startsWith('GIF89a')) return 'image/gif';
6
- if (header.startsWith('RIFF') && header.slice(8, 12) === 'WEBP') return 'image/webp';
7
- return undefined;
8
- }
9
-
10
- export function imageMediaTypeExtension(mediaType) {
11
- if (mediaType === 'image/jpeg') return 'jpg';
12
- return mediaType.split('/').at(-1) || 'img';
13
- }
@@ -1,24 +0,0 @@
1
- import { readFileSync } from 'node:fs';
2
-
3
- export function splitShellWords(line) {
4
- const tokens = [];
5
- const re = /"([^"\\]*(?:\\.[^"\\]*)*)"|'([^'\\]*(?:\\.[^'\\]*)*)'|(\S+)/g;
6
- let match;
7
- while ((match = re.exec(line))) {
8
- tokens.push((match[1] ?? match[2] ?? match[3]).replace(/\\(["'])/g, '$1'));
9
- }
10
- return tokens;
11
- }
12
-
13
- export function shellQuote(value) {
14
- return `'${String(value).replace(/'/g, `'\\''`)}'`;
15
- }
16
-
17
- export function readStdin() {
18
- if (process.stdin.isTTY) return '';
19
- try {
20
- return readFileSync(0, 'utf8');
21
- } catch {
22
- return '';
23
- }
24
- }
@@ -1,11 +0,0 @@
1
- export function printRows(rows) {
2
- const widths = [];
3
- for (const row of rows) {
4
- row.forEach((cell, index) => {
5
- widths[index] = Math.max(widths[index] ?? 0, String(cell).length);
6
- });
7
- }
8
- for (const row of rows) {
9
- console.log(row.map((cell, index) => String(cell).padEnd(widths[index])).join(' ').trimEnd());
10
- }
11
- }