@junejs/server 1.0.0-dev.14 → 1.0.0-dev.17
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/dist/adapter.d.ts +7 -1
- package/dist/adapter.js +62 -5
- package/dist/agent-compile.d.ts +35 -0
- package/dist/agent-compile.js +139 -0
- package/dist/agent-discover.d.ts +3 -2
- package/dist/agent-discover.js +18 -44
- package/dist/agent-durable.d.ts +5 -2
- package/dist/agent-durable.js +18 -8
- package/dist/build.js +73 -8
- package/dist/client-bundle.js +1 -1
- package/dist/index.d.ts +2 -1
- package/dist/index.js +2 -1
- package/dist/tsconfig-jsx.d.ts +2 -1
- package/dist/tsconfig-jsx.js +1 -1
- package/package.json +13 -3
- package/src/adapter.ts +84 -3
- package/src/agent-compile.ts +245 -0
- package/src/agent-discover.ts +39 -54
- package/src/agent-durable.ts +33 -12
- package/src/build.ts +124 -9
- package/src/index.ts +8 -0
- package/src/tsconfig-jsx.ts +2 -2
package/src/agent-durable.ts
CHANGED
|
@@ -208,7 +208,11 @@ export type DoAgentDef = {
|
|
|
208
208
|
// channel factories you mount on the worker, plus this DO's env.
|
|
209
209
|
channels?: (Channel | ChannelFactory)[];
|
|
210
210
|
env?: unknown;
|
|
211
|
-
|
|
211
|
+
// A resolved bag, OR an env-driven — possibly async — provider
|
|
212
|
+
// (bindWorkerResources' shape): opening a D1 handle is async and a DO
|
|
213
|
+
// constructor cannot await, so a provider is resolved lazily at the first
|
|
214
|
+
// turn (once per DO instance) with this def's `env`.
|
|
215
|
+
resources?: Resources | ((env: unknown) => Promise<Resources> | Resources);
|
|
212
216
|
services?: unknown;
|
|
213
217
|
// Called on every turn.failed for this session — the app's seam for routing turn
|
|
214
218
|
// failures to its own telemetry (Sentry, a ledger, …). Providing it REPLACES the
|
|
@@ -253,15 +257,25 @@ export class AgentDurableObject {
|
|
|
253
257
|
private readonly tools: Tool[];
|
|
254
258
|
private readonly channels: Channel[];
|
|
255
259
|
private readonly channelInstructions?: Record<string, string>;
|
|
256
|
-
//
|
|
257
|
-
//
|
|
258
|
-
|
|
260
|
+
// A bag is used as-is; a provider (bindWorkerResources' shape) is resolved
|
|
261
|
+
// lazily at the first turn with the def's env — opening a D1 handle is async
|
|
262
|
+
// and this constructor cannot await. Resolved once, shared across turns (env
|
|
263
|
+
// is stable per isolate, like bindWorkerResources memoizes per worker isolate).
|
|
264
|
+
private readonly resourcesInput: DoAgentDef["resources"];
|
|
265
|
+
private resourcesOpened: Promise<Resources> | undefined;
|
|
266
|
+
private readonly doEnv: unknown;
|
|
259
267
|
private readonly services: unknown;
|
|
268
|
+
private resolveResources(): Promise<Resources> {
|
|
269
|
+
return (this.resourcesOpened ??= Promise.resolve(
|
|
270
|
+
typeof this.resourcesInput === "function" ? this.resourcesInput(this.doEnv) : (this.resourcesInput ?? {}),
|
|
271
|
+
));
|
|
272
|
+
}
|
|
260
273
|
constructor(state: DurableObjectState, def: DoAgentDef) {
|
|
261
274
|
assertCoreRuntimeVersion(`AgentDurableObject(${def.name ?? "agent"})`); // #94: fail power-on, not mid-turn
|
|
262
275
|
const store = new DoSessionStore(state.storage);
|
|
263
276
|
const model = def.instructions ? withSystem(def.model, def.instructions) : def.model;
|
|
264
|
-
this.
|
|
277
|
+
this.resourcesInput = def.resources;
|
|
278
|
+
this.doEnv = def.env;
|
|
265
279
|
this.services = def.services;
|
|
266
280
|
const name = def.name ?? "agent";
|
|
267
281
|
// Failure observability (#76): a turn that dies after the fast-ACK has no other
|
|
@@ -368,8 +382,9 @@ export class AgentDurableObject {
|
|
|
368
382
|
// pipeline does; without it runInScope is a pass-through and ambient reads throw.
|
|
369
383
|
async turn(input: { turnId?: string; userText: string; event?: InboundEvent; trigger?: ProactiveTrigger; session?: string }): Promise<string> {
|
|
370
384
|
await ensureScope();
|
|
385
|
+
const resources = await this.resolveResources();
|
|
371
386
|
const session = this.resolveSession(input.session);
|
|
372
|
-
return runInScope({ resources
|
|
387
|
+
return runInScope({ resources, services: this.services }, () => session.turn(input));
|
|
373
388
|
}
|
|
374
389
|
// Fire-and-forget for custom shells (#77): resolves once the turn is durably ACCEPTED;
|
|
375
390
|
// it then runs under the DO's own lifetime (a DO stays alive while it has pending
|
|
@@ -377,8 +392,9 @@ export class AgentDurableObject {
|
|
|
377
392
|
// the default turn-failure log / onTurnError (#76).
|
|
378
393
|
async start(input: { turnId?: string; userText: string; event?: InboundEvent; trigger?: ProactiveTrigger; session?: string }): Promise<{ turnId: string }> {
|
|
379
394
|
await ensureScope();
|
|
395
|
+
const resources = await this.resolveResources();
|
|
380
396
|
const session = this.resolveSession(input.session);
|
|
381
|
-
return runInScope({ resources
|
|
397
|
+
return runInScope({ resources, services: this.services }, () => session.start(input));
|
|
382
398
|
}
|
|
383
399
|
// Session reset (#129) for custom shells — the direct sibling of the /reset route. No
|
|
384
400
|
// scope needed: reset touches only the store (no tools run).
|
|
@@ -432,12 +448,14 @@ export class AgentDurableObject {
|
|
|
432
448
|
}
|
|
433
449
|
// start() schedules the turn on the chain WITHIN the scope, so it runs with ambient
|
|
434
450
|
// db/services (ALS propagates to the .then continuation registered here); subscribing
|
|
435
|
-
// happens synchronously right after, before any event can emit.
|
|
451
|
+
// happens synchronously right after, before any event can emit. Resources resolve
|
|
452
|
+
// BEFORE this block — the section from start() to the subscription stays synchronous.
|
|
453
|
+
const resources = await this.resolveResources();
|
|
436
454
|
let session: AgentSession;
|
|
437
455
|
let started: { turnId: string };
|
|
438
456
|
try {
|
|
439
457
|
session = this.resolveSession(key);
|
|
440
|
-
started = runInScope({ resources
|
|
458
|
+
started = runInScope({ resources, services: this.services }, () => session.start({ userText, turnId, event, trigger, replace }));
|
|
441
459
|
} catch (err) {
|
|
442
460
|
// e.g. the session is suspended awaiting input, or the key mis-matches this
|
|
443
461
|
// object's identity — a client-resolvable conflict, not a crash
|
|
@@ -470,7 +488,7 @@ export class AgentDurableObject {
|
|
|
470
488
|
const events: AsyncIterable<TurnEvent> = { [Symbol.asyncIterator]: () => it };
|
|
471
489
|
const target = { channelId: event!.channelId, threadId: event!.threadId, recipientUserId: event!.user?.id, recipientTeamId: event!.teamId };
|
|
472
490
|
Promise.resolve()
|
|
473
|
-
.then(() => runInScope({ resources
|
|
491
|
+
.then(() => runInScope({ resources, services: this.services }, () => deliverChannel!.deliver!(target, events, { session: this.sessionKey })))
|
|
474
492
|
.catch(logRenderFailure)
|
|
475
493
|
.finally(() => { void it.return?.(); });
|
|
476
494
|
} catch (err) {
|
|
@@ -515,10 +533,13 @@ export class AgentDurableObject {
|
|
|
515
533
|
);
|
|
516
534
|
}
|
|
517
535
|
}
|
|
536
|
+
// Same discipline as /turn: resolve resources before the synchronous
|
|
537
|
+
// resume-then-subscribe section.
|
|
538
|
+
const resources = await this.resolveResources();
|
|
518
539
|
let session: AgentSession;
|
|
519
540
|
try {
|
|
520
541
|
session = this.resolveSession(key);
|
|
521
|
-
runInScope({ resources
|
|
542
|
+
runInScope({ resources, services: this.services }, () => session.resume(turnId, inputId, input, { by }));
|
|
522
543
|
} catch (err) {
|
|
523
544
|
const message = err instanceof Error ? err.message : String(err);
|
|
524
545
|
// 403: the resumer may not answer; 409: not suspended / wrong turn / wrong input id / key mismatch
|
|
@@ -538,7 +559,7 @@ export class AgentDurableObject {
|
|
|
538
559
|
const it = observeTurnEvents(session, turnId)[Symbol.asyncIterator]();
|
|
539
560
|
const events: AsyncIterable<TurnEvent> = { [Symbol.asyncIterator]: () => it };
|
|
540
561
|
Promise.resolve()
|
|
541
|
-
.then(() => runInScope({ resources
|
|
562
|
+
.then(() => runInScope({ resources, services: this.services }, () => resumeChannel!.deliverResume!(target!, events, { session: this.sessionKey })))
|
|
542
563
|
.catch(logRenderFailure)
|
|
543
564
|
.finally(() => { void it.return?.(); });
|
|
544
565
|
} catch (err) {
|
package/src/build.ts
CHANGED
|
@@ -32,6 +32,7 @@ import { localeHref } from "@junejs/core/i18n";
|
|
|
32
32
|
import { routeFromModule, type BrandedRoute } from "@junejs/core/route";
|
|
33
33
|
import { workers, vercel, deno, staticSite, type JuneAdapter, type ResourcePlan } from "./adapter";
|
|
34
34
|
import type { DocumentConfig } from "@junejs/core/document";
|
|
35
|
+
import { generateAgentModule } from "./agent-compile";
|
|
35
36
|
import { generateContentModule } from "./content";
|
|
36
37
|
import { createWorker, type WorkerManifest } from "./worker";
|
|
37
38
|
import { findMiddlewareFile } from "./router";
|
|
@@ -441,6 +442,20 @@ export async function buildManifest(appRoot: string): Promise<WorkerManifest> {
|
|
|
441
442
|
if (typeof mod.default === "function") extra = mod.default as ExtraHandler;
|
|
442
443
|
}
|
|
443
444
|
|
|
445
|
+
// The durable agent's DO address (createWorker routes the chat endpoint by
|
|
446
|
+
// it). Set whenever an agent/ directory exists — the surface is inert without
|
|
447
|
+
// an env.AGENT binding, so in-process consumers (prerender, the parity test)
|
|
448
|
+
// are unaffected.
|
|
449
|
+
let agentName: string | undefined;
|
|
450
|
+
const agentDir = join(appDir, frozen.agent.runtime.dir);
|
|
451
|
+
if (frozen.agent.runtime.enabled && existsSync(agentDir)) {
|
|
452
|
+
const cfgFile = join(agentDir, "agent.ts");
|
|
453
|
+
const cfg = existsSync(cfgFile)
|
|
454
|
+
? ((await import(pathToFileURL(cfgFile).href)).default as { name?: string } | undefined)
|
|
455
|
+
: undefined;
|
|
456
|
+
agentName = cfg?.name ?? basename(agentDir);
|
|
457
|
+
}
|
|
458
|
+
|
|
444
459
|
return {
|
|
445
460
|
routes,
|
|
446
461
|
dynamicRoutes,
|
|
@@ -450,6 +465,7 @@ export async function buildManifest(appRoot: string): Promise<WorkerManifest> {
|
|
|
450
465
|
loadings,
|
|
451
466
|
document: frozen.document,
|
|
452
467
|
agent: frozen.agent,
|
|
468
|
+
agentName,
|
|
453
469
|
i18n: frozen.i18n,
|
|
454
470
|
earlyHints: frozen.earlyHints,
|
|
455
471
|
extra,
|
|
@@ -521,6 +537,52 @@ export async function juneBuild(
|
|
|
521
537
|
config: fullConfig,
|
|
522
538
|
});
|
|
523
539
|
|
|
540
|
+
// ---- durable agent (the F7 mount): compile app/agent → _agent.gen.ts ------
|
|
541
|
+
// The generated entry mounts the compiled module statically (fs discovery
|
|
542
|
+
// can't run on workerd) and exports the per-session Durable Object class.
|
|
543
|
+
// Only a target with Durable Objects can host the session actor — elsewhere
|
|
544
|
+
// the agent surface is skipped with a notice, and an app without an agent/
|
|
545
|
+
// directory emits a byte-identical entry (the parity guarantee).
|
|
546
|
+
const agentDir = join(appDir, frozen.agent.runtime.dir);
|
|
547
|
+
let agentModule: { file: string } | null = null;
|
|
548
|
+
if (frozen.agent.runtime.enabled) {
|
|
549
|
+
const generated = generateAgentModule(agentDir);
|
|
550
|
+
if (generated && adapter.capabilities.durableObjects) {
|
|
551
|
+
agentModule = generated;
|
|
552
|
+
} else if (generated) {
|
|
553
|
+
console.warn(
|
|
554
|
+
`[june build] app/${frozen.agent.runtime.dir}/ found, but the ${adapter.name}() target has no Durable Objects — the durable agent is not mounted.`,
|
|
555
|
+
);
|
|
556
|
+
}
|
|
557
|
+
}
|
|
558
|
+
if (agentModule) {
|
|
559
|
+
// The generated DO's model is Claude, and workerd has no runtime module
|
|
560
|
+
// resolution — the SDK must be a real dependency of the app so the entry's
|
|
561
|
+
// STATIC import bundles it (@junejs/core treats it as an optional peer; the
|
|
562
|
+
// adapter's own lazy import can never be bundled). Fail the build with the
|
|
563
|
+
// fix, never ship a worker whose first model turn dies on a bare import.
|
|
564
|
+
// An explicit node_modules walk, not a resolver API: the check must behave
|
|
565
|
+
// identically on every host (Bun.resolveSync missed a symlinked scoped
|
|
566
|
+
// package on Linux CI that it found on macOS), and Rolldown does its own
|
|
567
|
+
// resolution at bundle time anyway — this is a preflight, not the resolver.
|
|
568
|
+
const sdkResolvable = (fromDir: string): boolean => {
|
|
569
|
+
// Absolute first: with a relative root (juneBuild(".")), dirname(".") is
|
|
570
|
+
// still "." and the walk would stop before reaching a hoisted parent.
|
|
571
|
+
for (let d = resolve(fromDir); ; ) {
|
|
572
|
+
if (existsSync(join(d, "node_modules", "@anthropic-ai", "sdk", "package.json"))) return true;
|
|
573
|
+
const parent = dirname(d);
|
|
574
|
+
if (parent === d) return false;
|
|
575
|
+
d = parent;
|
|
576
|
+
}
|
|
577
|
+
};
|
|
578
|
+
if (!sdkResolvable(appRoot)) {
|
|
579
|
+
throw new Error(
|
|
580
|
+
`app/${frozen.agent.runtime.dir}/ mounts a durable agent whose model is Claude — ` +
|
|
581
|
+
`add the SDK to the app so it bundles for workerd: bun add @anthropic-ai/sdk`,
|
|
582
|
+
);
|
|
583
|
+
}
|
|
584
|
+
}
|
|
585
|
+
|
|
524
586
|
// Compile the global stylesheet ONCE and content-hash it: the built worker and
|
|
525
587
|
// prerendered HTML link `/global.<hash>.css`, served immutable (cache forever,
|
|
526
588
|
// a content change ships a new URL → no revalidation, no stale window). Dev
|
|
@@ -691,11 +753,15 @@ export async function juneBuild(
|
|
|
691
753
|
} else if (hasResources) {
|
|
692
754
|
imports.push(`import { bindWorkerResources } from "@junejs/server/resources";`);
|
|
693
755
|
}
|
|
694
|
-
|
|
695
|
-
|
|
756
|
+
// One expression, TWO instances: the pipeline (createWorker) and the durable
|
|
757
|
+
// agent's DO each open their own provider — the DO is a separate isolate whose
|
|
758
|
+
// env must not be captured by the worker-side memoization.
|
|
759
|
+
const resourcesExpr = tursoDb
|
|
760
|
+
? `memoizeResources({ db: turso() })`
|
|
696
761
|
: hasResources
|
|
697
|
-
?
|
|
698
|
-
:
|
|
762
|
+
? `bindWorkerResources(${JSON.stringify(resourceFlags)})`
|
|
763
|
+
: null;
|
|
764
|
+
const resourcesField = resourcesExpr ? `\n resources: ${resourcesExpr},` : "";
|
|
699
765
|
|
|
700
766
|
// Opt-in Tier-3 data layer: import its installDataLayer from the declared module
|
|
701
767
|
// and call it at worker boot — the prod twin of the dev host's dataLayer.install()
|
|
@@ -723,6 +789,46 @@ export async function juneBuild(
|
|
|
723
789
|
}
|
|
724
790
|
const servicesField = servicesModule ? `\n services: __appServices,` : "";
|
|
725
791
|
|
|
792
|
+
// Durable agent: import the compiled agent module + the DO shell pieces, set
|
|
793
|
+
// agentName on the manifest (what activates createWorker's chat routing), and
|
|
794
|
+
// export the DO class the adapter's wrangler binding names. cloudflare:workers
|
|
795
|
+
// is a workerd runtime module — external to the bundle (see the predicate below).
|
|
796
|
+
if (agentModule) {
|
|
797
|
+
imports.push(`import __agentModule from ${JSON.stringify(importPath(genDir, agentModule.file))};`);
|
|
798
|
+
imports.push(`import { assembleDurable } from "@junejs/core/agent-config";`);
|
|
799
|
+
imports.push(`import { anthropic } from "@junejs/core/agent-models";`);
|
|
800
|
+
imports.push(`import { AgentDurableObject } from "@junejs/server/agent-durable";`);
|
|
801
|
+
imports.push(`import { DurableObject } from "cloudflare:workers";`);
|
|
802
|
+
// STATIC so Rolldown bundles the SDK (the adapter's own import is a
|
|
803
|
+
// non-literal lazy specifier — deliberately unbundleable); injected via
|
|
804
|
+
// anthropic({ client }), which skips that lazy path entirely.
|
|
805
|
+
imports.push(`import Anthropic from "@anthropic-ai/sdk";`);
|
|
806
|
+
}
|
|
807
|
+
const agentNameField = agentModule ? `\n agentName: __agentModule.config.name,` : "";
|
|
808
|
+
const doClass = agentModule
|
|
809
|
+
? `
|
|
810
|
+
// The durable agent: one Durable Object per session, the compiled agent/
|
|
811
|
+
// directory as its definition — adapted tools (+ read_skill when skills exist),
|
|
812
|
+
// the assembled system prompt, channel factories resolved with the DO's own
|
|
813
|
+
// env, and the app's declared resources opened from THIS isolate's env (lazily,
|
|
814
|
+
// at the first turn — the same ambient db a tool sees in native dev). Model:
|
|
815
|
+
// Anthropic over a statically bundled client (workerd cannot resolve a bare
|
|
816
|
+
// import at runtime), keyed by the ANTHROPIC_API_KEY secret — a missing secret
|
|
817
|
+
// surfaces as the SDK's own clear construction error on the first agent request.
|
|
818
|
+
const __agentDef = assembleDurable(__agentModule);
|
|
819
|
+
export class JuneAgentDO extends DurableObject {
|
|
820
|
+
#agent = new AgentDurableObject(this.ctx, {
|
|
821
|
+
...__agentDef,
|
|
822
|
+
model: anthropic({ model: __agentModule.config.model, client: new Anthropic({ apiKey: (this.env as { ANTHROPIC_API_KEY?: string }).ANTHROPIC_API_KEY }) }),
|
|
823
|
+
env: this.env,${resourcesExpr ? `\n resources: ${resourcesExpr},` : ""}${servicesModule ? "\n services: __appServices(this.env)," : ""}
|
|
824
|
+
});
|
|
825
|
+
fetch(req: Request): Promise<Response> {
|
|
826
|
+
return this.#agent.fetch(req);
|
|
827
|
+
}
|
|
828
|
+
}
|
|
829
|
+
`
|
|
830
|
+
: "";
|
|
831
|
+
|
|
726
832
|
const entry = `// AUTO-GENERATED by \`june build\` — do not edit. Regenerate: june build .
|
|
727
833
|
${adapterEntry.imports.join("\n")}
|
|
728
834
|
${imports.join("\n")}
|
|
@@ -741,12 +847,12 @@ ${chains.join("\n")}
|
|
|
741
847
|
${loadings.join("\n")}
|
|
742
848
|
},
|
|
743
849
|
document: ${JSON.stringify(frozen.document, null, 2).replace(/\n/g, "\n ")},
|
|
744
|
-
agent: ${JSON.stringify(frozen.agent)},${frozen.i18n ? `\n i18n: ${JSON.stringify(frozen.i18n)},` : ""}
|
|
850
|
+
agent: ${JSON.stringify(frozen.agent)},${agentNameField}${frozen.i18n ? `\n i18n: ${JSON.stringify(frozen.i18n)},` : ""}
|
|
745
851
|
earlyHints: ${JSON.stringify(frozen.earlyHints)},${builtExtraFile ? "\n extra," : ""}${resourcesField}${servicesField}
|
|
746
852
|
});
|
|
747
853
|
|
|
748
854
|
${adapterEntry.wrap("pipeline")}
|
|
749
|
-
`;
|
|
855
|
+
${doClass}`;
|
|
750
856
|
const entryFile = join(genDir, "worker-entry.tsx");
|
|
751
857
|
await writeFile(entryFile, entry);
|
|
752
858
|
|
|
@@ -773,6 +879,8 @@ ${adapterEntry.wrap("pipeline")}
|
|
|
773
879
|
external: (id: string) => {
|
|
774
880
|
// Bun built-ins exist only at Bun runtime, never in the workerd graph (see isBunSpecifier).
|
|
775
881
|
if (isBunSpecifier(id)) return true;
|
|
882
|
+
// workerd runtime modules (the durable-agent entry imports cloudflare:workers).
|
|
883
|
+
if (id.startsWith("cloudflare:")) return true;
|
|
776
884
|
// Binary assets stay external — wrangler's CompiledWasm/Data rules own them.
|
|
777
885
|
if (/\.(wasm|ttf|otf|woff2?|png|jpe?g|avif|webp)$/.test(id)) return true;
|
|
778
886
|
// Merge: adapter.buildExternal (target-specific, e.g. workers-og for the
|
|
@@ -960,16 +1068,23 @@ ${adapterEntry.wrap("pipeline")}
|
|
|
960
1068
|
const defaultName = workerName(pkgName ?? basename(appRoot));
|
|
961
1069
|
// A declared D1-backed db (sqlite/d1) → a D1 binding named DB (the name
|
|
962
1070
|
// bindWorkerResources reads). turso() connects from env, not a binding — no plan.
|
|
963
|
-
const plan: ResourcePlan =
|
|
964
|
-
resourcesCfg?.db && resourcesCfg.db.kind !== "turso"
|
|
1071
|
+
const plan: ResourcePlan = {
|
|
1072
|
+
...(resourcesCfg?.db && resourcesCfg.db.kind !== "turso"
|
|
965
1073
|
? { db: { binding: "DB", databaseName: `${defaultName}-db` } }
|
|
966
|
-
: {}
|
|
1074
|
+
: {}),
|
|
1075
|
+
// The durable agent's DO binding — the name createWorker reads (env.AGENT)
|
|
1076
|
+
// and the class the generated entry exports.
|
|
1077
|
+
...(agentModule ? { agent: { binding: "AGENT", className: "JuneAgentDO" } } : {}),
|
|
1078
|
+
};
|
|
967
1079
|
await adapter.emit({ appRoot, outDir, hasAssets, linkHeader, config: fullConfig, plan, defaultName, publicFiles });
|
|
968
1080
|
if (plan.db) {
|
|
969
1081
|
console.log(
|
|
970
1082
|
` ↳ d1 binding "${plan.db.binding}" emitted — set database_id in wrangler.jsonc (wrangler d1 create ${plan.db.databaseName})`,
|
|
971
1083
|
);
|
|
972
1084
|
}
|
|
1085
|
+
if (plan.agent) {
|
|
1086
|
+
console.log(` ↳ durable agent mounted (${plan.agent.className} → env.${plan.agent.binding}; chat at ${frozen.agent.runtime.chat.path})`);
|
|
1087
|
+
}
|
|
973
1088
|
|
|
974
1089
|
return {
|
|
975
1090
|
outFile,
|
package/src/index.ts
CHANGED
|
@@ -91,6 +91,14 @@ export {
|
|
|
91
91
|
freezeConfig,
|
|
92
92
|
type BuildResult,
|
|
93
93
|
} from "./build";
|
|
94
|
+
export {
|
|
95
|
+
generateAgentModule,
|
|
96
|
+
findAgentDir,
|
|
97
|
+
scanAgentDir,
|
|
98
|
+
emitAgentModule,
|
|
99
|
+
AGENT_MODULE_FILE,
|
|
100
|
+
type AgentDirScan,
|
|
101
|
+
} from "./agent-compile";
|
|
94
102
|
export { juneDeploy, type DeployResult } from "./deploy";
|
|
95
103
|
export { migrateD1, wranglerD1, resolveD1Database, type D1Exec } from "./d1-migrate";
|
|
96
104
|
export { startDevServer, type DevServer, type DevServerOptions } from "./dev";
|
package/src/tsconfig-jsx.ts
CHANGED
|
@@ -9,8 +9,8 @@ import { join } from "node:path";
|
|
|
9
9
|
// tsconfig.json is JSONC by convention (comments + trailing commas are idiomatic), and a strict
|
|
10
10
|
// JSON.parse failure here silently degrades to "not declared" → the conflict warning reappears.
|
|
11
11
|
// Strip comments (`//` only at line-start/after-whitespace so "https://…" in strings survives)
|
|
12
|
-
// and trailing commas before parsing.
|
|
13
|
-
const stripJsonc = (s: string): string =>
|
|
12
|
+
// and trailing commas before parsing. Shared: agent-compile's tsconfig sniff parses the same way.
|
|
13
|
+
export const stripJsonc = (s: string): string =>
|
|
14
14
|
s
|
|
15
15
|
.replace(/\/\*[\s\S]*?\*\//g, "")
|
|
16
16
|
.replace(/(^|\s)\/\/.*$/gm, "$1")
|