@ecmaos/coreutils 0.2.0 → 0.3.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/.turbo/turbo-build.log +1 -1
- package/CHANGELOG.md +25 -0
- package/LICENSE +1 -1
- package/dist/commands/cal.js +2 -2
- package/dist/commands/cal.js.map +1 -1
- package/dist/commands/cat.js +2 -2
- package/dist/commands/cd.js +2 -2
- package/dist/commands/chmod.d.ts.map +1 -1
- package/dist/commands/chmod.js +16 -11
- package/dist/commands/chmod.js.map +1 -1
- package/dist/commands/cp.js +2 -2
- package/dist/commands/cp.js.map +1 -1
- package/dist/commands/date.js +2 -2
- package/dist/commands/date.js.map +1 -1
- package/dist/commands/echo.js +2 -2
- package/dist/commands/echo.js.map +1 -1
- package/dist/commands/false.js +2 -2
- package/dist/commands/fetch.d.ts +4 -0
- package/dist/commands/fetch.d.ts.map +1 -0
- package/dist/commands/fetch.js +210 -0
- package/dist/commands/fetch.js.map +1 -0
- package/dist/commands/format.d.ts +4 -0
- package/dist/commands/format.d.ts.map +1 -0
- package/dist/commands/format.js +178 -0
- package/dist/commands/format.js.map +1 -0
- package/dist/commands/hash.d.ts +4 -0
- package/dist/commands/hash.d.ts.map +1 -0
- package/dist/commands/hash.js +200 -0
- package/dist/commands/hash.js.map +1 -0
- package/dist/commands/head.js +2 -2
- package/dist/commands/id.js +2 -2
- package/dist/commands/id.js.map +1 -1
- package/dist/commands/less.d.ts.map +1 -1
- package/dist/commands/less.js +53 -2
- package/dist/commands/less.js.map +1 -1
- package/dist/commands/ls.d.ts.map +1 -1
- package/dist/commands/ls.js +120 -97
- package/dist/commands/ls.js.map +1 -1
- package/dist/commands/man.d.ts +4 -0
- package/dist/commands/man.d.ts.map +1 -0
- package/dist/commands/man.js +554 -0
- package/dist/commands/man.js.map +1 -0
- package/dist/commands/mkdir.js +2 -2
- package/dist/commands/mkdir.js.map +1 -1
- package/dist/commands/mktemp.d.ts +4 -0
- package/dist/commands/mktemp.d.ts.map +1 -0
- package/dist/commands/mktemp.js +229 -0
- package/dist/commands/mktemp.js.map +1 -0
- package/dist/commands/nc.js +2 -2
- package/dist/commands/nc.js.map +1 -1
- package/dist/commands/passkey.js +3 -3
- package/dist/commands/pwd.js +2 -2
- package/dist/commands/pwd.js.map +1 -1
- package/dist/commands/rm.d.ts.map +1 -1
- package/dist/commands/rm.js +57 -12
- package/dist/commands/rm.js.map +1 -1
- package/dist/commands/rmdir.js +2 -2
- package/dist/commands/rmdir.js.map +1 -1
- package/dist/commands/sockets.js +1 -1
- package/dist/commands/stat.d.ts.map +1 -1
- package/dist/commands/stat.js +37 -15
- package/dist/commands/stat.js.map +1 -1
- package/dist/commands/tail.js +2 -2
- package/dist/commands/tar.d.ts +4 -0
- package/dist/commands/tar.d.ts.map +1 -0
- package/dist/commands/tar.js +693 -0
- package/dist/commands/tar.js.map +1 -0
- package/dist/commands/touch.js +2 -2
- package/dist/commands/touch.js.map +1 -1
- package/dist/commands/true.js +2 -2
- package/dist/commands/unzip.d.ts +4 -0
- package/dist/commands/unzip.d.ts.map +1 -0
- package/dist/commands/unzip.js +443 -0
- package/dist/commands/unzip.js.map +1 -0
- package/dist/commands/user.d.ts +4 -0
- package/dist/commands/user.d.ts.map +1 -0
- package/dist/commands/user.js +427 -0
- package/dist/commands/user.js.map +1 -0
- package/dist/commands/whoami.js +2 -2
- package/dist/commands/whoami.js.map +1 -1
- package/dist/commands/zip.d.ts +4 -0
- package/dist/commands/zip.d.ts.map +1 -0
- package/dist/commands/zip.js +264 -0
- package/dist/commands/zip.js.map +1 -0
- package/dist/index.d.ts +9 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +28 -1
- package/dist/index.js.map +1 -1
- package/package.json +6 -4
- package/src/commands/cal.ts +2 -2
- package/src/commands/cat.ts +2 -2
- package/src/commands/cd.ts +2 -2
- package/src/commands/chmod.ts +19 -11
- package/src/commands/cp.ts +2 -2
- package/src/commands/date.ts +2 -2
- package/src/commands/echo.ts +2 -2
- package/src/commands/false.ts +2 -2
- package/src/commands/fetch.ts +205 -0
- package/src/commands/format.ts +204 -0
- package/src/commands/hash.ts +215 -0
- package/src/commands/head.ts +2 -2
- package/src/commands/id.ts +2 -2
- package/src/commands/less.ts +50 -2
- package/src/commands/ls.ts +131 -91
- package/src/commands/man.ts +643 -0
- package/src/commands/mkdir.ts +2 -2
- package/src/commands/mktemp.ts +235 -0
- package/src/commands/nc.ts +2 -2
- package/src/commands/passkey.ts +3 -3
- package/src/commands/pwd.ts +2 -2
- package/src/commands/rm.ts +54 -12
- package/src/commands/rmdir.ts +2 -2
- package/src/commands/sockets.ts +1 -1
- package/src/commands/stat.ts +44 -16
- package/src/commands/tail.ts +2 -2
- package/src/commands/tar.ts +737 -0
- package/src/commands/touch.ts +2 -2
- package/src/commands/true.ts +2 -2
- package/src/commands/unzip.ts +517 -0
- package/src/commands/user.ts +436 -0
- package/src/commands/whoami.ts +2 -2
- package/src/commands/zip.ts +319 -0
- package/src/index.ts +28 -1
|
@@ -0,0 +1,235 @@
|
|
|
1
|
+
import path from 'path'
|
|
2
|
+
import type { Kernel, Process, Shell, Terminal } from '@ecmaos/types'
|
|
3
|
+
import { TerminalCommand } from '../shared/terminal-command.js'
|
|
4
|
+
import { writelnStdout, writelnStderr } from '../shared/helpers.js'
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* Generate random alphanumeric characters for template replacement
|
|
8
|
+
*/
|
|
9
|
+
function generateRandomChars(count: number): string {
|
|
10
|
+
const chars = '0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZabcdefghijklmnopqrstuvwxyz'
|
|
11
|
+
let result = ''
|
|
12
|
+
const cryptoApi = globalThis.crypto
|
|
13
|
+
if (!cryptoApi) {
|
|
14
|
+
throw new Error('Crypto API not available')
|
|
15
|
+
}
|
|
16
|
+
const randomValues = cryptoApi.getRandomValues(new Uint8Array(count))
|
|
17
|
+
for (let i = 0; i < count; i++) {
|
|
18
|
+
const randomValue = randomValues[i]
|
|
19
|
+
if (randomValue !== undefined) {
|
|
20
|
+
result += chars[randomValue % chars.length]
|
|
21
|
+
}
|
|
22
|
+
}
|
|
23
|
+
return result
|
|
24
|
+
}
|
|
25
|
+
|
|
26
|
+
/**
|
|
27
|
+
* Replace X's in template with random characters
|
|
28
|
+
*/
|
|
29
|
+
function replaceTemplate(template: string): string {
|
|
30
|
+
const xCount = (template.match(/X/g) || []).length
|
|
31
|
+
if (xCount === 0) {
|
|
32
|
+
// If no X's, append random suffix
|
|
33
|
+
return template + '.' + generateRandomChars(6)
|
|
34
|
+
}
|
|
35
|
+
|
|
36
|
+
let result = template
|
|
37
|
+
const randomChars = generateRandomChars(xCount)
|
|
38
|
+
let charIndex = 0
|
|
39
|
+
|
|
40
|
+
for (let i = 0; i < template.length; i++) {
|
|
41
|
+
if (template[i] === 'X') {
|
|
42
|
+
result = result.substring(0, i) + randomChars[charIndex] + result.substring(i + 1)
|
|
43
|
+
charIndex++
|
|
44
|
+
}
|
|
45
|
+
}
|
|
46
|
+
|
|
47
|
+
return result
|
|
48
|
+
}
|
|
49
|
+
|
|
50
|
+
function printUsage(process: Process | undefined, terminal: Terminal): void {
|
|
51
|
+
const usage = `Usage: mktemp [OPTION]... [TEMPLATE]
|
|
52
|
+
Create a temporary file or directory, safely, and print its name.
|
|
53
|
+
|
|
54
|
+
-d, --directory create a directory, not a file
|
|
55
|
+
-q, --quiet suppress error messages
|
|
56
|
+
-u, --dry-run do not create anything; merely print a name (unsafe)
|
|
57
|
+
-p DIR, --tmpdir=DIR interpret TEMPLATE relative to DIR; if DIR is not
|
|
58
|
+
specified, use \$TMPDIR if set, else /tmp. With
|
|
59
|
+
this option, TEMPLATE must not be an absolute name;
|
|
60
|
+
unlike with -t, TEMPLATE may contain slashes, but
|
|
61
|
+
mktemp creates only the final component
|
|
62
|
+
-t interpret TEMPLATE relative to the directory specified by
|
|
63
|
+
-p, or \$TMPDIR if -p is not given; if neither is
|
|
64
|
+
specified, use /tmp [deprecated]
|
|
65
|
+
--help display this help and exit
|
|
66
|
+
|
|
67
|
+
The TEMPLATE must contain at least 3 consecutive 'X's in last component.
|
|
68
|
+
If TEMPLATE is not specified, use tmp.XXXXXX, and --tmpdir implies -t.
|
|
69
|
+
|
|
70
|
+
Examples:
|
|
71
|
+
mktemp create a temp file in /tmp
|
|
72
|
+
mktemp -d create a temp directory in /tmp
|
|
73
|
+
mktemp /tmp/file.XXXXXX create a temp file with template
|
|
74
|
+
mktemp -d /tmp/dir.XXXXXX create a temp directory with template`
|
|
75
|
+
writelnStderr(process, terminal, usage)
|
|
76
|
+
}
|
|
77
|
+
|
|
78
|
+
export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal): TerminalCommand {
|
|
79
|
+
return new TerminalCommand({
|
|
80
|
+
command: 'mktemp',
|
|
81
|
+
description: 'Create a temporary file or directory',
|
|
82
|
+
kernel,
|
|
83
|
+
shell,
|
|
84
|
+
terminal,
|
|
85
|
+
run: async (pid: number, argv: string[]) => {
|
|
86
|
+
const process = kernel.processes.get(pid) as Process | undefined
|
|
87
|
+
|
|
88
|
+
if (!process) return 1
|
|
89
|
+
|
|
90
|
+
if (argv.length > 0 && (argv[0] === '--help' || argv[0] === '-h')) {
|
|
91
|
+
printUsage(process, terminal)
|
|
92
|
+
return 0
|
|
93
|
+
}
|
|
94
|
+
|
|
95
|
+
let createDirectory = false
|
|
96
|
+
let quiet = false
|
|
97
|
+
let dryRun = false
|
|
98
|
+
let tmpdir: string | undefined
|
|
99
|
+
let useTmpdir = false
|
|
100
|
+
let template: string | undefined
|
|
101
|
+
|
|
102
|
+
// Parse arguments
|
|
103
|
+
for (let i = 0; i < argv.length; i++) {
|
|
104
|
+
const arg = argv[i]
|
|
105
|
+
if (!arg) continue
|
|
106
|
+
|
|
107
|
+
if (arg === '--help' || arg === '-h') {
|
|
108
|
+
printUsage(process, terminal)
|
|
109
|
+
return 0
|
|
110
|
+
} else if (arg === '-d' || arg === '--directory') {
|
|
111
|
+
createDirectory = true
|
|
112
|
+
} else if (arg === '-q' || arg === '--quiet') {
|
|
113
|
+
quiet = true
|
|
114
|
+
} else if (arg === '-u' || arg === '--dry-run') {
|
|
115
|
+
dryRun = true
|
|
116
|
+
} else if (arg === '-t') {
|
|
117
|
+
useTmpdir = true
|
|
118
|
+
} else if (arg === '-p' || arg === '--tmpdir') {
|
|
119
|
+
useTmpdir = true
|
|
120
|
+
const dirArg = argv[i + 1]
|
|
121
|
+
if (dirArg && !dirArg.startsWith('-')) {
|
|
122
|
+
tmpdir = dirArg
|
|
123
|
+
i++ // Skip the next argument as it's the directory value
|
|
124
|
+
}
|
|
125
|
+
} else if (arg.startsWith('--tmpdir=')) {
|
|
126
|
+
useTmpdir = true
|
|
127
|
+
const dirValue = arg.split('=')[1]
|
|
128
|
+
if (dirValue) {
|
|
129
|
+
tmpdir = dirValue
|
|
130
|
+
}
|
|
131
|
+
} else if (!arg.startsWith('-')) {
|
|
132
|
+
// Positional argument - should be the template
|
|
133
|
+
if (!template) {
|
|
134
|
+
template = arg
|
|
135
|
+
} else {
|
|
136
|
+
if (!quiet) {
|
|
137
|
+
await writelnStderr(process, terminal, `mktemp: too many arguments`)
|
|
138
|
+
}
|
|
139
|
+
return 1
|
|
140
|
+
}
|
|
141
|
+
} else {
|
|
142
|
+
if (!quiet) {
|
|
143
|
+
await writelnStderr(process, terminal, `mktemp: invalid option -- '${arg.replace(/^-+/, '')}'`)
|
|
144
|
+
await writelnStderr(process, terminal, `Try 'mktemp --help' for more information.`)
|
|
145
|
+
}
|
|
146
|
+
return 1
|
|
147
|
+
}
|
|
148
|
+
}
|
|
149
|
+
|
|
150
|
+
// Determine the temp directory
|
|
151
|
+
let baseDir = '/tmp'
|
|
152
|
+
if (useTmpdir) {
|
|
153
|
+
if (tmpdir) {
|
|
154
|
+
baseDir = tmpdir
|
|
155
|
+
} else {
|
|
156
|
+
// Check TMPDIR environment variable
|
|
157
|
+
const envTmpdir = shell.env.get('TMPDIR')
|
|
158
|
+
if (envTmpdir) {
|
|
159
|
+
baseDir = envTmpdir
|
|
160
|
+
}
|
|
161
|
+
}
|
|
162
|
+
}
|
|
163
|
+
|
|
164
|
+
// Resolve base directory
|
|
165
|
+
const resolvedBaseDir = path.isAbsolute(baseDir) ? baseDir : path.resolve(shell.cwd, baseDir)
|
|
166
|
+
|
|
167
|
+
// Determine template
|
|
168
|
+
if (!template) {
|
|
169
|
+
template = 'tmp.XXXXXX'
|
|
170
|
+
}
|
|
171
|
+
|
|
172
|
+
// If template is absolute and useTmpdir is set, that's an error
|
|
173
|
+
if (useTmpdir && path.isAbsolute(template)) {
|
|
174
|
+
if (!quiet) {
|
|
175
|
+
await writelnStderr(process, terminal, `mktemp: with -p/--tmpdir, TEMPLATE must not be an absolute name`)
|
|
176
|
+
}
|
|
177
|
+
return 1
|
|
178
|
+
}
|
|
179
|
+
|
|
180
|
+
// Build the full path
|
|
181
|
+
let fullPath: string
|
|
182
|
+
if (path.isAbsolute(template)) {
|
|
183
|
+
fullPath = template
|
|
184
|
+
} else {
|
|
185
|
+
fullPath = path.join(resolvedBaseDir, template)
|
|
186
|
+
}
|
|
187
|
+
|
|
188
|
+
// Check that template has at least 3 X's in the last component
|
|
189
|
+
const basename = path.basename(fullPath)
|
|
190
|
+
const xCount = (basename.match(/X/g) || []).length
|
|
191
|
+
if (xCount < 3) {
|
|
192
|
+
if (!quiet) {
|
|
193
|
+
await writelnStderr(process, terminal, `mktemp: too few X's in template ${template}`)
|
|
194
|
+
}
|
|
195
|
+
return 1
|
|
196
|
+
}
|
|
197
|
+
|
|
198
|
+
// Replace template with random characters
|
|
199
|
+
const finalPath = replaceTemplate(fullPath)
|
|
200
|
+
|
|
201
|
+
// If dry-run, just print the name
|
|
202
|
+
if (dryRun) {
|
|
203
|
+
await writelnStdout(process, terminal, finalPath)
|
|
204
|
+
return 0
|
|
205
|
+
}
|
|
206
|
+
|
|
207
|
+
// Create the file or directory
|
|
208
|
+
try {
|
|
209
|
+
if (createDirectory) {
|
|
210
|
+
await shell.context.fs.promises.mkdir(finalPath, { recursive: true })
|
|
211
|
+
} else {
|
|
212
|
+
// Create parent directory if needed
|
|
213
|
+
const parentDir = path.dirname(finalPath)
|
|
214
|
+
try {
|
|
215
|
+
await shell.context.fs.promises.mkdir(parentDir, { recursive: true })
|
|
216
|
+
} catch {
|
|
217
|
+
// Parent might already exist, ignore
|
|
218
|
+
}
|
|
219
|
+
// Create empty file
|
|
220
|
+
await shell.context.fs.promises.writeFile(finalPath, '')
|
|
221
|
+
}
|
|
222
|
+
|
|
223
|
+
// Print the created path
|
|
224
|
+
await writelnStdout(process, terminal, finalPath)
|
|
225
|
+
return 0
|
|
226
|
+
} catch (error) {
|
|
227
|
+
if (!quiet) {
|
|
228
|
+
const errorMessage = error instanceof Error ? error.message : String(error)
|
|
229
|
+
await writelnStderr(process, terminal, `mktemp: ${errorMessage}`)
|
|
230
|
+
}
|
|
231
|
+
return 1
|
|
232
|
+
}
|
|
233
|
+
}
|
|
234
|
+
})
|
|
235
|
+
}
|
package/src/commands/nc.ts
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
import type { Kernel, Process, Shell, Terminal } from '@ecmaos/types'
|
|
2
2
|
import { TerminalEvents } from '@ecmaos/types'
|
|
3
3
|
import { TerminalCommand } from '../shared/terminal-command.js'
|
|
4
|
-
import { writelnStderr
|
|
4
|
+
import { writelnStderr } from '../shared/helpers.js'
|
|
5
5
|
|
|
6
6
|
function printUsage(process: Process | undefined, terminal: Terminal): void {
|
|
7
7
|
const usage = `Usage: nc [OPTIONS] <host> [port]
|
|
@@ -19,7 +19,7 @@ Examples:
|
|
|
19
19
|
nc -p 443 echo.websocket.org
|
|
20
20
|
nc -u wss://echo.websocket.org
|
|
21
21
|
nc -u https://example.com:443`
|
|
22
|
-
|
|
22
|
+
writelnStderr(process, terminal, usage)
|
|
23
23
|
}
|
|
24
24
|
|
|
25
25
|
interface ConnectionOptions {
|
package/src/commands/passkey.ts
CHANGED
|
@@ -13,7 +13,7 @@ Subcommands:
|
|
|
13
13
|
remove-all Remove all passkeys
|
|
14
14
|
|
|
15
15
|
--help display this help and exit`
|
|
16
|
-
|
|
16
|
+
writelnStderr(process, terminal, usage)
|
|
17
17
|
}
|
|
18
18
|
|
|
19
19
|
export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal): TerminalCommand {
|
|
@@ -186,7 +186,7 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
186
186
|
case 'remove': {
|
|
187
187
|
if (!id) {
|
|
188
188
|
await writelnStderr(process, terminal, chalk.red('Error: --id is required for remove command'))
|
|
189
|
-
await
|
|
189
|
+
await writelnStderr(process, terminal, 'Usage: passkey remove --id <id>')
|
|
190
190
|
return 1
|
|
191
191
|
}
|
|
192
192
|
|
|
@@ -223,7 +223,7 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
223
223
|
|
|
224
224
|
default:
|
|
225
225
|
await writelnStderr(process, terminal, chalk.red(`Error: Unknown subcommand: ${subcommand}`))
|
|
226
|
-
await
|
|
226
|
+
await writelnStderr(process, terminal, 'Run "passkey help" for usage information')
|
|
227
227
|
return 1
|
|
228
228
|
}
|
|
229
229
|
} catch (error) {
|
package/src/commands/pwd.ts
CHANGED
|
@@ -1,13 +1,13 @@
|
|
|
1
1
|
import type { Kernel, Process, Shell, Terminal } from '@ecmaos/types'
|
|
2
2
|
import { TerminalCommand } from '../shared/terminal-command.js'
|
|
3
|
-
import { writelnStdout } from '../shared/helpers.js'
|
|
3
|
+
import { writelnStdout, writelnStderr } from '../shared/helpers.js'
|
|
4
4
|
|
|
5
5
|
function printUsage(process: Process | undefined, terminal: Terminal): void {
|
|
6
6
|
const usage = `Usage: pwd
|
|
7
7
|
Print the name of the current working directory.
|
|
8
8
|
|
|
9
9
|
--help display this help and exit`
|
|
10
|
-
|
|
10
|
+
writelnStderr(process, terminal, usage)
|
|
11
11
|
}
|
|
12
12
|
|
|
13
13
|
export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal): TerminalCommand {
|
package/src/commands/rm.ts
CHANGED
|
@@ -7,7 +7,9 @@ function printUsage(process: Process | undefined, terminal: Terminal): void {
|
|
|
7
7
|
const usage = `Usage: rm [OPTION]... FILE...
|
|
8
8
|
Remove (unlink) the FILE(s).
|
|
9
9
|
|
|
10
|
-
--
|
|
10
|
+
-f, --force ignore nonexistent files and arguments, never prompt
|
|
11
|
+
-r, -R, --recursive remove directories and their contents recursively
|
|
12
|
+
--help display this help and exit`
|
|
11
13
|
writelnStderr(process, terminal, usage)
|
|
12
14
|
}
|
|
13
15
|
|
|
@@ -32,10 +34,32 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
32
34
|
return 0
|
|
33
35
|
}
|
|
34
36
|
|
|
37
|
+
let recursive = false
|
|
38
|
+
let force = false
|
|
35
39
|
const pathArray: string[] = []
|
|
40
|
+
|
|
36
41
|
for (const arg of argv) {
|
|
37
42
|
if (arg.startsWith('-') && arg !== '--') {
|
|
38
|
-
|
|
43
|
+
// Handle combined flags like -rf, -fr, -rR, etc.
|
|
44
|
+
if (arg === '--recursive' || arg === '-R') {
|
|
45
|
+
recursive = true
|
|
46
|
+
} else if (arg === '--force') {
|
|
47
|
+
force = true
|
|
48
|
+
} else if (arg.length > 1) {
|
|
49
|
+
// Parse individual flags in combined options like -rf
|
|
50
|
+
for (let i = 1; i < arg.length; i++) {
|
|
51
|
+
const flag = arg[i]
|
|
52
|
+
if (flag === 'r' || flag === 'R') {
|
|
53
|
+
recursive = true
|
|
54
|
+
} else if (flag === 'f') {
|
|
55
|
+
force = true
|
|
56
|
+
} else {
|
|
57
|
+
await writelnStderr(process, terminal, `rm: invalid option -- '${flag}'`)
|
|
58
|
+
await writelnStderr(process, terminal, "Try 'rm --help' for more information.")
|
|
59
|
+
return 1
|
|
60
|
+
}
|
|
61
|
+
}
|
|
62
|
+
} else {
|
|
39
63
|
await writelnStderr(process, terminal, `rm: invalid option -- '${arg.slice(1)}'`)
|
|
40
64
|
await writelnStderr(process, terminal, "Try 'rm --help' for more information.")
|
|
41
65
|
return 1
|
|
@@ -104,24 +128,42 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
104
128
|
|
|
105
129
|
for (const target of expandedPaths) {
|
|
106
130
|
if (!target || typeof target !== 'string') {
|
|
107
|
-
|
|
108
|
-
|
|
131
|
+
if (!force) {
|
|
132
|
+
await writelnStderr(process, terminal, `rm: ${String(target)}: No such file or directory`)
|
|
133
|
+
hasError = true
|
|
134
|
+
}
|
|
109
135
|
continue
|
|
110
136
|
}
|
|
111
137
|
|
|
112
138
|
const fullPath = path.resolve(shell.cwd, target)
|
|
113
139
|
|
|
114
140
|
try {
|
|
115
|
-
|
|
116
|
-
|
|
117
|
-
await shell.context.fs.promises.
|
|
118
|
-
|
|
119
|
-
|
|
141
|
+
// Check if it's a directory to validate recursive flag requirement
|
|
142
|
+
try {
|
|
143
|
+
const stat = await shell.context.fs.promises.stat(fullPath)
|
|
144
|
+
if (stat.isDirectory() && !recursive) {
|
|
145
|
+
await writelnStderr(process, terminal, `rm: ${target}: is a directory`)
|
|
146
|
+
hasError = true
|
|
147
|
+
continue
|
|
148
|
+
}
|
|
149
|
+
} catch (statError) {
|
|
150
|
+
// If stat fails, the file might not exist
|
|
151
|
+
// If force is enabled, we'll try to remove it anyway (rm will handle it)
|
|
152
|
+
// If force is not enabled, we'll let rm handle the error
|
|
120
153
|
}
|
|
154
|
+
|
|
155
|
+
// Use fs.promises.rm with appropriate options
|
|
156
|
+
await shell.context.fs.promises.rm(fullPath, {
|
|
157
|
+
recursive: recursive,
|
|
158
|
+
force: force
|
|
159
|
+
})
|
|
121
160
|
} catch (error) {
|
|
122
|
-
|
|
123
|
-
|
|
124
|
-
|
|
161
|
+
// If force is enabled, ignore errors
|
|
162
|
+
if (!force) {
|
|
163
|
+
const errorMessage = error instanceof Error ? error.message : String(error)
|
|
164
|
+
await writelnStderr(process, terminal, `rm: ${target}: ${errorMessage}`)
|
|
165
|
+
hasError = true
|
|
166
|
+
}
|
|
125
167
|
}
|
|
126
168
|
}
|
|
127
169
|
|
package/src/commands/rmdir.ts
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
import path from 'path'
|
|
2
2
|
import type { Kernel, Process, Shell, Terminal } from '@ecmaos/types'
|
|
3
3
|
import { TerminalCommand } from '../shared/terminal-command.js'
|
|
4
|
-
import {
|
|
4
|
+
import { writelnStderr } from '../shared/helpers.js'
|
|
5
5
|
|
|
6
6
|
function printUsage(process: Process | undefined, terminal: Terminal): void {
|
|
7
7
|
const usage = `Usage: rmdir [OPTION]... DIRECTORY...
|
|
8
8
|
Remove the DIRECTORY(ies), if they are empty.
|
|
9
9
|
|
|
10
10
|
--help display this help and exit`
|
|
11
|
-
|
|
11
|
+
writelnStderr(process, terminal, usage)
|
|
12
12
|
}
|
|
13
13
|
|
|
14
14
|
export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal): TerminalCommand {
|
package/src/commands/sockets.ts
CHANGED
|
@@ -26,7 +26,7 @@ Examples:
|
|
|
26
26
|
sockets create https://example.com:443 -t webtransport
|
|
27
27
|
sockets close abc-123-def-456
|
|
28
28
|
sockets show abc-123-def-456`
|
|
29
|
-
|
|
29
|
+
writelnStderr(process, terminal, usage)
|
|
30
30
|
}
|
|
31
31
|
|
|
32
32
|
function findConnectionById(kernel: Kernel, id: string): SocketConnection | undefined {
|
package/src/commands/stat.ts
CHANGED
|
@@ -3,14 +3,14 @@ import chalk from 'chalk'
|
|
|
3
3
|
import * as zipjs from '@zip.js/zip.js'
|
|
4
4
|
import type { Kernel, Process, Shell, Terminal } from '@ecmaos/types'
|
|
5
5
|
import { TerminalCommand } from '../shared/terminal-command.js'
|
|
6
|
-
import { writelnStdout } from '../shared/helpers.js'
|
|
6
|
+
import { writelnStdout, writelnStderr } from '../shared/helpers.js'
|
|
7
7
|
|
|
8
8
|
function printUsage(process: Process | undefined, terminal: Terminal): void {
|
|
9
9
|
const usage = `Usage: stat [OPTION]... FILE...
|
|
10
10
|
Display file or file system status.
|
|
11
11
|
|
|
12
12
|
--help display this help and exit`
|
|
13
|
-
|
|
13
|
+
writelnStderr(process, terminal, usage)
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal): TerminalCommand {
|
|
@@ -28,22 +28,50 @@ export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal):
|
|
|
28
28
|
return 0
|
|
29
29
|
}
|
|
30
30
|
|
|
31
|
-
|
|
32
|
-
const
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
|
|
39
|
-
|
|
40
|
-
|
|
41
|
-
|
|
42
|
-
|
|
43
|
-
|
|
31
|
+
// Filter out options/flags and get target paths
|
|
32
|
+
const targets = argv.length > 0
|
|
33
|
+
? argv.filter(arg => !arg.startsWith('-'))
|
|
34
|
+
: [shell.cwd]
|
|
35
|
+
|
|
36
|
+
if (targets.length === 0) {
|
|
37
|
+
targets.push(shell.cwd)
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
let hasError = false
|
|
41
|
+
|
|
42
|
+
for (const target of targets) {
|
|
43
|
+
const fullPath = path.resolve(shell.cwd, target)
|
|
44
|
+
|
|
45
|
+
try {
|
|
46
|
+
const stats = await shell.context.fs.promises.stat(fullPath)
|
|
47
|
+
|
|
48
|
+
if (targets.length > 1) {
|
|
49
|
+
await writelnStdout(process, terminal, `${target}:`)
|
|
50
|
+
}
|
|
51
|
+
await writelnStdout(process, terminal, JSON.stringify(stats, null, 2))
|
|
52
|
+
|
|
53
|
+
const extension = path.extname(fullPath)
|
|
54
|
+
if (extension === '.zip') {
|
|
55
|
+
const blob = new Blob([new Uint8Array(await shell.context.fs.promises.readFile(fullPath))])
|
|
56
|
+
const zipReader = new zipjs.ZipReader(new zipjs.BlobReader(blob))
|
|
57
|
+
const entries = await zipReader.getEntries()
|
|
58
|
+
await writelnStdout(process, terminal, chalk.bold('\nZIP Entries:'))
|
|
59
|
+
for (const entry of entries) {
|
|
60
|
+
await writelnStdout(process, terminal, `${chalk.blue(entry.filename)} (${entry.uncompressedSize} bytes)`)
|
|
61
|
+
}
|
|
62
|
+
}
|
|
63
|
+
|
|
64
|
+
if (targets.length > 1) {
|
|
65
|
+
await writelnStdout(process, terminal, '')
|
|
66
|
+
}
|
|
67
|
+
} catch (error) {
|
|
68
|
+
const errorMessage = error instanceof Error ? error.message : String(error)
|
|
69
|
+
await writelnStderr(process, terminal, `stat: ${target}: ${errorMessage}`)
|
|
70
|
+
hasError = true
|
|
44
71
|
}
|
|
45
72
|
}
|
|
46
|
-
|
|
73
|
+
|
|
74
|
+
return hasError ? 1 : 0
|
|
47
75
|
}
|
|
48
76
|
})
|
|
49
77
|
}
|
package/src/commands/tail.ts
CHANGED
|
@@ -2,7 +2,7 @@ import path from 'path'
|
|
|
2
2
|
import type { Kernel, Process, Shell, Terminal } from '@ecmaos/types'
|
|
3
3
|
import { TerminalEvents } from '@ecmaos/types'
|
|
4
4
|
import { TerminalCommand } from '../shared/terminal-command.js'
|
|
5
|
-
import {
|
|
5
|
+
import { writelnStderr } from '../shared/helpers.js'
|
|
6
6
|
|
|
7
7
|
function printUsage(process: Process | undefined, terminal: Terminal): void {
|
|
8
8
|
const usage = `Usage: tail [OPTION]... [FILE]...
|
|
@@ -10,7 +10,7 @@ Print the last 10 lines of each FILE to standard output.
|
|
|
10
10
|
|
|
11
11
|
-n, -nNUMBER print the last NUMBER lines instead of 10
|
|
12
12
|
--help display this help and exit`
|
|
13
|
-
|
|
13
|
+
writelnStderr(process, terminal, usage)
|
|
14
14
|
}
|
|
15
15
|
|
|
16
16
|
export function createCommand(kernel: Kernel, shell: Shell, terminal: Terminal): TerminalCommand {
|