open-claude-p 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.ja.md +708 -0
- package/README.ko.md +713 -0
- package/README.md +850 -0
- package/README.zh.md +708 -0
- package/bin/cli.js +782 -0
- package/package.json +68 -0
- package/scripts/postinstall.js +60 -0
- package/src/chat/event-filters.js +116 -0
- package/src/chat/index.js +1225 -0
- package/src/completion/detector.js +163 -0
- package/src/daemon/client.js +172 -0
- package/src/daemon/server.js +267 -0
- package/src/daemon/socket.js +78 -0
- package/src/index.js +908 -0
- package/src/options/index.js +4 -0
- package/src/options/parse-argv.js +214 -0
- package/src/options/spec.js +519 -0
- package/src/options/validate.js +104 -0
- package/src/output/index.js +8 -0
- package/src/output/json.js +83 -0
- package/src/output/registry.js +35 -0
- package/src/output/stream-json.js +111 -0
- package/src/output/text.js +94 -0
- package/src/parsers/ansi-strip.js +94 -0
- package/src/parsers/index.js +8 -0
- package/src/parsers/pipeline.js +50 -0
- package/src/parsers/registry.js +43 -0
- package/src/parsers/sentinel.js +41 -0
- package/src/parsers/tui-frame.js +256 -0
- package/src/print-mode.js +214 -0
- package/src/pty/index.js +3 -0
- package/src/pty/pool.js +127 -0
- package/src/pty/session.js +88 -0
- package/src/session-log.js +124 -0
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
// argv -> normalized options object.
|
|
2
|
+
//
|
|
3
|
+
// A small hand-rolled parser that consumes the OPTION_SPEC contract. No
|
|
4
|
+
// third-party dependency, to keep this package's runtime footprint to just
|
|
5
|
+
// `node-pty`.
|
|
6
|
+
//
|
|
7
|
+
// Supported forms:
|
|
8
|
+
// --flag boolean true (or array-marker for kind=array)
|
|
9
|
+
// --flag value string / number / enum / json / first array elem
|
|
10
|
+
// --flag=value inline value
|
|
11
|
+
// --flag a b c array kind: collect variadic until next flag
|
|
12
|
+
// --flag a --flag b array kind with repeatable: accumulates
|
|
13
|
+
// -x short flag
|
|
14
|
+
// -xyz bundled boolean shorts: -x -y -z
|
|
15
|
+
// -- end of options; remaining tokens are positional
|
|
16
|
+
// anything else positional
|
|
17
|
+
//
|
|
18
|
+
// Returns `{ options, positional, unknown, errors }`. Callers decide whether
|
|
19
|
+
// to fail on errors or treat unknown flags as forwarded pass-through.
|
|
20
|
+
|
|
21
|
+
import { OPTION_SPEC, getOption } from './spec.js';
|
|
22
|
+
|
|
23
|
+
/**
|
|
24
|
+
* @typedef {object} ParseResult
|
|
25
|
+
* @property {Record<string, unknown>} options
|
|
26
|
+
* @property {string[]} positional
|
|
27
|
+
* @property {string[]} unknown Tokens that look like flags but were not in the spec.
|
|
28
|
+
* @property {string[]} errors Human-readable error strings.
|
|
29
|
+
*/
|
|
30
|
+
|
|
31
|
+
/**
|
|
32
|
+
* @param {string[]} argv
|
|
33
|
+
* @returns {ParseResult}
|
|
34
|
+
*/
|
|
35
|
+
export function parseArgv(argv) {
|
|
36
|
+
/** @type {ParseResult} */
|
|
37
|
+
const out = { options: {}, positional: [], unknown: [], errors: [] };
|
|
38
|
+
|
|
39
|
+
// Pre-seed defaults so the validator sees them.
|
|
40
|
+
for (const spec of OPTION_SPEC) {
|
|
41
|
+
if (Object.prototype.hasOwnProperty.call(spec, 'default')) {
|
|
42
|
+
out.options[spec.name] = spec.default;
|
|
43
|
+
}
|
|
44
|
+
}
|
|
45
|
+
|
|
46
|
+
let i = 0;
|
|
47
|
+
while (i < argv.length) {
|
|
48
|
+
const tok = argv[i];
|
|
49
|
+
|
|
50
|
+
if (tok === '--') {
|
|
51
|
+
for (const rest of argv.slice(i + 1)) out.positional.push(rest);
|
|
52
|
+
break;
|
|
53
|
+
}
|
|
54
|
+
|
|
55
|
+
if (tok.startsWith('--')) {
|
|
56
|
+
// Long flag (possibly with inline =value).
|
|
57
|
+
const eq = tok.indexOf('=');
|
|
58
|
+
const name = eq === -1 ? tok.slice(2) : tok.slice(2, eq);
|
|
59
|
+
const inline = eq === -1 ? undefined : tok.slice(eq + 1);
|
|
60
|
+
const spec = getOption(name);
|
|
61
|
+
if (!spec) {
|
|
62
|
+
out.unknown.push(tok);
|
|
63
|
+
i++;
|
|
64
|
+
continue;
|
|
65
|
+
}
|
|
66
|
+
i = consumeOption(spec, argv, i, inline, out);
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
if (tok.length > 1 && tok.startsWith('-') && tok !== '-') {
|
|
71
|
+
// Short flag or bundle (e.g. -p or -pv).
|
|
72
|
+
const chars = tok.slice(1).split('');
|
|
73
|
+
// `consumedByValue` is true only if a non-boolean short flag was
|
|
74
|
+
// matched and consumeOption() already advanced `i` for us. In every
|
|
75
|
+
// other case (all booleans, all unknown, mixed unknown+boolean) we
|
|
76
|
+
// must advance i by one ourselves at the end.
|
|
77
|
+
let consumedByValue = false;
|
|
78
|
+
for (let k = 0; k < chars.length; k++) {
|
|
79
|
+
const ch = chars[k];
|
|
80
|
+
const spec = OPTION_SPEC.find((o) => o.short === ch);
|
|
81
|
+
if (!spec) {
|
|
82
|
+
out.unknown.push(`-${ch}`);
|
|
83
|
+
continue;
|
|
84
|
+
}
|
|
85
|
+
if (spec.kind !== 'boolean') {
|
|
86
|
+
// Non-boolean short. The value comes from the next argv token;
|
|
87
|
+
// bundling a non-boolean with trailing chars is rejected.
|
|
88
|
+
if (k !== chars.length - 1) {
|
|
89
|
+
out.errors.push(
|
|
90
|
+
`Short flag -${ch} requires a value and cannot be bundled with -${chars
|
|
91
|
+
.slice(k + 1)
|
|
92
|
+
.join('')}.`,
|
|
93
|
+
);
|
|
94
|
+
break;
|
|
95
|
+
}
|
|
96
|
+
i = consumeOption(spec, argv, i, undefined, out);
|
|
97
|
+
consumedByValue = true;
|
|
98
|
+
break;
|
|
99
|
+
}
|
|
100
|
+
// Boolean short: just set.
|
|
101
|
+
out.options[spec.name] = true;
|
|
102
|
+
}
|
|
103
|
+
if (!consumedByValue) i++;
|
|
104
|
+
continue;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
// Positional argument.
|
|
108
|
+
out.positional.push(tok);
|
|
109
|
+
i++;
|
|
110
|
+
}
|
|
111
|
+
|
|
112
|
+
return out;
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
/**
|
|
116
|
+
* Consume the value(s) for `spec` starting at argv index `i` (where argv[i]
|
|
117
|
+
* is the flag token itself). `inline` is the post-`=` value when present.
|
|
118
|
+
* Returns the new index to resume parsing at.
|
|
119
|
+
*
|
|
120
|
+
* @returns {number}
|
|
121
|
+
*/
|
|
122
|
+
function consumeOption(spec, argv, i, inline, out) {
|
|
123
|
+
const name = spec.name;
|
|
124
|
+
const flagToken = argv[i];
|
|
125
|
+
|
|
126
|
+
if (spec.kind === 'boolean') {
|
|
127
|
+
if (inline !== undefined) {
|
|
128
|
+
// --flag=true / --flag=false / --flag=1 / --flag=0
|
|
129
|
+
const v = inline.toLowerCase();
|
|
130
|
+
out.options[name] = v === 'true' || v === '1' || v === 'yes';
|
|
131
|
+
} else {
|
|
132
|
+
out.options[name] = true;
|
|
133
|
+
}
|
|
134
|
+
return i + 1;
|
|
135
|
+
}
|
|
136
|
+
|
|
137
|
+
if (spec.kind === 'array') {
|
|
138
|
+
/** @type {string[]} */
|
|
139
|
+
const arr = Array.isArray(out.options[name]) ? out.options[name] : [];
|
|
140
|
+
let j = i + 1;
|
|
141
|
+
if (inline !== undefined) {
|
|
142
|
+
arr.push(inline);
|
|
143
|
+
} else {
|
|
144
|
+
// Collect variadic values until the next flag-looking token.
|
|
145
|
+
while (j < argv.length && !looksLikeFlag(argv[j])) {
|
|
146
|
+
arr.push(argv[j]);
|
|
147
|
+
j++;
|
|
148
|
+
}
|
|
149
|
+
if (arr.length === 0) {
|
|
150
|
+
out.errors.push(`${flagToken} requires at least one value.`);
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
out.options[name] = arr;
|
|
154
|
+
return j;
|
|
155
|
+
}
|
|
156
|
+
|
|
157
|
+
// string / number / enum / json — consume exactly one value.
|
|
158
|
+
let raw;
|
|
159
|
+
if (inline !== undefined) {
|
|
160
|
+
raw = inline;
|
|
161
|
+
} else if (i + 1 < argv.length && !looksLikeFlag(argv[i + 1])) {
|
|
162
|
+
raw = argv[i + 1];
|
|
163
|
+
i += 1;
|
|
164
|
+
} else {
|
|
165
|
+
out.errors.push(`${flagToken} requires a value.`);
|
|
166
|
+
return i + 1;
|
|
167
|
+
}
|
|
168
|
+
|
|
169
|
+
const { value, error } = coerce(spec, raw);
|
|
170
|
+
if (error) out.errors.push(`${flagToken}: ${error}`);
|
|
171
|
+
else out.options[name] = value;
|
|
172
|
+
return i + 1;
|
|
173
|
+
}
|
|
174
|
+
|
|
175
|
+
/**
|
|
176
|
+
* @param {string} tok
|
|
177
|
+
*/
|
|
178
|
+
function looksLikeFlag(tok) {
|
|
179
|
+
if (tok === undefined) return false;
|
|
180
|
+
if (tok === '-' || tok === '--') return true;
|
|
181
|
+
return tok.startsWith('--') || /^-[A-Za-z]/.test(tok);
|
|
182
|
+
}
|
|
183
|
+
|
|
184
|
+
/**
|
|
185
|
+
* @param {object} spec
|
|
186
|
+
* @param {string} raw
|
|
187
|
+
* @returns {{ value?: unknown, error?: string }}
|
|
188
|
+
*/
|
|
189
|
+
function coerce(spec, raw) {
|
|
190
|
+
switch (spec.kind) {
|
|
191
|
+
case 'string':
|
|
192
|
+
return { value: raw };
|
|
193
|
+
case 'number': {
|
|
194
|
+
const n = Number(raw);
|
|
195
|
+
if (Number.isNaN(n)) return { error: `expected a number, got ${JSON.stringify(raw)}` };
|
|
196
|
+
return { value: n };
|
|
197
|
+
}
|
|
198
|
+
case 'enum':
|
|
199
|
+
if (!spec.choices.includes(raw)) {
|
|
200
|
+
return {
|
|
201
|
+
error: `expected one of ${spec.choices.join(', ')}, got ${JSON.stringify(raw)}`,
|
|
202
|
+
};
|
|
203
|
+
}
|
|
204
|
+
return { value: raw };
|
|
205
|
+
case 'json':
|
|
206
|
+
try {
|
|
207
|
+
return { value: JSON.parse(raw) };
|
|
208
|
+
} catch (e) {
|
|
209
|
+
return { error: `invalid JSON: ${e.message}` };
|
|
210
|
+
}
|
|
211
|
+
default:
|
|
212
|
+
return { error: `unsupported kind ${JSON.stringify(spec.kind)}` };
|
|
213
|
+
}
|
|
214
|
+
}
|