Open Multi-Agent Interactive Classroom — Get an immersive, multi-agent learning experience in just one click
This report summarizes scanner evidence for THU-MAIC/OpenMAIC, a TypeScript project with 42,014 GitHub stars. SynthScan examined 903,115 lines of code across 3549 source files, recording 1604 pattern matches distributed across 13 syntactic categories. The legacy adjusted pattern signal is 2.4 (Low pattern signal); it is not an authorship estimate.
Use the findings to ask whether maintainers can explain intent, verify dependencies, simplify unnecessary scaffolding, and focus review effort. Risk Payload v1 adds ownership, supply-chain, over-engineering, and review-effort vectors when available. These are prompts for human verification, not probabilities, security findings, or measured maintenance costs.
Use each vector to guide manual verification of the underlying findings.
Payload schema: 1.0.0 · Engine: 2.0.0 · Scoring: heuristic-density-v1 · Scan date: 2026-10-31.
Can maintainers explain intent, assumptions, and trade-offs? 1307 finding(s).
Are imports declared and package/API names verified? 137 finding(s).
Are wrappers, guards, and repeated structures necessary? 1250 finding(s).
Which changes need focused human review? 1604 finding(s).
This chart tracks the legacy adjusted pattern score across scan runs. Changes can reflect source changes, scan coverage, or detector/scoring versions; they do not measure AI adoption or prove that a team refactored code. Compare runs only when their scoring versions are compatible. The dashed line tracks the raw pattern-hit count.
Groups findings by configured severity weight. Severity is not a confidence estimate, security rating, or proof that a package is missing. Verify imports against the project's manifests and inspect each finding in its local design context.
This horizontal bar chart shows where configured pattern scores accumulate across directories. Treat the bars as locations to inspect, not as evidence of authorship or code quality. Use the file-level findings to decide whether a directory needs a focused ownership, dependency, complexity, or review check.
The scanner identified 1604 distinct pattern matches across 13 syntactic categories. Each entry below represents a discrete location in the source code where the engine recorded a detector match to inspect in context. Expand any category row to inspect the individual file paths, line numbers, code snippets, and the lexical context (CODE, COMMENT, or STRING) in which each match was detected.
Reading the findings table: The Severity column indicates the configured finding weight (CRITICAL / HIGH / MEDIUM / LOW). The Context column identifies whether the match occurred inside executable code, an inline comment, or a string literal — legacy comment-context matches receive a ×1.5 score weight. The ⚡ bolt icon marks clustered matches: three or more patterns within a 10-line window, each receiving an additional ×1.5 density multiplier under the legacy scoring model.
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | instrumentation.ts | 243 | async function validateBootConfiguration(): Promise<void> { | CODE |
| LOW | render-service/test/support/fakes.ts | 32 | export function createMemoryArtifactStore(): { | CODE |
| LOW | render-service/src/untrusted-html-csp.ts | 106 | function matchesAsciiDoctypePrefix(bytes: Uint8Array, index: number): boolean { | CODE |
| LOW | render-service/src/untrusted-html-csp.ts | 166 | export function injectUntrustedHtmlCspBytes( | CODE |
| LOW | render-service/src/resource-profile.ts | 63 | function requiredProducerEnvironment(profile: ResourceProfile): Record<string, string> { | CODE |
| LOW | render-service/src/resource-profile.ts | 78 | function assertCompatibleEnvironment(profile: ResourceProfile, env: NodeJS.ProcessEnv): void { | CODE |
| LOW | render-service/src/resource-profile.ts | 141 | export function validateResourceProfileStartup( | CODE |
| LOW | render-service/src/preview-katex.ts | 21 | export function resolveKatexDistDirectory(): string { | CODE |
| LOW | render-service/src/preview-validation.ts | 32 | export function invalidSlideCanvasElementError(scene: unknown): string | undefined { | CODE |
| LOW | render-service/src/preview-validation.ts | 55 | export function countNonSelfContainedSlideMediaReferences( | CODE |
| LOW | render-service/src/preview-validation.ts | 133 | export function findNonSelfContainedInteractiveReferences(html: string): string[] { | CODE |
| LOW | render-service/src/chunk-executor.ts | 217 | export function renderChunkInTerminatedProcess( | CODE |
| LOW | render-service/src/chunk-executor.ts | 280 | async function readCompositionDimensions( | CODE |
| LOW | render-service/src/preview-renderer.ts | 137 | export function injectInteractiveStorageShim(html: string): string { | CODE |
| LOW | render-service/src/preview-renderer.ts | 417 | export async function installPreviewRequestGuard(page: Page): Promise<() => void> { | CODE |
| LOW | render-service/src/render-executor.ts | 128 | export function buildRenderExecutionMetrics( | CODE |
| LOW | app/workbench/new/page.tsx | 13 | export default function WorkbenchNewCompatibilityPage() { | CODE |
| LOW | app/api/parse-pdf/route.ts | 130 | async function requestedDocumentProvider( | CODE |
| LOW | app/api/persistence/[...path]/route.ts | 92 | function indirectEgressWithinGrace( | CODE |
| LOW | app/api/persistence/[...path]/route.ts | 501 | async function handlePersistenceRequestInner( | CODE |
| LOW | tests/prosemirror/legacy-inline-math.test.ts | 30 | function htmlAfterOneCharacterEdit(html: string): string { | CODE |
| LOW⚡ | tests/workflows/ci-video-export-contract.test.ts | 82 | function assertMainPushVersionGate(workflow: Workflow): void { | CODE |
| LOW⚡ | tests/workflows/ci-video-export-contract.test.ts | 92 | function assertHyperframesLintContract(workflow: Workflow): void { | CODE |
| LOW⚡ | tests/workflows/ci-video-export-contract.test.ts | 102 | function assertHyperframesGateContract(workflow: Workflow): void { | CODE |
| LOW | tests/workflows/publish-packages-workflow.test.ts | 38 | function assertPublishedVersionHandoff(workflow: Workflow): void { | CODE |
| LOW | tests/server/url-guard-unconditional-invariant.test.ts | 158 | function findNodeEnvGuardedBodyLines(source: string): Set<number> { | CODE |
| LOW | tests/document/mineru-cloud.test.ts | 145 | function patchFirstEntryDeclaredSize(zipBuf: Buffer, declared: number): Buffer { | CODE |
| LOW | tests/pbl/v2/defensive-leaf-readers.test.ts | 16 | function projectWithMalformedOptionalLeaves(): PBLProjectV2 { | CODE |
| LOW | tests/pbl/v2/drain.test.ts | 51 | function deterministicPBLSessionId(stageId = STAGE_ID, learnerKey = LEARNER_KEY): string { | CODE |
| LOW | tests/workbench/draft-conversation-reset.test.ts | 54 | function shouldShowWorkbenchEmptyState(input: { | CODE |
| LOW | tests/workbench/workspace-material-handover.test.ts | 448 | async function uploadOldThenMaybeHandOver(handOver: boolean) { | CODE |
| LOW | tests/ai/openai-provider.test.ts | 26 | async function captureInjectedRequestBody( | CODE |
| LOW | tests/persistence/_material-library-scenarios.ts | 288 | export async function deletedThroughLinkScenario(h: ExtractionHarness): Promise<void> { | CODE |
| LOW | tests/persistence/_material-library-scenarios.ts | 491 | export async function legacyCopyLibraryToolsScenario(h: ExtractionHarness): Promise<void> { | CODE |
| LOW | tests/persistence/_material-library-scenarios.ts | 529 | export async function ownerListingWithSessionCopyScenario(h: ExtractionHarness): Promise<void> { | CODE |
| LOW | tests/persistence/_material-library-scenarios.ts | 551 | export async function sessionListingPaginationScenario(h: ExtractionHarness): Promise<void> { | CODE |
| LOW | tests/persistence/_material-library-scenarios.ts | 627 | export async function listingDerivedFieldsScenario(h: ExtractionHarness): Promise<void> { | CODE |
| LOW | tests/persistence/_material-library-scenarios.ts | 931 | export async function mediaLibraryScopeScenario(h: ExtractionHarness): Promise<void> { | CODE |
| LOW | tests/persistence/_material-library-scenarios.ts | 1011 | export async function releaseRefusedOutputsScenario(h: ExtractionHarness): Promise<void> { | CODE |
| LOW | tests/persistence/_material-library-scenarios.ts | 1380 | export async function documentImageBudgetScenario( | CODE |
| LOW | tests/persistence/_material-library-scenarios.ts | 1440 | export async function documentImagesQuotaScenario(h: ExtractionHarness): Promise<void> { | CODE |
| LOW | tests/persistence/_material-library-scenarios.ts | 1696 | export async function organizeAcrossClaimScenario(h: ExtractionHarness): Promise<void> { | CODE |
| LOW | tests/persistence/_material-library-scenarios.ts | 1723 | export async function watcherNullExtractionScenario(h: ExtractionHarness): Promise<void> { | CODE |
| LOW | tests/persistence/_owner-extraction-scenarios.ts | 367 | export async function uploadQueuesExtractionScenario(h: ExtractionHarness): Promise<void> { | CODE |
| LOW | tests/persistence/_owner-extraction-scenarios.ts | 440 | export async function twoConversationsOneExtractionScenario(h: ExtractionHarness): Promise<void> { | CODE |
| LOW | tests/persistence/_owner-extraction-scenarios.ts | 1032 | export async function schemaCompatibilityScenario(h: ExtractionHarness): Promise<void> { | CODE |
| LOW | tests/persistence/_owner-extraction-scenarios.ts | 1219 | export async function cacheCollectorOrderScenario(h: ExtractionHarness): Promise<void> { | CODE |
| LOW | tests/persistence/_owner-extraction-scenarios.ts | 1276 | export async function sameKeyConcurrentSourcesScenario(h: ExtractionHarness): Promise<void> { | CODE |
| LOW | tests/persistence/_owner-extraction-scenarios.ts | 1325 | export async function claimIntoSameContentScenario(h: ExtractionHarness): Promise<void> { | CODE |
| LOW | tests/persistence/_owner-extraction-scenarios.ts | 1405 | export async function failedImageDownloadScenario(h: ExtractionHarness): Promise<void> { | CODE |
| LOW | tests/persistence/_owner-extraction-scenarios.ts | 1460 | export async function cancelledImageDownloadScenario(h: ExtractionHarness): Promise<void> { | CODE |
| LOW | tests/persistence/_owner-extraction-scenarios.ts | 1576 | export async function sameBytesOtherMimeScenario(h: ExtractionHarness): Promise<void> { | CODE |
| LOW | tests/persistence/_owner-extraction-scenarios.ts | 1625 | export async function lostClaimStopsProvidersScenario(h: ExtractionHarness): Promise<void> { | CODE |
| LOW | tests/persistence/_owner-extraction-scenarios.ts | 1771 | export async function documentServiceUnavailableScenario(h: ExtractionHarness): Promise<void> { | CODE |
| LOW | tests/persistence/_owner-material-upgrade-scenarios.ts | 164 | export async function assetIdEraWithRowsScenario(h: UpgradeHarness): Promise<void> { | CODE |
| LOW | tests/persistence/_owner-material-upgrade-scenarios.ts | 189 | export async function preRootsDropRecoveryScenario(h: UpgradeHarness): Promise<void> { | CODE |
| LOW | tests/persistence/_owner-claim-scenarios.ts | 705 | export async function materialFolderClaimScenario(h: ClaimHarness): Promise<void> { | CODE |
| LOW | tests/persistence/_owner-claim-scenarios.ts | 734 | export async function unfiledOnlyMaterialClaimScenario(h: ClaimHarness): Promise<void> { | CODE |
| LOW | tests/persistence/_owner-claim-scenarios.ts | 749 | export async function emptyFoldersOnlyMaterialClaimScenario(h: ClaimHarness): Promise<void> { | CODE |
| LOW | tests/persistence/_owner-claim-scenarios.ts | 769 | export async function selfReassignMaterialFoldersScenario(h: ClaimHarness): Promise<void> { | CODE |
| 1030 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | openmaic.example.yml | 1 | # ============================================================================= | COMMENT |
| MEDIUM | openmaic.example.yml | 32 | # ============================================================================= | COMMENT |
| MEDIUM | app/page.tsx | 448 | // ─── Folder handlers ──────────────────────────────────────────────── | COMMENT |
| MEDIUM | app/page.tsx | 1970 | // ─── Classroom Card — clean, minimal style ────────────────────── | COMMENT |
| MEDIUM | tests/workbench/stage-freshness-sync.test.ts | 105 | // ── server doubles ────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/workbench/material-library-page.test.ts | 276 | // ── Reading and showing ──────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/workbench/material-library-page.test.ts | 533 | // ── Staying fresh (option B) on the page ─────────────────────────────────── | COMMENT |
| MEDIUM | tests/workbench/material-library-page.test.ts | 683 | // ── Leaving ──────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/workbench/material-library-page.test.ts | 697 | // ── Uploading ────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/workbench/material-library-page.test.ts | 848 | // ── New folder, inline ───────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/workbench/material-library-page.test.ts | 1176 | // ── Folder rows ──────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/workbench/material-library-page.test.ts | 1213 | // ── Renaming in place ────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/workbench/material-library-page.test.ts | 1666 | // ── Out of a folder, and the rows' columns (#1835 review §2, §3) ────────── | COMMENT |
| MEDIUM | tests/workbench/material-library-page.test.ts | 1666 | // ── Out of a folder, and the rows' columns (#1835 review §2, §3) ────────── | COMMENT |
| MEDIUM | tests/workbench/material-library-page.test.ts | 1712 | // ── The original, and Move to… (#1835 teacher feedback 3, review §6) ────── | COMMENT |
| MEDIUM | tests/workbench/material-library-page.test.ts | 1712 | // ── The original, and Move to… (#1835 teacher feedback 3, review §6) ────── | COMMENT |
| MEDIUM | tests/workbench/material-library-page.test.ts | 1852 | // ── Deleting ─────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/workbench/material-library-tree.test.ts | 19 | // ── A paging server ──────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/workbench/material-library-tree.test.ts | 130 | // ── The hook, mounted ────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/workbench/material-library-tree.test.ts | 236 | // ── T1–T3: reading the tree ──────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/workbench/material-library-tree.test.ts | 302 | // ── T4–T7: refreshing ────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/workbench/material-library-tree.test.ts | 402 | // ── T8–T10c: the teacher acts while reads are on their way ───────────────── | COMMENT |
| MEDIUM | tests/workbench/material-library-tree.test.ts | 509 | // ── T11–T12: search ──────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/workbench/material-library-tree.test.ts | 562 | // ── T14–T15: polling and runs ────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/workbench/material-library-tree.test.ts | 642 | // ── T16–T19: one refresh per return, nothing real swallowed ──────────────── | COMMENT |
| MEDIUM | tests/workbench/material-library-tree.test.ts | 728 | // ── T20: leaving the page ────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/workbench/material-library-tree.test.ts | 751 | // ── T21–T22: review of R2 ───────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/web-search/claude.test.ts | 3 | // ── AI SDK mocks ────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/web-search/claude.test.ts | 72 | // ── fetch interceptor: allowed_callers injection ────────────────────────── | COMMENT |
| MEDIUM | tests/web-search/claude.test.ts | 155 | // ── model + tool selection ───────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/web-search/claude.test.ts | 232 | // ── provider configuration ──────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/web-search/claude.test.ts | 294 | // ── result mapping ───────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/web-search/claude.test.ts | 372 | // ── errors ───────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/export/classroom-zip.test.ts | 12 | // ─── rewriteAudioRefsToIds ──────────────────────────────────── | COMMENT |
| MEDIUM | tests/export/classroom-zip.test.ts | 83 | // ─── actionsToManifest ──────────────────────────────────────── | COMMENT |
| MEDIUM | tests/export/classroom-zip.test.ts | 170 | // ─── Manifest round-trip ────────────────────────────────────── | COMMENT |
| MEDIUM | tests/media/resolve-stored-bytes-equivalence.test.ts | 92 | // ─── Frozen @ e1578083 — lib/export/classroom-zip-utils.ts ────────────────── | COMMENT |
| MEDIUM | tests/media/resolve-stored-bytes-equivalence.test.ts | 107 | // ─── Frozen @ e1578083 — lib/export/use-export-pptx.ts ────────────────────── | COMMENT |
| MEDIUM | tests/media/resolve-stored-bytes-equivalence.test.ts | 194 | // ─── Frozen @ e1578083 — lib/video-export-app/collect.ts ──────────────────── | COMMENT |
| MEDIUM | tests/media/resolve-stored-bytes-equivalence.test.ts | 264 | // ─── Matrix ───────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | tests/media/resolve-stored-bytes-equivalence.test.ts | 396 | // ─── Recording rig ────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/scene-renderers/quiz-view.tsx | 45 | // ─── Types ────────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/scene-renderers/quiz-view.tsx | 141 | // ─── Sub-components ───────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/scene-renderers/quiz-view.tsx | 691 | // ─── Main Component ───────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/chat/inline-action-tag.tsx | 32 | // ── Style tokens ────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/chat/inline-action-tag.tsx | 47 | // ── Action config ───────────────────────────────────────────── | COMMENT |
| MEDIUM | components/chat/inline-action-tag.tsx | 83 | // ── Component ───────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/edit/AgentsView/AgentRosterPanel.tsx | 47 | // ─── Avatar with camera overlay ────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/edit/AgentsView/AgentRosterPanel.tsx | 86 | // ─── Inline editable name ──────────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/edit/AgentsView/AgentRosterPanel.tsx | 156 | // ─── Persona textarea ───────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/edit/AgentsView/AgentRosterPanel.tsx | 219 | // ─── Teacher card ───────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/edit/AgentsView/AgentRosterPanel.tsx | 317 | // ─── Classmate card ──────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/edit/AgentsView/AgentRosterPanel.tsx | 475 | // ─── Main panel ─────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/workbench/compose-extras.tsx | 37 | // ── Skills (the `/` and composer `+` menus) ────────────────────────────────── | COMMENT |
| MEDIUM | components/workbench/compose-extras.tsx | 256 | // ── Materials ──────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/workbench/chat/tool-presentation.ts | 125 | // ── Small helpers ──────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/workbench/chat/tool-presentation.ts | 264 | // ── The rule table ─────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/workbench/chat/tool-presentation.ts | 511 | // ── The web ────────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/workbench/chat/tool-presentation.ts | 677 | // ── The plan ───────────────────────────────────────────────────────────── | COMMENT |
| MEDIUM | components/workbench/chat/tool-presentation.ts | 678 | // ── One page ───────────────────────────────────────────────────────────── | COMMENT |
| 100 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | openmaic.example.yml | 1 | # ============================================================================= | COMMENT |
| LOW | openmaic.example.yml | 21 | # - slots: which provider and model each use of AI gets by default. Users | COMMENT |
| LOW | openmaic.example.yml | 41 | COMMENT | |
| LOW | openmaic.example.yml | 61 | # Without voices/options.defaultVoice the built-in behavior is unchanged. | COMMENT |
| LOW | openmaic.example.yml | 81 | # apiKey: ${IMAGE_GLM_API_KEY} | COMMENT |
| LOW | openmaic.example.yml | 101 | # accessKeySecret: ${ALIDOCMIND_ACCESS_KEY_SECRET} | COMMENT |
| LOW | openmaic.example.yml | 121 | # model: openai:gpt-5.5 | COMMENT |
| LOW | docker-compose.db.yml | 1 | # Local development database: `pnpm db:up` / `pnpm db:down`. | COMMENT |
| LOW | docker-compose.yml | 41 | # The address the port above is published on, passed in so the app can | COMMENT |
| LOW | docker-compose.yml | 81 | test: ['CMD-SHELL', 'pg_isready -U openmaic -d openmaic'] | COMMENT |
| LOW | instrumentation.ts | 21 | COMMENT | |
| LOW | instrumentation.ts | 241 | * checks in `validateServerConfig`) are not here and never stop the process. | COMMENT |
| LOW | instrumentation.ts | 261 | // MODEL_ROUTES left without openmaic.yml, rather than discovered by the | COMMENT |
| LOW | instrumentation.ts | 281 | const { resolveAssetPendingTtlMs } = await import('@/lib/persistence/asset-pending-ttl'); | COMMENT |
| LOW | instrumentation.ts | 301 | // const { configurePersistenceHooks, configureAssetByteStore } = | COMMENT |
| LOW | next.config.ts | 21 | // sharp's native libvips libraries are loaded via dlopen and are not | COMMENT |
| LOW | render-service/docker-entrypoint.sh | 1 | #!/bin/sh | COMMENT |
| LOW | render-service/scripts/egress-smoke.sh | 1 | #!/bin/sh | COMMENT |
| LOW | app/layout.tsx | 21 | COMMENT | |
| LOW | app/api/persistence/[...path]/route.ts | 241 | // One identity for all three contracts, resolved server-side by the owner | COMMENT |
| LOW | tests/persistence/document-asset-references.pg.test.ts | 481 | const stamped = await lifecycle(assetId); | COMMENT |
| LOW | tests/lib/chat/pi/prompts.test.ts | 761 | const large = build(50000); | COMMENT |
| LOW | tests/media/proxy-media-cache.test.ts | 581 | // …and reads the COMPLETE body, byte-identical. | COMMENT |
| LOW | tests/media/resolve-stored-bytes-equivalence.test.ts | 601 | } | COMMENT |
| LOW | …ts/media/workbench-video-completion-resolution.test.ts | 201 | expectedMediaRef: undefined, | COMMENT |
| LOW | components/stage.tsx | 101 | // The provider is the host boundary. Session state intentionally does not | COMMENT |
| LOW | components/stage.tsx | 281 | // will mount fresh; its engine effect re-inits). Playback→edit must | COMMENT |
| LOW | components/stage.tsx | 381 | // Deliberately NO transform (translateY) on these layers: the edit | COMMENT |
| LOW | components/scene-renderers/classroom-complete.tsx | 361 | const trailItems = TYPE_ORDER.filter((type) => (summary.countsByType[type] ?? 0) > 0).map( | COMMENT |
| LOW | components/scene-renderers/classroom-complete.tsx | 381 | // container" both ways, we'd ping-pong between the two layouts (compact | COMMENT |
| LOW | components/scene-renderers/pbl-renderer.tsx | 81 | readonly sceneId: string; | COMMENT |
| LOW | components/scene-renderers/pbl-renderer.tsx | 101 | // blank during native fullscreen. Default to <body> (classroom is an | COMMENT |
| LOW | components/scene-renderers/pbl-renderer.tsx | 121 | // chat. Transient by design: a full page reload ends the streams and resets | COMMENT |
| LOW | components/scene-renderers/pbl/v2/hero.tsx | 161 | }; | COMMENT |
| LOW | components/scene-renderers/pbl/v2/hero.tsx | 181 | // Instructor mentor. The subtitle is a short fixed tagline (mirroring | COMMENT |
| LOW | components/scene-renderers/pbl/v2/workspace.tsx | 121 | const [taskBusy, setTaskBusy] = useState(false); | COMMENT |
| LOW | components/scene-renderers/pbl/v2/chat.tsx | 241 | // wrapup) is fired path-independently by the scenario stage-opener | COMMENT |
| LOW | components/edit/EditChromeRoot.tsx | 81 | // Safety net: the editor chunk (slide + quiz surface registration) is | COMMENT |
| LOW | components/edit/PlaybackChromeRoot.tsx | 1861 | // isDiscussionPaused value (e.g. voice input's onTranscription callback | COMMENT |
| LOW | components/edit/SlideNavRail/SlideNavRail.tsx | 61 | const insertSceneAfter = useStageStore.use.insertSceneAfter(); | COMMENT |
| LOW | components/edit/SlideNavRail/SlideNavRail.tsx | 301 | : prefersReducedMotion | COMMENT |
| LOW | components/edit/surfaces/slide/ElementPickLayer.tsx | 301 | // re-shape it — neither fires a window resize, but the portaled box tracks | COMMENT |
| LOW | components/edit/ActionsBar/ActionsBar.tsx | 1041 | const sceneOrder = scene?.order ?? 0; | COMMENT |
| LOW | components/workbench/WorkbenchChat.tsx | 981 | replaceDraft(''); | COMMENT |
| LOW | …ide-renderer/components/element/ImageElement/index.tsx | 41 | const { clipShape, imgPosition } = useClipImage(elementInfo); | COMMENT |
| LOW | …er/Editor/Canvas/hooks/useInsertFromCreateSelection.ts | 81 | const insertElementFromCreateSelection = useCallback( | COMMENT |
| LOW | packages/@openmaic/renderer/src/snapshot/index.ts | 141 | completeInlineMath(container); | COMMENT |
| LOW | packages/@openmaic/renderer/src/snapshot/index.ts | 201 | // attribute and renders nothing for an undecoded source), so a video that | COMMENT |
| LOW | packages/@openmaic/renderer/src/snapshot/index.ts | 221 | console.debug('[slideToPng] container ready', { | COMMENT |
| LOW | …s/@openmaic/importer/src/serializer/shapeSerializer.ts | 341 | tailEnd: LineEndInfo | undefined, | COMMENT |
| LOW | …es/@openmaic/importer/src/serializer/textSerializer.ts | 361 | // OOXML spcPct: 100000 = "single spacing" = 1.0× the font's line height. | COMMENT |
| LOW | …es/@openmaic/importer/src/serializer/textSerializer.ts | 1501 | // 由 -indent 合成 marL」的情形 marL==|indent|,取值不变、不受影响。 | COMMENT |
| LOW | …es/@openmaic/importer/src/serializer/textSerializer.ts | 1561 | // paragraphs need no <br/> — the wrapper <div> already has a fixed line | COMMENT |
| LOW | packages/@openmaic/importer/src/shapes/presets.ts | 4641 | // center = (g22-g17, g20) = (g22-g17, g20), endpoint = (g22-g17, g20+g17) | COMMENT |
| LOW | packages/@openmaic/importer/src/shapes/presets.ts | 4661 | // endY = (g10-g17)+g17*sin(180°) = g10-g17 = g20 | COMMENT |
| LOW | …aic/storage/test/agent-session-concurrency-contract.ts | 141 | // This is a result-consistency probe, not a deadlock probe. Every | COMMENT |
| LOW | …kages/@openmaic/storage/test/pg-asset-store.pg.test.ts | 1421 | // entry row unchanged -- so no EvalPlanQual -- and keeps its own | COMMENT |
| LOW | packages/@openmaic/storage/src/asset/collector.ts | 521 | // whole shape of the block below. The blob pass is correct with or without | COMMENT |
| LOW | packages/@openmaic/storage/src/asset/collector.ts | 581 | // pass leaves behind, and this one cannot starve a blob: every blob is | COMMENT |
| LOW | packages/@openmaic/storage/src/asset/collector.ts | 981 | const stageRow = stage.rows[0]; | COMMENT |
| 89 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | tests/classroom/restored-video-resolution.test.ts | 182 | expect(resolution).toEqual({ kind: 'placeholder' }); | CODE |
| LOW | tests/workbench/material-mention.test.ts | 778 | .getAttribute('placeholder'); | CODE |
| LOW | tests/workbench/media-lifecycle.test.ts | 79 | expect(resolveMediaRef(binding.sourceRef, binding.task).kind).toBe('placeholder'); | CODE |
| LOW | tests/hooks/use-slide-background-style.test.ts | 7 | resolution: { kind: 'placeholder' } as { kind: 'placeholder' } | { kind: 'url'; url: string }, | CODE |
| LOW | tests/hooks/use-slide-background-style.test.ts | 46 | mocks.resolution = { kind: 'placeholder' }; | CODE |
| LOW | tests/slide-renderer/screen-canvas-renderer.test.ts | 312 | expect(getPlaybackImageState({ kind: 'placeholder' })).toBe('pending'); | CODE |
| LOW | tests/slide-renderer/use-resolved-image-src.test.ts | 54 | expect(r.resolution).toEqual({ kind: 'placeholder' }); | CODE |
| LOW | tests/slide-renderer/use-resolved-image-src.test.ts | 110 | expect(r.resolution).toEqual({ kind: 'placeholder' }); | CODE |
| LOW | tests/slide-renderer/use-resolved-image-src.test.ts | 122 | expect(r.resolution).toEqual({ kind: 'placeholder' }); | CODE |
| LOW | tests/slide-renderer/use-resolved-image-src.test.ts | 149 | expect(r.resolution).toEqual({ kind: 'placeholder' }); | CODE |
| LOW | tests/video-export/interactive.test.ts | 63 | base: { kind: 'placeholder', reason: expect.stringContaining('missing') }, | CODE |
| LOW | tests/video-export/interactive.test.ts | 91 | kind: 'placeholder', | CODE |
| LOW | tests/video-export/visuals.test.ts | 597 | base: { kind: 'placeholder' }, | CODE |
| LOW | tests/export/pptx-scene-placeholders.test.ts | 351 | if (packEntry.kind !== 'placeholder' || standaloneEntry.kind !== 'placeholder') { | CODE |
| LOW | tests/export/pptx-scene-placeholders.test.ts | 365 | if (quiz.kind !== 'placeholder') throw new Error('expected placeholder'); | CODE |
| LOW | tests/export/pptx-scene-placeholders.test.ts | 510 | if (first.kind !== 'placeholder') throw new Error('expected placeholder'); | CODE |
| LOW | tests/export/pptx-scene-placeholders.test.ts | 668 | if (entry.kind !== 'placeholder') throw new Error('expected placeholder'); | CODE |
| LOW | tests/export/pptx-scene-placeholders.test.ts | 763 | if (entry.kind !== 'placeholder') throw new Error('expected placeholder'); | CODE |
| LOW | tests/import/import-media-assets.test.ts | 461 | { id: 'placeholder', type: 'image', src: 'gen_img_waiting' }, | CODE |
| LOW | tests/agent-runtime/dsl-tools.test.ts | 509 | const rejected = await patch.execute('placeholder', { | CODE |
| LOW | tests/media/resolve-media-ref.test.ts | 121 | expected: { kind: 'placeholder' }, | CODE |
| LOW | tests/media/resolve-media-ref.test.ts | 141 | expected: { kind: 'placeholder' }, | CODE |
| LOW | tests/media/resolve-media-ref.test.ts | 188 | kind: 'placeholder', | CODE |
| LOW | tests/media/resolve-media-ref.test.ts | 197 | { kind: 'placeholder' } as const, | CODE |
| LOW | tests/media/media-resolution-surface-matrix.test.ts | 167 | if (resolution.kind === 'pending' || resolution.kind === 'placeholder') return 'skeleton'; | CODE |
| LOW | tests/media/media-resolution-surface-matrix.test.ts | 422 | expect(markup).not.toContain('placeholder'); | CODE |
| LOW | components/whiteboard/whiteboard-canvas.tsx | 366 | key="placeholder" | CODE |
| LOW | components/slide-renderer/SlideThumbnail.tsx | 59 | media?.resolution.kind === 'pending' || media?.resolution.kind === 'placeholder'; | CODE |
| LOW | components/slide-renderer/SlideThumbnail.tsx | 146 | if (media?.resolution.kind === 'pending' || media?.resolution.kind === 'placeholder') { | CODE |
| LOW | …ide-renderer/components/element/VideoElement/index.tsx | 71 | {resolution.kind === 'pending' || resolution.kind === 'placeholder' ? ( | CODE |
| LOW | …r/components/element/VideoElement/BaseVideoElement.tsx | 50 | const showSkeleton = resolution.kind === 'pending' || resolution.kind === 'placeholder'; | CODE |
| LOW | …ide-renderer/components/element/ImageElement/index.tsx | 158 | {resolution.kind === 'pending' || resolution.kind === 'placeholder' ? ( | CODE |
| LOW | …r/components/element/ImageElement/BaseImageElement.tsx | 37 | const showSkeleton = resolution.kind === 'pending' || resolution.kind === 'placeholder'; | CODE |
| LOW | …ponents/slide-renderer/Editor/RendererScreenCanvas.tsx | 43 | media?.resolution.kind === 'pending' || media?.resolution.kind === 'placeholder'; | CODE |
| LOW | …ponents/slide-renderer/Editor/RendererScreenCanvas.tsx | 193 | if (resolution.kind === 'pending' || resolution.kind === 'placeholder') return 'pending'; | CODE |
| LOW | …ponents/slide-renderer/Editor/RendererScreenCanvas.tsx | 212 | const state = getPlaybackImageState(media?.resolution ?? { kind: 'placeholder' }); | CODE |
| LOW | packages/pptxgenjs/types/index.d.ts | 817 | 'placeholder' = 'placeholder', | CODE |
| LOW | packages/pptxgenjs/src/gen-objects.ts | 77 | else if (MASTER_OBJECTS[key] && key === 'placeholder') { | CODE |
| LOW | packages/pptxgenjs/src/gen-objects.ts | 1050 | item => item._type === 'placeholder' && item.options && item.options.placeholder && item.options.placeholder === it | CODE |
| LOW | packages/pptxgenjs/src/gen-xml.ts | 423 | strSlideXml += `<p:nvPr>${slideItemObj._type === 'placeholder' ? genXmlPlaceholder(slideItemObj) : genXmlPlaceholder | CODE |
| LOW | packages/pptxgenjs/src/gen-xml.ts | 1229 | else if (slideObj._type === 'placeholder') strSlideXml += `<a:lstStyle>${genXmlParagraphProperties(slideObj, true)}</a | CODE |
| LOW | packages/pptxgenjs/src/core-enums.ts | 729 | 'placeholder' = 'placeholder', | CODE |
| LOW | packages/pptxgenjs/src/core-enums.ts | 738 | 'placeholder' = 'placeholder', | CODE |
| LOW | lib/chat/pi/element-reference.ts | 1392 | 'placeholder', | CODE |
| LOW | lib/video-export/compile.ts | 94 | scene.base.kind === 'placeholder' && scene.base.reason | CODE |
| LOW | lib/video-export/compile.ts | 105 | base: { ...scene.base, kind: 'placeholder', reason }, | CODE |
| LOW | lib/video-export/ir.ts | 121 | kind: z.literal('placeholder'), | CODE |
| LOW | lib/video-export/passes/interactive.ts | 54 | return { ...timeline, base: { kind: 'placeholder', reason } }; | CODE |
| LOW | lib/video-export/passes/timeline.ts | 134 | base: { kind: supported ? 'slide-snapshot' : 'placeholder' }, | CODE |
| LOW | lib/video-export/emit-hyperframes/index.ts | 292 | : scene.base.kind === 'placeholder' | CODE |
| LOW | lib/export/pptx-scene-placeholders.ts | 107 | | { kind: 'placeholder'; placeholder: ScenePlaceholder }; | CODE |
| LOW | lib/export/pptx-scene-placeholders.ts | 259 | kind: 'placeholder', | CODE |
| LOW | lib/export/pptx-scene-placeholders.ts | 286 | kind: 'placeholder', | CODE |
| LOW | lib/export/pptx-scene-placeholders.ts | 313 | kind: 'placeholder', | CODE |
| LOW | lib/export/use-export-pptx.ts | 568 | if (entry.kind === 'placeholder') { | CODE |
| LOW | lib/i18n/workbench-locales/ko-KR.json | 33 | "placeholder": "답변을 적어 주세요", | CODE |
| LOW | lib/i18n/workbench-locales/ja-JP.json | 33 | "placeholder": "回答を入力", | CODE |
| LOW | lib/i18n/workbench-locales/ar-SA.json | 33 | "placeholder": "اكتب إجابتك", | CODE |
| LOW | lib/i18n/workbench-locales/pt-BR.json | 33 | "placeholder": "Escreva sua resposta", | CODE |
| LOW | lib/i18n/workbench-locales/de-DE.json | 33 | "placeholder": "Schreibe deine Antwort", | CODE |
| 68 more matches not shown… | ||||
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| CRITICAL | tests/video-export/video-render-cache.test.ts | 122 | expect(mocks.toast.loading.mock.calls.some(([key]) => key === 'export.videoCompiling')).toBe( | CODE |
| CRITICAL | …lide-renderer/components/element/ProsemirrorEditor.tsx | 179 | const mark = editorView.current.state.schema.marks.fontname.create({ | CODE |
| CRITICAL | …lide-renderer/components/element/ProsemirrorEditor.tsx | 185 | const mark = editorView.current.state.schema.marks.fontsize.create({ | CODE |
| CRITICAL | …lide-renderer/components/element/ProsemirrorEditor.tsx | 198 | const mark = editorView.current.state.schema.marks.fontsize.create({ | CODE |
| CRITICAL⚡ | …lide-renderer/components/element/ProsemirrorEditor.tsx | 211 | const mark = editorView.current.state.schema.marks.fontsize.create({ | CODE |
| CRITICAL⚡ | …lide-renderer/components/element/ProsemirrorEditor.tsx | 220 | const mark = editorView.current.state.schema.marks.forecolor.create({ | CODE |
| CRITICAL⚡ | …lide-renderer/components/element/ProsemirrorEditor.tsx | 230 | const mark = editorView.current.state.schema.marks.backcolor.create({ | CODE |
| CRITICAL | …lide-renderer/components/element/ProsemirrorEditor.tsx | 330 | const mark = editorView.current.state.schema.marks.link.create({ | CODE |
| CRITICAL | …lide-renderer/components/element/ProsemirrorEditor.tsx | 348 | const mark = editorView.current.state.schema.marks.link.create({ | CODE |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | CHANGELOG.md | 870 | - **Video export (MP4)** — Export a lesson as a rendered video: a `VideoTimeline` IR with a pure compile pipeline [#913] | CODE |
| MEDIUM | README.md | 50 | - **2026-09-24** — [v1.1.0](https://github.com/THU-MAIC/OpenMAIC/releases/tag/v1.1.0): agentic classroom chat (ask about | CODE |
| MEDIUM | tests/pbl/v2/completion-stats.test.ts | 178 | // When the scored coverage is present, the read-only scaffold fallback | COMMENT |
| MEDIUM | tests/pbl/v2/completion-stats.test.ts | 218 | // The structured review survives as an unscored scaffold. | COMMENT |
| MEDIUM | tests/pbl/v2/completion-stats.test.ts | 845 | const p = rpProjectWithGoals(); // scaffold has 2 goals for ms-rp | CODE |
| MEDIUM | tests/pbl/v2/planner.test.ts | 487 | // We can't run the full agentic loop without an LLM, but the | COMMENT |
| MEDIUM | tests/pbl/v2/instructor.test.ts | 728 | // resolves '' → intermediate, so the scaffold label + release threshold | COMMENT |
| MEDIUM | tests/web-search/firecrawl.test.ts | 26 | description: ' ## OpenMAIC\n\nOpen multi-agent interactive classroom. ', | CODE |
| MEDIUM | tests/web-search/firecrawl.test.ts | 75 | content: '## OpenMAIC Open multi-agent interactive classroom.', | CODE |
| MEDIUM | …c/generation/prompts-pbl/planner-single-call-system.md | 66 | 9. **Hints and descriptions GUIDE, never SOLVE — the #1 failure.** A hint or `description` must NEVER contain the litera | CODE |
| MEDIUM | lib/pbl/v2/agents/evaluator.ts | 296 | // scaffold. The guard keeps normal projects completely out of this path | COMMENT |
| MEDIUM | lib/pbl/v2/agents/instructor.ts | 477 | // During a stage-synthesis checkpoint the scaffold verdict is noise: | COMMENT |
| MEDIUM | lib/pbl/v2/agents/planner.ts | 152 | // The agentic loop. The Planner emits tool calls until | COMMENT |
| MEDIUM | lib/pbl/v2/operations/runtime/completion-stats.ts | 236 | // act, with a goals array of exactly the scaffold's length. A mismatch | COMMENT |
| MEDIUM | lib/pbl/v2/operations/runtime/completion-stats.ts | 318 | // alignment gate), still surface the authored act→goal scaffold read-only so | COMMENT |
| MEDIUM | lib/pbl/v2/operations/runtime/completion-stats.ts | 320 | // Mutually exclusive with goalCoverage; omitted when the scaffold is empty. | COMMENT |
| MEDIUM | lib/pbl/v2/operations/runtime/eval-prompts.ts | 465 | // the very same scaffold. This drives the "what you accomplished" credit and | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | …@openmaic/generation/templates/slide-content/system.md | 552 | #### Step 1: Design the background shape first | COMMENT |
| LOW | …@openmaic/generation/templates/slide-content/system.md | 563 | #### Step 2: Calculate text dimensions | COMMENT |
| LOW | …@openmaic/generation/templates/slide-content/system.md | 572 | #### Step 3: Center the text inside the shape | COMMENT |
| LOW⚡ | packages/@openmaic/generation/src/action-parser.ts | 48 | // Step 1: Strip markdown code fences if present | COMMENT |
| LOW⚡ | packages/@openmaic/generation/src/action-parser.ts | 51 | // Step 2: Find the JSON array range | COMMENT |
| LOW | packages/@openmaic/generation/src/action-parser.ts | 62 | // Step 3: Parse — try JSON.parse first, then jsonrepair, fallback to partial-json | COMMENT |
| LOW | packages/@openmaic/generation/src/action-parser.ts | 89 | // Step 4: Convert items to Action[] | COMMENT |
| LOW⚡ | packages/@openmaic/generation/src/action-parser.ts | 132 | // Step 5: Post-processing — discussion must be the last action, and at most one | COMMENT |
| LOW⚡ | packages/@openmaic/generation/src/action-parser.ts | 138 | // Step 6: Filter out slide-only actions for non-slide scenes (defense in depth) | COMMENT |
| LOW⚡ | packages/@openmaic/generation/src/action-parser.ts | 148 | // Step 7: Filter by allowedActions whitelist (defense in depth for role-based isolation) | COMMENT |
| LOW | lib/chat/structured-output.ts | 134 | // Step 1: Find the opening `[` if not yet found | COMMENT |
| LOW⚡ | lib/chat/structured-output.ts | 145 | // Step 2: Check if the array is complete (closing `]` found) | COMMENT |
| LOW⚡ | lib/chat/structured-output.ts | 149 | // Step 3: Try incremental parse — jsonrepair first (fixes unescaped quotes), fallback to partial-json | COMMENT |
| LOW | lib/chat/structured-output.ts | 170 | // Step 4: Determine how many items are fully complete | COMMENT |
| LOW | lib/chat/structured-output.ts | 184 | // Step 5: Emit newly completed items | COMMENT |
| LOW | lib/chat/structured-output.ts | 218 | // Step 6: Stream partial text delta for the trailing item | COMMENT |
| LOW | lib/chat/structured-output.ts | 230 | // Step 7: Mark done if array is closed | COMMENT |
| LOW | lib/pdf/mineru-cloud.ts | 518 | // Step 1: Create batch — request presigned upload URL | COMMENT |
| LOW | lib/pdf/mineru-cloud.ts | 557 | // Step 2: Upload document to presigned URL | COMMENT |
| LOW | lib/pdf/mineru-cloud.ts | 590 | // Step 3: Poll for completion | COMMENT |
| LOW | lib/audio/asr-providers.ts | 44 | * // Step 1: Upload audio file | COMMENT |
| LOW | lib/audio/asr-providers.ts | 69 | * // Step 2: Request transcription | COMMENT |
| LOW | lib/audio/asr-providers.ts | 84 | * // Step 3: Poll for completion | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW⚡ | packages/@openmaic/generation/src/action-parser.ts | 48 | // Step 1: Strip markdown code fences if present | COMMENT |
| LOW⚡ | packages/@openmaic/generation/src/action-parser.ts | 51 | // Step 2: Find the JSON array range | COMMENT |
| LOW | packages/@openmaic/generation/src/action-parser.ts | 62 | // Step 3: Parse — try JSON.parse first, then jsonrepair, fallback to partial-json | COMMENT |
| LOW | packages/@openmaic/generation/src/action-parser.ts | 89 | // Step 4: Convert items to Action[] | COMMENT |
| LOW⚡ | packages/@openmaic/generation/src/action-parser.ts | 132 | // Step 5: Post-processing — discussion must be the last action, and at most one | COMMENT |
| LOW⚡ | packages/@openmaic/generation/src/action-parser.ts | 138 | // Step 6: Filter out slide-only actions for non-slide scenes (defense in depth) | COMMENT |
| LOW⚡ | packages/@openmaic/generation/src/action-parser.ts | 148 | // Step 7: Filter by allowedActions whitelist (defense in depth for role-based isolation) | COMMENT |
| LOW | lib/chat/structured-output.ts | 134 | // Step 1: Find the opening `[` if not yet found | COMMENT |
| LOW⚡ | lib/chat/structured-output.ts | 145 | // Step 2: Check if the array is complete (closing `]` found) | COMMENT |
| LOW⚡ | lib/chat/structured-output.ts | 149 | // Step 3: Try incremental parse — jsonrepair first (fixes unescaped quotes), fallback to partial-json | COMMENT |
| LOW | lib/chat/structured-output.ts | 170 | // Step 4: Determine how many items are fully complete | COMMENT |
| LOW | lib/chat/structured-output.ts | 184 | // Step 5: Emit newly completed items | COMMENT |
| LOW | lib/chat/structured-output.ts | 218 | // Step 6: Stream partial text delta for the trailing item | COMMENT |
| LOW | lib/chat/structured-output.ts | 230 | // Step 7: Mark done if array is closed | COMMENT |
| LOW | lib/pdf/mineru-cloud.ts | 518 | // Step 1: Create batch — request presigned upload URL | COMMENT |
| LOW | lib/pdf/mineru-cloud.ts | 557 | // Step 2: Upload document to presigned URL | COMMENT |
| LOW | lib/pdf/mineru-cloud.ts | 590 | // Step 3: Poll for completion | COMMENT |
| LOW | lib/audio/asr-providers.ts | 44 | * // Step 1: Upload audio file | COMMENT |
| LOW | lib/audio/asr-providers.ts | 69 | * // Step 2: Request transcription | COMMENT |
| LOW | lib/audio/asr-providers.ts | 84 | * // Step 3: Poll for completion | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| HIGH | lib/legacy-browser-storage/schema.ts | 308 | // Version 8: Add generatedAgents table for AI-generated agent profiles | COMMENT |
| HIGH | lib/types/generation.ts | 155 | // AI-generated media requests (when PDF images are insufficient) | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | packages/@openmaic/generation/src/pbl/planner-core.ts | 161 | // a BCP-47 locale or a nuanced directive like "中文为主,英文技术术语保留原文". | COMMENT |
| MEDIUM | lib/web-search/brave.ts | 80 | // robust to that (and a future) swap; the title text is stripped of tags | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | components/slide-renderer/Editor/Canvas/index.tsx | 263 | // TODO: implement insertCustomShape | COMMENT |
| LOW | …mponents/slide-renderer/Editor/Canvas/hooks/useDrop.ts | 18 | // TODO: implement createTextElement | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| MEDIUM | lib/model-settings/client.ts | 282 | /** Whether the workspace has a language model: the effective `llm` is assigned. */ | COMMENT |
| Severity | File | Line | Snippet | Context |
|---|---|---|---|---|
| LOW | scripts/ci-run-parallel.sh | 5 | # Usage: | COMMENT |