@shivaedev/work-board 0.16.0 → 0.17.1
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/CHANGELOG.md +32 -0
- package/README.md +7 -7
- package/assets/react.css +1 -1
- package/assets/react.js +53 -39
- package/dist/browser/responses/cardContext.d.ts +8 -1
- package/dist/browser/responses/cardContext.d.ts.map +1 -1
- package/dist/browser/responses/cardContext.js +14 -6
- package/dist/browser/responses/cardContext.js.map +1 -1
- package/dist/browser/views/remaining.d.ts +0 -240
- package/dist/browser/views/remaining.d.ts.map +1 -1
- package/dist/browser/views/remaining.js +0 -2
- package/dist/browser/views/remaining.js.map +1 -1
- package/dist/browser/views/schema.d.ts +11 -0
- package/dist/browser/views/schema.d.ts.map +1 -1
- package/dist/browser/views/schema.js +1 -0
- package/dist/browser/views/schema.js.map +1 -1
- package/dist/client/formStatus.d.ts +1 -1
- package/dist/client/formStatus.d.ts.map +1 -1
- package/dist/client/formStatus.js +2 -2
- package/dist/client/formStatus.js.map +1 -1
- package/dist/client/react/AnswerContext.d.ts.map +1 -1
- package/dist/client/react/AnswerContext.js +5 -2
- package/dist/client/react/AnswerContext.js.map +1 -1
- package/dist/client/react/AnswerForm.d.ts.map +1 -1
- package/dist/client/react/AnswerForm.js +6 -2
- package/dist/client/react/AnswerForm.js.map +1 -1
- package/dist/client/react/AnswerMarkdown.d.ts +6 -0
- package/dist/client/react/AnswerMarkdown.d.ts.map +1 -0
- package/dist/client/react/AnswerMarkdown.js +7 -0
- package/dist/client/react/AnswerMarkdown.js.map +1 -0
- package/dist/client/react/AnswerMore.d.ts.map +1 -1
- package/dist/client/react/AnswerMore.js +2 -1
- package/dist/client/react/AnswerMore.js.map +1 -1
- package/dist/client/react/AnswerPanel.d.ts.map +1 -1
- package/dist/client/react/AnswerPanel.js +3 -2
- package/dist/client/react/AnswerPanel.js.map +1 -1
- package/dist/client/react/AnswerPrompts.d.ts.map +1 -1
- package/dist/client/react/AnswerPrompts.js +16 -10
- package/dist/client/react/AnswerPrompts.js.map +1 -1
- package/dist/client/react/BoardShell.js +1 -1
- package/dist/client/react/BoardShell.js.map +1 -1
- package/dist/client/react/DocumentAttention.d.ts.map +1 -1
- package/dist/client/react/DocumentAttention.js +2 -3
- package/dist/client/react/DocumentAttention.js.map +1 -1
- package/dist/client/react/DocumentMain.d.ts.map +1 -1
- package/dist/client/react/DocumentMain.js +1 -1
- package/dist/client/react/DocumentMain.js.map +1 -1
- package/dist/client/react/GoalPage.js +1 -1
- package/dist/client/react/GoalPage.js.map +1 -1
- package/dist/client/react/GoalProgressHeader.js +1 -1
- package/dist/client/react/GoalProgressHeader.js.map +1 -1
- package/dist/client/react/LibraryMain.d.ts.map +1 -1
- package/dist/client/react/LibraryMain.js +1 -1
- package/dist/client/react/LibraryMain.js.map +1 -1
- package/dist/client/react/LibraryPage.js +1 -1
- package/dist/client/react/LibraryPage.js.map +1 -1
- package/dist/client/react/ProjectionFrame.js +1 -1
- package/dist/client/react/ProjectionFrame.js.map +1 -1
- package/dist/client/react/ProjectionMain.d.ts.map +1 -1
- package/dist/client/react/ProjectionMain.js +1 -1
- package/dist/client/react/ProjectionMain.js.map +1 -1
- package/dist/client/react/PromptOption.d.ts.map +1 -1
- package/dist/client/react/PromptOption.js +7 -5
- package/dist/client/react/PromptOption.js.map +1 -1
- package/dist/client/react/RemainingMain.d.ts.map +1 -1
- package/dist/client/react/RemainingMain.js +1 -4
- package/dist/client/react/RemainingMain.js.map +1 -1
- package/dist/client/react/ResponseHistory.d.ts.map +1 -1
- package/dist/client/react/ResponseHistory.js +11 -5
- package/dist/client/react/ResponseHistory.js.map +1 -1
- package/dist/client/react/ResultPage.d.ts.map +1 -1
- package/dist/client/react/ResultPage.js +2 -1
- package/dist/client/react/ResultPage.js.map +1 -1
- package/dist/client/react/ShellApi.d.ts +0 -1
- package/dist/client/react/ShellApi.d.ts.map +1 -1
- package/dist/client/react/SystemMain.d.ts.map +1 -1
- package/dist/client/react/SystemMain.js +1 -1
- package/dist/client/react/SystemMain.js.map +1 -1
- package/dist/client/react/TodayNeeds.d.ts +5 -0
- package/dist/client/react/TodayNeeds.d.ts.map +1 -1
- package/dist/client/react/TodayNeeds.js +6 -3
- package/dist/client/react/TodayNeeds.js.map +1 -1
- package/dist/client/react/TodayOptionButton.d.ts +15 -0
- package/dist/client/react/TodayOptionButton.d.ts.map +1 -0
- package/dist/client/react/TodayOptionButton.js +10 -0
- package/dist/client/react/TodayOptionButton.js.map +1 -0
- package/dist/client/react/TodayOptions.d.ts.map +1 -1
- package/dist/client/react/TodayOptions.js +13 -11
- package/dist/client/react/TodayOptions.js.map +1 -1
- package/dist/client/react/TodayPage.d.ts.map +1 -1
- package/dist/client/react/TodayPage.js +7 -4
- package/dist/client/react/TodayPage.js.map +1 -1
- package/dist/client/react/activeRead.js +1 -1
- package/dist/client/react/activeRead.js.map +1 -1
- package/dist/client/react/entry.js +1 -1
- package/dist/client/react/entry.js.map +1 -1
- package/dist/client/react/loadBoardPage.d.ts.map +1 -1
- package/dist/client/react/loadBoardPage.js +6 -14
- package/dist/client/react/loadBoardPage.js.map +1 -1
- package/dist/client/react/loadProjection.d.ts.map +1 -1
- package/dist/client/react/loadProjection.js +1 -1
- package/dist/client/react/loadProjection.js.map +1 -1
- package/dist/client/react/loadRemaining.d.ts +17 -257
- package/dist/client/react/loadRemaining.d.ts.map +1 -1
- package/dist/client/react/loadRemaining.js +1 -3
- package/dist/client/react/loadRemaining.js.map +1 -1
- package/dist/client/react/pageQueries.d.ts.map +1 -1
- package/dist/client/react/pageQueries.js +1 -4
- package/dist/client/react/pageQueries.js.map +1 -1
- package/dist/client/react/readerLink.js +1 -1
- package/dist/client/react/readerLink.js.map +1 -1
- package/dist/client/react/remainingRoute.d.ts +1 -1
- package/dist/client/react/remainingRoute.d.ts.map +1 -1
- package/dist/client/react/remainingRoute.js +0 -2
- package/dist/client/react/remainingRoute.js.map +1 -1
- package/dist/client/react/resolvedDocumentFailure.d.ts.map +1 -0
- package/dist/client/react/resolvedDocumentFailure.js.map +1 -0
- package/dist/client/react/routeQuery.d.ts.map +1 -0
- package/dist/client/react/routeQuery.js.map +1 -0
- package/dist/client/react/useResponseForm.d.ts.map +1 -1
- package/dist/client/react/useResponseForm.js +2 -2
- package/dist/client/react/useResponseForm.js.map +1 -1
- package/dist/client/responses/summary.d.ts +1 -0
- package/dist/client/responses/summary.d.ts.map +1 -1
- package/dist/client/responses/summary.js +12 -1
- package/dist/client/responses/summary.js.map +1 -1
- package/dist/responses/url.js +1 -1
- package/dist/responses/url.js.map +1 -1
- package/dist/rpc/PageUrl.d.ts.map +1 -1
- package/dist/rpc/PageUrl.js +0 -1
- package/dist/rpc/PageUrl.js.map +1 -1
- package/dist/rpc/contract.d.ts +2195 -2885
- package/dist/rpc/contract.d.ts.map +1 -1
- package/dist/rpc/contract.js +6 -9
- package/dist/rpc/contract.js.map +1 -1
- package/dist/rpc/responseContract.d.ts +56 -56
- package/dist/server/{responses/service.d.ts → Responses.d.ts} +9 -21
- package/dist/server/Responses.d.ts.map +1 -0
- package/dist/server/{responses/service.js → Responses.js} +22 -22
- package/dist/server/Responses.js.map +1 -0
- package/dist/server/attention/inbox.d.ts +15 -2
- package/dist/server/attention/inbox.d.ts.map +1 -1
- package/dist/server/attention/inbox.js +44 -26
- package/dist/server/attention/inbox.js.map +1 -1
- package/dist/server/attention/managedRequestReceipt.d.ts +10 -0
- package/dist/server/attention/managedRequestReceipt.d.ts.map +1 -1
- package/dist/server/attention/managedRequestReceipt.js +29 -10
- package/dist/server/attention/managedRequestReceipt.js.map +1 -1
- package/dist/server/attention/projection.d.ts.map +1 -1
- package/dist/server/attention/projection.js +3 -2
- package/dist/server/attention/projection.js.map +1 -1
- package/dist/server/attention/requestInbox.d.ts +6 -3
- package/dist/server/attention/requestInbox.d.ts.map +1 -1
- package/dist/server/attention/requestInbox.js +3 -2
- package/dist/server/attention/requestInbox.js.map +1 -1
- package/dist/server/attention/requests.d.ts +1 -0
- package/dist/server/attention/requests.d.ts.map +1 -1
- package/dist/server/attention/requests.js +7 -3
- package/dist/server/attention/requests.js.map +1 -1
- package/dist/server/boardRuntime.d.ts +2 -2
- package/dist/server/boardRuntime.d.ts.map +1 -1
- package/dist/server/boardRuntime.js +12 -16
- package/dist/server/boardRuntime.js.map +1 -1
- package/dist/server/boardServices.d.ts +3 -4
- package/dist/server/boardServices.d.ts.map +1 -1
- package/dist/server/boardServices.js +5 -4
- package/dist/server/boardServices.js.map +1 -1
- package/dist/server/boardSocket.d.ts +1 -1
- package/dist/server/boardSocket.d.ts.map +1 -1
- package/dist/server/document/read.d.ts +4 -10
- package/dist/server/document/read.d.ts.map +1 -1
- package/dist/server/document/read.js +5 -5
- package/dist/server/document/read.js.map +1 -1
- package/dist/server/document/requests.d.ts.map +1 -1
- package/dist/server/document/requests.js +1 -2
- package/dist/server/document/requests.js.map +1 -1
- package/dist/server/handoffs/Service.d.ts +1 -2
- package/dist/server/handoffs/Service.d.ts.map +1 -1
- package/dist/server/handoffs/Service.js +14 -13
- package/dist/server/handoffs/Service.js.map +1 -1
- package/dist/server/http/assets.d.ts +0 -3
- package/dist/server/http/assets.d.ts.map +1 -1
- package/dist/server/http/assets.js +1 -7
- package/dist/server/http/assets.js.map +1 -1
- package/dist/server/http/boardRoutes.d.ts.map +1 -1
- package/dist/server/http/boardRoutes.js +3 -3
- package/dist/server/http/boardRoutes.js.map +1 -1
- package/dist/server/integration/responses.d.ts +207 -4
- package/dist/server/integration/responses.d.ts.map +1 -1
- package/dist/server/integration/responses.js +4 -2
- package/dist/server/integration/responses.js.map +1 -1
- package/dist/server/mcp/client.d.ts +869 -1098
- package/dist/server/mcp/client.d.ts.map +1 -1
- package/dist/server/mcp/queries.d.ts +47 -734
- package/dist/server/mcp/queries.d.ts.map +1 -1
- package/dist/server/mcp/queries.js +3 -3
- package/dist/server/mcp/queries.js.map +1 -1
- package/dist/server/packageInfo.d.ts +1 -1
- package/dist/server/packageInfo.js +1 -1
- package/dist/server/responses/readingActions.d.ts +10 -1
- package/dist/server/responses/readingActions.d.ts.map +1 -1
- package/dist/server/responses/readingActions.js +2 -4
- package/dist/server/responses/readingActions.js.map +1 -1
- package/dist/server/responses/registerQuestion.d.ts +2 -2
- package/dist/server/responses/registerQuestion.d.ts.map +1 -1
- package/dist/server/responses/registerQuestion.js +3 -3
- package/dist/server/responses/registerQuestion.js.map +1 -1
- package/dist/server/responses/retry.d.ts +2 -2
- package/dist/server/responses/retry.d.ts.map +1 -1
- package/dist/server/responses/retry.js +1 -1
- package/dist/server/responses/retry.js.map +1 -1
- package/dist/server/rpc/HandlerOptions.d.ts +0 -8
- package/dist/server/rpc/HandlerOptions.d.ts.map +1 -1
- package/dist/server/rpc/handlers.d.ts +1 -1
- package/dist/server/rpc/handlers.d.ts.map +1 -1
- package/dist/server/rpc/handlers.js +14 -13
- package/dist/server/rpc/handlers.js.map +1 -1
- package/dist/server/rpc/hints.d.ts +3 -5
- package/dist/server/rpc/hints.d.ts.map +1 -1
- package/dist/server/rpc/hints.js +5 -1
- package/dist/server/rpc/hints.js.map +1 -1
- package/dist/server/views/fleetItems.d.ts +2 -2
- package/dist/server/views/fleetItems.d.ts.map +1 -1
- package/dist/server/views/fleetItems.js +8 -3
- package/dist/server/views/fleetItems.js.map +1 -1
- package/dist/server/views/projectionQueries.d.ts +16 -9
- package/dist/server/views/projectionQueries.d.ts.map +1 -1
- package/dist/server/views/projectionQueries.js +6 -6
- package/dist/server/views/projectionQueries.js.map +1 -1
- package/dist/server/views/remainingQueries.d.ts +4 -252
- package/dist/server/views/remainingQueries.d.ts.map +1 -1
- package/dist/server/views/remainingQueries.js +11 -19
- package/dist/server/views/remainingQueries.js.map +1 -1
- package/dist/server/workspace.d.ts +222 -0
- package/dist/server/workspace.d.ts.map +1 -0
- package/dist/server/workspace.js +25 -0
- package/dist/server/workspace.js.map +1 -0
- package/docs/delivery/README.md +2 -2
- package/package.json +5 -5
- package/src/browser/responses/cardContext.ts +15 -6
- package/src/browser/views/remaining.ts +0 -3
- package/src/browser/views/schema.ts +1 -0
- package/src/client/formStatus.ts +2 -2
- package/src/client/react/AnswerContext.tsx +9 -4
- package/src/client/react/AnswerForm.tsx +25 -6
- package/src/client/react/AnswerMarkdown.tsx +15 -0
- package/src/client/react/AnswerMore.tsx +58 -46
- package/src/client/react/AnswerPanel.tsx +14 -8
- package/src/client/react/AnswerPrompts.tsx +33 -18
- package/src/client/react/BoardShell.tsx +1 -1
- package/src/client/react/DocumentAttention.tsx +2 -3
- package/src/client/react/DocumentMain.tsx +1 -1
- package/src/client/react/GoalPage.tsx +1 -1
- package/src/client/react/GoalProgressHeader.tsx +1 -1
- package/src/client/react/LibraryMain.tsx +1 -1
- package/src/client/react/LibraryPage.tsx +1 -1
- package/src/client/react/ProjectionFrame.tsx +1 -1
- package/src/client/react/ProjectionMain.tsx +1 -1
- package/src/client/react/PromptOption.tsx +39 -24
- package/src/client/react/RemainingMain.tsx +1 -11
- package/src/client/react/ResponseHistory.tsx +53 -14
- package/src/client/react/ResultPage.tsx +2 -2
- package/src/client/react/ShellApi.ts +0 -1
- package/src/client/react/SystemMain.tsx +1 -1
- package/src/client/react/TodayNeeds.tsx +21 -6
- package/src/client/react/TodayOptionButton.tsx +37 -0
- package/src/client/react/TodayOptions.tsx +38 -30
- package/src/client/react/TodayPage.tsx +18 -3
- package/src/client/react/activeRead.ts +1 -1
- package/src/client/react/entry.css +0 -6
- package/src/client/react/entry.tsx +1 -1
- package/src/client/react/loadBoardPage.ts +6 -15
- package/src/client/react/loadProjection.ts +1 -1
- package/src/client/react/loadRemaining.ts +1 -3
- package/src/client/react/pageQueries.ts +1 -4
- package/src/client/react/readerLink.ts +1 -1
- package/src/client/react/remainingRoute.ts +0 -2
- package/src/client/react/useResponseForm.ts +4 -2
- package/src/client/responses/summary.ts +13 -1
- package/src/responses/url.ts +1 -1
- package/src/rpc/PageUrl.ts +0 -1
- package/src/rpc/contract.ts +6 -9
- package/src/server/{responses/service.ts → Responses.ts} +21 -29
- package/src/server/attention/inbox.ts +51 -26
- package/src/server/attention/managedRequestReceipt.ts +41 -10
- package/src/server/attention/projection.ts +5 -2
- package/src/server/attention/requestInbox.ts +3 -2
- package/src/server/attention/requests.ts +7 -2
- package/src/server/boardRuntime.ts +20 -25
- package/src/server/boardServices.ts +7 -7
- package/src/server/document/read.ts +6 -14
- package/src/server/document/requests.ts +1 -2
- package/src/server/handoffs/Service.ts +16 -19
- package/src/server/http/assets.ts +1 -7
- package/src/server/http/boardRoutes.ts +3 -3
- package/src/server/integration/responses.ts +5 -3
- package/src/server/mcp/queries.ts +3 -3
- package/src/server/packageInfo.ts +1 -1
- package/src/server/responses/readingActions.ts +3 -3
- package/src/server/responses/registerQuestion.ts +5 -5
- package/src/server/responses/retry.ts +3 -3
- package/src/server/rpc/HandlerOptions.ts +0 -8
- package/src/server/rpc/handlers.ts +17 -15
- package/src/server/rpc/hints.ts +6 -3
- package/src/server/views/fleetItems.ts +8 -4
- package/src/server/views/projectionQueries.ts +6 -7
- package/src/server/views/remainingQueries.ts +11 -31
- package/src/server/workspace.ts +41 -0
- package/assets/native.js +0 -37
- package/dist/client/entry.d.ts +0 -3
- package/dist/client/entry.d.ts.map +0 -1
- package/dist/client/entry.js +0 -3
- package/dist/client/entry.js.map +0 -1
- package/dist/client/page/resolvedDocumentFailure.d.ts.map +0 -1
- package/dist/client/page/resolvedDocumentFailure.js.map +0 -1
- package/dist/client/page/routeQuery.d.ts.map +0 -1
- package/dist/client/page/routeQuery.js.map +0 -1
- package/dist/client/react/RespondPage.d.ts +0 -5
- package/dist/client/react/RespondPage.d.ts.map +0 -1
- package/dist/client/react/RespondPage.js +0 -5
- package/dist/client/react/RespondPage.js.map +0 -1
- package/dist/server/responses/service.d.ts.map +0 -1
- package/dist/server/responses/service.js.map +0 -1
- package/src/client/entry.ts +0 -3
- package/src/client/react/RespondPage.tsx +0 -8
- /package/dist/client/{page → react}/resolvedDocumentFailure.d.ts +0 -0
- /package/dist/client/{page → react}/resolvedDocumentFailure.js +0 -0
- /package/dist/client/{page → react}/routeQuery.d.ts +0 -0
- /package/dist/client/{page → react}/routeQuery.js +0 -0
- /package/src/client/{page → react}/resolvedDocumentFailure.ts +0 -0
- /package/src/client/{page → react}/routeQuery.ts +0 -0
|
@@ -2,7 +2,7 @@ export function readerLink(target: URL) {
|
|
|
2
2
|
return (
|
|
3
3
|
target.origin === location.origin
|
|
4
4
|
&& (target.pathname === "/"
|
|
5
|
-
|| /^\/_board\/(?:library|goals|system|diagnostics|handoff|result|
|
|
5
|
+
|| /^\/_board\/(?:library|goals|system|diagnostics|handoff|result|start|changes|inbox|overview|work)$/u.test(target.pathname)
|
|
6
6
|
|| target.pathname.startsWith("/_board/item/")
|
|
7
7
|
|| /\.md$/iu.test(target.pathname))
|
|
8
8
|
);
|
|
@@ -11,7 +11,7 @@ import { authorLabel } from "#client/responses/authorLabel.ts";
|
|
|
11
11
|
import { type ResponseInput, responseFormSchema } from "#client/responses/formSchema.ts";
|
|
12
12
|
import { responsePreview } from "#client/responses/preview.ts";
|
|
13
13
|
import { retainContext } from "#client/responses/retainContext.ts";
|
|
14
|
-
import { responseFeedback, responseSummary } from "#client/responses/summary.ts";
|
|
14
|
+
import { chosenLabels, responseFeedback, responseSummary } from "#client/responses/summary.ts";
|
|
15
15
|
import { sourceChanged } from "#client/sourceChanged.ts";
|
|
16
16
|
import { createResponse } from "./createResponse.ts";
|
|
17
17
|
import { useFormClient } from "./FormContext.ts";
|
|
@@ -116,7 +116,9 @@ export function useResponseForm(source: QuestionPreview, prompts: readonly Promp
|
|
|
116
116
|
setInteraction("cleared");
|
|
117
117
|
}
|
|
118
118
|
const previewed = preview !== undefined && same && Equal.equals(preview, values);
|
|
119
|
-
const { outcome, text: status } = formStatus(created, interaction, "response", (saved) =>
|
|
119
|
+
const { outcome, text: status } = formStatus(created, interaction, "response", (saved) =>
|
|
120
|
+
responseSaved(saved.id, created.dirty, chosenLabels(prompts, saved.answers)),
|
|
121
|
+
);
|
|
120
122
|
const summary = responseSummary(values, prompts, answers(values), attempted);
|
|
121
123
|
return {
|
|
122
124
|
answers: answers(values),
|
|
@@ -1,3 +1,4 @@
|
|
|
1
|
+
import { optionText, promptHeading } from "#browser/responses/cardContext.ts";
|
|
1
2
|
import type { Prompt } from "#browser/responses/Prompt.ts";
|
|
2
3
|
import type { PromptAnswer } from "#browser/responses/schema.ts";
|
|
3
4
|
import type { ResponseInput } from "./formSchema.ts";
|
|
@@ -14,7 +15,9 @@ export function responseSummary(values: ResponseInput, prompts: readonly Prompt[
|
|
|
14
15
|
: [];
|
|
15
16
|
return [
|
|
16
17
|
values.author.trim() ? "" : "Add your local author label.",
|
|
17
|
-
missing.length > 0
|
|
18
|
+
missing.length > 0
|
|
19
|
+
? `Unanswered: ${missing.map((prompt) => `“${promptHeading(prompt.source).title ?? `Question ${prompts.indexOf(prompt) + 1}`}”`).join(", ")}.`
|
|
20
|
+
: "",
|
|
18
21
|
]
|
|
19
22
|
.filter(Boolean)
|
|
20
23
|
.join(" ");
|
|
@@ -23,3 +26,12 @@ export function responseSummary(values: ResponseInput, prompts: readonly Prompt[
|
|
|
23
26
|
export function responseFeedback(status: string, outcome: string | undefined, summary: string) {
|
|
24
27
|
return outcome || status.startsWith("Draft cleared") ? status : summary || status;
|
|
25
28
|
}
|
|
29
|
+
|
|
30
|
+
export function chosenLabels(prompts: readonly Prompt[], answers: readonly PromptAnswer[] | undefined) {
|
|
31
|
+
return prompts
|
|
32
|
+
.flatMap((prompt) => {
|
|
33
|
+
const selected = answers?.find((answer) => answer.prompt === prompt.id)?.selected ?? [];
|
|
34
|
+
return prompt.options.filter((option) => selected.includes(option.id)).map((option) => optionText(option.id, option.source, "").label);
|
|
35
|
+
})
|
|
36
|
+
.join(", ");
|
|
37
|
+
}
|
package/src/responses/url.ts
CHANGED
|
@@ -1,3 +1,3 @@
|
|
|
1
1
|
export function responseUrl(item: string, request: string): string {
|
|
2
|
-
return `/_board/
|
|
2
|
+
return `/_board/item/${encodeURIComponent(item)}/#${encodeURIComponent(`answer-card-${request}`)}`;
|
|
3
3
|
}
|
package/src/rpc/PageUrl.ts
CHANGED
package/src/rpc/contract.ts
CHANGED
|
@@ -10,7 +10,7 @@ import { Library, LibraryInput } from "#browser/navigation/library.ts";
|
|
|
10
10
|
import { FleetItemsProjection } from "#browser/views/FleetItemsProjection.ts";
|
|
11
11
|
import { GoalsProjection } from "#browser/views/GoalsProjection.ts";
|
|
12
12
|
import { ResultProjection } from "#browser/views/ResultProjection.ts";
|
|
13
|
-
import { DiagnosticsProjection, HandoffProjection,
|
|
13
|
+
import { DiagnosticsProjection, HandoffProjection, StartProjection } from "#browser/views/remaining.ts";
|
|
14
14
|
import { BoardProjection, InboxProjection, WorkProjection } from "#browser/views/schema.ts";
|
|
15
15
|
import { handoffContract } from "#rpc/handoffContract.ts";
|
|
16
16
|
import { responseContract } from "#rpc/responseContract.ts";
|
|
@@ -53,15 +53,13 @@ const ReadWork = query("work", {
|
|
|
53
53
|
const ReadInbox = query("inbox", { reads: () => [workspace.list, index.list], rejections: { InternalServerError }, success: InboxProjection });
|
|
54
54
|
const ReadServer = query("server", { reads: () => [], rejections: { ServiceUnavailable }, success: Server });
|
|
55
55
|
const ReadDiagnostics = query("diagnostics", { reads: () => [workspace.list], rejections: { InternalServerError }, success: DiagnosticsProjection });
|
|
56
|
-
const ReadFleetItems = query("fleetItems", {
|
|
56
|
+
const ReadFleetItems = query("fleetItems", {
|
|
57
|
+
reads: () => [workspace.list, index.list],
|
|
58
|
+
rejections: { InternalServerError },
|
|
59
|
+
success: FleetItemsProjection,
|
|
60
|
+
});
|
|
57
61
|
const ReadGoals = query("goals", { reads: () => [workspace.list, index.list], rejections: { InternalServerError }, success: GoalsProjection });
|
|
58
62
|
const ReadStart = query("start", { reads: () => [workspace.list, index.list], rejections: { InternalServerError }, success: StartProjection });
|
|
59
|
-
const ReadRespond = query("respond", {
|
|
60
|
-
payload: { url: PageUrl },
|
|
61
|
-
reads: ({ url }) => [...pageKeys(url), index.list],
|
|
62
|
-
rejections: documentRejections,
|
|
63
|
-
success: RespondProjection,
|
|
64
|
-
});
|
|
65
63
|
const ReadHandoff = query("handoff", {
|
|
66
64
|
payload: { url: PageUrl },
|
|
67
65
|
reads: () => [workspace.list, index.list],
|
|
@@ -109,7 +107,6 @@ export const workContract = contract("work-board", {
|
|
|
109
107
|
ReadFleetItems,
|
|
110
108
|
ReadGoals,
|
|
111
109
|
ReadStart,
|
|
112
|
-
ReadRespond,
|
|
113
110
|
ReadHandoff,
|
|
114
111
|
ReadResult,
|
|
115
112
|
ReadNavigation,
|
|
@@ -1,29 +1,20 @@
|
|
|
1
|
-
import { Clock,
|
|
1
|
+
import { Clock, Effect, FileSystem, Path, Schema, Semaphore } from "effect";
|
|
2
2
|
import { defineService } from "@shivaedev/effect-service/define-service.ts";
|
|
3
3
|
import { Conflict, Forbidden, PreconditionFailed, ServiceUnavailable } from "@shivaedev/platform/errors/taxonomy.ts";
|
|
4
4
|
import { rpcBoundary } from "@shivaedev/platform/rpc-server/boundary.ts";
|
|
5
5
|
import type { DraftInput } from "#browser/responses/schema.ts";
|
|
6
|
-
import
|
|
7
|
-
import
|
|
8
|
-
import {
|
|
9
|
-
import {
|
|
10
|
-
import {
|
|
11
|
-
import {
|
|
12
|
-
import {
|
|
13
|
-
import {
|
|
14
|
-
import {
|
|
15
|
-
import {
|
|
16
|
-
import {
|
|
17
|
-
import {
|
|
18
|
-
import { validateSupersedes } from "./validateSupersedes.ts";
|
|
19
|
-
|
|
20
|
-
export interface ResponseOptions {
|
|
21
|
-
readonly changes: Changes;
|
|
22
|
-
readonly enabled: boolean;
|
|
23
|
-
readonly index: Effect.Effect<Snapshot, unknown>;
|
|
24
|
-
readonly root: string;
|
|
25
|
-
}
|
|
26
|
-
export class ResponseConfig extends Context.Service<ResponseConfig, ResponseOptions>()("WorkBoard/ResponseConfig") {}
|
|
6
|
+
import { awaitResponse } from "#server/responses/await.ts";
|
|
7
|
+
import { responseHistory } from "#server/responses/history.ts";
|
|
8
|
+
import { locate as locateQuestion } from "#server/responses/locate.ts";
|
|
9
|
+
import { makeResponse } from "#server/responses/make.ts";
|
|
10
|
+
import { publish } from "#server/responses/publish.ts";
|
|
11
|
+
import { readResponses } from "#server/responses/read.ts";
|
|
12
|
+
import { responseMarkdown } from "#server/responses/records.ts";
|
|
13
|
+
import { registerQuestion } from "#server/responses/registerQuestion.ts";
|
|
14
|
+
import { retryResponse } from "#server/responses/retry.ts";
|
|
15
|
+
import { validatedInput } from "#server/responses/validatedInput.ts";
|
|
16
|
+
import { validateSupersedes } from "#server/responses/validateSupersedes.ts";
|
|
17
|
+
import { Workspace } from "#server/workspace.ts";
|
|
27
18
|
|
|
28
19
|
function invalidResponse(cause: unknown): Conflict {
|
|
29
20
|
return Schema.is(Conflict)(cause)
|
|
@@ -34,19 +25,20 @@ function invalidResponse(cause: unknown): Conflict {
|
|
|
34
25
|
export const Responses = defineService({
|
|
35
26
|
id: "WorkBoard/Responses",
|
|
36
27
|
initialize: Effect.gen(function* () {
|
|
37
|
-
|
|
28
|
+
const workspace = yield* Workspace;
|
|
29
|
+
return { fs: yield* FileSystem.FileSystem, lock: yield* Semaphore.make(1), options: yield* workspace.settings(), workspace };
|
|
38
30
|
}),
|
|
39
|
-
methods: ({ options, fs, lock }) => {
|
|
40
|
-
const snapshot =
|
|
31
|
+
methods: ({ options, fs, lock, workspace }) => {
|
|
32
|
+
const snapshot = workspace.index().pipe(
|
|
41
33
|
rpcBoundary(ServiceUnavailable, {
|
|
42
34
|
message: "The workspace could not be indexed.",
|
|
43
35
|
unexpected: (message) => new ServiceUnavailable({ message }),
|
|
44
36
|
}),
|
|
45
37
|
);
|
|
46
|
-
const enabled = options.
|
|
38
|
+
const enabled = options.writable
|
|
47
39
|
? Effect.void
|
|
48
40
|
: Effect.fail(new Forbidden({ message: "Start with --responses to explicitly enable local question/response writes." }));
|
|
49
|
-
const locate = locateQuestion(options.root, options.
|
|
41
|
+
const locate = locateQuestion(options.root, options.realRoot, snapshot, fs);
|
|
50
42
|
const read = readResponses(snapshot);
|
|
51
43
|
const register = registerQuestion(options, snapshot, locate, read);
|
|
52
44
|
function record(draft: DraftInput) {
|
|
@@ -80,7 +72,7 @@ export const Responses = defineService({
|
|
|
80
72
|
question,
|
|
81
73
|
result.responses.reduce((time, saved) => Math.max(time, saved.response.recordedAt + 1), yield* Clock.currentTimeMillis),
|
|
82
74
|
);
|
|
83
|
-
yield* publish(options.root, options.
|
|
75
|
+
yield* publish(options.root, options.realRoot, response.id, responseMarkdown(response)).pipe(
|
|
84
76
|
Effect.ensuring(options.changes.refresh ?? Effect.void),
|
|
85
77
|
);
|
|
86
78
|
return response;
|
|
@@ -107,6 +99,6 @@ export const Responses = defineService({
|
|
|
107
99
|
register: (input: Parameters<typeof register>[0]) => lock.withPermit(register(input)),
|
|
108
100
|
};
|
|
109
101
|
},
|
|
110
|
-
requires: [
|
|
102
|
+
requires: [Workspace, FileSystem.FileSystem, Path.Path],
|
|
111
103
|
});
|
|
112
104
|
export type Responses = typeof Responses.Identifier;
|
|
@@ -6,7 +6,7 @@ import type { Snapshot } from "#server/search/snapshot.ts";
|
|
|
6
6
|
import { answeredQuestion } from "./questionState.ts";
|
|
7
7
|
import { requestInbox } from "./requestInbox.ts";
|
|
8
8
|
import { isMaintainerRequest } from "./requests.ts";
|
|
9
|
-
import { closedItem } from "./status.ts";
|
|
9
|
+
import { closedItem, deferredItem } from "./status.ts";
|
|
10
10
|
|
|
11
11
|
const automation = /^(?:codex|claude|fleet|orchestrator|agent|automation|bot|copilot)(?:$|[-_. /])/iu;
|
|
12
12
|
|
|
@@ -24,6 +24,10 @@ function addressedElsewhere(document: MetadataDocument, maintainer: string): boo
|
|
|
24
24
|
}
|
|
25
25
|
|
|
26
26
|
export function waitingReason(document: MetadataDocument, model: MetadataModel, maintainer = "maintainer"): string | undefined {
|
|
27
|
+
return deferredItem(document) ? undefined : attentionReason(document, model, maintainer);
|
|
28
|
+
}
|
|
29
|
+
|
|
30
|
+
function attentionReason(document: MetadataDocument, model: MetadataModel, maintainer: string): string | undefined {
|
|
27
31
|
const fields = document.parsed.fields;
|
|
28
32
|
if (!openItem(document) || fields.kind === "response" || fields.kind === "handoff" || fields.question) {
|
|
29
33
|
return undefined;
|
|
@@ -64,38 +68,59 @@ function inboxTarget(document: MetadataDocument, problem: string | undefined): s
|
|
|
64
68
|
return answer ? responseUrl(item, answer) : identityUrl(item);
|
|
65
69
|
}
|
|
66
70
|
|
|
67
|
-
|
|
68
|
-
if (snapshot.unavailable.length > 0) {
|
|
69
|
-
return [];
|
|
70
|
-
}
|
|
71
|
+
function directItems(snapshot: Snapshot, skipped: ReadonlySet<string>, reasonOf: (document: MetadataDocument) => string | undefined) {
|
|
71
72
|
const titles = new Map(snapshot.entries.filter((entry) => entry.kind === "document").map((entry) => [entry.file, entry.title]));
|
|
72
|
-
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
if (requests.files.has(document.file)) {
|
|
73
|
+
return snapshot.documents.flatMap((document) => {
|
|
74
|
+
const reason = skipped.has(document.file) ? undefined : reasonOf(document);
|
|
75
|
+
if (!reason) {
|
|
76
76
|
return [];
|
|
77
77
|
}
|
|
78
78
|
const id = document.parsed.fields.id;
|
|
79
79
|
const problem = identityProblem(document, snapshot.model);
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
88
|
-
|
|
89
|
-
|
|
90
|
-
|
|
91
|
-
|
|
92
|
-
|
|
93
|
-
: [];
|
|
80
|
+
return [
|
|
81
|
+
{
|
|
82
|
+
document,
|
|
83
|
+
href: inboxTarget(document, problem),
|
|
84
|
+
id: id ?? document.file,
|
|
85
|
+
modified: snapshot.modified.get(document.file),
|
|
86
|
+
problem,
|
|
87
|
+
reason,
|
|
88
|
+
request: undefined,
|
|
89
|
+
title: titles.get(document.file) ?? document.file,
|
|
90
|
+
unblocks: [id ?? ""],
|
|
91
|
+
},
|
|
92
|
+
];
|
|
94
93
|
});
|
|
95
|
-
|
|
94
|
+
}
|
|
95
|
+
|
|
96
|
+
function byAge(
|
|
97
|
+
left: { readonly id: string; readonly modified: number | undefined },
|
|
98
|
+
right: { readonly id: string; readonly modified: number | undefined },
|
|
99
|
+
) {
|
|
100
|
+
return (left.modified ?? 0) - (right.modified ?? 0) || left.id.localeCompare(right.id);
|
|
101
|
+
}
|
|
102
|
+
|
|
103
|
+
export function inboxItems(snapshot: Snapshot) {
|
|
104
|
+
if (snapshot.unavailable.length > 0) {
|
|
105
|
+
return [];
|
|
106
|
+
}
|
|
107
|
+
const requests = requestInbox(snapshot);
|
|
108
|
+
const you = requests.items.filter((item) => item.responseFrom.includes(snapshot.maintainer ?? "maintainer"));
|
|
109
|
+
const ordinary = directItems(snapshot, requests.files, (document) => waitingReason(document, snapshot.model, snapshot.maintainer))
|
|
96
110
|
.filter((item) => item.problem || !you.some((ask) => ask.id === item.id))
|
|
97
|
-
.map((item) => ({ ...item, earlierAsks: 0
|
|
98
|
-
return [...ordinary, ...you].sort(
|
|
111
|
+
.map((item) => ({ ...item, earlierAsks: 0 }));
|
|
112
|
+
return [...ordinary, ...you].sort(byAge);
|
|
113
|
+
}
|
|
114
|
+
|
|
115
|
+
export function laterItems(snapshot: Snapshot) {
|
|
116
|
+
if (snapshot.unavailable.length > 0) {
|
|
117
|
+
return [];
|
|
118
|
+
}
|
|
119
|
+
function parked(document: MetadataDocument) {
|
|
120
|
+
const reason = deferredItem(document) ? attentionReason(document, snapshot.model, snapshot.maintainer ?? "maintainer") : undefined;
|
|
121
|
+
return reason && (document.parsed.fields.nextAction ?? reason);
|
|
122
|
+
}
|
|
123
|
+
return directItems(snapshot, requestInbox(snapshot).files, parked).sort(byAge);
|
|
99
124
|
}
|
|
100
125
|
|
|
101
126
|
export function fleetRecords(model: MetadataModel): ReadonlySet<string> {
|
|
@@ -6,6 +6,13 @@ import { questionId, revisionOf } from "#server/responses/records.ts";
|
|
|
6
6
|
|
|
7
7
|
type Request = NonNullable<Metadata["attention"]>[number];
|
|
8
8
|
|
|
9
|
+
export type ManagedRequestState =
|
|
10
|
+
| { readonly _tag: "Open" }
|
|
11
|
+
| { readonly _tag: "Settled"; readonly receipt: RequestReceipt }
|
|
12
|
+
| { readonly _tag: "Conflicting"; readonly receipts: readonly string[] };
|
|
13
|
+
|
|
14
|
+
const open: ManagedRequestState = { _tag: "Open" };
|
|
15
|
+
|
|
9
16
|
function uniqueDocument(id: string, model: MetadataModel): MetadataDocument | undefined {
|
|
10
17
|
const matches = model.ids.get(id);
|
|
11
18
|
return matches?.length === 1 ? matches[0] : undefined;
|
|
@@ -38,7 +45,7 @@ function appliedAnswer(question: string, revision: string, responseId: string |
|
|
|
38
45
|
return current.length === 1 && current[0]?.id === responseId;
|
|
39
46
|
}
|
|
40
47
|
|
|
41
|
-
|
|
48
|
+
function registeredQuestion(document: MetadataDocument, request: Request, model: MetadataModel) {
|
|
42
49
|
const item = document.parsed.fields.id;
|
|
43
50
|
if (
|
|
44
51
|
request.managed !== true
|
|
@@ -57,7 +64,6 @@ export function managedRequestReceipt(document: MetadataDocument, request: Reque
|
|
|
57
64
|
const revision = revisionOf(source);
|
|
58
65
|
const id = questionId(item, request.id, revision, document.file);
|
|
59
66
|
const archived = uniqueDocument(id, model);
|
|
60
|
-
const index = responseIndex(model);
|
|
61
67
|
const question = registeredContext(archived, model);
|
|
62
68
|
if (
|
|
63
69
|
archived?.parsed.diagnostics.length !== 0
|
|
@@ -70,14 +76,13 @@ export function managedRequestReceipt(document: MetadataDocument, request: Reque
|
|
|
70
76
|
) {
|
|
71
77
|
return undefined;
|
|
72
78
|
}
|
|
73
|
-
|
|
74
|
-
|
|
75
|
-
|
|
76
|
-
|
|
77
|
-
const
|
|
78
|
-
const receipt = saved?.parsed.fields.requestReceipt;
|
|
79
|
+
return { id, revision };
|
|
80
|
+
}
|
|
81
|
+
|
|
82
|
+
function qualified(saved: MetadataDocument, question: string, revision: string, model: MetadataModel): RequestReceipt | undefined {
|
|
83
|
+
const receipt = saved.parsed.fields.requestReceipt;
|
|
79
84
|
if (
|
|
80
|
-
!
|
|
85
|
+
!receipt
|
|
81
86
|
|| saved.parsed.fields.kind !== "result"
|
|
82
87
|
|| saved.parsed.diagnostics.length > 0
|
|
83
88
|
|| !saved.parsed.fields.id
|
|
@@ -89,5 +94,31 @@ export function managedRequestReceipt(document: MetadataDocument, request: Reque
|
|
|
89
94
|
if (receipt.disposition === "superseded") {
|
|
90
95
|
return receipt.response === undefined ? receipt : undefined;
|
|
91
96
|
}
|
|
92
|
-
return appliedAnswer(
|
|
97
|
+
return appliedAnswer(question, revision, receipt.response, model) ? receipt : undefined;
|
|
98
|
+
}
|
|
99
|
+
|
|
100
|
+
function settling(receipts: readonly RequestReceipt[]): RequestReceipt | undefined {
|
|
101
|
+
return receipts.toSorted(
|
|
102
|
+
(left, right) => Number(right.disposition === "applied") - Number(left.disposition === "applied") || right.recordedAt - left.recordedAt,
|
|
103
|
+
)[0];
|
|
104
|
+
}
|
|
105
|
+
|
|
106
|
+
export function managedRequestState(document: MetadataDocument, request: Request, model: MetadataModel): ManagedRequestState {
|
|
107
|
+
const question = registeredQuestion(document, request, model);
|
|
108
|
+
const index = responseIndex(model);
|
|
109
|
+
if (!question || index.receiptProblems) {
|
|
110
|
+
return open;
|
|
111
|
+
}
|
|
112
|
+
const saved = index.receipts.get(question.id) ?? [];
|
|
113
|
+
const receipts = saved.flatMap((candidate) => qualified(candidate, question.id, question.revision, model) ?? []);
|
|
114
|
+
const receipt = receipts.length === saved.length ? settling(receipts) : undefined;
|
|
115
|
+
if (receipt) {
|
|
116
|
+
return { _tag: "Settled", receipt };
|
|
117
|
+
}
|
|
118
|
+
return receipts.length > 0 ? { _tag: "Conflicting", receipts: saved.map((candidate) => candidate.file) } : open;
|
|
119
|
+
}
|
|
120
|
+
|
|
121
|
+
export function managedRequestReceipt(document: MetadataDocument, request: Request, model: MetadataModel): RequestReceipt | undefined {
|
|
122
|
+
const state = managedRequestState(document, request, model);
|
|
123
|
+
return state._tag === "Settled" ? state.receipt : undefined;
|
|
93
124
|
}
|
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
import type { InboxProjection } from "#browser/views/schema.ts";
|
|
2
2
|
import type { Snapshot } from "#server/search/snapshot.ts";
|
|
3
|
-
import { inboxItems } from "./inbox.ts";
|
|
3
|
+
import { inboxItems, laterItems } from "./inbox.ts";
|
|
4
4
|
import { requestInbox } from "./requestInbox.ts";
|
|
5
5
|
import { attentionRequests } from "./requests.ts";
|
|
6
6
|
|
|
@@ -12,7 +12,9 @@ export function attentionProjection(snapshot: Snapshot): InboxProjection {
|
|
|
12
12
|
return cached;
|
|
13
13
|
}
|
|
14
14
|
const requests = requestInbox(snapshot);
|
|
15
|
-
function project
|
|
15
|
+
function project<
|
|
16
|
+
TRow extends { readonly document: { readonly file: string }; readonly request: string | undefined; readonly unblocks: readonly string[] },
|
|
17
|
+
>({ document, request: _request, unblocks: _unblocks, ...item }: TRow) {
|
|
16
18
|
return { ...item, file: document.file };
|
|
17
19
|
}
|
|
18
20
|
const you = inboxItems(snapshot).map(project);
|
|
@@ -22,6 +24,7 @@ export function attentionProjection(snapshot: Snapshot): InboxProjection {
|
|
|
22
24
|
complete: snapshot.unavailable.length === 0,
|
|
23
25
|
issues,
|
|
24
26
|
items: you,
|
|
27
|
+
later: laterItems(snapshot).map(project),
|
|
25
28
|
parked: requests.parked.map(project),
|
|
26
29
|
resolved: requests.resolved.map(project),
|
|
27
30
|
sourceIssues: issues.length > 0,
|
|
@@ -23,11 +23,12 @@ export function requestInbox(snapshot: Snapshot) {
|
|
|
23
23
|
return {
|
|
24
24
|
document: entry.document,
|
|
25
25
|
earlierAsks: 0,
|
|
26
|
-
href: responseUrl(entry.itemId, entry.request.id),
|
|
26
|
+
href: entry.problem === undefined ? responseUrl(entry.itemId, entry.request.id) : entry.href,
|
|
27
27
|
id: target?.parsed.fields.id ?? entry.itemId,
|
|
28
28
|
modified: snapshot.modified.get(entry.document.file),
|
|
29
|
-
problem:
|
|
29
|
+
problem: entry.problem,
|
|
30
30
|
reason: entry.request.managed ? `Managed decision: ${entry.request.reason}` : entry.request.reason,
|
|
31
|
+
request: entry.request.id,
|
|
31
32
|
responseFrom: entry.request.responseFrom,
|
|
32
33
|
title: (target ? titles.get(target.file) : undefined) ?? entry.title,
|
|
33
34
|
unblocks: entry.request.unblocks,
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import type { Metadata } from "#metadata/schema.ts";
|
|
2
|
-
import {
|
|
2
|
+
import { managedRequestState } from "#server/attention/managedRequestReceipt.ts";
|
|
3
3
|
import { identityUrl, referenceTarget } from "#server/metadata/links.ts";
|
|
4
4
|
import type { MetadataDocument } from "#server/metadata/model.ts";
|
|
5
5
|
import type { Snapshot } from "#server/search/snapshot.ts";
|
|
@@ -10,6 +10,7 @@ export interface AttentionEntry {
|
|
|
10
10
|
readonly href: string;
|
|
11
11
|
readonly itemId: string;
|
|
12
12
|
readonly line: number;
|
|
13
|
+
readonly problem: string | undefined;
|
|
13
14
|
readonly request: Request;
|
|
14
15
|
readonly title: string;
|
|
15
16
|
}
|
|
@@ -35,16 +36,20 @@ function requestsFor(document: MetadataDocument, snapshot: Snapshot, title: stri
|
|
|
35
36
|
request.state !== "open"
|
|
36
37
|
|| requests.filter((other) => other.id === request.id).length !== 1
|
|
37
38
|
|| request.unblocks.some((target) => !referenceTarget(target, snapshot.model))
|
|
38
|
-
|| managedRequestReceipt(document, request, snapshot.model) !== undefined
|
|
39
39
|
) {
|
|
40
40
|
return [];
|
|
41
41
|
}
|
|
42
|
+
const receipts = managedRequestState(document, request, snapshot.model);
|
|
43
|
+
if (receipts._tag === "Settled") {
|
|
44
|
+
return [];
|
|
45
|
+
}
|
|
42
46
|
return [
|
|
43
47
|
{
|
|
44
48
|
document,
|
|
45
49
|
href: `${identityUrl(itemId)}#attention-request-${encodeURIComponent(request.id)}`,
|
|
46
50
|
itemId,
|
|
47
51
|
line: lines[`attention.${index}`] ?? lines.attention ?? 2,
|
|
52
|
+
problem: receipts._tag === "Conflicting" ? `Request receipts disagree: ${receipts.receipts.join(", ")}` : undefined,
|
|
48
53
|
request,
|
|
49
54
|
title,
|
|
50
55
|
},
|
|
@@ -1,16 +1,15 @@
|
|
|
1
1
|
import { Context, Effect, FileSystem, Layer, Path, type PlatformError } from "effect";
|
|
2
|
-
import { DiagnosticsSources } from "#diagnostics/source.ts";
|
|
2
|
+
import { DiagnosticsConfig, DiagnosticsSources } from "#diagnostics/source.ts";
|
|
3
3
|
import type { BoardOptions } from "#server/board.ts";
|
|
4
4
|
import { boardServices } from "#server/boardServices.ts";
|
|
5
5
|
import { daemonDiagnostics } from "#server/diagnostics/daemon.ts";
|
|
6
|
-
import { readDocument } from "#server/document/read.ts";
|
|
7
6
|
import { watchChanges } from "#server/files/changes.ts";
|
|
8
7
|
import { homeIn } from "#server/files/home.ts";
|
|
9
8
|
import { checkBrowserAssets, mermaidRoot } from "#server/http/assets.ts";
|
|
10
9
|
import { Highlighter } from "#server/render/Highlighter.ts";
|
|
11
10
|
import type { HandlerOptions } from "#server/rpc/HandlerOptions.ts";
|
|
12
|
-
import { handlers } from "#server/rpc/handlers.ts";
|
|
13
11
|
import { type Snapshot, searchSnapshot } from "#server/search/snapshot.ts";
|
|
12
|
+
import { Workspace, WorkspaceConfig } from "#server/workspace.ts";
|
|
14
13
|
|
|
15
14
|
export const boardRuntime = Effect.fn("WorkBoard.boardRuntime")(function* (options: BoardOptions, server?: HandlerOptions["server"]) {
|
|
16
15
|
const home = yield* homeIn(options.root, options.home);
|
|
@@ -28,30 +27,26 @@ export const boardRuntime = Effect.fn("WorkBoard.boardRuntime")(function* (optio
|
|
|
28
27
|
);
|
|
29
28
|
const provided = yield* Effect.serviceOption(DiagnosticsSources);
|
|
30
29
|
const services = yield* Layer.build(
|
|
31
|
-
boardServices(
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
)
|
|
35
|
-
|
|
36
|
-
|
|
37
|
-
|
|
38
|
-
...(options.fleetPort === undefined ? {} : { fleetPort: options.fleetPort }),
|
|
39
|
-
changes,
|
|
40
|
-
document: (url) =>
|
|
41
|
-
Effect.provideContext(
|
|
42
|
-
readDocument({
|
|
30
|
+
boardServices({
|
|
31
|
+
...(options.fleetPort === undefined ? {} : { fleetPort: options.fleetPort }),
|
|
32
|
+
...(server === undefined ? {} : { server }),
|
|
33
|
+
}).pipe(
|
|
34
|
+
Layer.provideMerge(Workspace.layer),
|
|
35
|
+
Layer.provide([
|
|
36
|
+
Layer.succeed(WorkspaceConfig, {
|
|
43
37
|
changes,
|
|
44
38
|
home,
|
|
45
|
-
index: Effect.provideContext(index,
|
|
39
|
+
index: Effect.provideContext(index, platform),
|
|
46
40
|
root: options.root,
|
|
47
41
|
writable: options.responses === true,
|
|
48
|
-
})
|
|
49
|
-
|
|
50
|
-
|
|
51
|
-
|
|
52
|
-
|
|
53
|
-
|
|
54
|
-
|
|
55
|
-
|
|
56
|
-
|
|
42
|
+
}),
|
|
43
|
+
Layer.succeed(
|
|
44
|
+
DiagnosticsConfig,
|
|
45
|
+
provided._tag === "Some" ? { _tag: "Sources", sources: provided.value } : { _tag: "Read", read: daemonDiagnostics(options.fleetPort) },
|
|
46
|
+
),
|
|
47
|
+
]),
|
|
48
|
+
),
|
|
49
|
+
);
|
|
50
|
+
const context = Context.merge(platform, services);
|
|
51
|
+
return { changes, context, home, index, mermaid, rpcHandlers: Layer.succeedContext(services) };
|
|
57
52
|
});
|
|
@@ -1,10 +1,10 @@
|
|
|
1
|
-
import {
|
|
2
|
-
import { Diagnostics
|
|
1
|
+
import { Layer } from "effect";
|
|
2
|
+
import { Diagnostics } from "#diagnostics/source.ts";
|
|
3
3
|
import { HandoffsService } from "#server/handoffs/Service.ts";
|
|
4
|
-
import {
|
|
4
|
+
import { Responses } from "#server/Responses.ts";
|
|
5
|
+
import type { HandlerOptions } from "#server/rpc/HandlerOptions.ts";
|
|
6
|
+
import { handlers } from "#server/rpc/handlers.ts";
|
|
5
7
|
|
|
6
|
-
export function boardServices(options:
|
|
7
|
-
return Layer.mergeAll(Responses.layer, HandoffsService.layer, Diagnostics.layer)
|
|
8
|
-
Layer.provide(Layer.merge(Layer.succeed(ResponseConfig, options), Layer.succeed(DiagnosticsConfig, diagnostics))),
|
|
9
|
-
);
|
|
8
|
+
export function boardServices(options: HandlerOptions = {}) {
|
|
9
|
+
return Layer.unwrap(handlers(options)).pipe(Layer.provideMerge(Layer.mergeAll(Responses.layer, HandoffsService.layer, Diagnostics.layer)));
|
|
10
10
|
}
|
|
@@ -2,24 +2,17 @@ import { Effect, FileSystem } from "effect";
|
|
|
2
2
|
import { Conflict, NotFound, ServiceUnavailable } from "@shivaedev/platform/errors/taxonomy.ts";
|
|
3
3
|
import type { Document } from "#browser/document/schema.ts";
|
|
4
4
|
import { currentDocument } from "#server/currentDocument.ts";
|
|
5
|
-
import type { Changes } from "#server/files/changes.ts";
|
|
6
5
|
import type { MarkdownFile } from "#server/files/list.ts";
|
|
7
6
|
import { markdownPath } from "#server/files/markdownPath.ts";
|
|
7
|
+
import { locate } from "#server/responses/locate.ts";
|
|
8
8
|
import { readingActions } from "#server/responses/readingActions.ts";
|
|
9
9
|
import type { Snapshot } from "#server/search/snapshot.ts";
|
|
10
|
+
import type { WorkspaceSettings } from "#server/workspace.ts";
|
|
10
11
|
import { answerBody } from "./answerBody.ts";
|
|
11
12
|
import { readingContext } from "./readingContext.ts";
|
|
12
13
|
import { documentRequests } from "./requests.ts";
|
|
13
14
|
import { documentTargets } from "./targets.ts";
|
|
14
15
|
|
|
15
|
-
export interface DocumentOptions {
|
|
16
|
-
readonly changes: Changes;
|
|
17
|
-
readonly home: string | undefined;
|
|
18
|
-
readonly index: Effect.Effect<Snapshot, unknown>;
|
|
19
|
-
readonly root: string;
|
|
20
|
-
readonly writable: boolean;
|
|
21
|
-
}
|
|
22
|
-
|
|
23
16
|
const selected = Effect.fn("WorkBoard.selected")(function* (
|
|
24
17
|
url: string,
|
|
25
18
|
snapshot: Snapshot,
|
|
@@ -45,12 +38,11 @@ const selected = Effect.fn("WorkBoard.selected")(function* (
|
|
|
45
38
|
return { file, item };
|
|
46
39
|
});
|
|
47
40
|
|
|
48
|
-
export function readDocument({ changes, home,
|
|
49
|
-
return Effect.fn("WorkBoard.document")(function* (url: string) {
|
|
50
|
-
const snapshot = yield* index;
|
|
41
|
+
export function readDocument({ changes, home, root, realRoot, writable }: WorkspaceSettings) {
|
|
42
|
+
return Effect.fn("WorkBoard.document")(function* (url: string, snapshot: Snapshot) {
|
|
51
43
|
const files = yield* changes.files;
|
|
52
44
|
const { file, item } = yield* selected(url, snapshot, files, home);
|
|
53
|
-
const real = yield* markdownPath(root,
|
|
45
|
+
const real = yield* markdownPath(root, realRoot, file.path);
|
|
54
46
|
if (!real) {
|
|
55
47
|
return yield* Effect.fail(new NotFound({ message: "The document is missing." }));
|
|
56
48
|
}
|
|
@@ -65,7 +57,7 @@ export function readDocument({ changes, home, index, root, writable }: DocumentO
|
|
|
65
57
|
if (item && identity !== item) {
|
|
66
58
|
return yield* Effect.fail(new NotFound({ message: "The document is missing." }));
|
|
67
59
|
}
|
|
68
|
-
const questionActions = yield* readingActions(document, source, writable, identity);
|
|
60
|
+
const questionActions = yield* readingActions(document, source, writable, identity, locate(root, realRoot, Effect.succeed(snapshot), fs));
|
|
69
61
|
const titles = new Map(current.snapshot.entries.filter((entry) => entry.kind === "document").map((entry) => [entry.file, entry.title]));
|
|
70
62
|
const reading = readingContext(document, model, file.path === home, titles);
|
|
71
63
|
const targets = documentTargets(
|
|
@@ -1,6 +1,5 @@
|
|
|
1
1
|
import { ServiceUnavailable } from "@shivaedev/platform/errors/taxonomy.ts";
|
|
2
2
|
import type { DocumentRequest } from "#browser/document/schema.ts";
|
|
3
|
-
import { responseUrl } from "#responses/url.ts";
|
|
4
3
|
import { authoredQuestion, openItem } from "#server/attention/inbox.ts";
|
|
5
4
|
import { requestInbox } from "#server/attention/requestInbox.ts";
|
|
6
5
|
import { attentionRequests } from "#server/attention/requests.ts";
|
|
@@ -84,6 +83,6 @@ function requestOpenInSource(document: MetadataDocument, id: string): boolean {
|
|
|
84
83
|
|
|
85
84
|
function activeSource(document: MetadataDocument, snapshot: Snapshot, item: string, id: string) {
|
|
86
85
|
const managed = document.parsed.fields.attention?.find((entry) => entry.id === id)?.managed;
|
|
87
|
-
const eligible = !managed || requestInbox(snapshot).items.some((entry) => entry.
|
|
86
|
+
const eligible = !managed || requestInbox(snapshot).items.some((entry) => entry.document.file === document.file && entry.request === id);
|
|
88
87
|
return eligible ? requestSource(snapshot, item, id) : undefined;
|
|
89
88
|
}
|