toolcraft 0.0.800 → 0.0.802
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/composition.json +2 -2
- package/dist/composition.json +2 -2
- package/dist/human-in-loop/approval-tasks.js +3 -0
- package/dist/human-in-loop/plan-hash.js +6 -1
- package/dist/runtime.d.ts +6 -2
- package/node_modules/@poe-code/safe-fs/dist/fs/devices/path.js +6 -0
- package/node_modules/@poe-code/safe-fs/dist/fs/devices/plain-path.d.ts +2 -0
- package/node_modules/@poe-code/safe-fs/dist/fs/devices/plain-path.js +3 -0
- package/node_modules/@poe-code/safe-fs/dist/fs/real/index.js +32 -2
- package/node_modules/@poe-code/xml-ast/README.md +6 -2
- package/node_modules/@poe-code/xml-ast/dist/attributes.d.ts +10 -3
- package/node_modules/@poe-code/xml-ast/dist/attributes.js +6 -6
- package/node_modules/@poe-code/xml-ast/dist/frames.d.ts +9 -5
- package/node_modules/@poe-code/xml-ast/dist/frames.js +9 -9
- package/node_modules/@poe-code/xml-ast/dist/index.d.ts +11 -0
- package/node_modules/@poe-code/xml-ast/dist/index.js +65 -29
- package/node_modules/tiny-stdio-mcp-server/dist/composition.json +1 -1
- package/node_modules/toolcraft-design/dist/explorer/detail-content.js +1 -9
- package/node_modules/toolcraft-design/dist/explorer/keymap.js +1 -1
- package/node_modules/toolcraft-design/dist/explorer/reducer.js +1 -1
- package/node_modules/toolcraft-design/dist/explorer/runtime.js +2 -1
- package/node_modules/toolcraft-design/dist/prompts/primitives/spinner.js +1 -0
- package/node_modules/toolcraft-schema/package.json +1 -1
- package/package.json +2 -2
package/composition.json
CHANGED
|
@@ -138,7 +138,7 @@
|
|
|
138
138
|
},
|
|
139
139
|
{
|
|
140
140
|
"name": "toolcraft",
|
|
141
|
-
"version": "0.0.
|
|
141
|
+
"version": "0.0.802",
|
|
142
142
|
"license": "MIT"
|
|
143
143
|
},
|
|
144
144
|
{
|
|
@@ -148,7 +148,7 @@
|
|
|
148
148
|
},
|
|
149
149
|
{
|
|
150
150
|
"name": "toolcraft-schema",
|
|
151
|
-
"version": "0.0.
|
|
151
|
+
"version": "0.0.802",
|
|
152
152
|
"license": "MIT"
|
|
153
153
|
},
|
|
154
154
|
{
|
package/dist/composition.json
CHANGED
|
@@ -138,7 +138,7 @@
|
|
|
138
138
|
},
|
|
139
139
|
{
|
|
140
140
|
"name": "toolcraft",
|
|
141
|
-
"version": "0.0.
|
|
141
|
+
"version": "0.0.802",
|
|
142
142
|
"license": "MIT"
|
|
143
143
|
},
|
|
144
144
|
{
|
|
@@ -148,7 +148,7 @@
|
|
|
148
148
|
},
|
|
149
149
|
{
|
|
150
150
|
"name": "toolcraft-schema",
|
|
151
|
-
"version": "0.0.
|
|
151
|
+
"version": "0.0.802",
|
|
152
152
|
"license": "MIT"
|
|
153
153
|
},
|
|
154
154
|
{
|
|
@@ -136,6 +136,9 @@ function getTaskListDirectory(taskList) {
|
|
|
136
136
|
return isTaskListConfig(taskList) ? taskList.dir : "unknown";
|
|
137
137
|
}
|
|
138
138
|
function isDeepEqualStateMachine(left, right) {
|
|
139
|
+
if (left.initial !== right.initial) {
|
|
140
|
+
return false;
|
|
141
|
+
}
|
|
139
142
|
if (!areEqualStrings(left.states, right.states)) {
|
|
140
143
|
return false;
|
|
141
144
|
}
|
|
@@ -44,7 +44,12 @@ function normalizePlan(value, seen) {
|
|
|
44
44
|
}
|
|
45
45
|
const normalized = {};
|
|
46
46
|
for (const key of Object.keys(value).sort()) {
|
|
47
|
-
normalized
|
|
47
|
+
Object.defineProperty(normalized, key, {
|
|
48
|
+
value: normalizePlan(value[key], seen),
|
|
49
|
+
enumerable: true,
|
|
50
|
+
writable: true,
|
|
51
|
+
configurable: true
|
|
52
|
+
});
|
|
48
53
|
}
|
|
49
54
|
return normalized;
|
|
50
55
|
}
|
package/dist/runtime.d.ts
CHANGED
|
@@ -227,10 +227,14 @@ export interface CommandRequirementOptions {
|
|
|
227
227
|
}
|
|
228
228
|
export declare function resolveCommandSecrets(command: Command<any, any, any, any>, env?: Record<string, string | undefined>): Record<string, string | undefined>;
|
|
229
229
|
export declare function assertCommandRequirements(command: Command<any, any, any, any>, context: GroupCheckContext<any>, options?: CommandRequirementOptions): Promise<void>;
|
|
230
|
-
export declare function defineCommand<TServices extends object = EmptyServices, TName extends string = string, TParamsSchema extends ObjectSchema<any> = AnyObjectSchema, TSecrets extends SecretDeclarations | undefined = undefined, TResult = unknown, TOwnScope extends ScopeInput = undefined, TOwnHumanInLoop extends
|
|
230
|
+
export declare function defineCommand<TServices extends object = EmptyServices, TName extends string = string, TParamsSchema extends ObjectSchema<any> = AnyObjectSchema, TSecrets extends SecretDeclarations | undefined = undefined, TResult = unknown, TOwnScope extends ScopeInput = undefined, TOwnHumanInLoop extends {
|
|
231
|
+
mode: HumanInLoopMode;
|
|
232
|
+
} | null | undefined = undefined>(config: Omit<CommandConfig<TServices, TParamsSchema, TSecrets, TResult>, "name" | "scope" | "humanInLoop"> & {
|
|
231
233
|
name: TName;
|
|
232
234
|
scope?: TOwnScope;
|
|
233
|
-
humanInLoop?: TOwnHumanInLoop
|
|
235
|
+
humanInLoop?: (TOwnHumanInLoop | {
|
|
236
|
+
[K in keyof TOwnHumanInLoop]: TOwnHumanInLoop[K];
|
|
237
|
+
}) & (HumanInLoopConfig<TParamsSchema> | null);
|
|
234
238
|
}): Command<TServices, TParamsSchema, TSecrets, TResult> & TypedCommandMetadata<TName, TParamsSchema, TResult, TOwnScope, ResolveOwnHumanInLoopMode<TOwnHumanInLoop>>;
|
|
235
239
|
export declare function defineStreamCommand<TServices extends object = EmptyServices, TName extends string = string, TParamsSchema extends ObjectSchema<any> = AnyObjectSchema, TSecrets extends SecretDeclarations | undefined = undefined, TEventSchema extends AnySchema = AnySchema, TOwnScope extends ScopeInput = undefined>(config: Omit<StreamCommandConfig<TServices, TParamsSchema, TSecrets, TEventSchema>, "name" | "scope"> & {
|
|
236
240
|
name: TName;
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { plainDevicePathResolvers } from "./plain-path.js";
|
|
1
2
|
import { FsError, isFsError } from "../../contracts/errors.js";
|
|
2
3
|
import { pathByteLength, validatePath } from "../../contracts/virtual-path.js";
|
|
3
4
|
import { capturePathNamespace, pathNamespace } from "../path-namespace.js";
|
|
@@ -146,6 +147,11 @@ export async function resolveDevicePath(filesystem, path, options, followFinal =
|
|
|
146
147
|
const fast = tryResolveMemoryDevicePath(filesystem, path, resizeCreate);
|
|
147
148
|
if (fast !== undefined)
|
|
148
149
|
return fast;
|
|
150
|
+
if (followFinal && resizeCreate === undefined && traversal === undefined && isCleanAbsolutePath(path) && path !== "/" && path !== "/dev" && !path.startsWith("/dev/")) {
|
|
151
|
+
const resolved = await plainDevicePathResolvers.get(filesystem)?.(path, options);
|
|
152
|
+
if (resolved !== undefined)
|
|
153
|
+
return resolved;
|
|
154
|
+
}
|
|
149
155
|
}
|
|
150
156
|
const namespace = capturePathNamespace(filesystem, options);
|
|
151
157
|
if (resizeCreate !== undefined)
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { plainDevicePathResolvers } from "../devices/plain-path.js";
|
|
1
2
|
import { platform } from "#safe-fs-platform";
|
|
2
3
|
import { snapshotStagingCreation } from "../staging-cleanup.js";
|
|
3
4
|
import { snapshotConditionalChmod } from "../conditional-chmod.js";
|
|
@@ -121,6 +122,30 @@ export class RealFileSystem {
|
|
|
121
122
|
throw new FsError("ENOTSUP", { syscall: "root", message: "this backend requires a POSIX host" });
|
|
122
123
|
}
|
|
123
124
|
this.configuredRoot = root;
|
|
125
|
+
if (Object.getPrototypeOf(this) === RealFileSystem.prototype) {
|
|
126
|
+
plainDevicePathResolvers.set(this, async (path, options) => {
|
|
127
|
+
if (this.lstat !== realImplementation.lstat?.value || this.readlink !== realImplementation.readlink?.value)
|
|
128
|
+
return undefined;
|
|
129
|
+
try {
|
|
130
|
+
let target = await this.root(options);
|
|
131
|
+
const components = path.slice(1).split("/");
|
|
132
|
+
for (let index = 0; index < components.length; index++) {
|
|
133
|
+
options.signal?.throwIfAborted();
|
|
134
|
+
target = join(target, components[index]);
|
|
135
|
+
const stat = await native.lstat(target);
|
|
136
|
+
options.signal?.throwIfAborted();
|
|
137
|
+
if ((!stat.isFile() && !stat.isDirectory()) || (index < components.length - 1 && !stat.isDirectory()))
|
|
138
|
+
return undefined;
|
|
139
|
+
}
|
|
140
|
+
return path;
|
|
141
|
+
}
|
|
142
|
+
catch {
|
|
143
|
+
options.signal?.throwIfAborted();
|
|
144
|
+
// Missing entries, symlinks and other failures use generic routing.
|
|
145
|
+
return undefined;
|
|
146
|
+
}
|
|
147
|
+
});
|
|
148
|
+
}
|
|
124
149
|
this.renameNoReplace = typeof options === "string" ? undefined : options.renameNoReplace;
|
|
125
150
|
if (this.renameNoReplace !== undefined) {
|
|
126
151
|
if (!platform.nativeFileSystem.atomicRename)
|
|
@@ -140,10 +165,15 @@ export class RealFileSystem {
|
|
|
140
165
|
})();
|
|
141
166
|
const root = await this.rootPromise;
|
|
142
167
|
options.signal?.throwIfAborted();
|
|
143
|
-
|
|
168
|
+
const [canonical, metadata] = await Promise.allSettled([native.realpath(root), native.stat(root)]);
|
|
169
|
+
if (canonical.status === "rejected")
|
|
170
|
+
throw canonical.reason;
|
|
171
|
+
if (canonical.value !== root)
|
|
144
172
|
throw new FsError("EACCES");
|
|
145
173
|
options.signal?.throwIfAborted();
|
|
146
|
-
if (
|
|
174
|
+
if (metadata.status === "rejected")
|
|
175
|
+
throw metadata.reason;
|
|
176
|
+
if (!metadata.value.isDirectory())
|
|
147
177
|
throw new FsError("ENOTDIR");
|
|
148
178
|
options.signal?.throwIfAborted();
|
|
149
179
|
return root;
|
|
@@ -131,5 +131,9 @@ processing-instruction targets through source windows. Their events have an empt
|
|
|
131
131
|
`target` and a `targetSource` span; replay that span before retiring the source.
|
|
132
132
|
All body continuations carry the same target span. Short targets remain strings.
|
|
133
133
|
The stored document engine transfers these spans to its own token store and
|
|
134
|
-
streams targets during output.
|
|
135
|
-
|
|
134
|
+
streams targets during output. With `deferElementNames: true` and `retainTree: false`, long element local names
|
|
135
|
+
also use `nameSource`/`localNameSource` spans. Closing tags compare source windows;
|
|
136
|
+
element events retain the short `prefix` separately. Stored documents copy these
|
|
137
|
+
names into token references for formatting, XPath and xq grouping. Attribute names
|
|
138
|
+
and namespace prefixes longer than 512 UTF-16 units still retain their token cost;
|
|
139
|
+
this option does not impose a name-length limit.
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import type { XmlSourceSpan } from "./source.js";
|
|
1
2
|
import type { XmlNamespaceScope } from "./frames.js";
|
|
2
3
|
export interface XmlAttributeRecord {
|
|
3
4
|
name: string;
|
|
@@ -5,6 +6,9 @@ export interface XmlAttributeRecord {
|
|
|
5
6
|
localName: string;
|
|
6
7
|
value: string;
|
|
7
8
|
next: number;
|
|
9
|
+
nameSource?: XmlSourceSpan;
|
|
10
|
+
localNameSource?: XmlSourceSpan;
|
|
11
|
+
prefixSource?: XmlSourceSpan;
|
|
8
12
|
source?: {
|
|
9
13
|
start: number;
|
|
10
14
|
end: number;
|
|
@@ -20,10 +24,12 @@ export type XmlAttributeRequest = {
|
|
|
20
24
|
attributeOperation: 'has' | 'expanded';
|
|
21
25
|
state: XmlAttributeState;
|
|
22
26
|
name: string;
|
|
27
|
+
nameSource?: XmlSourceSpan;
|
|
23
28
|
found?: boolean;
|
|
24
29
|
namespace?: {
|
|
25
30
|
scope: XmlNamespaceScope;
|
|
26
31
|
prefix: string;
|
|
32
|
+
prefixSource?: XmlSourceSpan;
|
|
27
33
|
};
|
|
28
34
|
} | {
|
|
29
35
|
attributeOperation: 'append';
|
|
@@ -49,14 +55,15 @@ export declare class XmlAttributes {
|
|
|
49
55
|
get length(): number;
|
|
50
56
|
get size(): number;
|
|
51
57
|
get first(): number;
|
|
52
|
-
has(name: string): Generator<XmlAttributeRequest, boolean, void>;
|
|
58
|
+
has(name: string, nameSource?: XmlSourceSpan): Generator<XmlAttributeRequest, boolean, void>;
|
|
53
59
|
append(name: string, prefix: string, localName: string, value: string, source?: {
|
|
54
60
|
start: number;
|
|
55
61
|
end: number;
|
|
56
|
-
}): Generator<XmlAttributeRequest, void, void>;
|
|
62
|
+
}, nameSource?: XmlSourceSpan, localNameSource?: XmlSourceSpan, prefixSource?: XmlSourceSpan): Generator<XmlAttributeRequest, void, void>;
|
|
57
63
|
read(reference: number, values: boolean): Generator<XmlAttributeRequest, XmlAttributeRecord, void>;
|
|
58
64
|
expanded(name: string, namespace?: {
|
|
59
65
|
scope: XmlNamespaceScope;
|
|
60
66
|
prefix: string;
|
|
61
|
-
|
|
67
|
+
prefixSource?: XmlSourceSpan;
|
|
68
|
+
}, nameSource?: XmlSourceSpan): Generator<XmlAttributeRequest, boolean, void>;
|
|
62
69
|
}
|
|
@@ -12,25 +12,25 @@ export class XmlAttributes {
|
|
|
12
12
|
get length() { return this.state.length; }
|
|
13
13
|
get size() { return this.state.size; }
|
|
14
14
|
get first() { return this.state.first; }
|
|
15
|
-
*has(name) {
|
|
15
|
+
*has(name, nameSource) {
|
|
16
16
|
if (!this.length)
|
|
17
17
|
return false;
|
|
18
18
|
if (!this.external)
|
|
19
19
|
return this.names.has(name);
|
|
20
|
-
const request = { attributeOperation: 'has', state: this.state, name };
|
|
20
|
+
const request = { attributeOperation: 'has', state: this.state, name, ...(nameSource ? { nameSource } : {}) };
|
|
21
21
|
yield request;
|
|
22
22
|
if (request.found === undefined)
|
|
23
23
|
throw new TypeError('Incomplete XML attribute lookup');
|
|
24
24
|
return request.found;
|
|
25
25
|
}
|
|
26
|
-
*append(name, prefix, localName, value, source) {
|
|
26
|
+
*append(name, prefix, localName, value, source, nameSource, localNameSource, prefixSource) {
|
|
27
27
|
if (!this.external) {
|
|
28
28
|
this.names.set(name, value);
|
|
29
29
|
this.records.push({ name, prefix, localName });
|
|
30
30
|
this.state = { reference: 0, first: 1, length: this.records.length, size: this.names.size };
|
|
31
31
|
return;
|
|
32
32
|
}
|
|
33
|
-
const request = { attributeOperation: 'append', state: this.state, attribute: { name, prefix, localName, value, ...(source ? { source } : {}) } };
|
|
33
|
+
const request = { attributeOperation: 'append', state: this.state, attribute: { name, prefix, localName, value, ...(source ? { source } : {}), ...(nameSource ? { nameSource } : {}), ...(localNameSource ? { localNameSource } : {}), ...(prefixSource ? { prefixSource } : {}) } };
|
|
34
34
|
yield request;
|
|
35
35
|
if (!request.result)
|
|
36
36
|
throw new TypeError('Incomplete XML attribute append');
|
|
@@ -47,13 +47,13 @@ export class XmlAttributes {
|
|
|
47
47
|
throw new TypeError('Incomplete XML attribute read');
|
|
48
48
|
return request.result;
|
|
49
49
|
}
|
|
50
|
-
*expanded(name, namespace) {
|
|
50
|
+
*expanded(name, namespace, nameSource) {
|
|
51
51
|
if (!this.external) {
|
|
52
52
|
const found = this.expandedNames.has(name);
|
|
53
53
|
this.expandedNames.add(name);
|
|
54
54
|
return found;
|
|
55
55
|
}
|
|
56
|
-
const request = { attributeOperation: 'expanded', state: this.state, name, ...(namespace ? { namespace } : {}) };
|
|
56
|
+
const request = { attributeOperation: 'expanded', state: this.state, name, ...(namespace ? { namespace } : {}), ...(nameSource ? { nameSource } : {}) };
|
|
57
57
|
yield request;
|
|
58
58
|
if (request.found === undefined)
|
|
59
59
|
throw new TypeError('Incomplete XML expanded attribute lookup');
|
|
@@ -1,4 +1,4 @@
|
|
|
1
|
-
import type { XmlSourceStep } from './source.js';
|
|
1
|
+
import type { XmlSourceStep, XmlSourceSpan } from './source.js';
|
|
2
2
|
import type { XmlContent, XmlElement, XmlName } from './index.js';
|
|
3
3
|
export interface XmlParserFrame {
|
|
4
4
|
element: XmlElement;
|
|
@@ -37,27 +37,31 @@ export type XmlNamespaceRequest = {
|
|
|
37
37
|
readonly namespaceOperation: 'reference';
|
|
38
38
|
readonly scope: XmlNamespaceScope;
|
|
39
39
|
readonly prefix: string;
|
|
40
|
+
readonly prefixSource?: XmlSourceSpan;
|
|
40
41
|
reference?: number;
|
|
41
42
|
complete?: true;
|
|
42
43
|
} | {
|
|
43
44
|
readonly namespaceOperation: 'has';
|
|
44
45
|
readonly scope: XmlNamespaceScope;
|
|
45
46
|
readonly prefix: string;
|
|
47
|
+
readonly prefixSource?: XmlSourceSpan;
|
|
46
48
|
found?: boolean;
|
|
47
49
|
} | {
|
|
48
50
|
readonly namespaceOperation: 'get';
|
|
49
51
|
readonly scope: XmlNamespaceScope;
|
|
50
52
|
readonly prefix: string;
|
|
53
|
+
readonly prefixSource?: XmlSourceSpan;
|
|
51
54
|
value?: string;
|
|
52
55
|
complete?: true;
|
|
53
56
|
} | {
|
|
54
57
|
readonly namespaceOperation: 'set';
|
|
55
58
|
readonly scope: XmlNamespaceScope;
|
|
56
59
|
readonly prefix: string;
|
|
60
|
+
readonly prefixSource?: XmlSourceSpan;
|
|
57
61
|
readonly value: string | Generator<XmlSourceStep | string, void, void>;
|
|
58
62
|
result?: XmlNamespaceScope;
|
|
59
63
|
};
|
|
60
|
-
export declare function namespaceValue(scope: Map<string, string> | XmlNamespaceScope, prefix: string): Generator<XmlNamespaceRequest, string | undefined, void>;
|
|
61
|
-
export declare function namespaceMetadata(scope: Map<string, string> | XmlNamespaceScope, prefix: string, deferred?: boolean): Generator<XmlNamespaceRequest, Pick<XmlName, 'namespace' | 'namespaceReference'>, void>;
|
|
62
|
-
export declare function hasNamespace(scope: Map<string, string> | XmlNamespaceScope, prefix: string): Generator<XmlNamespaceRequest, boolean, void>;
|
|
63
|
-
export declare function bindNamespace(scope: Map<string, string> | XmlNamespaceScope, prefix: string, value: string | Generator<XmlSourceStep | string, void, void
|
|
64
|
+
export declare function namespaceValue(scope: Map<string, string> | XmlNamespaceScope, prefix: string, prefixSource?: XmlSourceSpan): Generator<XmlNamespaceRequest, string | undefined, void>;
|
|
65
|
+
export declare function namespaceMetadata(scope: Map<string, string> | XmlNamespaceScope, prefix: string, deferred?: boolean, prefixSource?: XmlSourceSpan): Generator<XmlNamespaceRequest, Pick<XmlName, 'namespace' | 'namespaceReference'>, void>;
|
|
66
|
+
export declare function hasNamespace(scope: Map<string, string> | XmlNamespaceScope, prefix: string, prefixSource?: XmlSourceSpan): Generator<XmlNamespaceRequest, boolean, void>;
|
|
67
|
+
export declare function bindNamespace(scope: Map<string, string> | XmlNamespaceScope, prefix: string, value: string | Generator<XmlSourceStep | string, void, void>, prefixSource?: XmlSourceSpan): Generator<XmlNamespaceRequest, Map<string, string> | XmlNamespaceScope, void>;
|
|
@@ -43,43 +43,43 @@ export class XmlFrames {
|
|
|
43
43
|
return frame;
|
|
44
44
|
}
|
|
45
45
|
}
|
|
46
|
-
export function* namespaceValue(scope, prefix) {
|
|
46
|
+
export function* namespaceValue(scope, prefix, prefixSource) {
|
|
47
47
|
if (scope instanceof Map)
|
|
48
48
|
return scope.get(prefix);
|
|
49
|
-
const request = { namespaceOperation: 'get', scope, prefix };
|
|
49
|
+
const request = { namespaceOperation: 'get', scope, prefix, ...(prefixSource ? { prefixSource } : {}) };
|
|
50
50
|
yield request;
|
|
51
51
|
if (!request.complete)
|
|
52
52
|
throw new TypeError('Incomplete XML namespace read');
|
|
53
53
|
return request.value;
|
|
54
54
|
}
|
|
55
|
-
export function* namespaceMetadata(scope, prefix, deferred = false) {
|
|
55
|
+
export function* namespaceMetadata(scope, prefix, deferred = false, prefixSource) {
|
|
56
56
|
if (!deferred || scope instanceof Map)
|
|
57
|
-
return { namespace: (yield* namespaceValue(scope, prefix)) ?? '' };
|
|
57
|
+
return { namespace: (yield* namespaceValue(scope, prefix, prefixSource)) ?? '' };
|
|
58
58
|
if (prefix === 'xml')
|
|
59
59
|
return { namespace: 'http://www.w3.org/XML/1998/namespace' };
|
|
60
|
-
const request = { namespaceOperation: 'reference', scope, prefix };
|
|
60
|
+
const request = { namespaceOperation: 'reference', scope, prefix, ...(prefixSource ? { prefixSource } : {}) };
|
|
61
61
|
yield request;
|
|
62
62
|
if (!request.complete)
|
|
63
63
|
throw new TypeError('Incomplete XML namespace reference lookup');
|
|
64
64
|
return { namespace: '', ...(request.reference === undefined ? {} : { namespaceReference: request.reference }) };
|
|
65
65
|
}
|
|
66
|
-
export function* hasNamespace(scope, prefix) {
|
|
66
|
+
export function* hasNamespace(scope, prefix, prefixSource) {
|
|
67
67
|
if (scope instanceof Map)
|
|
68
68
|
return scope.has(prefix);
|
|
69
|
-
const request = { namespaceOperation: 'has', scope, prefix };
|
|
69
|
+
const request = { namespaceOperation: 'has', scope, prefix, ...(prefixSource ? { prefixSource } : {}) };
|
|
70
70
|
yield request;
|
|
71
71
|
if (request.found === undefined)
|
|
72
72
|
throw new TypeError('Incomplete XML namespace membership lookup');
|
|
73
73
|
return request.found;
|
|
74
74
|
}
|
|
75
|
-
export function* bindNamespace(scope, prefix, value) {
|
|
75
|
+
export function* bindNamespace(scope, prefix, value, prefixSource) {
|
|
76
76
|
if (scope instanceof Map) {
|
|
77
77
|
if (typeof value !== 'string')
|
|
78
78
|
throw new TypeError('Streamed XML namespace values require external scopes');
|
|
79
79
|
scope.set(prefix, value);
|
|
80
80
|
return scope;
|
|
81
81
|
}
|
|
82
|
-
const request = { namespaceOperation: 'set', scope, prefix, value };
|
|
82
|
+
const request = { namespaceOperation: 'set', scope, prefix, value, ...(prefixSource ? { prefixSource } : {}) };
|
|
83
83
|
yield request;
|
|
84
84
|
if (!request.result)
|
|
85
85
|
throw new TypeError('Incomplete XML namespace update');
|
|
@@ -9,6 +9,13 @@ import type { XmlStreamEvent } from "./stream.js";
|
|
|
9
9
|
export { XmlLimitError } from "./errors.js";
|
|
10
10
|
export interface XmlName {
|
|
11
11
|
readonly name: string;
|
|
12
|
+
readonly nameSource?: XmlSourceSpan;
|
|
13
|
+
readonly nameReference?: number;
|
|
14
|
+
readonly localNameSource?: XmlSourceSpan;
|
|
15
|
+
readonly localNameReference?: number;
|
|
16
|
+
readonly prefix?: string;
|
|
17
|
+
readonly prefixSource?: XmlSourceSpan;
|
|
18
|
+
readonly prefixReference?: number;
|
|
12
19
|
readonly namespace: string;
|
|
13
20
|
readonly namespaceReference?: number;
|
|
14
21
|
readonly localName: string;
|
|
@@ -72,6 +79,10 @@ export interface XmlSourceLimits extends XmlStepLimits {
|
|
|
72
79
|
readonly deferNamespaces?: boolean;
|
|
73
80
|
/** Emit long processing-instruction targets as source spans. Requires fragmentContent. */
|
|
74
81
|
readonly deferContentNames?: boolean;
|
|
82
|
+
/** Defer long element names and, with external namespaces, their prefixes. */
|
|
83
|
+
readonly deferElementNames?: boolean;
|
|
84
|
+
/** Defer attribute names and namespace declaration prefixes to source spans. */
|
|
85
|
+
readonly deferAttributeNames?: boolean;
|
|
75
86
|
/** Store attribute collections through host requests and emit resolved attributes individually. */
|
|
76
87
|
readonly storeAttributes?: boolean;
|
|
77
88
|
readonly fragmentAttributes?: boolean;
|
|
@@ -70,7 +70,7 @@ function qualifiedNameSync(name, cache) {
|
|
|
70
70
|
}
|
|
71
71
|
/** Validate a name span without retaining its spelling. */
|
|
72
72
|
function* validateNameSpan(source, start, end) {
|
|
73
|
-
let first = true, colon =
|
|
73
|
+
let first = true, colon = -1, work = 0;
|
|
74
74
|
for (let offset = start; offset < end;) {
|
|
75
75
|
let point = yield* source.charCodeAt(offset);
|
|
76
76
|
if (point >= 0xd800 && point <= 0xdbff && offset + 1 < end) {
|
|
@@ -79,9 +79,9 @@ function* validateNameSpan(source, start, end) {
|
|
|
79
79
|
point = 0x10000 + (point - 0xd800) * 1024 + low - 0xdc00;
|
|
80
80
|
}
|
|
81
81
|
if (point === 58) {
|
|
82
|
-
if (colon || first)
|
|
82
|
+
if (colon >= 0 || first)
|
|
83
83
|
invalid("invalid qualified name");
|
|
84
|
-
colon =
|
|
84
|
+
colon = offset;
|
|
85
85
|
first = true;
|
|
86
86
|
}
|
|
87
87
|
else {
|
|
@@ -101,6 +101,7 @@ function* validateNameSpan(source, start, end) {
|
|
|
101
101
|
invalid("invalid qualified name");
|
|
102
102
|
if (work)
|
|
103
103
|
yield work;
|
|
104
|
+
return colon;
|
|
104
105
|
}
|
|
105
106
|
function* entity(source, start, end, recover) {
|
|
106
107
|
// Inspect only a bounded prefix, even for arbitrarily long numeric references.
|
|
@@ -294,6 +295,10 @@ function validateLimits(limits) {
|
|
|
294
295
|
}
|
|
295
296
|
export function* parseXmlSourceSteps(length, limits = {}) {
|
|
296
297
|
validateLimits(limits);
|
|
298
|
+
if (limits.deferAttributeNames && (!limits.storeAttributes || !limits.storeNamespaces))
|
|
299
|
+
throw new TypeError("Deferred attribute names require stored attributes and namespaces");
|
|
300
|
+
if (limits.deferElementNames && limits.retainTree !== false)
|
|
301
|
+
throw new TypeError("Deferred element names require retainTree: false");
|
|
297
302
|
if (limits.deferContentNames && !limits.fragmentContent)
|
|
298
303
|
throw new TypeError("Deferred XML content names require fragmentContent: true");
|
|
299
304
|
if (limits.fragmentAttributes && !limits.storeAttributes)
|
|
@@ -360,7 +365,24 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
360
365
|
}
|
|
361
366
|
return offset - start;
|
|
362
367
|
};
|
|
363
|
-
const
|
|
368
|
+
const sameName = function* (left, right, span) {
|
|
369
|
+
if (!left.nameSource && !span)
|
|
370
|
+
return left.name === right;
|
|
371
|
+
const leftLength = left.nameSource ? left.nameSource.end - left.nameSource.start : left.name.length;
|
|
372
|
+
const rightLength = span ? span.end - span.start : right.length;
|
|
373
|
+
if (leftLength !== rightLength)
|
|
374
|
+
return false;
|
|
375
|
+
for (let index = 0; index < leftLength; index += 512) {
|
|
376
|
+
const end = Math.min(leftLength, index + 512);
|
|
377
|
+
const a = left.nameSource ? yield* source.slice(left.nameSource.start + index, left.nameSource.start + end) : left.name.slice(index, end);
|
|
378
|
+
const b = span ? yield* source.slice(span.start + index, span.start + end) : right.slice(index, end);
|
|
379
|
+
yield end - index;
|
|
380
|
+
if (a !== b)
|
|
381
|
+
return false;
|
|
382
|
+
}
|
|
383
|
+
return true;
|
|
384
|
+
};
|
|
385
|
+
const scanName = function* (defer) {
|
|
364
386
|
const start = offset;
|
|
365
387
|
while (yield* source.has(offset)) {
|
|
366
388
|
const c = (yield* source.charCodeAt(offset));
|
|
@@ -374,8 +396,19 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
374
396
|
}
|
|
375
397
|
}
|
|
376
398
|
if (defer && offset - start > 512) {
|
|
377
|
-
yield* validateNameSpan(source, start, offset);
|
|
378
|
-
|
|
399
|
+
const colon = yield* validateNameSpan(source, start, offset);
|
|
400
|
+
if (defer === "content")
|
|
401
|
+
return ["", "", "", { start, end: offset }];
|
|
402
|
+
if (colon - start > 512 && !limits.storeNamespaces) {
|
|
403
|
+
const name = yield* source.slice(start, offset);
|
|
404
|
+
return [name, name.slice(0, colon - start), name.slice(colon - start + 1)];
|
|
405
|
+
}
|
|
406
|
+
const localStart = colon < 0 ? start : colon + 1;
|
|
407
|
+
const prefixSource = colon - start > 512 ? { start, end: colon } : undefined;
|
|
408
|
+
const prefix = colon < 0 || prefixSource ? "" : yield* source.slice(start, colon);
|
|
409
|
+
const localNameSource = offset - localStart > 512 ? { start: localStart, end: offset } : undefined;
|
|
410
|
+
const local = localNameSource ? "" : yield* source.slice(localStart, offset);
|
|
411
|
+
return ["", prefix, local, { start, end: offset }, localNameSource, prefixSource];
|
|
379
412
|
}
|
|
380
413
|
const name = (yield* source.slice(start, offset));
|
|
381
414
|
pendingWork += offset - start;
|
|
@@ -536,7 +569,7 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
536
569
|
else if ((yield* source.startsWith("<?", offset))) {
|
|
537
570
|
const start = offset;
|
|
538
571
|
offset += 2;
|
|
539
|
-
const [target, , , targetSource] = yield* scanName(limits.deferContentNames);
|
|
572
|
+
const [target, , , targetSource] = yield* scanName(limits.deferContentNames ? "content" : undefined);
|
|
540
573
|
while (pendingWork >= 512) {
|
|
541
574
|
yield 512;
|
|
542
575
|
pendingWork -= 512;
|
|
@@ -578,14 +611,14 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
578
611
|
}
|
|
579
612
|
else if ((yield* source.charCodeAt(offset + 1)) === 47) {
|
|
580
613
|
offset += 2;
|
|
581
|
-
const [name] = yield* scanName();
|
|
614
|
+
const [name, , , nameSource] = yield* scanName(limits.deferElementNames ? "element" : undefined);
|
|
582
615
|
yield* skipWhitespace();
|
|
583
616
|
while (pendingWork >= 512) {
|
|
584
617
|
yield 512;
|
|
585
618
|
pendingWork -= 512;
|
|
586
619
|
}
|
|
587
620
|
const closed = (yield* source.slice(offset++, offset)) === ">" ? (yield* stack.pop()) : undefined;
|
|
588
|
-
if (closed
|
|
621
|
+
if (!closed || !(yield* sameName(closed.element, name, nameSource))) {
|
|
589
622
|
if (!limits.recover)
|
|
590
623
|
invalid("mismatched closing tag");
|
|
591
624
|
limits.recover("mismatched closing tag");
|
|
@@ -596,9 +629,9 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
596
629
|
else {
|
|
597
630
|
offset++;
|
|
598
631
|
const repeated = previousEmpty && (yield* source.startsWith(previousEmpty.suffix, offset)) ? previousEmpty : undefined;
|
|
599
|
-
const [name, prefix, localName] = repeated
|
|
632
|
+
const [name, prefix, localName, nameSource, localNameSource, prefixSource] = repeated
|
|
600
633
|
? [repeated.name, repeated.prefix, repeated.localName]
|
|
601
|
-
: (yield* scanName());
|
|
634
|
+
: (yield* scanName(limits.deferElementNames ? "element" : undefined));
|
|
602
635
|
if (repeated)
|
|
603
636
|
offset += name.length;
|
|
604
637
|
// Preserve scan/validation work while reusing the admitted spelling.
|
|
@@ -623,12 +656,12 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
623
656
|
break;
|
|
624
657
|
if (ws === 0)
|
|
625
658
|
invalid("attributes require whitespace");
|
|
626
|
-
const [attribute, attrPrefix, attrLocal] = yield* scanName();
|
|
659
|
+
const [attribute, attrPrefix, attrLocal, nameSource, localNameSource, attrPrefixSource] = yield* scanName(limits.deferAttributeNames ? "attribute" : undefined);
|
|
627
660
|
while (pendingWork >= 512) {
|
|
628
661
|
yield 512;
|
|
629
662
|
pendingWork -= 512;
|
|
630
663
|
}
|
|
631
|
-
if ((yield* attributes.has(attribute)))
|
|
664
|
+
if ((yield* attributes.has(attribute, nameSource)))
|
|
632
665
|
invalid("duplicate attribute");
|
|
633
666
|
if (++attributeCount > maxAttributes)
|
|
634
667
|
throw new XmlLimitError("maxAttributes", "XML attribute limit exceeded");
|
|
@@ -693,13 +726,14 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
693
726
|
}
|
|
694
727
|
admitText(value);
|
|
695
728
|
}
|
|
696
|
-
yield* attributes.append(attribute, attrPrefix, attrLocal, value, limits.fragmentAttributes ? { start: offset, end } : undefined);
|
|
729
|
+
yield* attributes.append(attribute, attrPrefix, attrLocal, value, limits.fragmentAttributes ? { start: offset, end } : undefined, nameSource, localNameSource, attrPrefixSource);
|
|
697
730
|
offset = end + 1;
|
|
698
|
-
if (attribute === "xmlns" ||
|
|
699
|
-
const nsPrefix = attribute === "xmlns" ? "" :
|
|
731
|
+
if (attribute === "xmlns" || attrPrefix === "xmlns") {
|
|
732
|
+
const nsPrefix = attribute === "xmlns" ? "" : attrLocal;
|
|
733
|
+
const nsPrefixSource = attrPrefix === "xmlns" ? localNameSource : undefined;
|
|
700
734
|
if (nsPrefix === "xmlns" || (fragmented ? matchesXmlns : value === xmlnsNamespace)
|
|
701
735
|
|| (nsPrefix === "xml") !== (fragmented ? matchesXml : value === xmlNamespace)
|
|
702
|
-
|| (nsPrefix !== "" && (fragmented ? size === 0 : value === "")))
|
|
736
|
+
|| ((nsPrefix !== "" || nsPrefixSource) && (fragmented ? size === 0 : value === "")))
|
|
703
737
|
invalid("invalid namespace binding");
|
|
704
738
|
if (!ownsNamespaces && namespaces instanceof Map) {
|
|
705
739
|
const copy = new Map();
|
|
@@ -711,7 +745,7 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
711
745
|
ownsNamespaces = true;
|
|
712
746
|
}
|
|
713
747
|
namespaces = yield* bindNamespace(namespaces, nsPrefix, fragmented
|
|
714
|
-
? textFragments(source, valueStart, end, true, limits.recover ? () => { } : undefined, true) : value);
|
|
748
|
+
? textFragments(source, valueStart, end, true, limits.recover ? () => { } : undefined, true) : value, nsPrefixSource);
|
|
715
749
|
if (namespaces.size > maxNamespaces)
|
|
716
750
|
throw new XmlLimitError("maxNamespaces", "XML namespace scope limit exceeded");
|
|
717
751
|
}
|
|
@@ -721,15 +755,15 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
721
755
|
const record = yield* attributes.read(cursor, false);
|
|
722
756
|
cursor = record.next;
|
|
723
757
|
const { name: attribute, prefix: attrPrefix, localName: attrLocal } = record;
|
|
724
|
-
if (attribute === "xmlns" ||
|
|
758
|
+
if (attribute === "xmlns" || attrPrefix === "xmlns")
|
|
725
759
|
continue;
|
|
726
760
|
pendingWork += attribute.length;
|
|
727
|
-
if (attrPrefix && !(yield* hasNamespace(namespaces, attrPrefix)))
|
|
761
|
+
if ((attrPrefix || record.prefixSource) && !(yield* hasNamespace(namespaces, attrPrefix, record.prefixSource)))
|
|
728
762
|
invalid("unbound attribute prefix");
|
|
729
763
|
if (attributes.length > 1) {
|
|
730
764
|
const backed = limits.storeAttributes && !(namespaces instanceof Map) ? namespaces : undefined;
|
|
731
765
|
const key = backed ? attrLocal : `${attrPrefix ? (yield* namespaceValue(namespaces, attrPrefix)) : ""}\0${attrLocal}`;
|
|
732
|
-
if (yield* attributes.expanded(key, backed ? { scope: backed, prefix: attrPrefix } : undefined))
|
|
766
|
+
if (yield* attributes.expanded(key, backed ? { scope: backed, prefix: attrPrefix, ...(record.prefixSource ? { prefixSource: record.prefixSource } : {}) } : undefined, record.localNameSource))
|
|
733
767
|
invalid("duplicate expanded attribute");
|
|
734
768
|
}
|
|
735
769
|
}
|
|
@@ -739,14 +773,15 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
739
773
|
yield 512;
|
|
740
774
|
pendingWork -= 512;
|
|
741
775
|
}
|
|
742
|
-
if (prefix === "xmlns" || (prefix && !(yield* hasNamespace(namespaces, prefix))))
|
|
776
|
+
if (prefix === "xmlns" || ((prefix || prefixSource) && !(yield* hasNamespace(namespaces, prefix, prefixSource))))
|
|
743
777
|
invalid("unbound element prefix");
|
|
744
778
|
if (++nodes > maxNodes)
|
|
745
779
|
throw new XmlLimitError("maxNodes", "XML resource limit exceeded");
|
|
746
780
|
if (stack.length + 1 > maxDepth)
|
|
747
781
|
throw new XmlLimitError("maxDepth", "XML resource limit exceeded");
|
|
748
|
-
const namespace = yield* namespaceMetadata(namespaces, prefix, limits.deferNamespaces);
|
|
749
|
-
|
|
782
|
+
const namespace = yield* namespaceMetadata(namespaces, prefix, limits.deferNamespaces, prefixSource);
|
|
783
|
+
const elementName = { name, localName, ...(nameSource ? { nameSource, prefix } : {}), ...(localNameSource ? { localNameSource } : {}), ...(prefixSource ? { prefixSource } : {}) };
|
|
784
|
+
limits.onElement?.({ ...elementName, ...namespace }, (yield* stack.peek())?.element, stack.length + 1);
|
|
750
785
|
admitContent();
|
|
751
786
|
const retainedAttributes = [];
|
|
752
787
|
if (retainContent) {
|
|
@@ -766,7 +801,7 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
766
801
|
pendingWork -= 512;
|
|
767
802
|
}
|
|
768
803
|
const content = retain ? [] : undefined;
|
|
769
|
-
const element = { kind: "element",
|
|
804
|
+
const element = { kind: "element", ...elementName, ...namespace, children: [], text: "", content: content ?? emptyContent, attributes: retainContent ? retainedAttributes : emptyAttributes, namespaces: retainContent && namespaces instanceof Map ? namespaces : emptyNamespaces, ...(root === undefined && retainContent ? { prolog, epilog, ...(declaration === undefined ? {} : { declaration }) } : {}) };
|
|
770
805
|
const parent = (yield* stack.peek());
|
|
771
806
|
if (parent) {
|
|
772
807
|
if (retainTree) {
|
|
@@ -788,7 +823,7 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
788
823
|
}
|
|
789
824
|
// Only cache compact, attribute-free spellings. Namespace resolution and
|
|
790
825
|
// every admission counter still run for each distinct physical element.
|
|
791
|
-
if (empty && !attributes.length && name.length <= 512 && (yield* source.slice(offset - name.length - 3, offset)) === `<${name}/>`)
|
|
826
|
+
if (empty && !nameSource && !attributes.length && name.length <= 512 && (yield* source.slice(offset - name.length - 3, offset)) === `<${name}/>`)
|
|
792
827
|
previousEmpty = { suffix: name + "/>", name, prefix, localName };
|
|
793
828
|
limits.events?.({ type: "open", element, parent: parent?.element });
|
|
794
829
|
if (limits.storeAttributes && limits.onAttribute && retainContent) {
|
|
@@ -797,7 +832,8 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
797
832
|
const attribute = yield* attributes.read(cursor, true);
|
|
798
833
|
cursor = attribute.next;
|
|
799
834
|
const namespace = attribute.name === "xmlns" || attribute.prefix === "xmlns" ? { namespace: xmlnsNamespace }
|
|
800
|
-
: attribute.prefix ? yield* namespaceMetadata(namespaces, attribute.prefix, limits.deferNamespaces) : { namespace: "" };
|
|
835
|
+
: attribute.prefix || attribute.prefixSource ? yield* namespaceMetadata(namespaces, attribute.prefix, limits.deferNamespaces, attribute.prefixSource) : { namespace: "" };
|
|
836
|
+
const nameMetadata = { name: attribute.name, localName: attribute.localName, ...(attribute.nameSource ? { nameSource: attribute.nameSource, prefix: attribute.prefix } : {}), ...(attribute.localNameSource ? { localNameSource: attribute.localNameSource } : {}), ...(attribute.prefixSource ? { prefixSource: attribute.prefixSource } : {}) };
|
|
801
837
|
let continuation = false;
|
|
802
838
|
if (attribute.source) {
|
|
803
839
|
for (const part of textFragments(source, attribute.source.start, attribute.source.end, true, limits.recover ? () => { } : undefined, true)) {
|
|
@@ -805,13 +841,13 @@ export function* parseXmlSourceSteps(length, limits = {}) {
|
|
|
805
841
|
yield part;
|
|
806
842
|
continue;
|
|
807
843
|
}
|
|
808
|
-
limits.onAttribute({
|
|
844
|
+
limits.onAttribute({ ...nameMetadata, ...namespace, value: part }, element, continuation);
|
|
809
845
|
continuation = true;
|
|
810
846
|
yield 1;
|
|
811
847
|
}
|
|
812
848
|
}
|
|
813
849
|
if (!continuation) {
|
|
814
|
-
limits.onAttribute({
|
|
850
|
+
limits.onAttribute({ ...nameMetadata, ...namespace, value: attribute.value }, element);
|
|
815
851
|
yield 1;
|
|
816
852
|
}
|
|
817
853
|
}
|
|
@@ -6,7 +6,7 @@ export function prepareDetailContent(content, width) {
|
|
|
6
6
|
return { text: "", lines: [[]] };
|
|
7
7
|
}
|
|
8
8
|
width = Math.max(1, width);
|
|
9
|
-
const key = `${
|
|
9
|
+
const key = `${width}:${content}`;
|
|
10
10
|
const cached = markdownCache.get(key);
|
|
11
11
|
if (cached !== undefined)
|
|
12
12
|
return cached;
|
|
@@ -22,11 +22,3 @@ export function prepareDetailContent(content, width) {
|
|
|
22
22
|
markdownCache.set(key, prepared);
|
|
23
23
|
return prepared;
|
|
24
24
|
}
|
|
25
|
-
function contentHash(content) {
|
|
26
|
-
let hash = 2166136261;
|
|
27
|
-
for (let index = 0; index < content.length; index += 1) {
|
|
28
|
-
hash ^= content.charCodeAt(index);
|
|
29
|
-
hash = Math.imul(hash, 16777619);
|
|
30
|
-
}
|
|
31
|
-
return hash >>> 0;
|
|
32
|
-
}
|
|
@@ -112,6 +112,6 @@ function canonical(value) { return value.trim().toLowerCase().replace("control+"
|
|
|
112
112
|
function eventKey(event) {
|
|
113
113
|
const name = event.name ?? event.ch ?? "";
|
|
114
114
|
const modifiers = [event.ctrl ? "ctrl" : "", event.meta ? "meta" : "", event.shift ? "shift" : ""].filter(Boolean);
|
|
115
|
-
const normalized = name === "
|
|
115
|
+
const normalized = name === " " ? "space" : name.toLowerCase();
|
|
116
116
|
return [...modifiers, normalized].join("+");
|
|
117
117
|
}
|
|
@@ -941,7 +941,7 @@ function isBackspace(key) {
|
|
|
941
941
|
return key.name === "backspace" || key.name === "delete";
|
|
942
942
|
}
|
|
943
943
|
function isSelectionSpace(key) {
|
|
944
|
-
return key.name === "space" || key.ch === " ";
|
|
944
|
+
return key.name !== "paste" && (key.name === "space" || key.ch === " ");
|
|
945
945
|
}
|
|
946
946
|
function isConfirmYes(key) {
|
|
947
947
|
return key.ch === "y" || key.ch === "Y";
|
|
@@ -101,7 +101,8 @@ class ExplorerRuntime {
|
|
|
101
101
|
for (const ch of event.text.replaceAll("\n", "").replaceAll("\r", "")) {
|
|
102
102
|
this.dispatch({
|
|
103
103
|
type: "key",
|
|
104
|
-
|
|
104
|
+
// Pasted characters are text, even when they have a key binding.
|
|
105
|
+
key: { ch, name: "paste", ctrl: false, meta: false, shift: false }
|
|
105
106
|
});
|
|
106
107
|
}
|
|
107
108
|
return;
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "toolcraft",
|
|
3
|
-
"version": "0.0.
|
|
3
|
+
"version": "0.0.802",
|
|
4
4
|
"license": "MIT",
|
|
5
5
|
"type": "module",
|
|
6
6
|
"main": "dist/index.js",
|
|
@@ -177,7 +177,7 @@
|
|
|
177
177
|
"saxes"
|
|
178
178
|
],
|
|
179
179
|
"optionalDependencies": {
|
|
180
|
-
"toolcraft-schema": "0.0.
|
|
180
|
+
"toolcraft-schema": "0.0.802",
|
|
181
181
|
"toolcraft-design": "*",
|
|
182
182
|
"@poe-code/frontmatter": "*",
|
|
183
183
|
"@poe-code/agent-mcp-config": "*",
|