wicked-crew 0.16.12 → 0.16.13
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/README.md +2 -1
- package/dist/api/chat-history.d.ts +6 -0
- package/dist/api/chat-history.d.ts.map +1 -1
- package/dist/api/chat-history.js +21 -0
- package/dist/api/chat-history.js.map +1 -1
- package/dist/api/chat-proposals.d.ts +61 -6
- package/dist/api/chat-proposals.d.ts.map +1 -1
- package/dist/api/chat-proposals.js +252 -24
- package/dist/api/chat-proposals.js.map +1 -1
- package/dist/api/routes.d.ts +14 -2
- package/dist/api/routes.d.ts.map +1 -1
- package/dist/api/routes.js +119 -9
- package/dist/api/routes.js.map +1 -1
- package/dist/api/run-timing-index.d.ts +18 -0
- package/dist/api/run-timing-index.d.ts.map +1 -1
- package/dist/api/run-timing-index.js +34 -0
- package/dist/api/run-timing-index.js.map +1 -1
- package/dist/api/server.d.ts.map +1 -1
- package/dist/api/server.js +100 -1
- package/dist/api/server.js.map +1 -1
- package/dist/apps/spec.d.ts +3009 -0
- package/dist/apps/spec.d.ts.map +1 -0
- package/dist/apps/spec.js +870 -0
- package/dist/apps/spec.js.map +1 -0
- package/dist/cli/index.js +3 -3
- package/dist/cli/index.js.map +1 -1
- package/dist/core/run-boot-resume.d.ts +4 -1
- package/dist/core/run-boot-resume.d.ts.map +1 -1
- package/dist/core/run-boot-resume.js +6 -1
- package/dist/core/run-boot-resume.js.map +1 -1
- package/dist/editors/csp.d.ts +24 -4
- package/dist/editors/csp.d.ts.map +1 -1
- package/dist/editors/csp.js +35 -8
- package/dist/editors/csp.js.map +1 -1
- package/dist/editors/routes.d.ts +4 -1
- package/dist/editors/routes.d.ts.map +1 -1
- package/dist/editors/routes.js +30 -3
- package/dist/editors/routes.js.map +1 -1
- package/dist/editors/webrtc-guard.d.ts +94 -0
- package/dist/editors/webrtc-guard.d.ts.map +1 -0
- package/dist/editors/webrtc-guard.js +506 -0
- package/dist/editors/webrtc-guard.js.map +1 -0
- package/dist/interactive/bridge-pool.d.ts +11 -2
- package/dist/interactive/bridge-pool.d.ts.map +1 -1
- package/dist/interactive/bridge-pool.js +10 -1
- package/dist/interactive/bridge-pool.js.map +1 -1
- package/dist/interactive/doc-binding.d.ts +156 -0
- package/dist/interactive/doc-binding.d.ts.map +1 -0
- package/dist/interactive/doc-binding.js +277 -0
- package/dist/interactive/doc-binding.js.map +1 -0
- package/dist/interactive/doc-delete-routes.d.ts +3 -0
- package/dist/interactive/doc-delete-routes.d.ts.map +1 -1
- package/dist/interactive/doc-delete-routes.js +4 -0
- package/dist/interactive/doc-delete-routes.js.map +1 -1
- package/dist/interactive/draft-events.d.ts +89 -3
- package/dist/interactive/draft-events.d.ts.map +1 -1
- package/dist/interactive/draft-events.js +438 -27
- package/dist/interactive/draft-events.js.map +1 -1
- package/dist/interactive/edit-events.d.ts +2 -0
- package/dist/interactive/edit-events.d.ts.map +1 -1
- package/dist/interactive/edit-events.js +11 -0
- package/dist/interactive/edit-events.js.map +1 -1
- package/dist/interactive/proposal-create.d.ts +143 -0
- package/dist/interactive/proposal-create.d.ts.map +1 -0
- package/dist/interactive/proposal-create.js +318 -0
- package/dist/interactive/proposal-create.js.map +1 -0
- package/dist/interactive/proxy-routes.d.ts +60 -3
- package/dist/interactive/proxy-routes.d.ts.map +1 -1
- package/dist/interactive/proxy-routes.js +209 -3
- package/dist/interactive/proxy-routes.js.map +1 -1
- package/dist/interactive/source-packet.d.ts +126 -0
- package/dist/interactive/source-packet.d.ts.map +1 -0
- package/dist/interactive/source-packet.js +482 -0
- package/dist/interactive/source-packet.js.map +1 -0
- package/dist/studio/assets/{index-C_UIgTiy.js → index-u4O_7N-b.js} +1 -1
- package/dist/studio/editors/wicked-deck/editor.json +1 -1
- package/dist/studio/editors/wicked-deck/index.html +1 -1
- package/dist/studio/editors/wicked-doc/editor.json +1 -1
- package/dist/studio/editors/wicked-doc/index.html +1 -1
- package/dist/studio/editors/wicked-insights/editor.json +1 -1
- package/dist/studio/editors/wicked-insights/index.html +1 -1
- package/dist/studio/editors/wicked-page/editor.json +1 -1
- package/dist/studio/editors/wicked-page/index.html +1 -1
- package/dist/studio/editors/wicked-video/editor.json +1 -1
- package/dist/studio/editors/wicked-video/index.html +1 -1
- package/dist/studio/index.html +1 -1
- package/dist/studio/testid-inventory.json +1 -1
- package/endpoint-manifest.json +1 -1
- package/package.json +4 -3
package/dist/api/routes.js
CHANGED
|
@@ -6,9 +6,9 @@ import { z } from 'zod';
|
|
|
6
6
|
import { listRequirementsRead, getRequirement, patchRequirement, readRequirementsGraph, REQUIREMENTS_NOT_GENERATED, } from './requirements.js';
|
|
7
7
|
import { randomUUID } from 'node:crypto';
|
|
8
8
|
import { homedir } from 'node:os';
|
|
9
|
-
import { readFileSync, existsSync, mkdirSync } from 'node:fs';
|
|
9
|
+
import { readFileSync, existsSync, mkdirSync, realpathSync } from 'node:fs';
|
|
10
10
|
import { promises as fsp } from 'node:fs';
|
|
11
|
-
import { isAbsolute, join, relative, resolve } from 'node:path';
|
|
11
|
+
import { basename, isAbsolute, join, relative, resolve } from 'node:path';
|
|
12
12
|
import { fileURLToPath } from 'node:url';
|
|
13
13
|
import { videoPalette } from '../appearance/video-palette.js';
|
|
14
14
|
import { CampaignsUnsupportedError, ChatUnsupportedError, CoreAdapter, ElicitationUnsupportedError, GovernanceReplayUnsupportedError, PlanLaunchUnsupportedError, SteeringUnsupportedError, addonSupportsQeOverride, addonSupportsReducedAssurance, humanGatePhaseIds, settingsFilePath } from '../core/adapter.js';
|
|
@@ -105,8 +105,13 @@ import { deliverIdentityFor, deliverRepoFor, deliverTargetView, isGitHubLogin, p
|
|
|
105
105
|
import { credentialsMissingIn, deliverCredentialsProbe, missingCredentials } from '../core/deliver-credentials.js';
|
|
106
106
|
import { codebaseArchiveUrl } from './codebase-archive.js';
|
|
107
107
|
import { projectRepoCandidates } from '../interactive/doc-grounding.js';
|
|
108
|
-
import { artifactStatus, beneathSupported, buildTurnContext, chatMount, ChatMessageContextSchema, contextReadRoots, ensureRealDir, parseArtifactRef, readGroundingBeneath, seatPathOf, UNFILED_MOUNT, } from './chat-context.js';
|
|
109
|
-
import { registerInteractiveProxy } from '../interactive/proxy-routes.js';
|
|
108
|
+
import { artifactStatus, beneathSupported, buildTurnContext, chatMount, ChatMessageContextSchema, contextReadRoots, ensureRealDir, sha256Hex, parseArtifactRef, readGroundingBeneath, seatPathOf, UNFILED_MOUNT, } from './chat-context.js';
|
|
109
|
+
import { createDocInProcess, registerInteractiveProxy } from '../interactive/proxy-routes.js';
|
|
110
|
+
import { CreateLauncher } from '../interactive/proposal-create.js';
|
|
111
|
+
import { buildRunBrief } from './run-brief.js';
|
|
112
|
+
import { readBeneath } from './beneath.js';
|
|
113
|
+
/** A context brief copied into a document's packet, at most (the packet's per-file cap). */
|
|
114
|
+
const BRIEF_COPY_MAX = 512 * 1024;
|
|
110
115
|
import { registerInteractiveDocDelete } from '../interactive/doc-delete-routes.js';
|
|
111
116
|
import { registerInteractiveDocChecks } from '../interactive/doc-checks-routes.js';
|
|
112
117
|
import { crewStateHome, stateHomeOfDb } from '../projects/state-home.js';
|
|
@@ -928,15 +933,20 @@ runtime = {}) {
|
|
|
928
933
|
// off — each later slice turns its own on and registers its launcher. The TEST configuration (§13 A2) turns every
|
|
929
934
|
// operation's resolution on and registers a recording stub that starts nothing.
|
|
930
935
|
const chatArtifactsStub = runtime.chatArtifactsStub === true;
|
|
936
|
+
// A3: a real `create` exists whenever the draft seam can launch a proposal-bound draft (the launcher is registered
|
|
937
|
+
// below, once the bridge pool exists). Production advertises it; the test configuration keeps the recording stub only
|
|
938
|
+
// for the operations whose slices have not landed.
|
|
939
|
+
const realCreate = runtime.docBindings !== undefined && runtime.launchBoundDraft !== undefined;
|
|
940
|
+
const stubOps = realCreate ? ['refine', 'theme', 'demo'] : ['create', 'refine', 'theme', 'demo'];
|
|
931
941
|
const chatArtifactFlags = chatArtifactsStub
|
|
932
|
-
? { context: true, proposals: true, create: true, refine: true, theme: true, demo: true, stub: true }
|
|
933
|
-
: { context: true, proposals: true, create:
|
|
942
|
+
? { context: true, proposals: true, create: true, refine: true, theme: true, demo: true, stub: true, stubOps }
|
|
943
|
+
: { context: true, proposals: true, create: realCreate, refine: false, theme: false, demo: false };
|
|
934
944
|
const proposalLaunchers = new LaunchOnceRegistry();
|
|
935
945
|
if (chatArtifactsStub) {
|
|
936
946
|
// Under the registered `chats` entry (a new top-level state-home entry would make core refuse every launch), and
|
|
937
947
|
// not a `.jsonl` there (the boot sweep clears orphaned transcripts by that suffix).
|
|
938
948
|
const stub = new RecordingStubDispatcher(join(crewStateHome(), 'chats', 'proposal-stub', 'dispatches.ndjson'));
|
|
939
|
-
for (const kind of
|
|
949
|
+
for (const kind of stubOps)
|
|
940
950
|
proposalLaunchers.register(kind, stub);
|
|
941
951
|
}
|
|
942
952
|
const deliveryIndex = runtime.deliveryIndex ?? new DeliveryIndex();
|
|
@@ -1247,6 +1257,15 @@ runtime = {}) {
|
|
|
1247
1257
|
const chatId = runTimingIndex.chatIdFor(view.session.id);
|
|
1248
1258
|
if (chatId !== undefined)
|
|
1249
1259
|
view.session.chat_id = chatId;
|
|
1260
|
+
// DES-CHAT-ARTIFACTS-001 (A3): the proposal a run answers, the artifact it makes, and a landing that failed.
|
|
1261
|
+
const proposalOf = runTimingIndex.proposalOf(view.session.id);
|
|
1262
|
+
if (proposalOf !== undefined) {
|
|
1263
|
+
view.session.proposal_id = proposalOf.proposalId;
|
|
1264
|
+
view.session.artifact_ref = proposalOf.artifactRef;
|
|
1265
|
+
}
|
|
1266
|
+
const landingFailed = runTimingIndex.landingFailedOf(view.session.id);
|
|
1267
|
+
if (landingFailed !== undefined)
|
|
1268
|
+
view.session.landing_failed = landingFailed;
|
|
1250
1269
|
// crew#552: the onboarding run a chained capture was launched from — ABSENT otherwise.
|
|
1251
1270
|
const chainedFrom = runTimingIndex.chainedFromOf(view.session.id);
|
|
1252
1271
|
if (chainedFrom !== undefined)
|
|
@@ -2452,6 +2471,13 @@ runtime = {}) {
|
|
|
2452
2471
|
}
|
|
2453
2472
|
deliver = 'none';
|
|
2454
2473
|
}
|
|
2474
|
+
// DES-CHAT-ARTIFACTS-001 §4.3 (A3): one live job per chat, work and artifact runs together. A work launch filed under
|
|
2475
|
+
// a chat whose proposal's document attempt has no outcome yet is refused, as Go is refused the other way round.
|
|
2476
|
+
if (b.chatId !== undefined && chatArtifactFlags.proposals) {
|
|
2477
|
+
const live = await chatProposals.liveJobOf(b.chatId).catch(() => null);
|
|
2478
|
+
if (live !== null)
|
|
2479
|
+
return reply.code(409).send({ code: 'chat_busy', error: `This chat already has a job running (${live}). Wait, or stop that run.` });
|
|
2480
|
+
}
|
|
2455
2481
|
try {
|
|
2456
2482
|
const runId = await adapter.launchRun(input);
|
|
2457
2483
|
// crew#641/#642 (item 5): when a run is promoted from a chat, record how many seats
|
|
@@ -3698,7 +3724,9 @@ runtime = {}) {
|
|
|
3698
3724
|
isAskPath: (runId) => runTimingIndex.isAskPath(runId),
|
|
3699
3725
|
docsRoot: (projectId) => projectDocsRoot(adapter, projectSettings, projectId),
|
|
3700
3726
|
projectName: async (projectId) => (await adapter.projectGet(projectId).catch(() => null))?.name ?? null,
|
|
3701
|
-
|
|
3727
|
+
projectRepos: async (projectId) => (await projectRepoCandidates(adapter, projectId, (m) => app.log.warn(m))).map((r) => ({ id: r.repoRef, name: r.name })),
|
|
3728
|
+
attachments: (chatId) => chatAttachments.list(chatId).map((a) => ({ id: a.id, name: a.name, bytes: a.bytes, mediaType: a.mediaType })),
|
|
3729
|
+
repoIds: async () => new Set((await adapter.listRepos()).map((r) => r.id)),
|
|
3702
3730
|
workflowSteps: async (name, projectId) => {
|
|
3703
3731
|
// The preset a launch in this project resolves first (a project row wins over a global one), then the def.
|
|
3704
3732
|
const presets = await adapter.listPresets(projectId ?? undefined).catch(() => []);
|
|
@@ -5219,6 +5247,15 @@ runtime = {}) {
|
|
|
5219
5247
|
// but its work is complete and liftable — normalize to `completed` so the terminal branch
|
|
5220
5248
|
// below refuses resume with the DELIVER recovery (POST /runs/:id/deliver), not a re-entry.
|
|
5221
5249
|
const conflictStrand = normalizeStranded(run);
|
|
5250
|
+
// DES-CHAT-ARTIFACTS-001 §6.2 (A3): a chat proposal's FAILED attempt is never resumed from its cursor: its seam flight
|
|
5251
|
+
// is gone (a resume would finish without landing anything) and its retry may already run. Try again is the path.
|
|
5252
|
+
// A still-live bound run's own gate is approved as any run's.
|
|
5253
|
+
if (run.session.status === 'failed' && runtime.docBindings?.isBound(id) === true) {
|
|
5254
|
+
return reply.code(409).send({
|
|
5255
|
+
error: `run ${id} answered a chat proposal: it cannot be resumed. Use Try again on its card in the chat (a new attempt at the same document).`,
|
|
5256
|
+
recovery: 'retry',
|
|
5257
|
+
});
|
|
5258
|
+
}
|
|
5222
5259
|
// A TERMINAL run is refused LOUDLY, with the actual recovery named (crew#311 defect 2).
|
|
5223
5260
|
// The engine's `resume_run` no-ops on completed/cancelled and answers the status token, so
|
|
5224
5261
|
// this route used to reply 200 {"status":"cancelled"} — on the exact runs an operator was
|
|
@@ -8676,14 +8713,80 @@ runtime = {}) {
|
|
|
8676
8713
|
toReview: toReview.kind === 'ok' ? toReview.value : null,
|
|
8677
8714
|
});
|
|
8678
8715
|
});
|
|
8716
|
+
// DES-CHAT-ARTIFACTS-001 §5.2 (A3): a create's `chat_id` + `proposal_id` counts only through the caller's accepted record.
|
|
8717
|
+
const proposalGrant = (chatId, pid, actorId) => (CHAT_ID.test(chatId) ? chatProposals.grantFor(chatId, pid, actorId) : null);
|
|
8679
8718
|
registerInteractiveProxy(app, adapter, {
|
|
8680
8719
|
settings: projectSettings,
|
|
8681
8720
|
pool: interactiveBridges,
|
|
8682
8721
|
...(runtime.docGrounding !== undefined ? { grounding: runtime.docGrounding } : {}),
|
|
8683
8722
|
// crew#631: supply the standing roster so doc/demo creates can refuse an unavailable seat.
|
|
8684
8723
|
roster: () => rosterWithStanding(),
|
|
8724
|
+
proposalGrant,
|
|
8725
|
+
actorOf: (req) => actorOf(req).id,
|
|
8685
8726
|
log: (m) => app.log.warn(m),
|
|
8686
8727
|
});
|
|
8728
|
+
// A3: the real `create` launcher (§4.3 steps 2-3): one document and one run per proposal identity.
|
|
8729
|
+
if (realCreate) {
|
|
8730
|
+
const bindings = runtime.docBindings;
|
|
8731
|
+
proposalLaunchers.register('create', new CreateLauncher({
|
|
8732
|
+
bindings,
|
|
8733
|
+
runExists: async (runId) => (await adapter.sessions()).includes(runId),
|
|
8734
|
+
docsRoot: (projectId) => projectDocsRoot(adapter, projectSettings, projectId),
|
|
8735
|
+
createDoc: (projectId, body, actorId) => createDocInProcess(adapter, {
|
|
8736
|
+
settings: projectSettings,
|
|
8737
|
+
pool: interactiveBridges,
|
|
8738
|
+
...(runtime.docGrounding !== undefined ? { grounding: runtime.docGrounding } : {}),
|
|
8739
|
+
roster: () => rosterWithStanding(),
|
|
8740
|
+
proposalGrant,
|
|
8741
|
+
log: (m) => app.log.warn(m),
|
|
8742
|
+
}, projectId, body, actorId),
|
|
8743
|
+
launchBound: runtime.launchBoundDraft,
|
|
8744
|
+
...(runtime.fenceBoundDraft !== undefined ? { fence: runtime.fenceBoundDraft } : {}),
|
|
8745
|
+
records: (chatId) => chatHistory?.messages(chatId) ?? chatTranscripts?.read(chatId) ?? [],
|
|
8746
|
+
instanceOf: (chatId) => chatHistory?.stateOf(chatId)?.instance ?? null,
|
|
8747
|
+
chatIdOf: (chatId, instance) => (chatHistory === null ? chatId : chatHistory.idOfInstance(chatId, instance)),
|
|
8748
|
+
repos: async () => (await adapter.listRepos()).map((r) => ({ id: r.id, name: typeof r.name === 'string' && r.name.trim() !== '' ? r.name.trim() : basename(r.root_path), rootPath: r.root_path })),
|
|
8749
|
+
graphFor: async (projectId, chatId) => {
|
|
8750
|
+
if (projectId === null)
|
|
8751
|
+
return chatScopes.engineOf(chatId)?.codeGraphDb ?? null;
|
|
8752
|
+
const decision = await resolveProjectGraphBinding(adapter, projectId, undefined).catch(() => ({ binding: null }));
|
|
8753
|
+
return decision.binding?.dbPath ?? null;
|
|
8754
|
+
},
|
|
8755
|
+
clisJsonFor: (seats) => {
|
|
8756
|
+
const roster = rosterWithStanding();
|
|
8757
|
+
const picked = seats.map((k) => roster.find((s) => s.key === k));
|
|
8758
|
+
return picked.some((s) => s === undefined) ? null : JSON.stringify(picked);
|
|
8759
|
+
},
|
|
8760
|
+
styleOf: (entry) => {
|
|
8761
|
+
const seed = CATALOG_SEEDS.find((c) => c.id === entry);
|
|
8762
|
+
return seed !== undefined && seed.launch.kind === 'document' ? seed.launch.style : 'web';
|
|
8763
|
+
},
|
|
8764
|
+
packetDeps: {
|
|
8765
|
+
runs: chatContextDeps.runs,
|
|
8766
|
+
brief: (view) => buildRunBrief(view, { workOutput: chatContextDeps.workOutput, ...(chatContextDeps.acceptanceLine !== undefined ? { acceptanceLine: chatContextDeps.acceptanceLine } : {}) }),
|
|
8767
|
+
docsRoot: chatContextDeps.docsRoot,
|
|
8768
|
+
attachment: (chatId, id) => {
|
|
8769
|
+
const hit = chatAttachments.resolve(chatId, [id])[0];
|
|
8770
|
+
return hit === undefined ? null : { name: hit.name, path: hit.path };
|
|
8771
|
+
},
|
|
8772
|
+
// The exact brief a turn was given, from the live chat's scratch root, beneath it (no link followed), only when
|
|
8773
|
+
// its bytes still hash to what the turn recorded (A1's binding). Gone after the chat ends or the daemon restarts.
|
|
8774
|
+
contextBrief: (chatId, relPath, sha) => {
|
|
8775
|
+
const cwd = chatScopes.get(chatId)?.cwd;
|
|
8776
|
+
if (cwd === undefined)
|
|
8777
|
+
return null;
|
|
8778
|
+
try {
|
|
8779
|
+
const data = readBeneath(realpathSync(cwd), relPath, BRIEF_COPY_MAX).data;
|
|
8780
|
+
return sha256Hex(data) === sha ? data : null;
|
|
8781
|
+
}
|
|
8782
|
+
catch {
|
|
8783
|
+
return null;
|
|
8784
|
+
}
|
|
8785
|
+
},
|
|
8786
|
+
},
|
|
8787
|
+
log: (m) => app.log.warn(m),
|
|
8788
|
+
}));
|
|
8789
|
+
}
|
|
8687
8790
|
// ── Governed doc delete (crew#338) — the one door that changes BOTH stores ──
|
|
8688
8791
|
// `DELETE /projects/:id/interactive/docs/:doc` retires the doc on the bridge AND drops crew's
|
|
8689
8792
|
// handoff-ledger rows for it (the draft leg keys by document id, so a stale row claims the
|
|
@@ -8698,6 +8801,13 @@ runtime = {}) {
|
|
|
8698
8801
|
// the operator's real ~/.wicked-crew ledgers. The real sweep always arrives from
|
|
8699
8802
|
// `createServer`.
|
|
8700
8803
|
dropDocLedgerRows: runtime.dropDocLedgerRows ?? (() => ({ ok: true, removed_keys: [] })),
|
|
8804
|
+
// A3: a document a chat proposal is still drafting (or landing) is not retired under it.
|
|
8805
|
+
busyReason: (projectId, doc) => {
|
|
8806
|
+
const pending = runtime.docBindings?.busy(`${projectId === 'default' ? UNFILED_MOUNT : projectId}/${doc}`) ?? null;
|
|
8807
|
+
return pending !== null && (pending.launchingAt !== undefined || pending.launchedAt !== undefined || pending.emittedAt !== undefined)
|
|
8808
|
+
? `a chat proposal is still drafting this document (run ${pending.runId.slice(0, 8)}); wait for it to land, or stop that run first`
|
|
8809
|
+
: null;
|
|
8810
|
+
},
|
|
8701
8811
|
log: (m) => app.log.warn(m),
|
|
8702
8812
|
});
|
|
8703
8813
|
// ── A demo run's video as an editable document (the video editor re-cuts it through E1's per-doc API) ──
|
|
@@ -8776,6 +8886,6 @@ runtime = {}) {
|
|
|
8776
8886
|
const runEvalsPrepare = async (input) => {
|
|
8777
8887
|
await prepareRunEvalsLaunch(input, () => runAndRecord(defaultEvalDeps, { project: null, baseline: false, id: randomUUID(), now: new Date() }), runtime.evalRunsDir);
|
|
8778
8888
|
};
|
|
8779
|
-
return { decideGate, decisions, chatRecorder, considerations, search, decorateRun, runEvalsPrepare, chatProposals };
|
|
8889
|
+
return { decideGate, decisions, chatRecorder, considerations, search, decorateRun, runEvalsPrepare, chatProposals, proposalLaunchers };
|
|
8780
8890
|
}
|
|
8781
8891
|
//# sourceMappingURL=routes.js.map
|