@dawn-ai/core 0.1.7 → 0.2.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 +1 -1
- package/README.md +2 -2
- package/dist/capabilities/built-in/agents-md.d.ts +9 -0
- package/dist/capabilities/built-in/agents-md.d.ts.map +1 -0
- package/dist/capabilities/built-in/agents-md.js +54 -0
- package/dist/capabilities/built-in/frontmatter.d.ts +17 -0
- package/dist/capabilities/built-in/frontmatter.d.ts.map +1 -0
- package/dist/capabilities/built-in/frontmatter.js +47 -0
- package/dist/capabilities/built-in/plan-md-parser.d.ts +6 -0
- package/dist/capabilities/built-in/plan-md-parser.d.ts.map +1 -0
- package/dist/capabilities/built-in/plan-md-parser.js +18 -0
- package/dist/capabilities/built-in/planning.d.ts +7 -0
- package/dist/capabilities/built-in/planning.d.ts.map +1 -0
- package/dist/capabilities/built-in/planning.js +125 -0
- package/dist/capabilities/built-in/skills.d.ts +3 -0
- package/dist/capabilities/built-in/skills.d.ts.map +1 -0
- package/dist/capabilities/built-in/skills.js +114 -0
- package/dist/capabilities/built-in/subagents.d.ts +3 -0
- package/dist/capabilities/built-in/subagents.d.ts.map +1 -0
- package/dist/capabilities/built-in/subagents.js +99 -0
- package/dist/capabilities/built-in/workspace.d.ts +3 -0
- package/dist/capabilities/built-in/workspace.d.ts.map +1 -0
- package/dist/capabilities/built-in/workspace.js +187 -0
- package/dist/capabilities/registry.d.ts +21 -0
- package/dist/capabilities/registry.d.ts.map +1 -0
- package/dist/capabilities/registry.js +35 -0
- package/dist/capabilities/types.d.ts +56 -0
- package/dist/capabilities/types.d.ts.map +1 -0
- package/dist/capabilities/types.js +1 -0
- package/dist/config.d.ts.map +1 -1
- package/dist/config.js +16 -214
- package/dist/index.d.ts +10 -0
- package/dist/index.d.ts.map +1 -1
- package/dist/index.js +6 -0
- package/dist/typegen/extract-tool-schema.js +58 -3
- package/dist/typegen/extract-tool-types.js +2 -2
- package/dist/types.d.ts +24 -2
- package/dist/types.d.ts.map +1 -1
- package/package.json +13 -3
|
@@ -0,0 +1,187 @@
|
|
|
1
|
+
import { existsSync } from "node:fs";
|
|
2
|
+
import { join, resolve, sep } from "node:path";
|
|
3
|
+
import { suggestedCommandPattern, suggestedPathPattern } from "@dawn-ai/permissions";
|
|
4
|
+
import { localExec, localFilesystem } from "@dawn-ai/workspace";
|
|
5
|
+
import { interrupt } from "@langchain/langgraph";
|
|
6
|
+
import { z } from "zod";
|
|
7
|
+
const WORKSPACE_DIRNAME = "workspace";
|
|
8
|
+
/**
|
|
9
|
+
* Resolve the workspace root to a cwd-relative path. This matches the
|
|
10
|
+
* AGENTS.md capability's resolution (process.cwd() + "workspace") so
|
|
11
|
+
* the agent's memory and workspace tools point at the same directory.
|
|
12
|
+
*/
|
|
13
|
+
function workspaceRoot() {
|
|
14
|
+
return join(process.cwd(), WORKSPACE_DIRNAME);
|
|
15
|
+
}
|
|
16
|
+
const READ_FILE_INPUT = z.object({ path: z.string().min(1) });
|
|
17
|
+
const WRITE_FILE_INPUT = z.object({ path: z.string().min(1), content: z.string() });
|
|
18
|
+
const LIST_DIR_INPUT = z.object({ path: z.string().default(".") });
|
|
19
|
+
const RUN_BASH_INPUT = z.object({ command: z.string().min(1) });
|
|
20
|
+
function backendContext(workspaceRoot, signal) {
|
|
21
|
+
return { signal, workspaceRoot };
|
|
22
|
+
}
|
|
23
|
+
async function gatePathOp(permissions, operation, absPath, workspaceRoot) {
|
|
24
|
+
// If permissions store is absent, allow (legacy behavior — capability used without permissions context).
|
|
25
|
+
if (!permissions)
|
|
26
|
+
return { allowed: true };
|
|
27
|
+
if (permissions.mode === "bypass")
|
|
28
|
+
return { allowed: true };
|
|
29
|
+
const insideWorkspace = absPath === workspaceRoot || absPath.startsWith(workspaceRoot + sep);
|
|
30
|
+
// Inside workspace: always allow silently.
|
|
31
|
+
if (insideWorkspace)
|
|
32
|
+
return { allowed: true };
|
|
33
|
+
// Outside workspace: consult the store.
|
|
34
|
+
const decision = permissions.match(operation, absPath);
|
|
35
|
+
if (decision === "allow")
|
|
36
|
+
return { allowed: true };
|
|
37
|
+
if (decision === "deny") {
|
|
38
|
+
return { allowed: false, reason: `Permission denied by user: ${absPath}` };
|
|
39
|
+
}
|
|
40
|
+
// decision === "unknown"
|
|
41
|
+
if (permissions.mode === "non-interactive") {
|
|
42
|
+
return { allowed: false, reason: `Permission denied (fail-closed): ${absPath}` };
|
|
43
|
+
}
|
|
44
|
+
// Interactive: emit LangGraph interrupt and await user decision.
|
|
45
|
+
const result = await emitPermissionInterrupt({
|
|
46
|
+
kind: "path",
|
|
47
|
+
operation,
|
|
48
|
+
path: absPath,
|
|
49
|
+
permissions,
|
|
50
|
+
});
|
|
51
|
+
if (result === "deny") {
|
|
52
|
+
return { allowed: false, reason: `Permission denied by user: ${absPath}` };
|
|
53
|
+
}
|
|
54
|
+
return { allowed: true };
|
|
55
|
+
}
|
|
56
|
+
async function gateBashOp(permissions, command) {
|
|
57
|
+
if (!permissions)
|
|
58
|
+
return { allowed: true };
|
|
59
|
+
if (permissions.mode === "bypass")
|
|
60
|
+
return { allowed: true };
|
|
61
|
+
const decision = permissions.match("bash", command);
|
|
62
|
+
if (decision === "allow")
|
|
63
|
+
return { allowed: true };
|
|
64
|
+
if (decision === "deny") {
|
|
65
|
+
return { allowed: false, reason: `Permission denied by user: ${command}` };
|
|
66
|
+
}
|
|
67
|
+
if (permissions.mode === "non-interactive") {
|
|
68
|
+
return { allowed: false, reason: `Permission denied (fail-closed): ${command}` };
|
|
69
|
+
}
|
|
70
|
+
const result = await emitPermissionInterrupt({
|
|
71
|
+
kind: "command",
|
|
72
|
+
command,
|
|
73
|
+
permissions,
|
|
74
|
+
});
|
|
75
|
+
if (result === "deny") {
|
|
76
|
+
return { allowed: false, reason: `Permission denied by user: ${command}` };
|
|
77
|
+
}
|
|
78
|
+
return { allowed: true };
|
|
79
|
+
}
|
|
80
|
+
async function emitPermissionInterrupt(args) {
|
|
81
|
+
const interruptId = `perm-${Date.now()}-${Math.random().toString(36).slice(2, 8)}`;
|
|
82
|
+
const suggestedPattern = args.kind === "command"
|
|
83
|
+
? suggestedCommandPattern(args.command ?? "")
|
|
84
|
+
: suggestedPathPattern(args.path ?? "");
|
|
85
|
+
const payload = {
|
|
86
|
+
interruptId,
|
|
87
|
+
type: "permission-request",
|
|
88
|
+
kind: args.kind,
|
|
89
|
+
detail: args.kind === "command"
|
|
90
|
+
? { command: args.command ?? "", suggestedPattern }
|
|
91
|
+
: {
|
|
92
|
+
operation: args.operation ?? "readFile",
|
|
93
|
+
path: args.path ?? "",
|
|
94
|
+
suggestedPattern,
|
|
95
|
+
},
|
|
96
|
+
};
|
|
97
|
+
const decision = interrupt(payload);
|
|
98
|
+
if (decision === "deny")
|
|
99
|
+
return "deny";
|
|
100
|
+
if (decision === "always") {
|
|
101
|
+
const tool = args.kind === "command" ? "bash" : (args.operation ?? "readFile");
|
|
102
|
+
await args.permissions.addAllow(tool, suggestedPattern);
|
|
103
|
+
}
|
|
104
|
+
return "allow";
|
|
105
|
+
}
|
|
106
|
+
function buildWorkspaceTools(workspaceRoot, fs, exec, permissions) {
|
|
107
|
+
const readFile = {
|
|
108
|
+
name: "readFile",
|
|
109
|
+
description: "Read a UTF-8 file from the workspace.",
|
|
110
|
+
schema: READ_FILE_INPUT,
|
|
111
|
+
overridable: true,
|
|
112
|
+
run: async (input, ctx) => {
|
|
113
|
+
const { path } = READ_FILE_INPUT.parse(input);
|
|
114
|
+
const absPath = resolve(workspaceRoot, path);
|
|
115
|
+
const gate = await gatePathOp(permissions, "readFile", absPath, workspaceRoot);
|
|
116
|
+
if (!gate.allowed) {
|
|
117
|
+
throw new Error(gate.reason);
|
|
118
|
+
}
|
|
119
|
+
return fs.readFile(absPath, backendContext(workspaceRoot, ctx.signal));
|
|
120
|
+
},
|
|
121
|
+
};
|
|
122
|
+
const writeFile = {
|
|
123
|
+
name: "writeFile",
|
|
124
|
+
description: "Write a UTF-8 file inside the workspace.",
|
|
125
|
+
schema: WRITE_FILE_INPUT,
|
|
126
|
+
overridable: true,
|
|
127
|
+
run: async (input, ctx) => {
|
|
128
|
+
const { path, content } = WRITE_FILE_INPUT.parse(input);
|
|
129
|
+
const absPath = resolve(workspaceRoot, path);
|
|
130
|
+
const gate = await gatePathOp(permissions, "writeFile", absPath, workspaceRoot);
|
|
131
|
+
if (!gate.allowed) {
|
|
132
|
+
throw new Error(gate.reason);
|
|
133
|
+
}
|
|
134
|
+
const result = await fs.writeFile(absPath, content, backendContext(workspaceRoot, ctx.signal));
|
|
135
|
+
return `wrote ${result.bytesWritten} bytes to ${path}`;
|
|
136
|
+
},
|
|
137
|
+
};
|
|
138
|
+
const listDir = {
|
|
139
|
+
name: "listDir",
|
|
140
|
+
description: "List entries in a workspace directory.",
|
|
141
|
+
schema: LIST_DIR_INPUT,
|
|
142
|
+
overridable: true,
|
|
143
|
+
run: async (input, ctx) => {
|
|
144
|
+
const { path } = LIST_DIR_INPUT.parse(input);
|
|
145
|
+
const absPath = resolve(workspaceRoot, path);
|
|
146
|
+
const gate = await gatePathOp(permissions, "listDir", absPath, workspaceRoot);
|
|
147
|
+
if (!gate.allowed) {
|
|
148
|
+
throw new Error(gate.reason);
|
|
149
|
+
}
|
|
150
|
+
const entries = await fs.listDir(absPath, backendContext(workspaceRoot, ctx.signal));
|
|
151
|
+
return [...entries];
|
|
152
|
+
},
|
|
153
|
+
};
|
|
154
|
+
const runBash = {
|
|
155
|
+
name: "runBash",
|
|
156
|
+
description: "Run a shell command inside the workspace.",
|
|
157
|
+
schema: RUN_BASH_INPUT,
|
|
158
|
+
overridable: true,
|
|
159
|
+
run: async (input, ctx) => {
|
|
160
|
+
const { command } = RUN_BASH_INPUT.parse(input);
|
|
161
|
+
const gate = await gateBashOp(permissions, command);
|
|
162
|
+
if (!gate.allowed) {
|
|
163
|
+
throw new Error(gate.reason);
|
|
164
|
+
}
|
|
165
|
+
return exec.runCommand({ command }, backendContext(workspaceRoot, ctx.signal));
|
|
166
|
+
},
|
|
167
|
+
};
|
|
168
|
+
return [readFile, writeFile, listDir, runBash];
|
|
169
|
+
}
|
|
170
|
+
export function createWorkspaceMarker() {
|
|
171
|
+
return {
|
|
172
|
+
name: "workspace",
|
|
173
|
+
detect: async (_routeDir, _context) => existsSync(workspaceRoot()),
|
|
174
|
+
load: async (_routeDir, context) => {
|
|
175
|
+
const root = workspaceRoot();
|
|
176
|
+
if (!existsSync(root))
|
|
177
|
+
return {};
|
|
178
|
+
const fs = context.backends?.filesystem ?? localFilesystem();
|
|
179
|
+
const exec = context.backends?.exec ?? localExec();
|
|
180
|
+
const permissions = context.permissions;
|
|
181
|
+
if (permissions?.mode === "bypass") {
|
|
182
|
+
console.warn("[dawn:permissions] mode=bypass — path-jail disabled, all bash unrestricted. Do not use in production.");
|
|
183
|
+
}
|
|
184
|
+
return { tools: buildWorkspaceTools(root, fs, exec, permissions) };
|
|
185
|
+
},
|
|
186
|
+
};
|
|
187
|
+
}
|
|
@@ -0,0 +1,21 @@
|
|
|
1
|
+
import type { CapabilityContribution, CapabilityMarker, CapabilityMarkerContext } from "./types.js";
|
|
2
|
+
export type { CapabilityMarker, CapabilityMarkerContext };
|
|
3
|
+
export interface CapabilityRegistry {
|
|
4
|
+
readonly markers: ReadonlyArray<CapabilityMarker>;
|
|
5
|
+
}
|
|
6
|
+
export interface AppliedContribution {
|
|
7
|
+
readonly markerName: string;
|
|
8
|
+
readonly contribution: CapabilityContribution;
|
|
9
|
+
}
|
|
10
|
+
export interface CapabilityError {
|
|
11
|
+
readonly markerName: string;
|
|
12
|
+
readonly phase: "detect" | "load";
|
|
13
|
+
readonly message: string;
|
|
14
|
+
}
|
|
15
|
+
export interface ApplyResult {
|
|
16
|
+
readonly contributions: ReadonlyArray<AppliedContribution>;
|
|
17
|
+
readonly errors: ReadonlyArray<CapabilityError>;
|
|
18
|
+
}
|
|
19
|
+
export declare function createCapabilityRegistry(markers: ReadonlyArray<CapabilityMarker>): CapabilityRegistry;
|
|
20
|
+
export declare function applyCapabilities(registry: CapabilityRegistry, routeDir: string, context: CapabilityMarkerContext): Promise<ApplyResult>;
|
|
21
|
+
//# sourceMappingURL=registry.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"registry.d.ts","sourceRoot":"","sources":["../../src/capabilities/registry.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,sBAAsB,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,MAAM,YAAY,CAAA;AAEnG,YAAY,EAAE,gBAAgB,EAAE,uBAAuB,EAAE,CAAA;AAEzD,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,OAAO,EAAE,aAAa,CAAC,gBAAgB,CAAC,CAAA;CAClD;AAED,MAAM,WAAW,mBAAmB;IAClC,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,YAAY,EAAE,sBAAsB,CAAA;CAC9C;AAED,MAAM,WAAW,eAAe;IAC9B,QAAQ,CAAC,UAAU,EAAE,MAAM,CAAA;IAC3B,QAAQ,CAAC,KAAK,EAAE,QAAQ,GAAG,MAAM,CAAA;IACjC,QAAQ,CAAC,OAAO,EAAE,MAAM,CAAA;CACzB;AAED,MAAM,WAAW,WAAW;IAC1B,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAC,mBAAmB,CAAC,CAAA;IAC1D,QAAQ,CAAC,MAAM,EAAE,aAAa,CAAC,eAAe,CAAC,CAAA;CAChD;AAED,wBAAgB,wBAAwB,CACtC,OAAO,EAAE,aAAa,CAAC,gBAAgB,CAAC,GACvC,kBAAkB,CAEpB;AAED,wBAAsB,iBAAiB,CACrC,QAAQ,EAAE,kBAAkB,EAC5B,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,uBAAuB,GAC/B,OAAO,CAAC,WAAW,CAAC,CAgCtB"}
|
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
export function createCapabilityRegistry(markers) {
|
|
2
|
+
return { markers };
|
|
3
|
+
}
|
|
4
|
+
export async function applyCapabilities(registry, routeDir, context) {
|
|
5
|
+
const contributions = [];
|
|
6
|
+
const errors = [];
|
|
7
|
+
for (const marker of registry.markers) {
|
|
8
|
+
let detected;
|
|
9
|
+
try {
|
|
10
|
+
detected = await marker.detect(routeDir, context);
|
|
11
|
+
}
|
|
12
|
+
catch (error) {
|
|
13
|
+
errors.push({
|
|
14
|
+
markerName: marker.name,
|
|
15
|
+
phase: "detect",
|
|
16
|
+
message: error instanceof Error ? error.message : String(error),
|
|
17
|
+
});
|
|
18
|
+
continue;
|
|
19
|
+
}
|
|
20
|
+
if (!detected)
|
|
21
|
+
continue;
|
|
22
|
+
try {
|
|
23
|
+
const contribution = await marker.load(routeDir, context);
|
|
24
|
+
contributions.push({ markerName: marker.name, contribution });
|
|
25
|
+
}
|
|
26
|
+
catch (error) {
|
|
27
|
+
errors.push({
|
|
28
|
+
markerName: marker.name,
|
|
29
|
+
phase: "load",
|
|
30
|
+
message: error instanceof Error ? error.message : String(error),
|
|
31
|
+
});
|
|
32
|
+
}
|
|
33
|
+
}
|
|
34
|
+
return { contributions, errors };
|
|
35
|
+
}
|
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
import type { PermissionsStore } from "@dawn-ai/permissions";
|
|
2
|
+
import type { DawnAgent } from "@dawn-ai/sdk";
|
|
3
|
+
import type { ExecBackend, FilesystemBackend } from "@dawn-ai/workspace";
|
|
4
|
+
import type { ResolvedStateField, RouteManifest } from "../types.js";
|
|
5
|
+
export interface CapabilityMarkerContext {
|
|
6
|
+
readonly routeManifest: RouteManifest;
|
|
7
|
+
readonly descriptor: DawnAgent | undefined;
|
|
8
|
+
readonly descriptorRouteMap?: ReadonlyMap<DawnAgent, string>;
|
|
9
|
+
readonly backends?: {
|
|
10
|
+
readonly filesystem?: FilesystemBackend;
|
|
11
|
+
readonly exec?: ExecBackend;
|
|
12
|
+
};
|
|
13
|
+
readonly permissions?: PermissionsStore;
|
|
14
|
+
}
|
|
15
|
+
export interface DawnToolDefinition {
|
|
16
|
+
readonly description?: string;
|
|
17
|
+
readonly name: string;
|
|
18
|
+
readonly run: (input: unknown, context: {
|
|
19
|
+
readonly middleware?: Readonly<Record<string, unknown>>;
|
|
20
|
+
readonly signal: AbortSignal;
|
|
21
|
+
}) => Promise<unknown> | unknown;
|
|
22
|
+
readonly schema?: unknown;
|
|
23
|
+
}
|
|
24
|
+
export interface PromptFragment {
|
|
25
|
+
readonly placement: "after_user_prompt";
|
|
26
|
+
/**
|
|
27
|
+
* Render this fragment given the current state of the agent's channels.
|
|
28
|
+
* Called every model turn so the rendered text can reflect live state
|
|
29
|
+
* (e.g., the current todos list is re-injected each turn).
|
|
30
|
+
*/
|
|
31
|
+
readonly render: (state: Readonly<Record<string, unknown>>) => string;
|
|
32
|
+
}
|
|
33
|
+
export interface StreamTransformerInput {
|
|
34
|
+
readonly toolName: string;
|
|
35
|
+
readonly toolOutput: unknown;
|
|
36
|
+
}
|
|
37
|
+
export interface StreamTransformerOutput {
|
|
38
|
+
readonly event: string;
|
|
39
|
+
readonly data: unknown;
|
|
40
|
+
}
|
|
41
|
+
export interface StreamTransformer {
|
|
42
|
+
readonly observes: "tool_result";
|
|
43
|
+
readonly transform: (input: StreamTransformerInput) => Iterable<StreamTransformerOutput> | AsyncIterable<StreamTransformerOutput>;
|
|
44
|
+
}
|
|
45
|
+
export interface CapabilityContribution {
|
|
46
|
+
readonly tools?: ReadonlyArray<DawnToolDefinition>;
|
|
47
|
+
readonly stateFields?: ReadonlyArray<ResolvedStateField>;
|
|
48
|
+
readonly promptFragment?: PromptFragment;
|
|
49
|
+
readonly streamTransformers?: ReadonlyArray<StreamTransformer>;
|
|
50
|
+
}
|
|
51
|
+
export interface CapabilityMarker {
|
|
52
|
+
readonly name: string;
|
|
53
|
+
readonly detect: (routeDir: string, context: CapabilityMarkerContext) => Promise<boolean>;
|
|
54
|
+
readonly load: (routeDir: string, context: CapabilityMarkerContext) => Promise<CapabilityContribution>;
|
|
55
|
+
}
|
|
56
|
+
//# sourceMappingURL=types.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"types.d.ts","sourceRoot":"","sources":["../../src/capabilities/types.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,gBAAgB,EAAE,MAAM,sBAAsB,CAAA;AAC5D,OAAO,KAAK,EAAE,SAAS,EAAE,MAAM,cAAc,CAAA;AAC7C,OAAO,KAAK,EAAE,WAAW,EAAE,iBAAiB,EAAE,MAAM,oBAAoB,CAAA;AACxE,OAAO,KAAK,EAAE,kBAAkB,EAAE,aAAa,EAAE,MAAM,aAAa,CAAA;AAEpE,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,aAAa,EAAE,aAAa,CAAA;IACrC,QAAQ,CAAC,UAAU,EAAE,SAAS,GAAG,SAAS,CAAA;IAC1C,QAAQ,CAAC,kBAAkB,CAAC,EAAE,WAAW,CAAC,SAAS,EAAE,MAAM,CAAC,CAAA;IAC5D,QAAQ,CAAC,QAAQ,CAAC,EAAE;QAClB,QAAQ,CAAC,UAAU,CAAC,EAAE,iBAAiB,CAAA;QACvC,QAAQ,CAAC,IAAI,CAAC,EAAE,WAAW,CAAA;KAC5B,CAAA;IACD,QAAQ,CAAC,WAAW,CAAC,EAAE,gBAAgB,CAAA;CACxC;AAED,MAAM,WAAW,kBAAkB;IACjC,QAAQ,CAAC,WAAW,CAAC,EAAE,MAAM,CAAA;IAC7B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,GAAG,EAAE,CACZ,KAAK,EAAE,OAAO,EACd,OAAO,EAAE;QACP,QAAQ,CAAC,UAAU,CAAC,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,CAAA;QACvD,QAAQ,CAAC,MAAM,EAAE,WAAW,CAAA;KAC7B,KACE,OAAO,CAAC,OAAO,CAAC,GAAG,OAAO,CAAA;IAC/B,QAAQ,CAAC,MAAM,CAAC,EAAE,OAAO,CAAA;CAC1B;AAED,MAAM,WAAW,cAAc;IAC7B,QAAQ,CAAC,SAAS,EAAE,mBAAmB,CAAA;IACvC;;;;OAIG;IACH,QAAQ,CAAC,MAAM,EAAE,CAAC,KAAK,EAAE,QAAQ,CAAC,MAAM,CAAC,MAAM,EAAE,OAAO,CAAC,CAAC,KAAK,MAAM,CAAA;CACtE;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,QAAQ,EAAE,MAAM,CAAA;IACzB,QAAQ,CAAC,UAAU,EAAE,OAAO,CAAA;CAC7B;AAED,MAAM,WAAW,uBAAuB;IACtC,QAAQ,CAAC,KAAK,EAAE,MAAM,CAAA;IACtB,QAAQ,CAAC,IAAI,EAAE,OAAO,CAAA;CACvB;AAED,MAAM,WAAW,iBAAiB;IAChC,QAAQ,CAAC,QAAQ,EAAE,aAAa,CAAA;IAChC,QAAQ,CAAC,SAAS,EAAE,CAClB,KAAK,EAAE,sBAAsB,KAC1B,QAAQ,CAAC,uBAAuB,CAAC,GAAG,aAAa,CAAC,uBAAuB,CAAC,CAAA;CAChF;AAED,MAAM,WAAW,sBAAsB;IACrC,QAAQ,CAAC,KAAK,CAAC,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAAA;IAClD,QAAQ,CAAC,WAAW,CAAC,EAAE,aAAa,CAAC,kBAAkB,CAAC,CAAA;IACxD,QAAQ,CAAC,cAAc,CAAC,EAAE,cAAc,CAAA;IACxC,QAAQ,CAAC,kBAAkB,CAAC,EAAE,aAAa,CAAC,iBAAiB,CAAC,CAAA;CAC/D;AAED,MAAM,WAAW,gBAAgB;IAC/B,QAAQ,CAAC,IAAI,EAAE,MAAM,CAAA;IACrB,QAAQ,CAAC,MAAM,EAAE,CAAC,QAAQ,EAAE,MAAM,EAAE,OAAO,EAAE,uBAAuB,KAAK,OAAO,CAAC,OAAO,CAAC,CAAA;IACzF,QAAQ,CAAC,IAAI,EAAE,CACb,QAAQ,EAAE,MAAM,EAChB,OAAO,EAAE,uBAAuB,KAC7B,OAAO,CAAC,sBAAsB,CAAC,CAAA;CACrC"}
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
export {};
|
package/dist/config.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"config.d.ts","sourceRoot":"","sources":["../src/config.ts"],"names":[],"mappings":"AAKA,OAAO,KAAK,EAAc,qBAAqB,EAAE,gBAAgB,EAAE,MAAM,YAAY,CAAA;AAErF,eAAO,MAAM,gBAAgB,mBAAmB,CAAA;AAchD,wBAAsB,cAAc,CAAC,OAAO,EAAE,qBAAqB,GAAG,OAAO,CAAC,gBAAgB,CAAC,CAkB9F"}
|
package/dist/config.js
CHANGED
|
@@ -1,225 +1,27 @@
|
|
|
1
1
|
import { constants } from "node:fs";
|
|
2
|
-
import { access
|
|
2
|
+
import { access } from "node:fs/promises";
|
|
3
3
|
import { join } from "node:path";
|
|
4
|
+
import { pathToFileURL } from "node:url";
|
|
4
5
|
export const DAWN_CONFIG_FILE = "dawn.config.ts";
|
|
6
|
+
let loaderPromise;
|
|
7
|
+
async function registerTsxLoader() {
|
|
8
|
+
loaderPromise ??= (async () => {
|
|
9
|
+
const { register } = (await import("tsx/esm/api"));
|
|
10
|
+
register();
|
|
11
|
+
})();
|
|
12
|
+
await loaderPromise;
|
|
13
|
+
}
|
|
5
14
|
export async function loadDawnConfig(options) {
|
|
6
15
|
const configPath = join(options.appRoot, DAWN_CONFIG_FILE);
|
|
7
16
|
await access(configPath, constants.F_OK);
|
|
8
|
-
|
|
17
|
+
await registerTsxLoader();
|
|
18
|
+
const mod = (await import(pathToFileURL(configPath).href));
|
|
19
|
+
if (!mod.default || typeof mod.default !== "object") {
|
|
20
|
+
throw new Error(`${DAWN_CONFIG_FILE} must export default an object. Got: ${typeof mod.default}`);
|
|
21
|
+
}
|
|
9
22
|
return {
|
|
10
23
|
appRoot: options.appRoot,
|
|
11
|
-
config:
|
|
24
|
+
config: mod.default,
|
|
12
25
|
configPath,
|
|
13
26
|
};
|
|
14
27
|
}
|
|
15
|
-
function parseDawnConfig(source) {
|
|
16
|
-
const parser = new DawnConfigParser(source);
|
|
17
|
-
return parser.parse();
|
|
18
|
-
}
|
|
19
|
-
class DawnConfigParser {
|
|
20
|
-
tokens;
|
|
21
|
-
currentIndex = 0;
|
|
22
|
-
stringBindings = new Map();
|
|
23
|
-
constructor(source) {
|
|
24
|
-
this.tokens = tokenize(source);
|
|
25
|
-
}
|
|
26
|
-
parse() {
|
|
27
|
-
while (this.match("const")) {
|
|
28
|
-
this.parseConstDeclaration();
|
|
29
|
-
this.consumeOptional("semicolon");
|
|
30
|
-
}
|
|
31
|
-
this.consume("export");
|
|
32
|
-
this.consume("default");
|
|
33
|
-
const config = this.parseConfigObject();
|
|
34
|
-
this.consumeOptional("semicolon");
|
|
35
|
-
this.consume("eof");
|
|
36
|
-
return config;
|
|
37
|
-
}
|
|
38
|
-
parseConstDeclaration() {
|
|
39
|
-
const identifier = this.consume("identifier");
|
|
40
|
-
this.consume("equals");
|
|
41
|
-
const value = this.consume("string");
|
|
42
|
-
this.stringBindings.set(identifier.value, value.value);
|
|
43
|
-
}
|
|
44
|
-
parseConfigObject() {
|
|
45
|
-
this.consume("lbrace");
|
|
46
|
-
let appDir;
|
|
47
|
-
while (!this.check("rbrace")) {
|
|
48
|
-
const property = this.consume("identifier");
|
|
49
|
-
if (property.value !== "appDir") {
|
|
50
|
-
throw unsupportedConfig(`unsupported property "${property.value}"`);
|
|
51
|
-
}
|
|
52
|
-
const resolvedValue = this.match("colon")
|
|
53
|
-
? this.parsePropertyValue()
|
|
54
|
-
: this.resolveIdentifier(property.value);
|
|
55
|
-
appDir = resolvedValue;
|
|
56
|
-
if (!this.match("comma")) {
|
|
57
|
-
break;
|
|
58
|
-
}
|
|
59
|
-
}
|
|
60
|
-
this.consume("rbrace");
|
|
61
|
-
return appDir ? { appDir } : {};
|
|
62
|
-
}
|
|
63
|
-
parsePropertyValue() {
|
|
64
|
-
if (this.check("string")) {
|
|
65
|
-
return this.consume("string").value;
|
|
66
|
-
}
|
|
67
|
-
if (this.check("identifier")) {
|
|
68
|
-
return this.resolveIdentifier(this.consume("identifier").value);
|
|
69
|
-
}
|
|
70
|
-
throw unsupportedConfig("property values must be string literals or const identifiers");
|
|
71
|
-
}
|
|
72
|
-
resolveIdentifier(identifier) {
|
|
73
|
-
const resolved = this.stringBindings.get(identifier);
|
|
74
|
-
if (!resolved) {
|
|
75
|
-
throw unsupportedConfig(`unknown identifier "${identifier}"`);
|
|
76
|
-
}
|
|
77
|
-
return resolved;
|
|
78
|
-
}
|
|
79
|
-
match(type) {
|
|
80
|
-
if (!this.check(type)) {
|
|
81
|
-
return false;
|
|
82
|
-
}
|
|
83
|
-
this.currentIndex += 1;
|
|
84
|
-
return true;
|
|
85
|
-
}
|
|
86
|
-
consume(type) {
|
|
87
|
-
const token = this.peek();
|
|
88
|
-
if (token.type !== type) {
|
|
89
|
-
throw unsupportedConfig(`expected ${type} but found ${describeToken(token)}`);
|
|
90
|
-
}
|
|
91
|
-
this.currentIndex += 1;
|
|
92
|
-
return token;
|
|
93
|
-
}
|
|
94
|
-
consumeOptional(type) {
|
|
95
|
-
this.match(type);
|
|
96
|
-
}
|
|
97
|
-
check(type) {
|
|
98
|
-
return this.peek().type === type;
|
|
99
|
-
}
|
|
100
|
-
peek() {
|
|
101
|
-
return this.tokens[this.currentIndex] ?? { type: "eof" };
|
|
102
|
-
}
|
|
103
|
-
}
|
|
104
|
-
function tokenize(source) {
|
|
105
|
-
const tokens = [];
|
|
106
|
-
let index = source.startsWith("\uFEFF") ? 1 : 0;
|
|
107
|
-
while (index < source.length) {
|
|
108
|
-
const character = source[index];
|
|
109
|
-
if (!character) {
|
|
110
|
-
break;
|
|
111
|
-
}
|
|
112
|
-
if (isWhitespace(character)) {
|
|
113
|
-
index += 1;
|
|
114
|
-
continue;
|
|
115
|
-
}
|
|
116
|
-
if (character === "/" && source[index + 1] === "/") {
|
|
117
|
-
index += 2;
|
|
118
|
-
while (index < source.length && source[index] !== "\n") {
|
|
119
|
-
index += 1;
|
|
120
|
-
}
|
|
121
|
-
continue;
|
|
122
|
-
}
|
|
123
|
-
if (character === "/" && source[index + 1] === "*") {
|
|
124
|
-
const commentEnd = source.indexOf("*/", index + 2);
|
|
125
|
-
if (commentEnd === -1) {
|
|
126
|
-
throw unsupportedConfig("unterminated block comment");
|
|
127
|
-
}
|
|
128
|
-
index = commentEnd + 2;
|
|
129
|
-
continue;
|
|
130
|
-
}
|
|
131
|
-
if (character === "{") {
|
|
132
|
-
tokens.push({ type: "lbrace" });
|
|
133
|
-
index += 1;
|
|
134
|
-
continue;
|
|
135
|
-
}
|
|
136
|
-
if (character === "}") {
|
|
137
|
-
tokens.push({ type: "rbrace" });
|
|
138
|
-
index += 1;
|
|
139
|
-
continue;
|
|
140
|
-
}
|
|
141
|
-
if (character === ":") {
|
|
142
|
-
tokens.push({ type: "colon" });
|
|
143
|
-
index += 1;
|
|
144
|
-
continue;
|
|
145
|
-
}
|
|
146
|
-
if (character === ",") {
|
|
147
|
-
tokens.push({ type: "comma" });
|
|
148
|
-
index += 1;
|
|
149
|
-
continue;
|
|
150
|
-
}
|
|
151
|
-
if (character === "=") {
|
|
152
|
-
tokens.push({ type: "equals" });
|
|
153
|
-
index += 1;
|
|
154
|
-
continue;
|
|
155
|
-
}
|
|
156
|
-
if (character === ";") {
|
|
157
|
-
tokens.push({ type: "semicolon" });
|
|
158
|
-
index += 1;
|
|
159
|
-
continue;
|
|
160
|
-
}
|
|
161
|
-
if (character === '"' || character === "'") {
|
|
162
|
-
const [value, nextIndex] = readStringLiteral(source, index, character);
|
|
163
|
-
tokens.push({ type: "string", value });
|
|
164
|
-
index = nextIndex;
|
|
165
|
-
continue;
|
|
166
|
-
}
|
|
167
|
-
if (isIdentifierStart(character)) {
|
|
168
|
-
const [identifier, nextIndex] = readIdentifier(source, index);
|
|
169
|
-
index = nextIndex;
|
|
170
|
-
if (identifier === "const" || identifier === "export" || identifier === "default") {
|
|
171
|
-
tokens.push({ type: identifier });
|
|
172
|
-
}
|
|
173
|
-
else {
|
|
174
|
-
tokens.push({ type: "identifier", value: identifier });
|
|
175
|
-
}
|
|
176
|
-
continue;
|
|
177
|
-
}
|
|
178
|
-
throw unsupportedConfig(`unexpected token "${character}"`);
|
|
179
|
-
}
|
|
180
|
-
tokens.push({ type: "eof" });
|
|
181
|
-
return tokens;
|
|
182
|
-
}
|
|
183
|
-
function readStringLiteral(source, startIndex, quote) {
|
|
184
|
-
let index = startIndex + 1;
|
|
185
|
-
let value = "";
|
|
186
|
-
while (index < source.length) {
|
|
187
|
-
const character = source[index];
|
|
188
|
-
if (!character) {
|
|
189
|
-
break;
|
|
190
|
-
}
|
|
191
|
-
if (character === "\\") {
|
|
192
|
-
throw unsupportedConfig("escaped string literals are not supported");
|
|
193
|
-
}
|
|
194
|
-
if (character === quote) {
|
|
195
|
-
return [value, index + 1];
|
|
196
|
-
}
|
|
197
|
-
value += character;
|
|
198
|
-
index += 1;
|
|
199
|
-
}
|
|
200
|
-
throw unsupportedConfig("unterminated string literal");
|
|
201
|
-
}
|
|
202
|
-
function readIdentifier(source, startIndex) {
|
|
203
|
-
let index = startIndex + 1;
|
|
204
|
-
while (index < source.length && isIdentifierPart(source[index] ?? "")) {
|
|
205
|
-
index += 1;
|
|
206
|
-
}
|
|
207
|
-
return [source.slice(startIndex, index), index];
|
|
208
|
-
}
|
|
209
|
-
function isIdentifierStart(character) {
|
|
210
|
-
return /[A-Za-z_$]/.test(character);
|
|
211
|
-
}
|
|
212
|
-
function isIdentifierPart(character) {
|
|
213
|
-
return /[A-Za-z0-9_$]/.test(character);
|
|
214
|
-
}
|
|
215
|
-
function isWhitespace(character) {
|
|
216
|
-
return /\s/.test(character);
|
|
217
|
-
}
|
|
218
|
-
function describeToken(token) {
|
|
219
|
-
return token.type === "identifier" || token.type === "string"
|
|
220
|
-
? `${token.type} "${token.value}"`
|
|
221
|
-
: token.type;
|
|
222
|
-
}
|
|
223
|
-
function unsupportedConfig(reason) {
|
|
224
|
-
return new Error(`Unsupported dawn.config.ts syntax: ${reason}. Supported subset: optional const string declarations followed by export default { appDir } or export default { appDir: "..." }.`);
|
|
225
|
-
}
|
package/dist/index.d.ts
CHANGED
|
@@ -1,3 +1,13 @@
|
|
|
1
|
+
export type { ThreadsStore } from "@dawn-ai/sqlite-storage";
|
|
2
|
+
export { createAgentsMdMarker } from "./capabilities/built-in/agents-md.js";
|
|
3
|
+
export type { RuntimeTodo } from "./capabilities/built-in/planning.js";
|
|
4
|
+
export { createPlanningMarker } from "./capabilities/built-in/planning.js";
|
|
5
|
+
export { createSkillsMarker } from "./capabilities/built-in/skills.js";
|
|
6
|
+
export { createSubagentsMarker } from "./capabilities/built-in/subagents.js";
|
|
7
|
+
export { createWorkspaceMarker } from "./capabilities/built-in/workspace.js";
|
|
8
|
+
export type { AppliedContribution, ApplyResult, CapabilityError, CapabilityRegistry, } from "./capabilities/registry.js";
|
|
9
|
+
export { applyCapabilities, createCapabilityRegistry } from "./capabilities/registry.js";
|
|
10
|
+
export type { CapabilityContribution, CapabilityMarker, CapabilityMarkerContext, DawnToolDefinition, PromptFragment, StreamTransformer, StreamTransformerInput, StreamTransformerOutput, } from "./capabilities/types.js";
|
|
1
11
|
export { loadDawnConfig } from "./config.js";
|
|
2
12
|
export { discoverRoutes } from "./discovery/discover-routes.js";
|
|
3
13
|
export { assertDawnRoutesDir, findDawnApp } from "./discovery/find-dawn-app.js";
|
package/dist/index.d.ts.map
CHANGED
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AAC/D,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAA;AAC/E,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,eAAe,GAChB,MAAM,+BAA+B,CAAA;AACtC,YAAY,EAAE,yBAAyB,EAAE,MAAM,iCAAiC,CAAA;AAChF,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AACpE,YAAY,EAAE,yBAAyB,EAAE,MAAM,kCAAkC,CAAA;AACjF,OAAO,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAA;AAC7E,YAAY,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAA;AAC9E,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAA;AAC1E,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAA;AACnF,YAAY,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAA;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAA;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAA;AAChE,YAAY,EACV,UAAU,EACV,iBAAiB,EACjB,qBAAqB,EACrB,mBAAmB,EACnB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,EACrB,gBAAgB,EAChB,qBAAqB,EACrB,kBAAkB,EAClB,eAAe,EACf,SAAS,EACT,aAAa,EACb,YAAY,EACZ,gBAAgB,EAChB,cAAc,EACd,iBAAiB,GAClB,MAAM,YAAY,CAAA"}
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,YAAY,EAAE,MAAM,yBAAyB,CAAA;AAC3D,OAAO,EAAE,oBAAoB,EAAE,MAAM,sCAAsC,CAAA;AAC3E,YAAY,EAAE,WAAW,EAAE,MAAM,qCAAqC,CAAA;AACtE,OAAO,EAAE,oBAAoB,EAAE,MAAM,qCAAqC,CAAA;AAC1E,OAAO,EAAE,kBAAkB,EAAE,MAAM,mCAAmC,CAAA;AACtE,OAAO,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAA;AAC5E,OAAO,EAAE,qBAAqB,EAAE,MAAM,sCAAsC,CAAA;AAC5E,YAAY,EACV,mBAAmB,EACnB,WAAW,EACX,eAAe,EACf,kBAAkB,GACnB,MAAM,4BAA4B,CAAA;AACnC,OAAO,EAAE,iBAAiB,EAAE,wBAAwB,EAAE,MAAM,4BAA4B,CAAA;AACxF,YAAY,EACV,sBAAsB,EACtB,gBAAgB,EAChB,uBAAuB,EACvB,kBAAkB,EAClB,cAAc,EACd,iBAAiB,EACjB,sBAAsB,EACtB,uBAAuB,GACxB,MAAM,yBAAyB,CAAA;AAChC,OAAO,EAAE,cAAc,EAAE,MAAM,aAAa,CAAA;AAC5C,OAAO,EAAE,cAAc,EAAE,MAAM,gCAAgC,CAAA;AAC/D,OAAO,EAAE,mBAAmB,EAAE,WAAW,EAAE,MAAM,8BAA8B,CAAA;AAC/E,OAAO,EACL,gBAAgB,EAChB,mBAAmB,EACnB,eAAe,GAChB,MAAM,+BAA+B,CAAA;AACtC,YAAY,EAAE,yBAAyB,EAAE,MAAM,iCAAiC,CAAA;AAChF,OAAO,EAAE,kBAAkB,EAAE,MAAM,iCAAiC,CAAA;AACpE,YAAY,EAAE,yBAAyB,EAAE,MAAM,kCAAkC,CAAA;AACjF,OAAO,EAAE,0BAA0B,EAAE,MAAM,kCAAkC,CAAA;AAC7E,YAAY,EAAE,uBAAuB,EAAE,MAAM,iCAAiC,CAAA;AAC9E,OAAO,EAAE,wBAAwB,EAAE,MAAM,iCAAiC,CAAA;AAC1E,OAAO,EAAE,eAAe,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAA;AACnF,YAAY,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAA;AACvE,OAAO,EAAE,gBAAgB,EAAE,MAAM,iCAAiC,CAAA;AAClE,OAAO,EAAE,eAAe,EAAE,MAAM,gCAAgC,CAAA;AAChE,YAAY,EACV,UAAU,EACV,iBAAiB,EACjB,qBAAqB,EACrB,mBAAmB,EACnB,iBAAiB,EACjB,kBAAkB,EAClB,kBAAkB,EAClB,qBAAqB,EACrB,gBAAgB,EAChB,qBAAqB,EACrB,kBAAkB,EAClB,eAAe,EACf,SAAS,EACT,aAAa,EACb,YAAY,EACZ,gBAAgB,EAChB,cAAc,EACd,iBAAiB,GAClB,MAAM,YAAY,CAAA"}
|
package/dist/index.js
CHANGED
|
@@ -1,3 +1,9 @@
|
|
|
1
|
+
export { createAgentsMdMarker } from "./capabilities/built-in/agents-md.js";
|
|
2
|
+
export { createPlanningMarker } from "./capabilities/built-in/planning.js";
|
|
3
|
+
export { createSkillsMarker } from "./capabilities/built-in/skills.js";
|
|
4
|
+
export { createSubagentsMarker } from "./capabilities/built-in/subagents.js";
|
|
5
|
+
export { createWorkspaceMarker } from "./capabilities/built-in/workspace.js";
|
|
6
|
+
export { applyCapabilities, createCapabilityRegistry } from "./capabilities/registry.js";
|
|
1
7
|
export { loadDawnConfig } from "./config.js";
|
|
2
8
|
export { discoverRoutes } from "./discovery/discover-routes.js";
|
|
3
9
|
export { assertDawnRoutesDir, findDawnApp } from "./discovery/find-dawn-app.js";
|