@shivaedev/work-board 0.15.0 → 0.17.0
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 +24 -0
- package/README.md +4 -4
- package/assets/react.css +1 -1
- package/assets/react.js +52 -39
- 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/client/document/Mermaid.d.ts.map +1 -1
- package/dist/client/document/Mermaid.js +4 -10
- package/dist/client/document/Mermaid.js.map +1 -1
- package/dist/client/document/View.js +1 -1
- package/dist/client/document/View.js.map +1 -1
- package/dist/client/react/BoardShell.d.ts.map +1 -1
- package/dist/client/react/BoardShell.js +28 -23
- 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/DocumentContext.d.ts.map +1 -1
- package/dist/client/react/DocumentContext.js +6 -4
- package/dist/client/react/DocumentContext.js.map +1 -1
- package/dist/client/react/LiveControls.d.ts.map +1 -1
- package/dist/client/react/LiveControls.js +1 -6
- package/dist/client/react/LiveControls.js.map +1 -1
- package/dist/client/react/PhoneNavigation.d.ts +3 -1
- package/dist/client/react/PhoneNavigation.d.ts.map +1 -1
- package/dist/client/react/PhoneNavigation.js +8 -13
- package/dist/client/react/PhoneNavigation.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/ReadingLibrary.d.ts.map +1 -1
- package/dist/client/react/ReadingLibrary.js +2 -6
- package/dist/client/react/ReadingLibrary.js.map +1 -1
- package/dist/client/react/ReadingReadyContext.d.ts +6 -0
- package/dist/client/react/ReadingReadyContext.d.ts.map +1 -0
- package/dist/client/react/ReadingReadyContext.js +7 -0
- package/dist/client/react/ReadingReadyContext.js.map +1 -0
- package/dist/client/react/RemainingMain.d.ts.map +1 -1
- package/dist/client/react/RemainingMain.js +0 -3
- package/dist/client/react/RemainingMain.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/SessionContext.d.ts +3 -0
- package/dist/client/react/SessionContext.d.ts.map +1 -0
- package/dist/client/react/SessionContext.js +3 -0
- package/dist/client/react/SessionContext.js.map +1 -0
- 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 +3 -1
- package/dist/client/react/SystemMain.js.map +1 -1
- package/dist/client/react/ThemeContext.d.ts +2 -0
- package/dist/client/react/ThemeContext.d.ts.map +1 -0
- package/dist/client/react/ThemeContext.js +3 -0
- package/dist/client/react/ThemeContext.js.map +1 -0
- package/dist/client/react/TodayOptions.d.ts.map +1 -1
- package/dist/client/react/TodayOptions.js +2 -2
- package/dist/client/react/TodayOptions.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 +5 -13
- package/dist/client/react/loadBoardPage.js.map +1 -1
- package/dist/client/react/loadRemaining.d.ts +124 -364
- package/dist/client/react/loadRemaining.d.ts.map +1 -1
- package/dist/client/react/loadRemaining.js +0 -2
- package/dist/client/react/loadRemaining.js.map +1 -1
- package/dist/client/react/navigationLocation.d.ts +2 -0
- package/dist/client/react/navigationLocation.d.ts.map +1 -1
- package/dist/client/react/navigationLocation.js +10 -0
- package/dist/client/react/navigationLocation.js.map +1 -1
- package/dist/client/react/pageQueries.d.ts.map +1 -1
- package/dist/client/react/pageQueries.js +0 -3
- 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/scheduleReading.d.ts.map +1 -1
- package/dist/client/react/scheduleReading.js +1 -10
- package/dist/client/react/scheduleReading.js.map +1 -1
- package/dist/client/react/useAppearance.d.ts +2 -1
- package/dist/client/react/useAppearance.d.ts.map +1 -1
- package/dist/client/react/useAppearance.js +1 -2
- package/dist/client/react/useAppearance.js.map +1 -1
- package/dist/client/react/useBoardNavigation.d.ts +1 -1
- package/dist/client/react/useBoardNavigation.d.ts.map +1 -1
- package/dist/client/react/useBoardNavigation.js +13 -17
- package/dist/client/react/useBoardNavigation.js.map +1 -1
- package/dist/client/react/useDiagnosticsPolling.d.ts +4 -1
- package/dist/client/react/useDiagnosticsPolling.d.ts.map +1 -1
- package/dist/client/react/useDiagnosticsPolling.js +9 -7
- package/dist/client/react/useDiagnosticsPolling.js.map +1 -1
- package/dist/client/react/useSidebar.d.ts.map +1 -1
- package/dist/client/react/useSidebar.js +5 -3
- package/dist/client/react/useSidebar.js.map +1 -1
- package/dist/render/{failed.d.ts → Failed.d.ts} +1 -1
- package/dist/render/Failed.d.ts.map +1 -0
- package/dist/render/{failed.js → Failed.js} +1 -1
- package/dist/render/Failed.js.map +1 -0
- package/dist/render/code.d.ts +2 -2
- package/dist/render/code.d.ts.map +1 -1
- package/dist/render/code.js +15 -13
- package/dist/render/code.js.map +1 -1
- package/dist/render/footnoteIds.d.ts +3 -0
- package/dist/render/footnoteIds.d.ts.map +1 -0
- package/dist/render/{footnotes.js → footnoteIds.js} +11 -9
- package/dist/render/footnoteIds.js.map +1 -0
- 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 +25 -748
- 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/handoffContract.d.ts +33 -33
- 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 +2 -0
- package/dist/server/attention/inbox.d.ts.map +1 -1
- package/dist/server/attention/inbox.js +1 -0
- package/dist/server/attention/inbox.js.map +1 -1
- package/dist/server/attention/projection.js +1 -1
- package/dist/server/attention/projection.js.map +1 -1
- package/dist/server/attention/requestInbox.d.ts +3 -0
- package/dist/server/attention/requestInbox.d.ts.map +1 -1
- package/dist/server/attention/requestInbox.js +1 -0
- package/dist/server/attention/requestInbox.js.map +1 -1
- package/dist/server/board.d.ts +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 +1060 -1300
- package/dist/server/mcp/client.d.ts.map +1 -1
- package/dist/server/mcp/queries.d.ts +24 -744
- 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/render/Highlighter.d.ts +1 -1
- package/dist/server/render/Highlighter.js +1 -1
- package/dist/server/render/markdown.d.ts +1 -1
- package/dist/server/render/markdown.js +2 -2
- package/dist/server/render/markdown.js.map +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/serve.d.ts +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 +5 -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/package.json +6 -37
- package/src/browser/views/remaining.ts +0 -3
- package/src/client/document/Mermaid.ts +4 -10
- package/src/client/document/View.ts +1 -1
- package/src/client/react/BoardShell.tsx +37 -24
- package/src/client/react/DocumentAttention.tsx +2 -3
- package/src/client/react/DocumentContext.tsx +6 -4
- package/src/client/react/LiveControls.tsx +1 -14
- package/src/client/react/PhoneNavigation.tsx +20 -15
- package/src/client/react/ProjectionFrame.tsx +1 -1
- package/src/client/react/ReadingLibrary.tsx +2 -6
- package/src/client/react/ReadingReadyContext.ts +11 -0
- package/src/client/react/RemainingMain.tsx +0 -10
- package/src/client/react/ResultPage.tsx +2 -2
- package/src/client/react/SessionContext.ts +4 -0
- package/src/client/react/ShellApi.ts +0 -1
- package/src/client/react/SystemMain.tsx +3 -1
- package/src/client/react/ThemeContext.ts +3 -0
- package/src/client/react/TodayOptions.tsx +2 -2
- package/src/client/react/entry.tsx +1 -1
- package/src/client/react/loadBoardPage.ts +5 -14
- package/src/client/react/loadRemaining.ts +0 -2
- package/src/client/react/navigationLocation.ts +12 -0
- package/src/client/react/pageQueries.ts +0 -3
- package/src/client/react/readerLink.ts +1 -1
- package/src/client/react/remainingRoute.ts +0 -2
- package/src/client/react/scheduleReading.ts +1 -10
- package/src/client/react/useAppearance.ts +2 -3
- package/src/client/react/useBoardNavigation.ts +13 -18
- package/src/client/react/useDiagnosticsPolling.ts +14 -7
- package/src/client/react/useSidebar.ts +5 -3
- package/src/render/code.ts +3 -4
- package/src/render/{footnotes.ts → footnoteIds.ts} +12 -10
- 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 +1 -0
- package/src/server/attention/projection.ts +1 -1
- package/src/server/attention/requestInbox.ts +1 -0
- package/src/server/board.ts +1 -1
- 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/render/Highlighter.ts +1 -1
- package/src/server/render/markdown.ts +2 -2
- 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/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/render/failed.d.ts.map +0 -1
- package/dist/render/failed.js.map +0 -1
- package/dist/render/footnotes.d.ts +0 -3
- package/dist/render/footnotes.d.ts.map +0 -1
- package/dist/render/footnotes.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/src/render/{failed.ts → Failed.ts} +0 -0
|
@@ -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;
|
|
@@ -12,7 +12,7 @@ export function attentionProjection(snapshot: Snapshot): InboxProjection {
|
|
|
12
12
|
return cached;
|
|
13
13
|
}
|
|
14
14
|
const requests = requestInbox(snapshot);
|
|
15
|
-
function project({ document, unblocks: _unblocks, ...item }: ReturnType<typeof inboxItems>[number]) {
|
|
15
|
+
function project({ document, request: _request, unblocks: _unblocks, ...item }: ReturnType<typeof inboxItems>[number]) {
|
|
16
16
|
return { ...item, file: document.file };
|
|
17
17
|
}
|
|
18
18
|
const you = inboxItems(snapshot).map(project);
|
|
@@ -28,6 +28,7 @@ export function requestInbox(snapshot: Snapshot) {
|
|
|
28
28
|
modified: snapshot.modified.get(entry.document.file),
|
|
29
29
|
problem: undefined,
|
|
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,
|
package/src/server/board.ts
CHANGED
|
@@ -3,7 +3,7 @@ import { HttpRouter } from "effect/http";
|
|
|
3
3
|
import { RpcSerialization, RpcServer } from "effect/rpc";
|
|
4
4
|
import type { InternalServerError } from "@shivaedev/platform/errors/taxonomy.ts";
|
|
5
5
|
import { localRpcGuard } from "@shivaedev/platform/rpc-server/local.ts";
|
|
6
|
-
import type { RenderFailed } from "#render/
|
|
6
|
+
import type { RenderFailed } from "#render/Failed.ts";
|
|
7
7
|
import { workRpcs } from "#rpc/contract.ts";
|
|
8
8
|
import { boardRuntime } from "#server/boardRuntime.ts";
|
|
9
9
|
import type { HomeMissing } from "#server/files/home.ts";
|
|
@@ -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
|
}
|
|
@@ -9,26 +9,27 @@ import { handoffFrom, handoffMarkdown, handoffPrompt, matchesHandoff } from "#se
|
|
|
9
9
|
import { handoffSource } from "#server/handoffs/source.ts";
|
|
10
10
|
import { publish } from "#server/responses/publish.ts";
|
|
11
11
|
import { revisionOf } from "#server/responses/records.ts";
|
|
12
|
-
import {
|
|
12
|
+
import { Workspace } from "#server/workspace.ts";
|
|
13
13
|
|
|
14
14
|
export const HandoffsService = defineService({
|
|
15
15
|
id: "WorkBoard/HandoffsService",
|
|
16
16
|
initialize: Effect.gen(function* () {
|
|
17
|
-
|
|
17
|
+
const workspace = yield* Workspace;
|
|
18
|
+
return { fs: yield* FileSystem.FileSystem, lock: yield* Semaphore.make(1), options: yield* workspace.settings(), workspace };
|
|
18
19
|
}),
|
|
19
|
-
methods: ({ options, fs, lock }) => {
|
|
20
|
-
const snapshot =
|
|
20
|
+
methods: ({ options, fs, lock, workspace }) => {
|
|
21
|
+
const snapshot = workspace.index().pipe(
|
|
21
22
|
rpcBoundary(ServiceUnavailable, {
|
|
22
23
|
message: "The workspace could not be indexed.",
|
|
23
24
|
unexpected: (message) => new ServiceUnavailable({ message }),
|
|
24
25
|
}),
|
|
25
26
|
);
|
|
26
|
-
const locate = handoffSource(options.root, options.
|
|
27
|
+
const locate = handoffSource(options.root, options.realRoot, snapshot, fs);
|
|
27
28
|
const read = Effect.fn("WorkBoard.read")(function* (item: string) {
|
|
28
29
|
const data = yield* snapshot;
|
|
29
30
|
const unknown = [...data.unavailable];
|
|
30
31
|
const records = data.documents.flatMap((document) => {
|
|
31
|
-
const record = handoffFrom(document, options.
|
|
32
|
+
const record = handoffFrom(document, options.realRoot);
|
|
32
33
|
if (
|
|
33
34
|
(record && data.model.ids.get(record.id)?.length !== 1)
|
|
34
35
|
|| (document.parsed.fields.kind === "handoff" && !record)
|
|
@@ -45,7 +46,7 @@ export const HandoffsService = defineService({
|
|
|
45
46
|
if (!record || record.file !== `handoffs/${input.id}.md` || !matchesHandoff(record, input) || revisionOf(record.context) !== input.revision) {
|
|
46
47
|
return yield* Effect.fail(new Conflict({ message: "This handoff identity moved, is duplicated or records different direction." }));
|
|
47
48
|
}
|
|
48
|
-
const path = yield* markdownPath(options.root, options.
|
|
49
|
+
const path = yield* markdownPath(options.root, options.realRoot, record.file);
|
|
49
50
|
if (!path) {
|
|
50
51
|
return yield* Effect.fail(new NotFound({ message: "The prepared handoff moved or disappeared." }));
|
|
51
52
|
}
|
|
@@ -55,20 +56,20 @@ export const HandoffsService = defineService({
|
|
|
55
56
|
unexpected: (message) => new ServiceUnavailable({ message }),
|
|
56
57
|
}),
|
|
57
58
|
);
|
|
58
|
-
yield* publish(options.root, options.
|
|
59
|
+
yield* publish(options.root, options.realRoot, record.id, raw, "handoffs");
|
|
59
60
|
return record;
|
|
60
61
|
});
|
|
61
62
|
|
|
62
63
|
function prepare(input: HandoffInput) {
|
|
63
64
|
return lock.withPermit(
|
|
64
65
|
Effect.gen(function* () {
|
|
65
|
-
if (!options.
|
|
66
|
+
if (!options.writable) {
|
|
66
67
|
return yield* Effect.fail(new Forbidden({ message: "Restart with --responses to enable local response/handoff writes." }));
|
|
67
68
|
}
|
|
68
69
|
const data = yield* snapshot;
|
|
69
70
|
const existing = data.model.ids.get(input.id);
|
|
70
71
|
if (existing?.length) {
|
|
71
|
-
const record = existing.length === 1 ? handoffFrom(existing[0], options.
|
|
72
|
+
const record = existing.length === 1 ? handoffFrom(existing[0], options.realRoot) : undefined;
|
|
72
73
|
return yield* reconcile(record, input);
|
|
73
74
|
}
|
|
74
75
|
const current = yield* locate(input.item);
|
|
@@ -91,21 +92,17 @@ export const HandoffsService = defineService({
|
|
|
91
92
|
state: "requested",
|
|
92
93
|
},
|
|
93
94
|
id: input.id,
|
|
94
|
-
prompt: handoffPrompt(join(options.
|
|
95
|
+
prompt: handoffPrompt(join(options.realRoot, file)),
|
|
95
96
|
};
|
|
96
|
-
yield* publish(
|
|
97
|
-
options.
|
|
98
|
-
|
|
99
|
-
record.id,
|
|
100
|
-
handoffMarkdown(record.id, record.handoff, record.context),
|
|
101
|
-
"handoffs",
|
|
102
|
-
).pipe(Effect.ensuring(options.changes.refresh ?? Effect.void));
|
|
97
|
+
yield* publish(options.root, options.realRoot, record.id, handoffMarkdown(record.id, record.handoff, record.context), "handoffs").pipe(
|
|
98
|
+
Effect.ensuring(options.changes.refresh ?? Effect.void),
|
|
99
|
+
);
|
|
103
100
|
return record;
|
|
104
101
|
}),
|
|
105
102
|
);
|
|
106
103
|
}
|
|
107
104
|
return { locate, prepare, read };
|
|
108
105
|
},
|
|
109
|
-
requires: [
|
|
106
|
+
requires: [Workspace, FileSystem.FileSystem, Path.Path],
|
|
110
107
|
});
|
|
111
108
|
export type HandoffsService = typeof HandoffsService.Identifier;
|
|
@@ -35,7 +35,6 @@ export function mermaidFile(root: string) {
|
|
|
35
35
|
|
|
36
36
|
export const MERMAID_ROUTE: HttpRouter.PathInput = `${MERMAID}*`;
|
|
37
37
|
|
|
38
|
-
export const NATIVE_ROUTE: HttpRouter.PathInput = "/_board/native.js";
|
|
39
38
|
function missingBundle(file: string) {
|
|
40
39
|
return `Work Board browser bundle assets/${file} is missing. Run pnpm --filter @shivaedev/work-board build:browser from the repository root to build it.`;
|
|
41
40
|
}
|
|
@@ -57,16 +56,11 @@ const checkAssets = Effect.fn("WorkBoard.checkAssets")(function* (files: readonl
|
|
|
57
56
|
}
|
|
58
57
|
});
|
|
59
58
|
|
|
60
|
-
export function checkNativeAsset() {
|
|
61
|
-
return checkAssets(["native.js"]);
|
|
62
|
-
}
|
|
63
59
|
export function checkBrowserAssets() {
|
|
64
|
-
return checkAssets(["
|
|
60
|
+
return checkAssets(["react.js", "react.css"]);
|
|
65
61
|
}
|
|
66
|
-
export const nativeAsset = bundledAsset("native.js", "text/javascript");
|
|
67
62
|
|
|
68
63
|
const BUNDLED_ASSETS: ReadonlyArray<readonly [HttpRouter.PathInput, ReturnType<typeof bundledAsset>]> = [
|
|
69
|
-
[NATIVE_ROUTE, nativeAsset],
|
|
70
64
|
["/_board/react.js", bundledAsset("react.js", "text/javascript")],
|
|
71
65
|
["/_board/react.css", bundledAsset("react.css", "text/css")],
|
|
72
66
|
];
|
|
@@ -2,13 +2,13 @@ import { Effect, type FileSystem, type Path, type Scope } from "effect";
|
|
|
2
2
|
import { HttpRouter, type HttpServerRequest, HttpServerResponse } from "effect/http";
|
|
3
3
|
import { loopbackOnly } from "@shivaedev/platform/rpc-server/local.ts";
|
|
4
4
|
import type { Diagnostics } from "#diagnostics/source.ts";
|
|
5
|
+
import { responseUrl } from "#responses/url.ts";
|
|
5
6
|
import type { BoardOptions } from "#server/board.ts";
|
|
6
7
|
import type { boardRuntime } from "#server/boardRuntime.ts";
|
|
7
8
|
import type { HandoffsService } from "#server/handoffs/Service.ts";
|
|
8
|
-
import { identityUrl } from "#server/metadata/links.ts";
|
|
9
9
|
import { shell } from "#server/page/shell.ts";
|
|
10
|
+
import { Responses } from "#server/Responses.ts";
|
|
10
11
|
import type { Highlighter } from "#server/render/Highlighter.ts";
|
|
11
|
-
import { Responses } from "#server/responses/service.ts";
|
|
12
12
|
import { ASSET_HANDLERS, MERMAID_ROUTE, mermaidFile } from "./assets.ts";
|
|
13
13
|
import { attachment } from "./attachment.ts";
|
|
14
14
|
import { identity } from "./identity.ts";
|
|
@@ -47,7 +47,7 @@ export function boardRoutes(options: BoardOptions, runtime: Effect.Success<Retur
|
|
|
47
47
|
const params = new URL(request.url, "http://127.0.0.1").searchParams;
|
|
48
48
|
const service = yield* Responses;
|
|
49
49
|
const preview = yield* service.locate(params.get("item") ?? "", params.get("request") ?? "");
|
|
50
|
-
return HttpServerResponse.redirect(
|
|
50
|
+
return HttpServerResponse.redirect(responseUrl(preview.item, preview.request));
|
|
51
51
|
}).pipe(Effect.catch(() => Effect.succeed(respond("Response unavailable", "text/html", 409)))),
|
|
52
52
|
);
|
|
53
53
|
for (const view of ["system", "start", "handoff", "result", "library", "goals", "work"] as const) {
|
|
@@ -5,13 +5,14 @@ import {
|
|
|
5
5
|
RecordedResponse as RecordedResponseSchema,
|
|
6
6
|
} from "#browser/responses/schema.ts";
|
|
7
7
|
import { currentResponses } from "#responses/current.ts";
|
|
8
|
+
import { Responses } from "#server/Responses.ts";
|
|
8
9
|
import { makeResponse } from "#server/responses/make.ts";
|
|
9
10
|
import { publish } from "#server/responses/publish.ts";
|
|
10
11
|
import { readResponses } from "#server/responses/read.ts";
|
|
11
12
|
import { questionFrom, questionId, questionMarkdown, responseMarkdown, revisionOf } from "#server/responses/records.ts";
|
|
12
|
-
import { type
|
|
13
|
+
import { type WorkspaceOptions as InternalWorkspaceOptions, Workspace, WorkspaceConfig } from "#server/workspace.ts";
|
|
13
14
|
|
|
14
|
-
export type
|
|
15
|
+
export type WorkspaceOptions = InternalWorkspaceOptions;
|
|
15
16
|
export type DraftInput = typeof DraftInputSchema.Type;
|
|
16
17
|
export type Question = typeof QuestionSchema.Type;
|
|
17
18
|
export type Reading = typeof ReadingSchema.Type;
|
|
@@ -28,9 +29,10 @@ export const responses = {
|
|
|
28
29
|
questionMarkdown,
|
|
29
30
|
Reading: ReadingSchema,
|
|
30
31
|
RecordedResponse: RecordedResponseSchema,
|
|
31
|
-
ResponseConfig,
|
|
32
32
|
Responses,
|
|
33
33
|
readResponses,
|
|
34
34
|
responseMarkdown,
|
|
35
35
|
revisionOf,
|
|
36
|
+
Workspace,
|
|
37
|
+
WorkspaceConfig,
|
|
36
38
|
} as const;
|
|
@@ -2,6 +2,7 @@ import { Clock, Effect } from "effect";
|
|
|
2
2
|
import { cardStatus } from "#browser/views/now.ts";
|
|
3
3
|
import type { InboxProjection } from "#browser/views/schema.ts";
|
|
4
4
|
import { fileUrl } from "#files/url.ts";
|
|
5
|
+
import { responseUrl } from "#responses/url.ts";
|
|
5
6
|
import { identityUrl } from "#server/metadata/links.ts";
|
|
6
7
|
import type { BoardClient } from "./client.ts";
|
|
7
8
|
|
|
@@ -11,12 +12,11 @@ export const needsYou = Effect.fn("BoardMcp.needsYou")(function* (client: BoardC
|
|
|
11
12
|
const you = yield* Effect.forEach(inbox.you, (row) =>
|
|
12
13
|
Effect.gen(function* () {
|
|
13
14
|
const document = yield* client("work-board.document", { url: fileUrl(row.file) });
|
|
14
|
-
const
|
|
15
|
-
const decision = document.requests.find((entry) => entry.id === request);
|
|
15
|
+
const decision = document.requests.find((entry) => responseUrl(document.metadata.id ?? "", entry.id) === row.href);
|
|
16
16
|
return {
|
|
17
17
|
...row,
|
|
18
18
|
ageMs: row.modified === undefined ? null : Math.max(0, now - row.modified),
|
|
19
|
-
options: (
|
|
19
|
+
options: (decision ? decision.options : document.metadata.options) ?? [],
|
|
20
20
|
prompts: decision?.prompts ?? [],
|
|
21
21
|
promptUnavailable: decision?.promptUnavailable,
|
|
22
22
|
recommended: decision?.recommended ?? document.metadata.recommended,
|
|
@@ -1,2 +1,2 @@
|
|
|
1
1
|
export const NAME = "work-board";
|
|
2
|
-
export const VERSION = "0.
|
|
2
|
+
export const VERSION = "0.17.0";
|
|
@@ -2,7 +2,7 @@ import { Effect } from "effect";
|
|
|
2
2
|
import { createHighlighter } from "shiki";
|
|
3
3
|
import { defineService } from "@shivaedev/effect-service/define-service.ts";
|
|
4
4
|
import { codeBlocks, THEMES } from "#render/code.ts";
|
|
5
|
-
import { RenderFailed } from "#render/
|
|
5
|
+
import { RenderFailed } from "#render/Failed.ts";
|
|
6
6
|
|
|
7
7
|
export const Highlighter = defineService({
|
|
8
8
|
id: "WorkBoard/Highlighter",
|
|
@@ -7,8 +7,8 @@ import type { PluggableList } from "unified";
|
|
|
7
7
|
import type { documentHeadings } from "#render/documentHeadings.ts";
|
|
8
8
|
import { documentLinks } from "#render/documentLinks.ts";
|
|
9
9
|
import { documentPlugins } from "#render/documentPlugins.ts";
|
|
10
|
-
import { RenderFailed } from "#render/
|
|
11
|
-
import { footnoteIds } from "#render/
|
|
10
|
+
import { RenderFailed } from "#render/Failed.ts";
|
|
11
|
+
import { footnoteIds } from "#render/footnoteIds.ts";
|
|
12
12
|
import { Highlighter } from "./Highlighter.ts";
|
|
13
13
|
|
|
14
14
|
export interface RenderOptions {
|
|
@@ -3,7 +3,7 @@ import { BadRequest } from "@shivaedev/platform/errors/taxonomy.ts";
|
|
|
3
3
|
import { responseUrl } from "#responses/url.ts";
|
|
4
4
|
import { authoredQuestion } from "#server/attention/inbox.ts";
|
|
5
5
|
import type { MetadataDocument } from "#server/metadata/model.ts";
|
|
6
|
-
import {
|
|
6
|
+
import type { locate } from "./locate.ts";
|
|
7
7
|
import { questionTemplate } from "./template.ts";
|
|
8
8
|
|
|
9
9
|
export const readingActions = Effect.fn("WorkBoard.readingActions")(function* (
|
|
@@ -11,16 +11,16 @@ export const readingActions = Effect.fn("WorkBoard.readingActions")(function* (
|
|
|
11
11
|
source: string,
|
|
12
12
|
enabled: boolean,
|
|
13
13
|
identity: string | undefined,
|
|
14
|
+
locateQuestion: ReturnType<typeof locate>,
|
|
14
15
|
) {
|
|
15
16
|
if (!(enabled && identity)) {
|
|
16
17
|
return undefined;
|
|
17
18
|
}
|
|
18
|
-
const service = yield* Responses;
|
|
19
19
|
const item = identity;
|
|
20
20
|
const requests = authoredQuestion(document) ? ["answer"] : (document.parsed.fields.attention ?? []).map((request) => request.id);
|
|
21
21
|
const actions = new Map<string, string>();
|
|
22
22
|
for (const request of requests) {
|
|
23
|
-
const question = yield*
|
|
23
|
+
const question = yield* locateQuestion(item, request).pipe(Effect.option);
|
|
24
24
|
if (question._tag === "Some" && question.value.context === source) {
|
|
25
25
|
const template = yield* Effect.try({
|
|
26
26
|
catch: (cause) => new BadRequest({ message: cause instanceof Error ? cause.message : "Review the question template and retry." }),
|
|
@@ -2,21 +2,21 @@ import { Clock, Effect } from "effect";
|
|
|
2
2
|
import { Conflict, Forbidden, PreconditionFailed, type ServiceUnavailable } from "@shivaedev/platform/errors/taxonomy.ts";
|
|
3
3
|
import type { Question } from "#browser/responses/schema.ts";
|
|
4
4
|
import type { Snapshot } from "#server/search/snapshot.ts";
|
|
5
|
+
import type { WorkspaceSettings } from "#server/workspace.ts";
|
|
5
6
|
import type { locate as locateQuestion } from "./locate.ts";
|
|
6
7
|
import { publish } from "./publish.ts";
|
|
7
8
|
import type { readResponses } from "./read.ts";
|
|
8
9
|
import { questionMarkdown } from "./records.ts";
|
|
9
|
-
import type { ResponseOptions } from "./service.ts";
|
|
10
10
|
|
|
11
11
|
const HOURS_48 = 48 * 60 * 60 * 1000;
|
|
12
12
|
export function registerQuestion(
|
|
13
|
-
options:
|
|
13
|
+
options: WorkspaceSettings,
|
|
14
14
|
snapshot: Effect.Effect<Snapshot, ServiceUnavailable>,
|
|
15
15
|
locate: ReturnType<typeof locateQuestion>,
|
|
16
16
|
read: ReturnType<typeof readResponses>,
|
|
17
17
|
) {
|
|
18
18
|
return Effect.fn("WorkBoard.registerQuestion")(function* (input: { readonly item: string; readonly request: string; readonly revision: string }) {
|
|
19
|
-
if (!options.
|
|
19
|
+
if (!options.writable) {
|
|
20
20
|
return yield* Effect.fail(new Forbidden({ message: "Start with --responses to explicitly enable local question/response writes." }));
|
|
21
21
|
}
|
|
22
22
|
const preview = yield* locate(input.item, input.request);
|
|
@@ -32,7 +32,7 @@ export function registerQuestion(
|
|
|
32
32
|
);
|
|
33
33
|
}
|
|
34
34
|
const saved = (yield* read(preview.id)).question;
|
|
35
|
-
yield* publish(options.root, options.
|
|
35
|
+
yield* publish(options.root, options.realRoot, saved.id, questionMarkdown(saved));
|
|
36
36
|
return saved;
|
|
37
37
|
}
|
|
38
38
|
const now = yield* Clock.currentTimeMillis;
|
|
@@ -49,7 +49,7 @@ export function registerQuestion(
|
|
|
49
49
|
source: preview.source,
|
|
50
50
|
},
|
|
51
51
|
};
|
|
52
|
-
yield* publish(options.root, options.
|
|
52
|
+
yield* publish(options.root, options.realRoot, question.id, questionMarkdown(question)).pipe(
|
|
53
53
|
Effect.ensuring(options.changes.refresh ?? Effect.void),
|
|
54
54
|
);
|
|
55
55
|
return question;
|
|
@@ -3,15 +3,15 @@ import { Conflict } from "@shivaedev/platform/errors/taxonomy.ts";
|
|
|
3
3
|
import type { DraftInput, RecordedResponse } from "#browser/responses/schema.ts";
|
|
4
4
|
import type { ResponseRejection } from "#rpc/rejections.ts";
|
|
5
5
|
import type { Snapshot } from "#server/search/snapshot.ts";
|
|
6
|
+
import type { WorkspaceSettings } from "#server/workspace.ts";
|
|
6
7
|
import { publish } from "./publish.ts";
|
|
7
8
|
import { matchesResponse, responseMarkdown } from "./records.ts";
|
|
8
|
-
import type { ResponseOptions } from "./service.ts";
|
|
9
9
|
|
|
10
10
|
export const retryResponse = Effect.fn("WorkBoard.retryResponse")(function* (
|
|
11
11
|
existing: RecordedResponse,
|
|
12
12
|
input: DraftInput,
|
|
13
13
|
snapshot: Effect.Effect<Snapshot, ResponseRejection>,
|
|
14
|
-
options:
|
|
14
|
+
options: WorkspaceSettings,
|
|
15
15
|
) {
|
|
16
16
|
if (!matchesResponse(existing, input)) {
|
|
17
17
|
return yield* Effect.fail(new Conflict({ message: "The response identity already records different content." }));
|
|
@@ -19,5 +19,5 @@ export const retryResponse = Effect.fn("WorkBoard.retryResponse")(function* (
|
|
|
19
19
|
if ((yield* snapshot).model.ids.get(input.id)?.[0]?.file !== `responses/${input.id}.md`) {
|
|
20
20
|
return yield* Effect.fail(new Conflict({ message: "The saved response moved. Read its existing record instead of retrying a write." }));
|
|
21
21
|
}
|
|
22
|
-
yield* publish(options.root, options.
|
|
22
|
+
yield* publish(options.root, options.realRoot, existing.id, responseMarkdown(existing));
|
|
23
23
|
});
|
|
@@ -1,16 +1,8 @@
|
|
|
1
1
|
import type { Effect } from "effect";
|
|
2
2
|
import type { ServiceUnavailable } from "@shivaedev/platform/errors/taxonomy.ts";
|
|
3
|
-
import type { Document } from "#browser/document/schema.ts";
|
|
4
3
|
import type { Server } from "#rpc/Server.ts";
|
|
5
|
-
import type { Changes } from "#server/files/changes.ts";
|
|
6
|
-
import type { Snapshot } from "#server/search/snapshot.ts";
|
|
7
4
|
|
|
8
5
|
export interface HandlerOptions {
|
|
9
|
-
readonly changes: Changes;
|
|
10
|
-
readonly document?: (url: string) => Effect.Effect<Document, unknown>;
|
|
11
6
|
readonly fleetPort?: number | null;
|
|
12
|
-
readonly home: string | undefined;
|
|
13
|
-
readonly index: Effect.Effect<Snapshot, unknown>;
|
|
14
7
|
readonly server?: Effect.Effect<typeof Server.Type, ServiceUnavailable>;
|
|
15
|
-
readonly writable?: boolean;
|
|
16
8
|
}
|