@shivaedev/work-board 0.16.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 +18 -0
- package/README.md +4 -4
- 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/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/ProjectionFrame.js +1 -1
- package/dist/client/react/ProjectionFrame.js.map +1 -1
- 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/ShellApi.d.ts +0 -1
- package/dist/client/react/ShellApi.d.ts.map +1 -1
- 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 +109 -349
- 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/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/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 +2203 -2926
- 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 +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/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 +2 -242
- 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/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 +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 +3 -3
- package/src/browser/views/remaining.ts +0 -3
- package/src/client/react/DocumentAttention.tsx +2 -3
- package/src/client/react/ProjectionFrame.tsx +1 -1
- package/src/client/react/RemainingMain.tsx +0 -10
- package/src/client/react/ResultPage.tsx +2 -2
- package/src/client/react/ShellApi.ts +0 -1
- 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/pageQueries.ts +0 -3
- package/src/client/react/readerLink.ts +1 -1
- package/src/client/react/remainingRoute.ts +0 -2
- 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/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/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
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"workspace.js","sourceRoot":"","sources":["../../src/server/workspace.ts"],"names":[],"mappings":"AAAA,OAAO,EAAE,OAAO,EAAE,MAAM,EAAE,UAAU,EAAE,IAAI,EAAsB,MAAM,QAAQ,CAAC;AAC/E,OAAO,EAAE,aAAa,EAAE,MAAM,6CAA6C,CAAC;AAE5E,OAAO,EAAE,YAAY,EAAE,MAAM,0BAA0B,CAAC;AAgBxD,MAAM,OAAO,eAAgB,SAAQ,OAAO,CAAC,OAAO,EAAqC,CAAC,2BAA2B,CAAC;CAAG;AAEzH,MAAM,CAAC,MAAM,SAAS,GAAG,aAAa,CAAC;IACtC,EAAE,EAAE,qBAAqB;IACzB,UAAU,EAAE,MAAM,CAAC,GAAG,CAAC,QAAQ,CAAC;QAC/B,OAAO,KAAK,CAAC,CAAC,eAAe,CAAC;IAC/B,CAAC,CAAC;IACF,OAAO,EAAE,CAAC,EAAE,KAAK,EAAE,GAAG,OAAO,EAAE,EAAE,EAAE;QAClC,MAAM,QAAQ,GAAG,EAAE,GAAG,OAAO,EAAE,QAAQ,EAAE,OAAO,CAAC,OAAO,CAAC,QAAQ,EAAE,CAAC;QACpE,MAAM,IAAI,GAAG,YAAY,CAAC,QAAQ,CAAC,CAAC;QACpC,SAAS,QAAQ,CAAC,GAAW;YAC5B,OAAO,MAAM,CAAC,OAAO,CAAC,KAAK,EAAE,CAAC,QAAQ,EAAE,EAAE,CAAC,IAAI,CAAC,GAAG,EAAE,QAAQ,CAAC,CAAC,CAAC;QACjE,CAAC;QACD,OAAO;YACN,QAAQ;YACR,KAAK,EAAE,GAAG,EAAE,CAAC,KAAK;YAClB,QAAQ,EAAE,GAAG,EAAE,CAAC,MAAM,CAAC,OAAO,CAAC,QAAQ,CAAC;SACxC,CAAC;IACH,CAAC;IACD,QAAQ,EAAE,CAAC,eAAe,EAAE,UAAU,CAAC,UAAU,EAAE,IAAI,CAAC,IAAI,CAAC;CAC7D,CAAC,CAAC"}
|
package/package.json
CHANGED
|
@@ -1,6 +1,6 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@shivaedev/work-board",
|
|
3
|
-
"version": "0.
|
|
3
|
+
"version": "0.17.0",
|
|
4
4
|
"description": "Serve a folder of markdown files as a live local page that updates in place when a file changes",
|
|
5
5
|
"homepage": "https://github.com/ShivaeDev/platform/tree/main/packages/work-board#readme",
|
|
6
6
|
"bugs": {
|
|
@@ -411,7 +411,7 @@
|
|
|
411
411
|
"dependencies": {
|
|
412
412
|
"@shivaedev/effect-contract": "0.5.1",
|
|
413
413
|
"@shivaedev/effect-service": "0.3.0",
|
|
414
|
-
"@shivaedev/platform": "0.14.
|
|
414
|
+
"@shivaedev/platform": "0.14.4",
|
|
415
415
|
"mdast-util-directive": "3.1.1",
|
|
416
416
|
"mermaid": "12.1.0",
|
|
417
417
|
"react": "19.3.0",
|
|
@@ -470,7 +470,7 @@
|
|
|
470
470
|
},
|
|
471
471
|
"scripts": {
|
|
472
472
|
"build": "node --eval \"import('node:fs').then(({ rmSync }) => rmSync('dist', { force: true, recursive: true }))\" && tsc --project tsconfig.build.json && pnpm build:browser",
|
|
473
|
-
"build:browser": "esbuild src/
|
|
473
|
+
"build:browser": "esbuild src/server/responses/agent-cli.ts --bundle --platform=node --format=esm --conditions=source --minify --outfile=assets/agent.js && vite build",
|
|
474
474
|
"ready": "pnpm typecheck && pnpm test && pnpm build",
|
|
475
475
|
"test": "pnpm test:prepare && vitest run",
|
|
476
476
|
"test:prepare": "pnpm build:browser",
|
|
@@ -1,5 +1,4 @@
|
|
|
1
1
|
import { Schema } from "effect";
|
|
2
|
-
import { Document, DocumentRequest } from "#browser/document/schema.ts";
|
|
3
2
|
import { HandoffPreview, HandoffReading } from "#browser/handoffs/schema.ts";
|
|
4
3
|
import { DiagnosticsSnapshot } from "#diagnostics/daemonContract.ts";
|
|
5
4
|
|
|
@@ -11,8 +10,6 @@ export const StartProjection = Schema.Struct({
|
|
|
11
10
|
templates: Schema.Array(Schema.Struct({ file: Schema.String, label: Schema.String, source: Schema.String })),
|
|
12
11
|
});
|
|
13
12
|
export type StartProjection = typeof StartProjection.Type;
|
|
14
|
-
export const RespondProjection = Schema.Struct({ document: Document, request: DocumentRequest });
|
|
15
|
-
export type RespondProjection = typeof RespondProjection.Type;
|
|
16
13
|
export const HandoffProjection = Schema.Struct({
|
|
17
14
|
background: Schema.String,
|
|
18
15
|
goal: Schema.String,
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { Document } from "#browser/document/schema.ts";
|
|
2
2
|
import { fileUrl } from "#files/url.ts";
|
|
3
|
+
import { responseUrl } from "#responses/url.ts";
|
|
3
4
|
import { keyed } from "./keyed.ts";
|
|
4
5
|
import { Reference } from "./Reference.tsx";
|
|
5
6
|
export function DocumentAttention({ document }: { readonly document: Document }) {
|
|
@@ -28,9 +29,7 @@ function Request({ document, index }: { readonly document: Document; readonly in
|
|
|
28
29
|
document.metadata.attention?.filter((entry) => entry.id === request.id).length === 1
|
|
29
30
|
? `attention-request-${request.id}`
|
|
30
31
|
: `attention-record-${index}`;
|
|
31
|
-
const respond = document.
|
|
32
|
-
? `#answer-card-${request.id}`
|
|
33
|
-
: `/_board/respond?item=${encodeURIComponent(document.metadata.id ?? "")}&request=${encodeURIComponent(request.id)}`;
|
|
32
|
+
const respond = responseUrl(document.metadata.id ?? "", request.id);
|
|
34
33
|
const targets = request.unblocks.map((target, targetIndex) => (
|
|
35
34
|
<span key={target}>
|
|
36
35
|
{targetIndex > 0 && ", "}
|
|
@@ -130,7 +130,7 @@ function projectionView(route: ProjectionRoute | RemainingRoute) {
|
|
|
130
130
|
if (route === "board") {
|
|
131
131
|
return "";
|
|
132
132
|
}
|
|
133
|
-
return route
|
|
133
|
+
return route;
|
|
134
134
|
}
|
|
135
135
|
|
|
136
136
|
function failureStatus(missing: boolean, conflict: boolean) {
|
|
@@ -4,7 +4,6 @@ import { HandoffPage } from "./HandoffPage.tsx";
|
|
|
4
4
|
import { LibraryMain } from "./LibraryMain.tsx";
|
|
5
5
|
import type { MainLocation } from "./mainLocation.ts";
|
|
6
6
|
import { ProjectionFrame } from "./ProjectionFrame.tsx";
|
|
7
|
-
import { RespondPage } from "./RespondPage.tsx";
|
|
8
7
|
import { ResultPage } from "./ResultPage.tsx";
|
|
9
8
|
import type { RemainingRoute } from "./remainingRoute.ts";
|
|
10
9
|
import type { ShellApi } from "./ShellApi.ts";
|
|
@@ -45,15 +44,6 @@ export function RemainingMain({
|
|
|
45
44
|
);
|
|
46
45
|
case "system":
|
|
47
46
|
return <SystemMain api={api} onPage={onPage} url={url} />;
|
|
48
|
-
case "respond":
|
|
49
|
-
return (
|
|
50
|
-
<ProjectionFrame
|
|
51
|
-
{...options}
|
|
52
|
-
atom={api.respond.query({ url }, routeQueryOptions)}
|
|
53
|
-
location={() => ({ file: "Respond", status: 200, view: "response" })}
|
|
54
|
-
render={(data) => <RespondPage data={data} />}
|
|
55
|
-
/>
|
|
56
|
-
);
|
|
57
47
|
case "handoff":
|
|
58
48
|
return (
|
|
59
49
|
<ProjectionFrame
|
|
@@ -1,5 +1,6 @@
|
|
|
1
1
|
import type { ResultProjection } from "#browser/views/ResultProjection.ts";
|
|
2
2
|
import { fileUrl } from "#files/url.ts";
|
|
3
|
+
import { responseUrl } from "#responses/url.ts";
|
|
3
4
|
import { DocumentMetadata } from "./DocumentMetadata.tsx";
|
|
4
5
|
import { ReadingPanel } from "./ReadingPanel.tsx";
|
|
5
6
|
import { ResponseMarkdown } from "./ResponseMarkdown.tsx";
|
|
@@ -14,8 +15,7 @@ export function ResultPage({ data }: { readonly data: ResultProjection }) {
|
|
|
14
15
|
);
|
|
15
16
|
const links = actions.map((entry) => (
|
|
16
17
|
<li key={entry.id}>
|
|
17
|
-
<a href={
|
|
18
|
-
{entry.reason}
|
|
18
|
+
<a href={responseUrl(document.identity ?? "", entry.id)}>Review {entry.id}</a> — {entry.reason}
|
|
19
19
|
</li>
|
|
20
20
|
));
|
|
21
21
|
return (
|
|
@@ -9,7 +9,6 @@ export interface ShellApi {
|
|
|
9
9
|
readonly inbox: Pick<BrowserClient["api"]["inbox"], "query">;
|
|
10
10
|
readonly library: Pick<BrowserClient["api"]["library"], "query">;
|
|
11
11
|
readonly navigation: Pick<BrowserClient["api"]["navigation"], "query">;
|
|
12
|
-
readonly respond: Pick<BrowserClient["api"]["respond"], "query">;
|
|
13
12
|
readonly result: Pick<BrowserClient["api"]["result"], "query">;
|
|
14
13
|
readonly search: Pick<BrowserClient["api"]["search"], "query">;
|
|
15
14
|
readonly start: Pick<BrowserClient["api"]["start"], "query">;
|
|
@@ -12,6 +12,7 @@ import { Popover } from "#client/react/components/ui/Popover.tsx";
|
|
|
12
12
|
import { authorLabel } from "#client/responses/authorLabel.ts";
|
|
13
13
|
import { saveFailure } from "#client/saveFailure.ts";
|
|
14
14
|
import { fileUrl } from "#files/url.ts";
|
|
15
|
+
import { responseUrl } from "#responses/url.ts";
|
|
15
16
|
import { createResponse } from "./createResponse.ts";
|
|
16
17
|
import { useFormClient } from "./FormContext.ts";
|
|
17
18
|
import type { ShellApi } from "./ShellApi.ts";
|
|
@@ -19,8 +20,7 @@ import type { ShellApi } from "./ShellApi.ts";
|
|
|
19
20
|
export function TodayOptions({ api, item }: { readonly api: ShellApi; readonly item: InboxProjection["you"][number] }) {
|
|
20
21
|
const query = useQuery(documentQuery(api, fileUrl(item.file)), { keepPreviousData: true });
|
|
21
22
|
const data = Option.getOrUndefined(query.data);
|
|
22
|
-
const
|
|
23
|
-
const request = data?.requests.find((entry) => entry.id === requestId && entry.open);
|
|
23
|
+
const request = data?.requests.find((entry) => entry.open && responseUrl(data.metadata.id ?? "", entry.id) === item.href);
|
|
24
24
|
return data
|
|
25
25
|
&& !item.problem
|
|
26
26
|
&& request?.preview
|
|
@@ -17,7 +17,7 @@ export async function loadBoardPage({
|
|
|
17
17
|
location,
|
|
18
18
|
abortController,
|
|
19
19
|
}: Pick<LoaderFnContext, "location" | "abortController"> & { readonly context: { readonly shell?: RouterShell } }) {
|
|
20
|
-
|
|
20
|
+
redirectLegacy(location.pathname, location.searchStr);
|
|
21
21
|
if (!shell) {
|
|
22
22
|
return undefined;
|
|
23
23
|
}
|
|
@@ -25,7 +25,6 @@ export async function loadBoardPage({
|
|
|
25
25
|
const url = location.pathname + location.searchStr;
|
|
26
26
|
try {
|
|
27
27
|
const navigation = await loadQuery(registry, navigationQuery(api), { abortController });
|
|
28
|
-
await redirectResponse(shell, url, location.pathname, abortController);
|
|
29
28
|
const projection = projectionRoute(location.pathname, navigation.home);
|
|
30
29
|
if (projection) {
|
|
31
30
|
await loadProjection(registry, api, projection, url, abortController);
|
|
@@ -55,22 +54,14 @@ export async function loadBoardPage({
|
|
|
55
54
|
}
|
|
56
55
|
}
|
|
57
56
|
|
|
58
|
-
async function redirectResponse({ api, registry }: RouterShell, url: string, pathname: string, abortController: AbortController) {
|
|
59
|
-
if (pathname !== "/_board/respond") {
|
|
60
|
-
return;
|
|
61
|
-
}
|
|
62
|
-
const response = await loadRemaining(registry, api, "respond", url, abortController);
|
|
63
|
-
if (response && "request" in response) {
|
|
64
|
-
const item = response.document.identity ?? response.request.preview?.item ?? "";
|
|
65
|
-
throw redirect({ href: `/_board/item/${encodeURIComponent(item)}/#answer-card-${encodeURIComponent(response.request.id)}`, replace: true });
|
|
66
|
-
}
|
|
67
|
-
}
|
|
68
|
-
|
|
69
57
|
function mustRethrow(controller: AbortController, error: unknown) {
|
|
70
58
|
return controller.signal.aborted || isRedirect(error);
|
|
71
59
|
}
|
|
72
60
|
|
|
73
|
-
function
|
|
61
|
+
function redirectLegacy(pathname: string, search: string) {
|
|
62
|
+
if (pathname === "/_board/respond") {
|
|
63
|
+
throw redirect({ href: pathname + search, reloadDocument: true });
|
|
64
|
+
}
|
|
74
65
|
const retired: Readonly<Record<string, string>> = {
|
|
75
66
|
"/_board/changes": "/_board/library?view=recently-changed",
|
|
76
67
|
"/_board/diagnostics": "/_board/system",
|
|
@@ -22,8 +22,6 @@ export function loadRemaining(
|
|
|
22
22
|
loadQuery(registry, api.diagnostics.query(undefined, routeQueryOptions), { abortController }),
|
|
23
23
|
loadQuery(registry, api.fleetItems.query(undefined, routeQueryOptions), { abortController }),
|
|
24
24
|
]);
|
|
25
|
-
case "respond":
|
|
26
|
-
return loadQuery(registry, api.respond.query({ url }, routeQueryOptions), { abortController });
|
|
27
25
|
case "handoff":
|
|
28
26
|
return loadQuery(registry, api.handoff.query({ url }, routeQueryOptions), { abortController });
|
|
29
27
|
case "result":
|
|
@@ -29,9 +29,6 @@ export function pageQueries(api: ShellApi, kind: string, url: string): readonly
|
|
|
29
29
|
if (kind === "board") {
|
|
30
30
|
return [api.board.query({ url }, routeQueryOptions)];
|
|
31
31
|
}
|
|
32
|
-
if (kind === "respond") {
|
|
33
|
-
return [api.respond.query({ url }, routeQueryOptions)];
|
|
34
|
-
}
|
|
35
32
|
if (kind === "handoff") {
|
|
36
33
|
return [api.handoff.query({ url }, routeQueryOptions)];
|
|
37
34
|
}
|
|
@@ -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
|
);
|
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;
|
|
@@ -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,
|
|
@@ -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
|
}
|