@agimon-ai/doompi-author 0.0.1-alpha.2
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/LICENSE +21 -0
- package/README.md +37 -0
- package/dist/_virtual/_rolldown/runtime.cjs +1 -0
- package/dist/adapters/authorApi.cjs +2 -0
- package/dist/adapters/authorApi.cjs.map +1 -0
- package/dist/adapters/authorBridgeApi.cjs +2 -0
- package/dist/adapters/authorBridgeApi.cjs.map +1 -0
- package/dist/adapters/authorDocumentApi.cjs +2 -0
- package/dist/adapters/authorDocumentApi.cjs.map +1 -0
- package/dist/adapters/pi/authorBridgeClient.cjs +2 -0
- package/dist/adapters/pi/authorBridgeClient.cjs.map +1 -0
- package/dist/adapters/pi/authorTools.cjs +2 -0
- package/dist/adapters/pi/authorTools.cjs.map +1 -0
- package/dist/adapters/pi/extension.cjs +2 -0
- package/dist/adapters/pi/extension.cjs.map +1 -0
- package/dist/adapters/structuredDocuments/common.cjs +2 -0
- package/dist/adapters/structuredDocuments/common.cjs.map +1 -0
- package/dist/adapters/structuredDocuments/csv.cjs +7 -0
- package/dist/adapters/structuredDocuments/csv.cjs.map +1 -0
- package/dist/adapters/structuredDocuments/index.cjs +2 -0
- package/dist/adapters/structuredDocuments/index.cjs.map +1 -0
- package/dist/adapters/structuredDocuments/markdownSlides.cjs +6 -0
- package/dist/adapters/structuredDocuments/markdownSlides.cjs.map +1 -0
- package/dist/adapters/structuredDocuments/ooxmlArchive.cjs +2 -0
- package/dist/adapters/structuredDocuments/ooxmlArchive.cjs.map +1 -0
- package/dist/adapters/structuredDocuments/pptx.cjs +2 -0
- package/dist/adapters/structuredDocuments/pptx.cjs.map +1 -0
- package/dist/adapters/structuredDocuments/xlsx.cjs +2 -0
- package/dist/adapters/structuredDocuments/xlsx.cjs.map +1 -0
- package/dist/adapters/structuredDocuments/xmlText.cjs +2 -0
- package/dist/adapters/structuredDocuments/xmlText.cjs.map +1 -0
- package/dist/adapters/webAuthorChannel.cjs +2 -0
- package/dist/adapters/webAuthorChannel.cjs.map +1 -0
- package/dist/commands/doomAuthorCommand.cjs +2 -0
- package/dist/commands/doomAuthorCommand.cjs.map +1 -0
- package/dist/container/index.cjs +2 -0
- package/dist/container/index.cjs.map +1 -0
- package/dist/extensions/pi.cjs +1 -0
- package/dist/extensions/pi.d.cts +2 -0
- package/dist/extensions/pi.d.mts +2 -0
- package/dist/extensions/pi.mjs +1 -0
- package/dist/index.cjs +1 -0
- package/dist/index.d.cts +21 -0
- package/dist/index.d.mts +21 -0
- package/dist/index.mjs +1 -0
- package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/engine/helpers/union.d.cts +6 -0
- package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/engine/helpers/union.d.cts.map +1 -0
- package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/engine/helpers/union.d.mts +6 -0
- package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/engine/helpers/union.d.mts.map +1 -0
- package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/_optional.d.cts +7 -0
- package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/_optional.d.cts.map +1 -0
- package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/_optional.d.mts +7 -0
- package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/_optional.d.mts.map +1 -0
- package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/object.d.cts +12 -0
- package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/object.d.cts.map +1 -0
- package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/object.d.mts +12 -0
- package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/object.d.mts.map +1 -0
- package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/properties.d.cts +12 -0
- package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/properties.d.cts.map +1 -0
- package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/properties.d.mts +12 -0
- package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/properties.d.mts.map +1 -0
- package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/record.d.cts +9 -0
- package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/record.d.cts.map +1 -0
- package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/record.d.mts +9 -0
- package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/record.d.mts.map +1 -0
- package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/schema.d.cts +4 -0
- package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/schema.d.cts.map +1 -0
- package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/schema.d.mts +4 -0
- package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/schema.d.mts.map +1 -0
- package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/string.d.cts +9 -0
- package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/string.d.cts.map +1 -0
- package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/string.d.mts +9 -0
- package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/string.d.mts.map +1 -0
- package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/unknown.d.cts +8 -0
- package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/unknown.d.cts.map +1 -0
- package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/unknown.d.mts +8 -0
- package/dist/node_modules/.pnpm/typebox@1.3.25/node_modules/typebox/build/type/types/unknown.d.mts.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/authorApi.d.cts +15 -0
- package/dist/packages/minor/doompi-author/src/adapters/authorApi.d.cts.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/authorApi.d.mts +15 -0
- package/dist/packages/minor/doompi-author/src/adapters/authorApi.d.mts.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/authorApi.mjs +2 -0
- package/dist/packages/minor/doompi-author/src/adapters/authorApi.mjs.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/authorBridgeApi.d.cts +6 -0
- package/dist/packages/minor/doompi-author/src/adapters/authorBridgeApi.d.cts.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/authorBridgeApi.d.mts +6 -0
- package/dist/packages/minor/doompi-author/src/adapters/authorBridgeApi.d.mts.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/authorBridgeApi.mjs +2 -0
- package/dist/packages/minor/doompi-author/src/adapters/authorBridgeApi.mjs.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/authorDocumentApi.d.cts +11 -0
- package/dist/packages/minor/doompi-author/src/adapters/authorDocumentApi.d.cts.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/authorDocumentApi.d.mts +11 -0
- package/dist/packages/minor/doompi-author/src/adapters/authorDocumentApi.d.mts.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/authorDocumentApi.mjs +2 -0
- package/dist/packages/minor/doompi-author/src/adapters/authorDocumentApi.mjs.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/pi/authorBridgeClient.d.cts +18 -0
- package/dist/packages/minor/doompi-author/src/adapters/pi/authorBridgeClient.d.cts.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/pi/authorBridgeClient.d.mts +18 -0
- package/dist/packages/minor/doompi-author/src/adapters/pi/authorBridgeClient.d.mts.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/pi/authorBridgeClient.mjs +2 -0
- package/dist/packages/minor/doompi-author/src/adapters/pi/authorBridgeClient.mjs.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/pi/authorTools.d.cts +9 -0
- package/dist/packages/minor/doompi-author/src/adapters/pi/authorTools.d.cts.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/pi/authorTools.d.mts +9 -0
- package/dist/packages/minor/doompi-author/src/adapters/pi/authorTools.d.mts.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/pi/authorTools.mjs +2 -0
- package/dist/packages/minor/doompi-author/src/adapters/pi/authorTools.mjs.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/pi/extension.d.cts +19 -0
- package/dist/packages/minor/doompi-author/src/adapters/pi/extension.d.cts.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/pi/extension.d.mts +19 -0
- package/dist/packages/minor/doompi-author/src/adapters/pi/extension.d.mts.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/pi/extension.mjs +2 -0
- package/dist/packages/minor/doompi-author/src/adapters/pi/extension.mjs.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/common.mjs +2 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/common.mjs.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/csv.d.cts +7 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/csv.d.cts.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/csv.d.mts +7 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/csv.d.mts.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/csv.mjs +7 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/csv.mjs.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/index.d.cts +13 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/index.d.cts.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/index.d.mts +13 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/index.d.mts.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/index.mjs +2 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/index.mjs.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/markdownSlides.d.cts +7 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/markdownSlides.d.cts.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/markdownSlides.d.mts +7 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/markdownSlides.d.mts.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/markdownSlides.mjs +6 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/markdownSlides.mjs.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/ooxmlArchive.d.cts +13 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/ooxmlArchive.d.cts.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/ooxmlArchive.d.mts +13 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/ooxmlArchive.d.mts.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/ooxmlArchive.mjs +2 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/ooxmlArchive.mjs.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/pptx.d.cts +7 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/pptx.d.cts.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/pptx.d.mts +7 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/pptx.d.mts.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/pptx.mjs +2 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/pptx.mjs.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/xlsx.d.cts +7 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/xlsx.d.cts.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/xlsx.d.mts +7 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/xlsx.d.mts.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/xlsx.mjs +2 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/xlsx.mjs.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/xmlText.mjs +2 -0
- package/dist/packages/minor/doompi-author/src/adapters/structuredDocuments/xmlText.mjs.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/webAuthorChannel.d.cts +6 -0
- package/dist/packages/minor/doompi-author/src/adapters/webAuthorChannel.d.cts.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/webAuthorChannel.d.mts +6 -0
- package/dist/packages/minor/doompi-author/src/adapters/webAuthorChannel.d.mts.map +1 -0
- package/dist/packages/minor/doompi-author/src/adapters/webAuthorChannel.mjs +2 -0
- package/dist/packages/minor/doompi-author/src/adapters/webAuthorChannel.mjs.map +1 -0
- package/dist/packages/minor/doompi-author/src/commands/doomAuthorCommand.mjs +2 -0
- package/dist/packages/minor/doompi-author/src/commands/doomAuthorCommand.mjs.map +1 -0
- package/dist/packages/minor/doompi-author/src/container/index.d.cts +5 -0
- package/dist/packages/minor/doompi-author/src/container/index.d.cts.map +1 -0
- package/dist/packages/minor/doompi-author/src/container/index.d.mts +5 -0
- package/dist/packages/minor/doompi-author/src/container/index.d.mts.map +1 -0
- package/dist/packages/minor/doompi-author/src/container/index.mjs +2 -0
- package/dist/packages/minor/doompi-author/src/container/index.mjs.map +1 -0
- package/dist/packages/minor/doompi-author/src/schemas/authorTools.d.cts +16 -0
- package/dist/packages/minor/doompi-author/src/schemas/authorTools.d.cts.map +1 -0
- package/dist/packages/minor/doompi-author/src/schemas/authorTools.d.mts +16 -0
- package/dist/packages/minor/doompi-author/src/schemas/authorTools.d.mts.map +1 -0
- package/dist/packages/minor/doompi-author/src/schemas/authorTools.mjs +2 -0
- package/dist/packages/minor/doompi-author/src/schemas/authorTools.mjs.map +1 -0
- package/dist/packages/minor/doompi-author/src/services/authorBridgeState.d.cts +31 -0
- package/dist/packages/minor/doompi-author/src/services/authorBridgeState.d.cts.map +1 -0
- package/dist/packages/minor/doompi-author/src/services/authorBridgeState.d.mts +31 -0
- package/dist/packages/minor/doompi-author/src/services/authorBridgeState.d.mts.map +1 -0
- package/dist/packages/minor/doompi-author/src/services/authorBridgeState.mjs +2 -0
- package/dist/packages/minor/doompi-author/src/services/authorBridgeState.mjs.map +1 -0
- package/dist/packages/minor/doompi-author/src/services/authorCatalog.d.cts +10 -0
- package/dist/packages/minor/doompi-author/src/services/authorCatalog.d.cts.map +1 -0
- package/dist/packages/minor/doompi-author/src/services/authorCatalog.d.mts +10 -0
- package/dist/packages/minor/doompi-author/src/services/authorCatalog.d.mts.map +1 -0
- package/dist/packages/minor/doompi-author/src/services/authorMode.d.cts +19 -0
- package/dist/packages/minor/doompi-author/src/services/authorMode.d.cts.map +1 -0
- package/dist/packages/minor/doompi-author/src/services/authorMode.d.mts +19 -0
- package/dist/packages/minor/doompi-author/src/services/authorMode.d.mts.map +1 -0
- package/dist/packages/minor/doompi-author/src/services/authorMode.mjs +3 -0
- package/dist/packages/minor/doompi-author/src/services/authorMode.mjs.map +1 -0
- package/dist/packages/minor/doompi-author/src/services/extensionService.d.cts +7 -0
- package/dist/packages/minor/doompi-author/src/services/extensionService.d.cts.map +1 -0
- package/dist/packages/minor/doompi-author/src/services/extensionService.d.mts +7 -0
- package/dist/packages/minor/doompi-author/src/services/extensionService.d.mts.map +1 -0
- package/dist/packages/minor/doompi-author/src/services/extensionService.mjs +2 -0
- package/dist/packages/minor/doompi-author/src/services/extensionService.mjs.map +1 -0
- package/dist/packages/minor/doompi-author/src/types/author.d.cts +39 -0
- package/dist/packages/minor/doompi-author/src/types/author.d.cts.map +1 -0
- package/dist/packages/minor/doompi-author/src/types/author.d.mts +39 -0
- package/dist/packages/minor/doompi-author/src/types/author.d.mts.map +1 -0
- package/dist/packages/minor/doompi-author/src/types/author.mjs +2 -0
- package/dist/packages/minor/doompi-author/src/types/author.mjs.map +1 -0
- package/dist/packages/minor/doompi-author/src/types/authorApi.d.cts +23 -0
- package/dist/packages/minor/doompi-author/src/types/authorApi.d.cts.map +1 -0
- package/dist/packages/minor/doompi-author/src/types/authorApi.d.mts +23 -0
- package/dist/packages/minor/doompi-author/src/types/authorApi.d.mts.map +1 -0
- package/dist/packages/minor/doompi-author/src/types/authorApi.mjs +2 -0
- package/dist/packages/minor/doompi-author/src/types/authorApi.mjs.map +1 -0
- package/dist/packages/minor/doompi-author/src/types/extension.d.cts +16 -0
- package/dist/packages/minor/doompi-author/src/types/extension.d.cts.map +1 -0
- package/dist/packages/minor/doompi-author/src/types/extension.d.mts +16 -0
- package/dist/packages/minor/doompi-author/src/types/extension.d.mts.map +1 -0
- package/dist/packages/minor/doompi-author/src/types/structuredDocuments.d.cts +60 -0
- package/dist/packages/minor/doompi-author/src/types/structuredDocuments.d.cts.map +1 -0
- package/dist/packages/minor/doompi-author/src/types/structuredDocuments.d.mts +60 -0
- package/dist/packages/minor/doompi-author/src/types/structuredDocuments.d.mts.map +1 -0
- package/dist/packages/minor/doompi-author/src/types/webAuthor.d.cts +67 -0
- package/dist/packages/minor/doompi-author/src/types/webAuthor.d.cts.map +1 -0
- package/dist/packages/minor/doompi-author/src/types/webAuthor.d.mts +67 -0
- package/dist/packages/minor/doompi-author/src/types/webAuthor.d.mts.map +1 -0
- package/dist/packages/minor/doompi-author/src/types/webAuthor.mjs +2 -0
- package/dist/packages/minor/doompi-author/src/types/webAuthor.mjs.map +1 -0
- package/dist/schemas/authorTools.cjs +2 -0
- package/dist/schemas/authorTools.cjs.map +1 -0
- package/dist/services/authorBridgeState.cjs +2 -0
- package/dist/services/authorBridgeState.cjs.map +1 -0
- package/dist/services/authorMode.cjs +3 -0
- package/dist/services/authorMode.cjs.map +1 -0
- package/dist/services/extensionService.cjs +2 -0
- package/dist/services/extensionService.cjs.map +1 -0
- package/dist/sessionApi.cjs +1 -0
- package/dist/sessionApi.d.cts +7 -0
- package/dist/sessionApi.d.mts +7 -0
- package/dist/sessionApi.mjs +1 -0
- package/dist/types/author.cjs +2 -0
- package/dist/types/author.cjs.map +1 -0
- package/dist/types/authorApi.cjs +2 -0
- package/dist/types/authorApi.cjs.map +1 -0
- package/dist/types/webAuthor.cjs +2 -0
- package/dist/types/webAuthor.cjs.map +1 -0
- package/dist/webHub.cjs +1 -0
- package/dist/webHub.d.cts +2 -0
- package/dist/webHub.d.mts +2 -0
- package/dist/webHub.mjs +1 -0
- package/llms.txt +11 -0
- package/package.json +140 -0
- package/src/exports/webClient.ts +76 -0
- package/src/prompts/doompi-use-author/SKILL.md +17 -0
- package/src/types/author.ts +45 -0
- package/src/types/structuredDocuments.ts +63 -0
- package/src/types/webAuthor.ts +85 -0
- package/src/web/api/authorBroker.ts +14 -0
- package/src/web/api/authorBrowserBridge.ts +225 -0
- package/src/web/api/authorFiles.ts +219 -0
- package/src/web/api/authorMedia.ts +19 -0
- package/src/web/api/authorRuntime.ts +164 -0
- package/src/web/components/AuthorDocumentPanel.tsx +232 -0
- package/src/web/components/AuthorGridOverlay.tsx +81 -0
- package/src/web/components/AuthorMediaPreview.tsx +41 -0
- package/src/web/components/AuthorMediaView.tsx +356 -0
- package/src/web/components/AuthorPanel.tsx +105 -0
- package/src/web/components/AuthorRegionDrafts.tsx +102 -0
- package/src/web/components/AuthorRequestLog.tsx +179 -0
- package/src/web/components/AuthorStructuredView.tsx +121 -0
- package/src/web/components/AuthorTextView.tsx +97 -0
- package/src/web/components/AuthorToolPalette.tsx +103 -0
- package/src/web/components/AuthorVideoControls.tsx +111 -0
- package/src/web/components/DescribeAuthorToolsToolCard.tsx +50 -0
- package/src/web/components/OpenAuthoringFileToolCard.tsx +66 -0
- package/src/web/components/UseAuthorToolsToolCard.tsx +50 -0
- package/src/web/index.ts +68 -0
- package/src/web/lib/authorGrid.ts +124 -0
- package/src/web/lib/authorRegions.ts +30 -0
- package/src/web/lib/authorViewportTypes.ts +202 -0
- package/src/web/lib/describeAuthorToolsToolRender.ts +20 -0
- package/src/web/lib/useAuthorToolsToolRender.ts +20 -0
- package/src/web/stores/authorCapture.ts +322 -0
- package/src/web/stores/authorGridTools.ts +316 -0
- package/src/web/stores/authorProfiles.ts +130 -0
- package/src/web/stores/authorRequestLifecycle.ts +82 -0
- package/src/web/stores/authorStore.ts +60 -0
- package/src/web/stores/authorWorkspaceStore.ts +525 -0
- package/src/web/tsconfig.json +22 -0
|
@@ -0,0 +1,179 @@
|
|
|
1
|
+
import type { AuthorNativeAnchor, AuthorRequestRecord } from '../lib/authorViewportTypes.ts';
|
|
2
|
+
|
|
3
|
+
const STATUS_LABELS: Record<AuthorRequestRecord['status'], string> = {
|
|
4
|
+
REQUESTED: 'Request queued',
|
|
5
|
+
CHANGING: 'Agent working',
|
|
6
|
+
CHANGED: 'Change ready',
|
|
7
|
+
COMPLETE: 'Request completed',
|
|
8
|
+
FAILED: 'Request failed',
|
|
9
|
+
CANCELLED: 'Request cancelled',
|
|
10
|
+
};
|
|
11
|
+
|
|
12
|
+
const STATUS_STYLES: Record<AuthorRequestRecord['status'], string> = {
|
|
13
|
+
REQUESTED: 'border-doom-yellow/35 bg-doom-yellow/5 text-doom-yellow',
|
|
14
|
+
CHANGING: 'border-doom-magenta/45 bg-doom-magenta/10 text-doom-yellow',
|
|
15
|
+
CHANGED: 'border-doom-cyan/40 bg-doom-cyan/5 text-doom-cyan',
|
|
16
|
+
COMPLETE: 'border-doom-green/40 bg-doom-green/5 text-doom-green',
|
|
17
|
+
FAILED: 'border-doom-red/45 bg-doom-red/10 text-doom-red',
|
|
18
|
+
CANCELLED: 'border-doom-border bg-doom-panel text-doom-dim',
|
|
19
|
+
};
|
|
20
|
+
|
|
21
|
+
function requestInstruction(requestText: string): string {
|
|
22
|
+
const referencedContext = requestText.search(/(?:^|\s+)Referenced context "/u);
|
|
23
|
+
return requestText
|
|
24
|
+
.slice(0, referencedContext < 0 ? undefined : referencedContext)
|
|
25
|
+
.replace(/^Please address the attached feedback\.\s*Request ID: \S+\s*/u, '')
|
|
26
|
+
.trim();
|
|
27
|
+
}
|
|
28
|
+
|
|
29
|
+
function documentName(path: string): string {
|
|
30
|
+
return path.replaceAll('\\', '/').split('/').at(-1) || path;
|
|
31
|
+
}
|
|
32
|
+
|
|
33
|
+
function anchorLabel(anchor: AuthorNativeAnchor): string {
|
|
34
|
+
switch (anchor.kind) {
|
|
35
|
+
case 'text-range':
|
|
36
|
+
return anchor.startLine === anchor.endLine
|
|
37
|
+
? `Line ${anchor.startLine}`
|
|
38
|
+
: `Lines ${anchor.startLine}–${anchor.endLine}`;
|
|
39
|
+
case 'cell':
|
|
40
|
+
return [anchor.sheet, anchor.location].filter(Boolean).join(' · ');
|
|
41
|
+
case 'slide-element':
|
|
42
|
+
return `Slide ${anchor.slide} · ${anchor.location}`;
|
|
43
|
+
case 'image-rect':
|
|
44
|
+
return 'Image region';
|
|
45
|
+
case 'pdf-page-rect':
|
|
46
|
+
return `Page ${anchor.page}`;
|
|
47
|
+
case 'video-time-rect': {
|
|
48
|
+
const minutes = Math.floor(anchor.timeSeconds / 60);
|
|
49
|
+
const seconds = Math.floor(anchor.timeSeconds % 60)
|
|
50
|
+
.toString()
|
|
51
|
+
.padStart(2, '0');
|
|
52
|
+
return `Video ${minutes}:${seconds}`;
|
|
53
|
+
}
|
|
54
|
+
}
|
|
55
|
+
}
|
|
56
|
+
|
|
57
|
+
function progressLabel(request: AuthorRequestRecord): string {
|
|
58
|
+
const total = request.regions.length;
|
|
59
|
+
const pending = request.pendingRegions?.length;
|
|
60
|
+
if (request.status === 'CHANGING' && request.currentOperation === 'Agent is working on this request')
|
|
61
|
+
return 'Processing request';
|
|
62
|
+
if (request.status === 'CHANGING' && pending !== undefined) return `${total - pending} of ${total} regions applied`;
|
|
63
|
+
if (request.status === 'CHANGED') return 'Changes applied · awaiting save';
|
|
64
|
+
if (request.status === 'COMPLETE') return 'Agent finished processing this request';
|
|
65
|
+
if (request.status === 'FAILED') return 'Stopped with an error';
|
|
66
|
+
if (request.status === 'CANCELLED') return 'Stopped before completion';
|
|
67
|
+
return `${total} region${total === 1 ? '' : 's'} queued`;
|
|
68
|
+
}
|
|
69
|
+
|
|
70
|
+
function RequestRecord({ request, prominent = false }: { request: AuthorRequestRecord; prominent?: boolean }) {
|
|
71
|
+
const instruction = requestInstruction(request.requestText);
|
|
72
|
+
return (
|
|
73
|
+
<article data-testid={prominent ? 'author-active-request' : undefined} className="space-y-3">
|
|
74
|
+
<header className="border-b border-doom-border-soft pb-3">
|
|
75
|
+
<p className="text-[9px] font-bold tracking-[0.18em] text-doom-faint">DOCUMENT CONTEXT</p>
|
|
76
|
+
<p className="mt-2 flex items-center gap-2 truncate text-[13px] font-bold text-doom-hi">
|
|
77
|
+
<span aria-hidden className="text-doom-magenta">
|
|
78
|
+
↗
|
|
79
|
+
</span>
|
|
80
|
+
{documentName(request.documentPath)}
|
|
81
|
+
</p>
|
|
82
|
+
</header>
|
|
83
|
+
|
|
84
|
+
<section aria-label="Request locations" className="rounded border border-doom-border bg-doom-panel p-3">
|
|
85
|
+
<ol className="space-y-3">
|
|
86
|
+
{request.regions.map((region, index) => (
|
|
87
|
+
<li key={region.id} className="space-y-2">
|
|
88
|
+
<p className="font-mono text-[9px] font-bold uppercase tracking-[0.14em] text-doom-yellow">
|
|
89
|
+
WHERE · {request.regions.length > 1 ? `${index + 1} · ` : ''}
|
|
90
|
+
{documentName(request.documentPath)} / {anchorLabel(region.anchor)} · rev {request.revision}
|
|
91
|
+
</p>
|
|
92
|
+
{region.quote ? (
|
|
93
|
+
<blockquote className="line-clamp-3 text-[11px] italic leading-relaxed text-doom-text">
|
|
94
|
+
“{region.quote}”
|
|
95
|
+
</blockquote>
|
|
96
|
+
) : null}
|
|
97
|
+
<p className="text-[10px] leading-relaxed text-doom-dim">{region.comment}</p>
|
|
98
|
+
</li>
|
|
99
|
+
))}
|
|
100
|
+
</ol>
|
|
101
|
+
</section>
|
|
102
|
+
|
|
103
|
+
<section
|
|
104
|
+
data-testid={prominent ? 'author-operation-card' : undefined}
|
|
105
|
+
className={`rounded border p-3 ${STATUS_STYLES[request.status]}`}
|
|
106
|
+
>
|
|
107
|
+
<p className="font-mono text-[10px] font-bold tracking-[0.14em]">
|
|
108
|
+
●{' '}
|
|
109
|
+
{request.status === 'CHANGING'
|
|
110
|
+
? 'WORKING'
|
|
111
|
+
: request.status === 'COMPLETE'
|
|
112
|
+
? 'COMPLETED'
|
|
113
|
+
: request.status === 'FAILED'
|
|
114
|
+
? 'ERROR'
|
|
115
|
+
: request.status}
|
|
116
|
+
</p>
|
|
117
|
+
<p className="mt-2 text-[12px] leading-relaxed text-doom-hi">
|
|
118
|
+
{request.currentOperation || STATUS_LABELS[request.status]}
|
|
119
|
+
</p>
|
|
120
|
+
{request.error ? <p className="mt-2 text-[10px] leading-relaxed text-doom-red">{request.error}</p> : null}
|
|
121
|
+
{request.before !== undefined || request.after !== undefined ? (
|
|
122
|
+
<details className="mt-2 border-t border-current/20 pt-2 text-[10px] text-doom-dim">
|
|
123
|
+
<summary className="cursor-pointer select-none">change preview</summary>
|
|
124
|
+
{request.before !== undefined ? (
|
|
125
|
+
<pre className="mt-2 max-h-28 overflow-auto whitespace-pre-wrap break-words font-mono">
|
|
126
|
+
before: {request.before}
|
|
127
|
+
</pre>
|
|
128
|
+
) : null}
|
|
129
|
+
{request.after !== undefined ? (
|
|
130
|
+
<pre className="mt-2 max-h-28 overflow-auto whitespace-pre-wrap break-words font-mono">
|
|
131
|
+
after: {request.after}
|
|
132
|
+
</pre>
|
|
133
|
+
) : null}
|
|
134
|
+
</details>
|
|
135
|
+
) : null}
|
|
136
|
+
</section>
|
|
137
|
+
|
|
138
|
+
<section className="space-y-2">
|
|
139
|
+
<p className="text-[9px] font-bold tracking-[0.18em] text-doom-faint">REQUEST · HOW TO CHANGE</p>
|
|
140
|
+
<div className="rounded border border-doom-border bg-doom-deep p-3">
|
|
141
|
+
<p className="whitespace-pre-wrap text-[11px] leading-relaxed text-doom-text">
|
|
142
|
+
{instruction || 'No additional instruction.'}
|
|
143
|
+
</p>
|
|
144
|
+
</div>
|
|
145
|
+
</section>
|
|
146
|
+
|
|
147
|
+
<footer className="font-mono text-[9px] text-doom-dim">{progressLabel(request)}</footer>
|
|
148
|
+
</article>
|
|
149
|
+
);
|
|
150
|
+
}
|
|
151
|
+
|
|
152
|
+
export function AuthorRequestLog({ requests }: { requests: readonly AuthorRequestRecord[] }) {
|
|
153
|
+
const latest = requests.at(-1);
|
|
154
|
+
const earlier = requests.slice(0, -1).toReversed();
|
|
155
|
+
return (
|
|
156
|
+
<section data-testid="author-request-history" className="space-y-3">
|
|
157
|
+
<h3 className="text-[9px] font-bold tracking-[0.18em] text-doom-faint">AUTHORING</h3>
|
|
158
|
+
{latest === undefined ? (
|
|
159
|
+
<p className="text-[11px] leading-relaxed text-doom-dim">No requests or changes yet.</p>
|
|
160
|
+
) : (
|
|
161
|
+
<RequestRecord request={latest} prominent />
|
|
162
|
+
)}
|
|
163
|
+
{earlier.length > 0 ? (
|
|
164
|
+
<details className="border-t border-doom-border-soft pt-3" data-testid="author-earlier-requests">
|
|
165
|
+
<summary className="cursor-pointer select-none text-[9px] font-bold tracking-[0.14em] text-doom-faint">
|
|
166
|
+
EARLIER REQUESTS ({earlier.length})
|
|
167
|
+
</summary>
|
|
168
|
+
<ol className="mt-3 space-y-5">
|
|
169
|
+
{earlier.map((request) => (
|
|
170
|
+
<li key={request.id}>
|
|
171
|
+
<RequestRecord request={request} />
|
|
172
|
+
</li>
|
|
173
|
+
))}
|
|
174
|
+
</ol>
|
|
175
|
+
</details>
|
|
176
|
+
) : null}
|
|
177
|
+
</section>
|
|
178
|
+
);
|
|
179
|
+
}
|
|
@@ -0,0 +1,121 @@
|
|
|
1
|
+
import { Button } from '@agimon-ai/doompi-web-components';
|
|
2
|
+
import { useEffect } from 'react';
|
|
3
|
+
import type { DocumentFragment } from '../../types/structuredDocuments.ts';
|
|
4
|
+
import type { AuthorDisplayedRegion } from '../lib/authorViewportTypes.ts';
|
|
5
|
+
import { registerAuthorGridResolver } from '../lib/authorGrid.ts';
|
|
6
|
+
import {
|
|
7
|
+
reviseAuthorFragment,
|
|
8
|
+
setAuthorRegionCandidate,
|
|
9
|
+
type AuthorWorkspaceDocument,
|
|
10
|
+
} from '../stores/authorWorkspaceStore.ts';
|
|
11
|
+
|
|
12
|
+
export function AuthorStructuredView({
|
|
13
|
+
sessionId,
|
|
14
|
+
document,
|
|
15
|
+
displayedRegions,
|
|
16
|
+
}: {
|
|
17
|
+
sessionId: string;
|
|
18
|
+
document: AuthorWorkspaceDocument;
|
|
19
|
+
displayedRegions: readonly AuthorDisplayedRegion[];
|
|
20
|
+
}) {
|
|
21
|
+
useEffect(
|
|
22
|
+
() =>
|
|
23
|
+
registerAuthorGridResolver(sessionId, (cell, geometry) => {
|
|
24
|
+
const { originX = 0, originY = 0, width, height } = geometry.viewport;
|
|
25
|
+
const element = window.document.elementFromPoint(
|
|
26
|
+
originX + cell.center.x * width,
|
|
27
|
+
originY + cell.center.y * height,
|
|
28
|
+
);
|
|
29
|
+
const fragmentId = element?.closest<HTMLElement>('[data-author-fragment]')?.dataset.authorFragment;
|
|
30
|
+
const fragment = document.fragments?.find((candidate) => candidate.id === fragmentId);
|
|
31
|
+
if (fragment === undefined || fragment.readOnly === true) return undefined;
|
|
32
|
+
if (document.kind === 'csv' || document.kind === 'xlsx') {
|
|
33
|
+
return {
|
|
34
|
+
anchor: { kind: 'cell', fragmentId: fragment.id, location: fragment.location },
|
|
35
|
+
quote: fragment.text,
|
|
36
|
+
};
|
|
37
|
+
}
|
|
38
|
+
const slide = Number(fragment.location.match(/(?:slide\s*|slides\/slide)(\d+)/u)?.[1]);
|
|
39
|
+
if (!Number.isSafeInteger(slide)) return undefined;
|
|
40
|
+
return {
|
|
41
|
+
anchor: { kind: 'slide-element', fragmentId: fragment.id, location: fragment.location, slide },
|
|
42
|
+
quote: fragment.text,
|
|
43
|
+
};
|
|
44
|
+
}),
|
|
45
|
+
[document.fragments, document.kind, document.version, sessionId],
|
|
46
|
+
);
|
|
47
|
+
const displayedByFragment = new Map(
|
|
48
|
+
displayedRegions.flatMap(({ ordinal, region }) =>
|
|
49
|
+
region.anchor.kind === 'cell' || region.anchor.kind === 'slide-element'
|
|
50
|
+
? [[region.anchor.fragmentId, ordinal] as const]
|
|
51
|
+
: [],
|
|
52
|
+
),
|
|
53
|
+
);
|
|
54
|
+
const cells = document.kind === 'csv' || document.kind === 'xlsx';
|
|
55
|
+
const groups = new Map<string, DocumentFragment[]>();
|
|
56
|
+
for (const fragment of document.fragments ?? []) {
|
|
57
|
+
const key = cells
|
|
58
|
+
? document.kind === 'csv'
|
|
59
|
+
? fragment.location.split(',')[0]!
|
|
60
|
+
: fragment.location.replace(/![A-Z]+(\d+)$/, '!row $1')
|
|
61
|
+
: fragment.location;
|
|
62
|
+
const group = groups.get(key) ?? [];
|
|
63
|
+
group.push(fragment);
|
|
64
|
+
groups.set(key, group);
|
|
65
|
+
}
|
|
66
|
+
return (
|
|
67
|
+
<div data-testid="author-structured" className="min-h-0 flex-1 space-y-3 overflow-auto p-4">
|
|
68
|
+
{!cells ? <p className="text-[10px] text-doom-faint">Slide text view, not a layout-faithful rendering.</p> : null}
|
|
69
|
+
{[...groups].map(([location, fragments]) => (
|
|
70
|
+
<section key={location} className="space-y-1">
|
|
71
|
+
<h3 className="text-[10px] text-doom-faint">{location}</h3>
|
|
72
|
+
<div className={cells ? 'flex gap-1' : 'space-y-2'}>
|
|
73
|
+
{fragments.map((fragment) => (
|
|
74
|
+
<div
|
|
75
|
+
key={fragment.id}
|
|
76
|
+
data-author-fragment={fragment.id}
|
|
77
|
+
data-author-region={displayedByFragment.get(fragment.id)}
|
|
78
|
+
className={`${cells ? 'w-40 shrink-0' : ''} relative rounded ${displayedByFragment.has(fragment.id) ? 'ring-1 ring-doom-yellow' : ''}`}
|
|
79
|
+
>
|
|
80
|
+
{displayedByFragment.has(fragment.id) ? (
|
|
81
|
+
<span className="absolute -left-1 -top-1 z-10 flex h-4 min-w-4 items-center justify-center rounded-full bg-doom-yellow px-1 text-[9px] font-bold text-doom-deep">
|
|
82
|
+
{displayedByFragment.get(fragment.id)}
|
|
83
|
+
</span>
|
|
84
|
+
) : null}
|
|
85
|
+
<Button
|
|
86
|
+
size="xs"
|
|
87
|
+
variant="ghost"
|
|
88
|
+
onClick={(event) => {
|
|
89
|
+
const bounds = event.currentTarget.getBoundingClientRect();
|
|
90
|
+
const slide = Number(fragment.location.match(/(?:slide\s*|slides\/slide)(\d+)/)?.[1]);
|
|
91
|
+
if (!cells && !Number.isSafeInteger(slide)) return;
|
|
92
|
+
setAuthorRegionCandidate(sessionId, {
|
|
93
|
+
documentPath: document.path,
|
|
94
|
+
revision: document.version,
|
|
95
|
+
sourceSha256: document.sourceSha256,
|
|
96
|
+
quote: fragment.text,
|
|
97
|
+
anchor: cells
|
|
98
|
+
? { kind: 'cell', fragmentId: fragment.id, location: fragment.location }
|
|
99
|
+
: { kind: 'slide-element', fragmentId: fragment.id, location: fragment.location, slide },
|
|
100
|
+
viewport: { width: bounds.width, height: bounds.height },
|
|
101
|
+
createdAt: Date.now(),
|
|
102
|
+
});
|
|
103
|
+
}}
|
|
104
|
+
>
|
|
105
|
+
mark {fragment.location}
|
|
106
|
+
</Button>
|
|
107
|
+
<textarea
|
|
108
|
+
aria-label={fragment.location}
|
|
109
|
+
value={fragment.text}
|
|
110
|
+
readOnly={fragment.readOnly === true}
|
|
111
|
+
className="w-full rounded border border-doom-border bg-doom-deep p-2 text-[11px] text-doom-text"
|
|
112
|
+
onChange={(event) => reviseAuthorFragment(sessionId, document.path, fragment.id, event.target.value)}
|
|
113
|
+
/>
|
|
114
|
+
</div>
|
|
115
|
+
))}
|
|
116
|
+
</div>
|
|
117
|
+
</section>
|
|
118
|
+
))}
|
|
119
|
+
</div>
|
|
120
|
+
);
|
|
121
|
+
}
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import { CodeEditor, Markdown, type CodeEditorController } from '@agimon-ai/doompi-web-components';
|
|
2
|
+
import { useEffect, useRef } from 'react';
|
|
3
|
+
import type { AuthorDisplayedRegion } from '../lib/authorViewportTypes.ts';
|
|
4
|
+
import { registerAuthorGridResolver } from '../lib/authorGrid.ts';
|
|
5
|
+
import {
|
|
6
|
+
authorDocument,
|
|
7
|
+
reviseAuthorDocument,
|
|
8
|
+
setAuthorRegionCandidate,
|
|
9
|
+
type AuthorWorkspaceDocument,
|
|
10
|
+
} from '../stores/authorWorkspaceStore.ts';
|
|
11
|
+
|
|
12
|
+
export function AuthorTextView({
|
|
13
|
+
sessionId,
|
|
14
|
+
document,
|
|
15
|
+
preview,
|
|
16
|
+
displayedRegions,
|
|
17
|
+
}: {
|
|
18
|
+
sessionId: string;
|
|
19
|
+
document: AuthorWorkspaceDocument;
|
|
20
|
+
preview: boolean;
|
|
21
|
+
displayedRegions: readonly AuthorDisplayedRegion[];
|
|
22
|
+
}) {
|
|
23
|
+
const host = useRef<HTMLDivElement>(null);
|
|
24
|
+
const editor = useRef<CodeEditorController>(null);
|
|
25
|
+
useEffect(
|
|
26
|
+
() =>
|
|
27
|
+
registerAuthorGridResolver(sessionId, (cell, geometry) => {
|
|
28
|
+
if (preview || editor.current === null) return undefined;
|
|
29
|
+
const { originX = 0, originY = 0, width, height } = geometry.viewport;
|
|
30
|
+
const range = editor.current.resolveViewportRegion({
|
|
31
|
+
left: originX + cell.rect.x * width,
|
|
32
|
+
top: originY + cell.rect.y * height,
|
|
33
|
+
right: originX + (cell.rect.x + cell.rect.width) * width,
|
|
34
|
+
bottom: originY + (cell.rect.y + cell.rect.height) * height,
|
|
35
|
+
});
|
|
36
|
+
if (range === null || range.from === range.to) return undefined;
|
|
37
|
+
return {
|
|
38
|
+
anchor: {
|
|
39
|
+
kind: 'text-range',
|
|
40
|
+
startOffset: range.from,
|
|
41
|
+
endOffset: range.to,
|
|
42
|
+
startLine: range.startLine,
|
|
43
|
+
endLine: range.endLine,
|
|
44
|
+
},
|
|
45
|
+
quote: range.text,
|
|
46
|
+
};
|
|
47
|
+
}),
|
|
48
|
+
[preview, sessionId],
|
|
49
|
+
);
|
|
50
|
+
useEffect(() => {
|
|
51
|
+
editor.current?.setMarkedRanges(
|
|
52
|
+
displayedRegions.flatMap(({ ordinal, region }) =>
|
|
53
|
+
region.anchor.kind === 'text-range'
|
|
54
|
+
? [{ from: region.anchor.startOffset, to: region.anchor.endOffset, label: String(ordinal) }]
|
|
55
|
+
: [],
|
|
56
|
+
),
|
|
57
|
+
);
|
|
58
|
+
}, [displayedRegions]);
|
|
59
|
+
return (
|
|
60
|
+
<div ref={host} className="flex min-h-0 flex-1 flex-col">
|
|
61
|
+
{preview ? (
|
|
62
|
+
<div data-testid="author-markdown" className="min-h-0 flex-1 overflow-auto p-4 text-[12px] text-doom-text">
|
|
63
|
+
<Markdown text={document.content ?? ''} />
|
|
64
|
+
</div>
|
|
65
|
+
) : (
|
|
66
|
+
<CodeEditor
|
|
67
|
+
value={document.content ?? ''}
|
|
68
|
+
path={document.path}
|
|
69
|
+
data-testid="author-editor"
|
|
70
|
+
controllerRef={editor}
|
|
71
|
+
className="min-h-0 flex-1"
|
|
72
|
+
onChange={(content) => reviseAuthorDocument(sessionId, document.path, content)}
|
|
73
|
+
onSelect={(range) => {
|
|
74
|
+
const current = authorDocument(sessionId, document.path);
|
|
75
|
+
const bounds = host.current?.getBoundingClientRect();
|
|
76
|
+
if (!current || !bounds || range.from === range.to) return;
|
|
77
|
+
setAuthorRegionCandidate(sessionId, {
|
|
78
|
+
documentPath: current.path,
|
|
79
|
+
revision: current.version,
|
|
80
|
+
sourceSha256: current.sourceSha256,
|
|
81
|
+
quote: range.text,
|
|
82
|
+
anchor: {
|
|
83
|
+
kind: 'text-range',
|
|
84
|
+
startOffset: range.from,
|
|
85
|
+
endOffset: range.to,
|
|
86
|
+
startLine: range.startLine,
|
|
87
|
+
endLine: range.endLine,
|
|
88
|
+
},
|
|
89
|
+
viewport: { width: bounds.width, height: bounds.height },
|
|
90
|
+
createdAt: Date.now(),
|
|
91
|
+
});
|
|
92
|
+
}}
|
|
93
|
+
/>
|
|
94
|
+
)}
|
|
95
|
+
</div>
|
|
96
|
+
);
|
|
97
|
+
}
|
|
@@ -0,0 +1,103 @@
|
|
|
1
|
+
import { Button } from '@agimon-ai/doompi-web-components';
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
import type { AuthorDocumentKind, AuthorToolMode } from '../lib/authorViewportTypes.ts';
|
|
4
|
+
import {
|
|
5
|
+
authorDocument,
|
|
6
|
+
authorSessionWorkspace,
|
|
7
|
+
reviseAuthorDocument,
|
|
8
|
+
setAuthorRegionCandidate,
|
|
9
|
+
setAuthorToolMode,
|
|
10
|
+
} from '../stores/authorWorkspaceStore.ts';
|
|
11
|
+
|
|
12
|
+
export function AuthorToolPalette({
|
|
13
|
+
sessionId,
|
|
14
|
+
kind,
|
|
15
|
+
activeTool,
|
|
16
|
+
}: {
|
|
17
|
+
sessionId: string;
|
|
18
|
+
kind: AuthorDocumentKind;
|
|
19
|
+
activeTool: AuthorToolMode;
|
|
20
|
+
}) {
|
|
21
|
+
const [error, setError] = useState<string>();
|
|
22
|
+
const format = (style: 'Bold' | 'Heading' | 'Link' | 'List') => {
|
|
23
|
+
const session = authorSessionWorkspace(sessionId);
|
|
24
|
+
const selected = session.candidate;
|
|
25
|
+
const document = selected && authorDocument(sessionId, selected.documentPath);
|
|
26
|
+
if (
|
|
27
|
+
!selected ||
|
|
28
|
+
!document ||
|
|
29
|
+
selected.anchor.kind !== 'text-range' ||
|
|
30
|
+
selected.revision !== document.version ||
|
|
31
|
+
selected.sourceSha256 !== document.sourceSha256
|
|
32
|
+
) {
|
|
33
|
+
setError('Select text in the document first.');
|
|
34
|
+
return;
|
|
35
|
+
}
|
|
36
|
+
const { startOffset, endOffset } = selected.anchor;
|
|
37
|
+
const content = document.content ?? '';
|
|
38
|
+
const text = content.slice(startOffset, endOffset);
|
|
39
|
+
const replacement =
|
|
40
|
+
style === 'Bold'
|
|
41
|
+
? `**${text}**`
|
|
42
|
+
: style === 'Link'
|
|
43
|
+
? `[${text}](https://)`
|
|
44
|
+
: text
|
|
45
|
+
.split('\n')
|
|
46
|
+
.map((line) => `${style === 'Heading' ? '## ' : '- '}${line}`)
|
|
47
|
+
.join('\n');
|
|
48
|
+
reviseAuthorDocument(
|
|
49
|
+
sessionId,
|
|
50
|
+
document.path,
|
|
51
|
+
content.slice(0, startOffset) + replacement + content.slice(endOffset),
|
|
52
|
+
);
|
|
53
|
+
setAuthorRegionCandidate(sessionId, undefined);
|
|
54
|
+
setError(undefined);
|
|
55
|
+
};
|
|
56
|
+
const tools = [
|
|
57
|
+
{
|
|
58
|
+
label: 'Region',
|
|
59
|
+
glyph: '⌗',
|
|
60
|
+
action: () => setAuthorToolMode(sessionId, activeTool === 'mark' ? 'select' : 'mark'),
|
|
61
|
+
active: activeTool === 'mark',
|
|
62
|
+
},
|
|
63
|
+
...(kind === 'markdown'
|
|
64
|
+
? [
|
|
65
|
+
{ label: 'Bold', glyph: 'B', action: () => format('Bold') },
|
|
66
|
+
{ label: 'Heading', glyph: 'H', action: () => format('Heading') },
|
|
67
|
+
{ label: 'Link', glyph: '↗', action: () => format('Link') },
|
|
68
|
+
{ label: 'List', glyph: '≡', action: () => format('List') },
|
|
69
|
+
]
|
|
70
|
+
: []),
|
|
71
|
+
{ label: 'Comment', glyph: '□', action: () => setAuthorToolMode(sessionId, 'mark') },
|
|
72
|
+
];
|
|
73
|
+
return (
|
|
74
|
+
<section data-testid="author-tool-palette" className="space-y-2 border-b border-doom-border-soft pb-3">
|
|
75
|
+
<div className="flex justify-between text-xs text-doom-dim">
|
|
76
|
+
<h3 className="font-bold tracking-widest">TOOLS</h3>
|
|
77
|
+
<span>focused tab</span>
|
|
78
|
+
</div>
|
|
79
|
+
<div className="grid grid-cols-3 gap-1.5">
|
|
80
|
+
{tools.map((tool) => (
|
|
81
|
+
<Button
|
|
82
|
+
key={tool.label}
|
|
83
|
+
size="md"
|
|
84
|
+
variant="outline"
|
|
85
|
+
aria-label={tool.label === 'Region' ? 'mark region' : tool.label}
|
|
86
|
+
aria-pressed={tool.active}
|
|
87
|
+
onClick={tool.action}
|
|
88
|
+
className={`min-h-11 min-w-11 gap-1.5 rounded border text-sm [@media(pointer:fine)]:min-h-8 sm:text-xs ${tool.active ? 'border-doom-red bg-doom-red/10 text-doom-red hover:bg-doom-red/15' : 'border-doom-border bg-doom-panel text-doom-dim'}`}
|
|
89
|
+
>
|
|
90
|
+
<span aria-hidden="true">{tool.glyph}</span>
|
|
91
|
+
{tool.label}
|
|
92
|
+
</Button>
|
|
93
|
+
))}
|
|
94
|
+
</div>
|
|
95
|
+
<p className="text-sm leading-normal text-doom-dim sm:text-xs">
|
|
96
|
+
{activeTool === 'mark'
|
|
97
|
+
? 'Drag over the document to mark a region.'
|
|
98
|
+
: 'Choose Region to mark an area for a comment.'}
|
|
99
|
+
</p>
|
|
100
|
+
{error ? <output className="block text-sm text-doom-red">{error}</output> : null}
|
|
101
|
+
</section>
|
|
102
|
+
);
|
|
103
|
+
}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
import { Button, type MediaPlaybackState } from '@agimon-ai/doompi-web-components';
|
|
2
|
+
import { useState } from 'react';
|
|
3
|
+
|
|
4
|
+
export function videoTimeLabel(seconds: number): string {
|
|
5
|
+
const milliseconds = Math.max(0, Math.round((Number.isFinite(seconds) ? seconds : 0) * 1000));
|
|
6
|
+
return `${String(Math.floor(milliseconds / 60000)).padStart(2, '0')}:${String(Math.floor(milliseconds / 1000) % 60).padStart(2, '0')}.${String(milliseconds % 1000).padStart(3, '0')}`;
|
|
7
|
+
}
|
|
8
|
+
|
|
9
|
+
export function AuthorVideoControls({
|
|
10
|
+
playback,
|
|
11
|
+
ready,
|
|
12
|
+
locked,
|
|
13
|
+
marking,
|
|
14
|
+
onSeek,
|
|
15
|
+
onToggle,
|
|
16
|
+
onAnnotate,
|
|
17
|
+
}: {
|
|
18
|
+
playback: MediaPlaybackState;
|
|
19
|
+
ready: boolean;
|
|
20
|
+
locked: boolean;
|
|
21
|
+
marking: boolean;
|
|
22
|
+
onSeek: (seconds: number) => void;
|
|
23
|
+
onToggle: () => void;
|
|
24
|
+
onAnnotate: () => void;
|
|
25
|
+
}) {
|
|
26
|
+
const [seconds, setSeconds] = useState('');
|
|
27
|
+
const duration = playback.duration;
|
|
28
|
+
const invalid =
|
|
29
|
+
seconds.trim() === '' || !Number.isFinite(Number(seconds)) || Number(seconds) < 0 || Number(seconds) > duration;
|
|
30
|
+
const buttonClass = 'min-h-11 px-3 text-sm [@media(pointer:fine)]:min-h-8 sm:text-xs';
|
|
31
|
+
return (
|
|
32
|
+
<section
|
|
33
|
+
aria-label="Video annotation controls"
|
|
34
|
+
className="mt-2 space-y-2 rounded border border-doom-border bg-doom-panel p-2.5 text-sm text-doom-text sm:text-xs"
|
|
35
|
+
>
|
|
36
|
+
<div className="flex flex-wrap items-center justify-between gap-3">
|
|
37
|
+
<output aria-label="Playback position" className="font-mono text-sm tabular-nums">
|
|
38
|
+
{videoTimeLabel(playback.currentTime)} / {videoTimeLabel(duration)}
|
|
39
|
+
</output>
|
|
40
|
+
<span className="text-doom-dim">
|
|
41
|
+
{locked
|
|
42
|
+
? 'Annotation draft: add or discard it before seeking.'
|
|
43
|
+
: marking
|
|
44
|
+
? 'Frame paused. Drag a region on the video.'
|
|
45
|
+
: 'Seek to a moment, then choose Annotate this frame.'}
|
|
46
|
+
</span>
|
|
47
|
+
</div>
|
|
48
|
+
<input
|
|
49
|
+
aria-label="Video timeline"
|
|
50
|
+
type="range"
|
|
51
|
+
min={0}
|
|
52
|
+
max={duration || 0}
|
|
53
|
+
step={0.001}
|
|
54
|
+
value={Math.min(playback.currentTime, duration)}
|
|
55
|
+
disabled={locked || duration <= 0}
|
|
56
|
+
onChange={(event) => onSeek(Number(event.target.value))}
|
|
57
|
+
className="h-11 w-full cursor-pointer accent-doom-blue [@media(pointer:fine)]:h-6"
|
|
58
|
+
/>
|
|
59
|
+
<div className="flex flex-wrap items-center gap-2">
|
|
60
|
+
<Button className={buttonClass} disabled={locked || duration <= 0} onClick={onToggle}>
|
|
61
|
+
{playback.playing ? 'Pause' : 'Play'}
|
|
62
|
+
</Button>
|
|
63
|
+
<Button
|
|
64
|
+
className={buttonClass}
|
|
65
|
+
disabled={locked || duration <= 0}
|
|
66
|
+
onClick={() => onSeek(Math.max(0, playback.currentTime - 0.1))}
|
|
67
|
+
aria-label="Seek back 0.1 seconds"
|
|
68
|
+
>
|
|
69
|
+
−0.1s
|
|
70
|
+
</Button>
|
|
71
|
+
<Button
|
|
72
|
+
className={buttonClass}
|
|
73
|
+
disabled={locked || duration <= 0}
|
|
74
|
+
onClick={() => onSeek(Math.min(duration, playback.currentTime + 0.1))}
|
|
75
|
+
aria-label="Seek forward 0.1 seconds"
|
|
76
|
+
>
|
|
77
|
+
+0.1s
|
|
78
|
+
</Button>
|
|
79
|
+
<Button variant="primary" className={buttonClass} disabled={locked || !ready} onClick={onAnnotate}>
|
|
80
|
+
Annotate this frame
|
|
81
|
+
</Button>
|
|
82
|
+
<form
|
|
83
|
+
className="flex flex-wrap items-center gap-2 sm:ml-auto"
|
|
84
|
+
onSubmit={(event) => {
|
|
85
|
+
event.preventDefault();
|
|
86
|
+
if (!invalid && !locked) onSeek(Number(seconds));
|
|
87
|
+
}}
|
|
88
|
+
>
|
|
89
|
+
<label htmlFor="author-video-seconds" className="text-doom-dim">
|
|
90
|
+
Go to seconds
|
|
91
|
+
</label>
|
|
92
|
+
<input
|
|
93
|
+
id="author-video-seconds"
|
|
94
|
+
type="number"
|
|
95
|
+
min={0}
|
|
96
|
+
max={duration}
|
|
97
|
+
step={0.001}
|
|
98
|
+
value={seconds}
|
|
99
|
+
onChange={(event) => setSeconds(event.target.value)}
|
|
100
|
+
disabled={locked || duration <= 0}
|
|
101
|
+
placeholder="1.250"
|
|
102
|
+
className="h-11 w-24 rounded border border-doom-border bg-doom-deep px-2 text-base [@media(pointer:fine)]:h-8 sm:text-xs"
|
|
103
|
+
/>
|
|
104
|
+
<Button type="submit" className={buttonClass} disabled={locked || duration <= 0 || invalid}>
|
|
105
|
+
Go
|
|
106
|
+
</Button>
|
|
107
|
+
</form>
|
|
108
|
+
</div>
|
|
109
|
+
</section>
|
|
110
|
+
);
|
|
111
|
+
}
|
|
@@ -0,0 +1,50 @@
|
|
|
1
|
+
import {
|
|
2
|
+
collapseLines,
|
|
3
|
+
MessageItem,
|
|
4
|
+
MessageItemBody,
|
|
5
|
+
MessageItemHeader,
|
|
6
|
+
MessageItemStatus,
|
|
7
|
+
MessageLines,
|
|
8
|
+
toolTone,
|
|
9
|
+
} from '@agimon-ai/doompi-web-components';
|
|
10
|
+
import type { ToolMessageRenderProps } from '@agimon-ai/doompi-web-contracts';
|
|
11
|
+
import {
|
|
12
|
+
describeAuthorToolsCallSummary,
|
|
13
|
+
describeAuthorToolsCollapsedLines,
|
|
14
|
+
describeAuthorToolsResultLines,
|
|
15
|
+
} from '../lib/describeAuthorToolsToolRender.ts';
|
|
16
|
+
|
|
17
|
+
/**
|
|
18
|
+
* The describe_author_tools tool's timeline item: Describe the current Author viewport capabilities. The shell owns
|
|
19
|
+
* the frame, the outcome tone, the status badge, and the expand toggle; this
|
|
20
|
+
* card supplies the header summary and the body lines, and says whether it
|
|
21
|
+
* hides any so the toggle appears only when it reveals something.
|
|
22
|
+
*/
|
|
23
|
+
export function DescribeAuthorToolsToolCard({ toolName, args, result, running, isError }: ToolMessageRenderProps) {
|
|
24
|
+
const lines = describeAuthorToolsResultLines(result);
|
|
25
|
+
const collapsed = collapseLines(lines, describeAuthorToolsCollapsedLines, false);
|
|
26
|
+
return (
|
|
27
|
+
<MessageItem tone={toolTone({ running, isError })} expandable={collapsed.hidden > 0}>
|
|
28
|
+
{({ expanded }) => {
|
|
29
|
+
const view = expanded ? collapseLines(lines, describeAuthorToolsCollapsedLines, true) : collapsed;
|
|
30
|
+
return (
|
|
31
|
+
<>
|
|
32
|
+
<MessageItemHeader title={toolName}>
|
|
33
|
+
<span data-testid={`tool-call-${toolName}`} className="min-w-0 flex-1 truncate text-doom-text">
|
|
34
|
+
{describeAuthorToolsCallSummary(args)}
|
|
35
|
+
</span>
|
|
36
|
+
</MessageItemHeader>
|
|
37
|
+
{view.shown.length > 0 || running || isError ? (
|
|
38
|
+
<MessageItemBody data-testid={`tool-result-${toolName}`} className="flex flex-col gap-1">
|
|
39
|
+
{view.shown.length > 0 ? <MessageLines lines={view.shown} /> : null}
|
|
40
|
+
{view.hidden > 0 ? <MessageItemStatus expands>{view.hidden} more line(s)</MessageItemStatus> : null}
|
|
41
|
+
{running ? <MessageItemStatus tone="running">running</MessageItemStatus> : null}
|
|
42
|
+
{isError ? <MessageItemStatus tone="error">failed</MessageItemStatus> : null}
|
|
43
|
+
</MessageItemBody>
|
|
44
|
+
) : null}
|
|
45
|
+
</>
|
|
46
|
+
);
|
|
47
|
+
}}
|
|
48
|
+
</MessageItem>
|
|
49
|
+
);
|
|
50
|
+
}
|