@xandreed/plugin-workspace 0.0.0-stage → 0.14.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +4 -2
- package/dist/bash-tool.adapter.d.ts +15 -0
- package/dist/bash-tool.adapter.js +72 -0
- package/dist/bash.adapter.d.ts +29 -0
- package/dist/bash.adapter.js +69 -0
- package/dist/bash.adapter.test.d.ts +1 -0
- package/dist/file-system.adapter.d.ts +20 -0
- package/dist/file-system.adapter.js +52 -0
- package/dist/file-system.adapter.test.d.ts +1 -0
- package/dist/index.d.ts +12 -0
- package/dist/index.js +35 -0
- package/dist/local-system.entity.d.ts +40 -0
- package/dist/local-system.entity.functions.d.ts +52 -0
- package/dist/local-system.entity.functions.js +32 -0
- package/dist/local-system.entity.functions.test.d.ts +1 -0
- package/dist/local-system.entity.js +11 -0
- package/dist/plugin.adapter.d.ts +120 -0
- package/dist/plugin.adapter.js +27 -0
- package/dist/plugin.adapter.test.d.ts +1 -0
- package/dist/read-tools.adapter.d.ts +33 -0
- package/dist/read-tools.adapter.js +100 -0
- package/dist/skills/skills-directory.adapter.d.ts +62 -0
- package/dist/skills/skills-directory.adapter.js +30 -0
- package/dist/skills/skills-directory.adapter.test.d.ts +1 -0
- package/dist/skills/skills-directory.entity.d.ts +96 -0
- package/dist/skills/skills-directory.entity.functions.d.ts +33 -0
- package/dist/skills/skills-directory.entity.functions.js +45 -0
- package/dist/skills/skills-directory.entity.functions.test.d.ts +1 -0
- package/dist/skills/skills-directory.entity.js +35 -0
- package/dist/text-edit.entity.d.ts +32 -0
- package/dist/text-edit.entity.functions.d.ts +32 -0
- package/dist/text-edit.entity.functions.js +68 -0
- package/dist/text-edit.entity.functions.test.d.ts +1 -0
- package/dist/text-edit.entity.js +15 -0
- package/dist/text-search.entity.d.ts +23 -0
- package/dist/text-search.entity.functions.d.ts +51 -0
- package/dist/text-search.entity.functions.js +30 -0
- package/dist/text-search.entity.functions.test.d.ts +1 -0
- package/dist/text-search.entity.js +10 -0
- package/dist/text-window.entity.d.ts +46 -0
- package/dist/text-window.entity.functions.d.ts +54 -0
- package/dist/text-window.entity.functions.js +88 -0
- package/dist/text-window.entity.functions.test.d.ts +1 -0
- package/dist/text-window.entity.js +21 -0
- package/dist/workspace-path.entity.d.ts +22 -0
- package/dist/workspace-path.entity.functions.d.ts +60 -0
- package/dist/workspace-path.entity.functions.js +63 -0
- package/dist/workspace-path.entity.functions.test.d.ts +1 -0
- package/dist/workspace-path.entity.js +8 -0
- package/dist/workspace-tools.adapter.d.ts +21 -0
- package/dist/workspace-tools.adapter.js +46 -0
- package/dist/workspace-tools.adapter.test.d.ts +1 -0
- package/dist/workspace-tools.entity.d.ts +433 -0
- package/dist/workspace-tools.entity.functions.d.ts +51 -0
- package/dist/workspace-tools.entity.functions.js +124 -0
- package/dist/workspace-tools.entity.functions.test.d.ts +1 -0
- package/dist/workspace-tools.entity.js +133 -0
- package/dist/workspace-tools.journey.test.d.ts +1 -0
- package/dist/write-tools.adapter.d.ts +12 -0
- package/dist/write-tools.adapter.js +77 -0
- package/package.json +29 -4
|
@@ -0,0 +1,133 @@
|
|
|
1
|
+
import { Result, Schema } from "effect";
|
|
2
|
+
import { AttachmentRejectedReason, BASH_ENV_ALLOWLIST, BashTermination, compileGlob, ImageMediaType, Media } from "@xandreed/core";
|
|
3
|
+
export const WorkspaceToolName = Schema.Literals(["read", "write", "edit", "ls", "find", "grep", "bash"]), WorkspaceSkillName = Schema.Literals(["read", "edit", "shell"]), WORKSPACE_PERMISSIONS = { write: "fs.write", exec: "shell.exec" };
|
|
4
|
+
const atLeast = (minimum) => Schema.Int.check(Schema.isGreaterThanOrEqualTo(minimum)), between = (minimum, maximum) => Schema.Int.check(Schema.isBetween({ minimum, maximum })), InsideWorkspace = Schema.String.check(Schema.makeFilter((path) => path.length > 0 && !path.startsWith("/") && !path.split("/").includes("..") ? !0 : "a path relative to the workspace root, without a .. segment")), Glob = Schema.String.check(Schema.makeFilter((glob) => Result.match(compileGlob(glob, { dot: !0 }), { onSuccess: () => !0, onFailure: (reason) => `not a usable glob: ${reason}` })));
|
|
5
|
+
export const WorkspaceToolsConfig = Schema.Struct({
|
|
6
|
+
tools: Schema.Array(WorkspaceToolName),
|
|
7
|
+
always: Schema.Array(WorkspaceSkillName),
|
|
8
|
+
confine: Schema.Boolean,
|
|
9
|
+
protect: Schema.Array(Glob),
|
|
10
|
+
exclude: Schema.Array(Glob),
|
|
11
|
+
maxLines: between(1, 1e5),
|
|
12
|
+
maxBytes: between(1024, 10485760),
|
|
13
|
+
lsEntries: between(1, 1e5),
|
|
14
|
+
findResults: between(1, 1e5),
|
|
15
|
+
grepMatches: between(1, 1e4),
|
|
16
|
+
grepLineChars: between(16, 1e5),
|
|
17
|
+
maxFileBytes: between(1024, 1073741824),
|
|
18
|
+
readImages: Schema.Boolean,
|
|
19
|
+
fuzzyEdit: Schema.Boolean,
|
|
20
|
+
bashTimeoutMs: atLeast(1),
|
|
21
|
+
bashMaxTimeoutMs: atLeast(1),
|
|
22
|
+
bashEnv: Schema.Record(Schema.String, Schema.String),
|
|
23
|
+
bashInheritEnv: Schema.Boolean,
|
|
24
|
+
bashEnvAllow: Schema.Array(Schema.String),
|
|
25
|
+
bashSessionEnv: Schema.Boolean,
|
|
26
|
+
spillDir: Schema.NullOr(InsideWorkspace),
|
|
27
|
+
spillKeep: between(1, 1e4),
|
|
28
|
+
progressMs: between(1, 60000),
|
|
29
|
+
environmentSection: Schema.Boolean,
|
|
30
|
+
sectionOrder: Schema.Int
|
|
31
|
+
}).check(Schema.makeFilter((config) => config.bashTimeoutMs <= config.bashMaxTimeoutMs ? !0 : "bashTimeoutMs must not exceed bashMaxTimeoutMs")), workspaceToolsDefaults = {
|
|
32
|
+
tools: ["read", "write", "edit", "ls", "find", "grep", "bash"],
|
|
33
|
+
always: ["read"],
|
|
34
|
+
confine: !0,
|
|
35
|
+
protect: [".git/**", ".efferent/**"],
|
|
36
|
+
exclude: ["node_modules", ".git", ".efferent"],
|
|
37
|
+
maxLines: 2000,
|
|
38
|
+
maxBytes: 51200,
|
|
39
|
+
lsEntries: 500,
|
|
40
|
+
findResults: 1000,
|
|
41
|
+
grepMatches: 100,
|
|
42
|
+
grepLineChars: 500,
|
|
43
|
+
maxFileBytes: 33554432,
|
|
44
|
+
readImages: !0,
|
|
45
|
+
fuzzyEdit: !0,
|
|
46
|
+
bashTimeoutMs: 120000,
|
|
47
|
+
bashMaxTimeoutMs: 600000,
|
|
48
|
+
bashEnv: {},
|
|
49
|
+
bashInheritEnv: !1,
|
|
50
|
+
bashEnvAllow: BASH_ENV_ALLOWLIST,
|
|
51
|
+
bashSessionEnv: !1,
|
|
52
|
+
spillDir: ".efferent/runtime/tool-output",
|
|
53
|
+
spillKeep: 50,
|
|
54
|
+
progressMs: 250,
|
|
55
|
+
environmentSection: !0,
|
|
56
|
+
sectionOrder: 800
|
|
57
|
+
}, ReadParams = Schema.Struct({
|
|
58
|
+
path: Schema.String,
|
|
59
|
+
offset: Schema.optionalKey(atLeast(1)),
|
|
60
|
+
limit: Schema.optionalKey(atLeast(1))
|
|
61
|
+
}), ReadResult = Schema.Union([
|
|
62
|
+
Schema.TaggedStruct("Text", {
|
|
63
|
+
path: Schema.String,
|
|
64
|
+
text: Schema.String,
|
|
65
|
+
firstLine: Schema.Int,
|
|
66
|
+
lastLine: Schema.Int,
|
|
67
|
+
totalLines: Schema.Int,
|
|
68
|
+
next: Schema.NullOr(Schema.Int),
|
|
69
|
+
clipped: Schema.Boolean,
|
|
70
|
+
lossy: Schema.Boolean
|
|
71
|
+
}),
|
|
72
|
+
Schema.TaggedStruct("Binary", {
|
|
73
|
+
path: Schema.String,
|
|
74
|
+
bytes: Schema.Int,
|
|
75
|
+
mediaType: Schema.NullOr(Schema.String)
|
|
76
|
+
}),
|
|
77
|
+
Schema.TaggedStruct("Image", {
|
|
78
|
+
path: Schema.String,
|
|
79
|
+
image: Media
|
|
80
|
+
}),
|
|
81
|
+
Schema.TaggedStruct("ImageRejected", {
|
|
82
|
+
path: Schema.String,
|
|
83
|
+
mediaType: ImageMediaType,
|
|
84
|
+
bytes: Schema.Int,
|
|
85
|
+
reason: AttachmentRejectedReason,
|
|
86
|
+
message: Schema.String
|
|
87
|
+
})
|
|
88
|
+
]), WriteParams = Schema.Struct({ path: Schema.String, content: Schema.String }), WriteResult = Schema.Struct({ path: Schema.String, bytes: Schema.Int, created: Schema.Boolean }), TextEdit = Schema.Struct({ oldText: Schema.String, newText: Schema.String }), EditParams = Schema.Struct({ path: Schema.String, edits: Schema.NonEmptyArray(TextEdit) }), EditResult = Schema.Struct({
|
|
89
|
+
path: Schema.String,
|
|
90
|
+
replaced: Schema.Int,
|
|
91
|
+
normalized: Schema.Boolean,
|
|
92
|
+
firstChangedLine: Schema.Int,
|
|
93
|
+
diff: Schema.String
|
|
94
|
+
}), LsParams = Schema.Struct({ path: Schema.optionalKey(Schema.String), limit: Schema.optionalKey(atLeast(1)) }), LsEntry = Schema.Struct({ name: Schema.String, kind: Schema.Literals(["file", "directory", "symlink", "other"]) }), LsResult = Schema.Struct({ path: Schema.String, entries: Schema.Array(LsEntry), total: Schema.Int }), FindParams = Schema.Struct({ pattern: Schema.String, path: Schema.optionalKey(Schema.String), limit: Schema.optionalKey(atLeast(1)) }), FindResult = Schema.Struct({ pattern: Schema.String, path: Schema.String, paths: Schema.Array(Schema.String), truncated: Schema.Boolean }), GrepParams = Schema.Struct({
|
|
95
|
+
pattern: Schema.String,
|
|
96
|
+
path: Schema.optionalKey(Schema.String),
|
|
97
|
+
glob: Schema.optionalKey(Schema.String),
|
|
98
|
+
ignoreCase: Schema.optionalKey(Schema.Boolean),
|
|
99
|
+
literal: Schema.optionalKey(Schema.Boolean),
|
|
100
|
+
context: Schema.optionalKey(between(0, 10)),
|
|
101
|
+
limit: Schema.optionalKey(atLeast(1))
|
|
102
|
+
}), GrepLine = Schema.Struct({ path: Schema.String, line: Schema.Int, text: Schema.String, match: Schema.Boolean }), GrepResult = Schema.Struct({
|
|
103
|
+
pattern: Schema.String,
|
|
104
|
+
path: Schema.String,
|
|
105
|
+
lines: Schema.Array(GrepLine),
|
|
106
|
+
matches: Schema.Int,
|
|
107
|
+
files: Schema.Int,
|
|
108
|
+
truncated: Schema.Boolean,
|
|
109
|
+
skipped: Schema.Int
|
|
110
|
+
}), BashParams = Schema.Struct({
|
|
111
|
+
command: Schema.String,
|
|
112
|
+
timeout: Schema.optionalKey(atLeast(1)),
|
|
113
|
+
stdin: Schema.optionalKey(Schema.String)
|
|
114
|
+
}), BashToolResult = Schema.Struct({
|
|
115
|
+
command: Schema.String,
|
|
116
|
+
output: Schema.String,
|
|
117
|
+
exitCode: Schema.NullOr(Schema.Int),
|
|
118
|
+
signal: Schema.NullOr(Schema.String),
|
|
119
|
+
termination: BashTermination,
|
|
120
|
+
truncated: Schema.Boolean,
|
|
121
|
+
totalLines: Schema.Int,
|
|
122
|
+
fullOutput: Schema.NullOr(Schema.String),
|
|
123
|
+
fullOutputCut: Schema.Boolean,
|
|
124
|
+
durationMs: Schema.Number
|
|
125
|
+
}), workspaceToolSchemas = {
|
|
126
|
+
read: { name: "read", parametersSchema: ReadParams, successSchema: ReadResult },
|
|
127
|
+
write: { name: "write", parametersSchema: WriteParams, successSchema: WriteResult },
|
|
128
|
+
edit: { name: "edit", parametersSchema: EditParams, successSchema: EditResult },
|
|
129
|
+
ls: { name: "ls", parametersSchema: LsParams, successSchema: LsResult },
|
|
130
|
+
find: { name: "find", parametersSchema: FindParams, successSchema: FindResult },
|
|
131
|
+
grep: { name: "grep", parametersSchema: GrepParams, successSchema: GrepResult },
|
|
132
|
+
bash: { name: "bash", parametersSchema: BashParams, successSchema: BashToolResult }
|
|
133
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
|
@@ -0,0 +1,12 @@
|
|
|
1
|
+
import type { RegisteredTool } from "@xandreed/core";
|
|
2
|
+
import type { WorkspaceToolContext } from "./read-tools.adapter.js";
|
|
3
|
+
/** `write`: create a file, or replace all of one, through a temporary file and a rename (see `save`). */
|
|
4
|
+
export declare const writeTool: (context: WorkspaceToolContext) => RegisteredTool;
|
|
5
|
+
/**
|
|
6
|
+
* `edit`: exact replacements in a UTF-8 text file, all matched against the
|
|
7
|
+
* file as it was, with the BOM and line endings kept. A file that is not
|
|
8
|
+
* valid UTF-8 is refused (`NotUtf8`): writing its decoded text back would
|
|
9
|
+
* turn every byte that is not into U+FFFD, lines the edits never touched
|
|
10
|
+
* included.
|
|
11
|
+
*/
|
|
12
|
+
export declare const editTool: (context: WorkspaceToolContext) => RegisteredTool;
|
|
@@ -0,0 +1,77 @@
|
|
|
1
|
+
import { Tool } from "effect/ai";
|
|
2
|
+
import { Effect, Option, Random, RcMap } from "effect";
|
|
3
|
+
import { defineTool, Failure } from "@xandreed/core";
|
|
4
|
+
import { applyTextEdits, unifiedDiff } from "./text-edit.entity.functions.js";
|
|
5
|
+
import { decodeText, encodeText, formatBytes, looksBinary, utf8Length } from "./text-window.entity.functions.js";
|
|
6
|
+
import { checkWritable, fsFailure, openWorkspace, resolveTarget } from "./workspace-path.entity.functions.js";
|
|
7
|
+
import { EditParams, EditResult, WORKSPACE_PERMISSIONS, WriteParams, WriteResult } from "./workspace-tools.entity.js";
|
|
8
|
+
import { compactEdit, compactWrite, renderEdit, renderWrite, toolDescriptions } from "./workspace-tools.entity.functions.js";
|
|
9
|
+
import { failure, fileSubjects, notAFile } from "./read-tools.adapter.js";
|
|
10
|
+
const WriteTool = (description) => Tool.make("write", { description, parameters: WriteParams, success: WriteResult, failure: Failure, failureMode: "return" }), EditTool = (description) => Tool.make("edit", { description, parameters: EditParams, success: EditResult, failure: Failure, failureMode: "return" }), holding = (context, path) => (change) => Effect.scoped(RcMap.get(context.locks, path).pipe(Effect.flatMap((lock) => lock.withPermits(1)(change)))), existing = (access, target) => access.fs.stat(target.path).pipe(Effect.map(Option.some), Effect.catchIf((error) => error.reason === "NotFound", () => Effect.succeed(Option.none())), Effect.mapError(fsFailure(target.display))), notForNewFiles = 3657, save = (access, target, content, before) => {
|
|
11
|
+
const mode = Option.flatMap(before, (info) => info.mode), inPlace = access.fs.write(target.path, content), replaced = Effect.gen(function* () {
|
|
12
|
+
const suffix = (yield* Random.nextIntBetween(0, 2147483647)).toString(36), temporary = access.path.join(access.path.dirname(target.path), `.${access.path.basename(target.path)}.${suffix}.efferent-tmp`), discard = access.fs.remove(temporary).pipe(Effect.ignore);
|
|
13
|
+
yield* access.fs.write(temporary, content, { createParents: !0 });
|
|
14
|
+
if (!(yield* Option.match(mode, {
|
|
15
|
+
onNone: () => Effect.succeed(!0),
|
|
16
|
+
onSome: (kept) => access.fs.stat(temporary).pipe(Effect.map((fresh) => Option.contains(fresh.mode, kept)), Effect.tapError(() => discard))
|
|
17
|
+
})))
|
|
18
|
+
return yield* discard.pipe(Effect.andThen(inPlace));
|
|
19
|
+
yield* access.fs.rename(temporary, target.path).pipe(Effect.tapError(() => discard));
|
|
20
|
+
});
|
|
21
|
+
return (Option.exists(mode, (bits) => (bits & notForNewFiles) !== 0) ? inPlace : replaced).pipe(Effect.mapError(fsFailure(target.display)));
|
|
22
|
+
};
|
|
23
|
+
export const writeTool = (context) => defineTool({
|
|
24
|
+
tool: WriteTool(toolDescriptions(context.config).write),
|
|
25
|
+
handler: (params) => Effect.gen(function* () {
|
|
26
|
+
const access = yield* openWorkspace(context.path), target = yield* resolveTarget(access, params.path, { confine: context.config.confine });
|
|
27
|
+
yield* checkWritable(access, target, context.protect);
|
|
28
|
+
return yield* holding(context, target.path)(Effect.gen(function* () {
|
|
29
|
+
const before = yield* existing(access, target);
|
|
30
|
+
if (Option.exists(before, (info) => info.kind === "directory"))
|
|
31
|
+
return yield* Effect.fail(failure("IsDirectory", `${target.display} is a directory`));
|
|
32
|
+
if (Option.exists(before, (info) => info.kind !== "file"))
|
|
33
|
+
return yield* Effect.fail(notAFile(target.display, "write"));
|
|
34
|
+
if (params.content.length === 0 && Option.exists(before, (info) => info.size > 0))
|
|
35
|
+
return yield* Effect.fail(failure("WouldEmpty", `${target.display} has content; write refuses to empty it. Use edit to remove parts of it, or bash to delete it`));
|
|
36
|
+
yield* save(access, target, params.content, before);
|
|
37
|
+
return { path: target.display, bytes: utf8Length(params.content), created: Option.isNone(before) };
|
|
38
|
+
}));
|
|
39
|
+
}),
|
|
40
|
+
view: { version: "1", render: renderWrite, compact: compactWrite, subjects: (result) => fileSubjects(result.path) },
|
|
41
|
+
annotations: { permissions: [WORKSPACE_PERMISSIONS.write] }
|
|
42
|
+
}), editTool = (context) => defineTool({
|
|
43
|
+
tool: EditTool(toolDescriptions(context.config).edit),
|
|
44
|
+
handler: (params) => Effect.gen(function* () {
|
|
45
|
+
const { config } = context, access = yield* openWorkspace(context.path), target = yield* resolveTarget(access, params.path, { confine: config.confine });
|
|
46
|
+
yield* checkWritable(access, target, context.protect);
|
|
47
|
+
return yield* holding(context, target.path)(Effect.gen(function* () {
|
|
48
|
+
const before = yield* existing(access, target), info = yield* Option.match(before, {
|
|
49
|
+
onNone: () => Effect.fail(failure("NotFound", `${target.display} does not exist; use write to create it`)),
|
|
50
|
+
onSome: Effect.succeed
|
|
51
|
+
});
|
|
52
|
+
if (info.kind === "directory")
|
|
53
|
+
return yield* Effect.fail(failure("IsDirectory", `${target.display} is a directory`));
|
|
54
|
+
if (info.kind !== "file")
|
|
55
|
+
return yield* Effect.fail(notAFile(target.display, "edit"));
|
|
56
|
+
if (info.size > config.maxFileBytes)
|
|
57
|
+
return yield* Effect.fail(failure("FileTooLarge", `${target.display} is ${formatBytes(info.size)}, more than the ${formatBytes(config.maxFileBytes)} edit loads`));
|
|
58
|
+
const bytes = yield* access.fs.readBytes(target.path).pipe(Effect.mapError(fsFailure(target.display)));
|
|
59
|
+
if (looksBinary(bytes))
|
|
60
|
+
return yield* Effect.fail(failure("Binary", `${target.display} is a binary file; edit changes text files only`));
|
|
61
|
+
const decoded = decodeText(bytes);
|
|
62
|
+
if (decoded.lossy)
|
|
63
|
+
return yield* Effect.fail(failure("NotUtf8", `${target.display} is not valid UTF-8 (Latin-1 or another encoding, say); edit changes UTF-8 text files only, since it would replace the bytes it cannot decode. Use bash (sed, iconv) to change it`));
|
|
64
|
+
const plan = yield* Effect.fromResult(applyTextEdits(decoded.text, params.edits, { fuzzy: config.fuzzyEdit }));
|
|
65
|
+
yield* save(access, target, encodeText({ text: plan.text, bom: decoded.bom }), before);
|
|
66
|
+
return {
|
|
67
|
+
path: target.display,
|
|
68
|
+
replaced: plan.replaced,
|
|
69
|
+
normalized: plan.normalized,
|
|
70
|
+
firstChangedLine: plan.firstChangedLine,
|
|
71
|
+
diff: unifiedDiff(target.display, plan.before, plan.after, config.maxBytes)
|
|
72
|
+
};
|
|
73
|
+
}));
|
|
74
|
+
}),
|
|
75
|
+
view: { version: "1", render: renderEdit, compact: compactEdit, subjects: (result) => fileSubjects(result.path) },
|
|
76
|
+
annotations: { permissions: [WORKSPACE_PERMISSIONS.write] }
|
|
77
|
+
});
|
package/package.json
CHANGED
|
@@ -1,6 +1,31 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@xandreed/plugin-workspace",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
|
|
6
|
-
|
|
3
|
+
"version": "0.14.0",
|
|
4
|
+
"engines": {
|
|
5
|
+
"node": ">=24",
|
|
6
|
+
"bun": ">=1.3.0"
|
|
7
|
+
},
|
|
8
|
+
"type": "module",
|
|
9
|
+
"description": "The local machine as the FileSystem and Bash ports (node:fs and node:child_process adapters and the plugin that provides them), the workspace tools an agent works with (read, write, edit, ls, find, grep and bash) and skills from directories of SKILL.md files (Node 24 and Bun, on Linux and macOS).",
|
|
10
|
+
"main": "./dist/index.js",
|
|
11
|
+
"exports": {
|
|
12
|
+
".": {
|
|
13
|
+
"types": "./dist/index.d.ts",
|
|
14
|
+
"default": "./dist/index.js"
|
|
15
|
+
}
|
|
16
|
+
},
|
|
17
|
+
"dependencies": {
|
|
18
|
+
"@xandreed/core": "0.14.0",
|
|
19
|
+
"effect": "4.0.7"
|
|
20
|
+
},
|
|
21
|
+
"private": false,
|
|
22
|
+
"types": "./dist/index.d.ts",
|
|
23
|
+
"files": [
|
|
24
|
+
"dist",
|
|
25
|
+
"skills",
|
|
26
|
+
"profiles",
|
|
27
|
+
"README.md",
|
|
28
|
+
"LICENSE"
|
|
29
|
+
],
|
|
30
|
+
"license": "MIT"
|
|
31
|
+
}
|