@taskmark/ui 0.2.2 → 0.2.5
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/README.md +23 -7
- package/app/api/taskmark-reload/route.ts +103 -0
- package/app/board/page.tsx +6 -4
- package/app/globals.css +17 -1
- package/app/layout.tsx +2 -0
- package/bin/lib/static-preview.mjs +110 -0
- package/bin/lib/watch-board-markdown.mjs +65 -0
- package/bin/taskmark.js +254 -46
- package/components/board/app-bar.tsx +31 -34
- package/components/board/board-dev-reloader.tsx +49 -0
- package/components/board/epic-list.tsx +2 -4
- package/components/board/markdown-content.tsx +1 -2
- package/components/board/overall-work-items-list.tsx +2 -1
- package/components/board/static-board-app.tsx +0 -1
- package/components/board/story-list.tsx +2 -1
- package/components/board/task-list.tsx +2 -1
- package/components/board/work-item-sheet.tsx +15 -2
- package/components/board/work-items-list.tsx +2 -2
- package/components/setup/setup-wizard.tsx +2 -6
- package/dist/prod-next/BUILD_ID +1 -0
- package/dist/{standalone/.next → prod-next}/app-path-routes-manifest.json +3 -2
- package/dist/{standalone/.next → prod-next}/build-manifest.json +3 -3
- package/dist/prod-next/export-marker.json +6 -0
- package/dist/prod-next/images-manifest.json +68 -0
- package/dist/prod-next/next-minimal-server.js.nft.json +1 -0
- package/dist/prod-next/next-server.js.nft.json +1 -0
- package/dist/{standalone/.next → prod-next}/prerender-manifest.json +3 -3
- package/dist/{standalone/.next → prod-next}/react-loadable-manifest.json +2 -2
- package/dist/prod-next/required-server-files.js +337 -0
- package/dist/{standalone/.next → prod-next}/required-server-files.json +0 -7
- package/dist/{standalone/.next → prod-next}/routes-manifest.json +6 -0
- package/dist/prod-next/server/app/_global-error/page.js +32 -0
- package/dist/prod-next/server/app/_global-error/page.js.nft.json +1 -0
- package/dist/prod-next/server/app/_global-error/page_client-reference-manifest.js +1 -0
- package/dist/{standalone/.next → prod-next}/server/app/_global-error.html +1 -1
- package/dist/{standalone/.next → prod-next}/server/app/_global-error.rsc +1 -1
- package/dist/{standalone/.next → prod-next}/server/app/_global-error.segments/_full.segment.rsc +1 -1
- package/dist/{standalone/.next → prod-next}/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
- package/dist/{standalone/.next → prod-next}/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
- package/dist/{standalone/.next → prod-next}/server/app/_global-error.segments/_head.segment.rsc +1 -1
- package/dist/{standalone/.next → prod-next}/server/app/_global-error.segments/_index.segment.rsc +1 -1
- package/dist/{standalone/.next → prod-next}/server/app/_global-error.segments/_tree.segment.rsc +1 -1
- package/dist/prod-next/server/app/_not-found/page.js +2 -0
- package/dist/prod-next/server/app/_not-found/page.js.nft.json +1 -0
- package/dist/prod-next/server/app/_not-found/page_client-reference-manifest.js +1 -0
- package/dist/prod-next/server/app/_not-found.html +1 -0
- package/dist/prod-next/server/app/_not-found.rsc +21 -0
- package/dist/prod-next/server/app/_not-found.segments/_full.segment.rsc +21 -0
- package/dist/{standalone/.next → prod-next}/server/app/_not-found.segments/_head.segment.rsc +1 -1
- package/dist/prod-next/server/app/_not-found.segments/_index.segment.rsc +8 -0
- package/dist/{standalone/.next → prod-next}/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
- package/dist/{standalone/.next → prod-next}/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
- package/dist/{standalone/.next → prod-next}/server/app/_not-found.segments/_tree.segment.rsc +2 -2
- package/dist/prod-next/server/app/api/taskmark-reload/route.js +1 -0
- package/dist/prod-next/server/app/api/taskmark-reload/route.js.nft.json +1 -0
- package/dist/prod-next/server/app/api/taskmark-reload/route_client-reference-manifest.js +1 -0
- package/dist/prod-next/server/app/board/page.js +50 -0
- package/dist/prod-next/server/app/board/page.js.nft.json +1 -0
- package/dist/prod-next/server/app/board/page_client-reference-manifest.js +1 -0
- package/dist/{standalone/.next → prod-next}/server/app/favicon.ico/route.js +1 -1
- package/dist/prod-next/server/app/favicon.ico/route.js.nft.json +1 -0
- package/dist/prod-next/server/app/page.js +2 -0
- package/dist/prod-next/server/app/page.js.nft.json +1 -0
- package/dist/prod-next/server/app/page_client-reference-manifest.js +1 -0
- package/dist/prod-next/server/app/setup/page.js +2 -0
- package/dist/prod-next/server/app/setup/page.js.nft.json +1 -0
- package/dist/prod-next/server/app/setup/page_client-reference-manifest.js +1 -0
- package/dist/{standalone/.next → prod-next}/server/app-paths-manifest.json +3 -2
- package/dist/{standalone/.next → prod-next}/server/chunks/319.js +1 -1
- package/dist/{standalone/.next → prod-next}/server/chunks/490.js +1 -1
- package/dist/prod-next/server/chunks/57.js +19 -0
- package/dist/prod-next/server/chunks/616.js +1 -0
- package/dist/prod-next/server/chunks/708.js +1 -0
- package/dist/prod-next/server/chunks/724.js +1 -0
- package/dist/{standalone/.next/server/chunks/445.js → prod-next/server/chunks/741.js} +2 -2
- package/dist/prod-next/server/functions-config-manifest.json +6 -0
- package/dist/prod-next/server/interception-route-rewrite-manifest.js +1 -0
- package/dist/{standalone/.next → prod-next}/server/middleware-build-manifest.js +1 -1
- package/dist/prod-next/server/middleware-react-loadable-manifest.js +1 -0
- package/dist/prod-next/server/pages/404.html +1 -0
- package/dist/{standalone/.next → prod-next}/server/pages/500.html +1 -1
- package/dist/prod-next/server/server-reference-manifest.js +1 -0
- package/dist/prod-next/server/server-reference-manifest.json +1 -0
- package/dist/prod-next/static/chunks/51.e9139a9ea6eb36b9.js +1 -0
- package/dist/{standalone/.next/static/chunks/781-f9f201ddc8c8591a.js → prod-next/static/chunks/613-6f794154d28bb75a.js} +1 -1
- package/dist/prod-next/static/chunks/app/_global-error/page-d34451c04262dd7d.js +1 -0
- package/dist/prod-next/static/chunks/app/api/taskmark-reload/route-d34451c04262dd7d.js +1 -0
- package/dist/prod-next/static/chunks/app/board/page-cd1d9be0c0127225.js +1 -0
- package/dist/prod-next/static/chunks/app/layout-856e8a282e69e7d0.js +1 -0
- package/dist/prod-next/static/chunks/app/page-d34451c04262dd7d.js +1 -0
- package/dist/prod-next/static/chunks/app/setup/page-c3003359e8becc84.js +1 -0
- package/dist/prod-next/static/chunks/next/dist/client/components/builtin/app-error-d34451c04262dd7d.js +1 -0
- package/dist/prod-next/static/chunks/next/dist/client/components/builtin/forbidden-d34451c04262dd7d.js +1 -0
- package/dist/prod-next/static/chunks/next/dist/client/components/builtin/not-found-d34451c04262dd7d.js +1 -0
- package/dist/prod-next/static/chunks/next/dist/client/components/builtin/unauthorized-d34451c04262dd7d.js +1 -0
- package/dist/prod-next/static/chunks/webpack-bfe8992962004e2b.js +1 -0
- package/dist/prod-next/static/css/2e6ec4c80894e3c0.css +1 -0
- package/dist/prod-next/static/wbcgYS3Jw87KqhnA9ttOL/_buildManifest.js +1 -0
- package/dist/public/taskmark-snapshot.json +1 -0
- package/lib/display-path.ts +6 -0
- package/lib/taskmark/dev-reload-token.ts +5 -0
- package/lib/taskmark/project-label.ts +3 -2
- package/lib/taskmark/validate.ts +4 -4
- package/next.config.ts +3 -8
- package/package.json +6 -4
- package/public/taskmark-snapshot.json +1 -1
- package/scripts/build-static.mjs +10 -1
- package/scripts/prepare-standalone.mjs +53 -20
- package/dist/standalone/.next/BUILD_ID +0 -1
- package/dist/standalone/.next/server/app/_global-error/page.js +0 -32
- package/dist/standalone/.next/server/app/_global-error/page.js.nft.json +0 -1
- package/dist/standalone/.next/server/app/_global-error/page_client-reference-manifest.js +0 -1
- package/dist/standalone/.next/server/app/_not-found/page.js +0 -2
- package/dist/standalone/.next/server/app/_not-found/page.js.nft.json +0 -1
- package/dist/standalone/.next/server/app/_not-found/page_client-reference-manifest.js +0 -1
- package/dist/standalone/.next/server/app/_not-found.html +0 -1
- package/dist/standalone/.next/server/app/_not-found.rsc +0 -20
- package/dist/standalone/.next/server/app/_not-found.segments/_full.segment.rsc +0 -20
- package/dist/standalone/.next/server/app/_not-found.segments/_index.segment.rsc +0 -7
- package/dist/standalone/.next/server/app/board/page.js +0 -50
- package/dist/standalone/.next/server/app/board/page.js.nft.json +0 -1
- package/dist/standalone/.next/server/app/board/page_client-reference-manifest.js +0 -1
- package/dist/standalone/.next/server/app/favicon.ico/route.js.nft.json +0 -1
- package/dist/standalone/.next/server/app/page.js +0 -2
- package/dist/standalone/.next/server/app/page.js.nft.json +0 -1
- package/dist/standalone/.next/server/app/page_client-reference-manifest.js +0 -1
- package/dist/standalone/.next/server/app/setup/page.js +0 -2
- package/dist/standalone/.next/server/app/setup/page.js.nft.json +0 -1
- package/dist/standalone/.next/server/app/setup/page_client-reference-manifest.js +0 -1
- package/dist/standalone/.next/server/chunks/57.js +0 -19
- package/dist/standalone/.next/server/chunks/570.js +0 -1
- package/dist/standalone/.next/server/chunks/600.js +0 -1
- package/dist/standalone/.next/server/chunks/666.js +0 -1
- package/dist/standalone/.next/server/functions-config-manifest.json +0 -4
- package/dist/standalone/.next/server/middleware-react-loadable-manifest.js +0 -1
- package/dist/standalone/.next/server/pages/404.html +0 -1
- package/dist/standalone/.next/server/server-reference-manifest.js +0 -1
- package/dist/standalone/.next/server/server-reference-manifest.json +0 -1
- package/dist/standalone/.next/static/O83kNzYUmJlkfw7SS-SsU/_buildManifest.js +0 -1
- package/dist/standalone/.next/static/chunks/826.92750d8ed3a55429.js +0 -1
- package/dist/standalone/.next/static/chunks/app/_global-error/page-82d456ade9f47021.js +0 -1
- package/dist/standalone/.next/static/chunks/app/board/page-f609a854d76933c2.js +0 -1
- package/dist/standalone/.next/static/chunks/app/layout-3745e06d87691845.js +0 -1
- package/dist/standalone/.next/static/chunks/app/page-82d456ade9f47021.js +0 -1
- package/dist/standalone/.next/static/chunks/app/setup/page-acaffda2083bf4d0.js +0 -1
- package/dist/standalone/.next/static/chunks/next/dist/client/components/builtin/app-error-82d456ade9f47021.js +0 -1
- package/dist/standalone/.next/static/chunks/next/dist/client/components/builtin/forbidden-82d456ade9f47021.js +0 -1
- package/dist/standalone/.next/static/chunks/next/dist/client/components/builtin/not-found-82d456ade9f47021.js +0 -1
- package/dist/standalone/.next/static/chunks/next/dist/client/components/builtin/unauthorized-82d456ade9f47021.js +0 -1
- package/dist/standalone/.next/static/chunks/webpack-f181688592aeb1f6.js +0 -1
- package/dist/standalone/.next/static/css/7af268deac5c5edb.css +0 -1
- package/dist/standalone/node_modules/next/dist/compiled/jest-worker/processChild.js +0 -1
- package/dist/standalone/node_modules/next/dist/compiled/jest-worker/threadChild.js +0 -1
- package/dist/standalone/node_modules/next/dist/server/lib/start-server.js +0 -494
- package/dist/standalone/node_modules/next/dist/server/next-server.js +0 -1429
- package/dist/standalone/node_modules/next/dist/server/next.js +0 -455
- package/dist/standalone/node_modules/next/dist/server/require-hook.js +0 -82
- package/dist/standalone/node_modules/next/dist/server/route-modules/app-page/module.compiled.js +0 -36
- package/dist/standalone/node_modules/next/dist/server/route-modules/pages/module.compiled.js +0 -20
- package/dist/standalone/node_modules/styled-jsx/index.js +0 -1
- package/dist/standalone/node_modules/styled-jsx/package.json +0 -132
- package/dist/standalone/node_modules/styled-jsx/style.js +0 -1
- package/dist/standalone/package.json +0 -76
- package/dist/standalone/public/taskmark-snapshot.json +0 -1
- package/dist/standalone/server.js +0 -44
- /package/dist/{standalone/.next → prod-next}/package.json +0 -0
- /package/dist/{standalone/.next → prod-next}/server/app/_global-error.meta +0 -0
- /package/dist/{standalone/.next → prod-next}/server/app/_not-found.meta +0 -0
- /package/dist/{standalone/.next → prod-next}/server/app/favicon.ico.body +0 -0
- /package/dist/{standalone/.next → prod-next}/server/app/favicon.ico.meta +0 -0
- /package/dist/{standalone/.next → prod-next}/server/chunks/318.js +0 -0
- /package/dist/{standalone/.next → prod-next}/server/middleware-manifest.json +0 -0
- /package/dist/{standalone/.next → prod-next}/server/next-font-manifest.js +0 -0
- /package/dist/{standalone/.next → prod-next}/server/next-font-manifest.json +0 -0
- /package/dist/{standalone/.next → prod-next}/server/pages-manifest.json +0 -0
- /package/dist/{standalone/.next → prod-next}/server/prefetch-hints.json +0 -0
- /package/dist/{standalone/.next → prod-next}/server/webpack-runtime.js +0 -0
- /package/dist/{standalone/.next → prod-next}/static/chunks/4bd1b696-deb4a0a1da1923b0.js +0 -0
- /package/dist/{standalone/.next → prod-next}/static/chunks/669-8103441c67b185da.js +0 -0
- /package/dist/{standalone/.next → prod-next}/static/chunks/701-df3ee5f1cf837b1a.js +0 -0
- /package/dist/{standalone/.next → prod-next}/static/chunks/794-25668765560cb197.js +0 -0
- /package/dist/{standalone/.next → prod-next}/static/chunks/app/_not-found/page-0b3785af737e7968.js +0 -0
- /package/dist/{standalone/.next → prod-next}/static/chunks/framework-b29f9083d3cda3b2.js +0 -0
- /package/dist/{standalone/.next → prod-next}/static/chunks/main-app-bfb36455d24b3e5a.js +0 -0
- /package/dist/{standalone/.next → prod-next}/static/chunks/main-bb33c46a9c25dee8.js +0 -0
- /package/dist/{standalone/.next → prod-next}/static/chunks/next/dist/client/components/builtin/global-error-dc53ab29e0491fe4.js +0 -0
- /package/dist/{standalone/.next → prod-next}/static/chunks/polyfills-42372ed130431b0a.js +0 -0
- /package/dist/{standalone/.next → prod-next}/static/css/c593627ceef17a4b.css +0 -0
- /package/dist/{standalone/.next → prod-next}/static/media/36966cca54120369-s.p.woff2 +0 -0
- /package/dist/{standalone/.next → prod-next}/static/media/982ceffe7b733b3b-s.p.woff2 +0 -0
- /package/dist/{standalone/.next → prod-next}/static/media/b7387a63dd068245-s.woff2 +0 -0
- /package/dist/{standalone/.next → prod-next}/static/media/b8bfb68ab9ab617c-s.woff2 +0 -0
- /package/dist/{standalone/.next → prod-next}/static/media/e1aab0933260df4d-s.woff2 +0 -0
- /package/dist/{standalone/.next/static/O83kNzYUmJlkfw7SS-SsU → prod-next/static/wbcgYS3Jw87KqhnA9ttOL}/_ssgManifest.js +0 -0
- /package/dist/{standalone/public → public}/apple-touch-icon.png +0 -0
- /package/dist/{standalone/public → public}/favicon-96x96.png +0 -0
- /package/dist/{standalone/public → public}/favicon.ico +0 -0
- /package/dist/{standalone/public → public}/favicon.svg +0 -0
- /package/dist/{standalone/public → public}/file.svg +0 -0
- /package/dist/{standalone/public → public}/globe.svg +0 -0
- /package/dist/{standalone/public → public}/next.svg +0 -0
- /package/dist/{standalone/public → public}/og/og-default.png +0 -0
- /package/dist/{standalone/public → public}/site.webmanifest +0 -0
- /package/dist/{standalone/public → public}/tm_dark.png +0 -0
- /package/dist/{standalone/public → public}/tm_light.png +0 -0
- /package/dist/{standalone/public → public}/vercel.svg +0 -0
- /package/dist/{standalone/public → public}/web-app-manifest-192x192.png +0 -0
- /package/dist/{standalone/public → public}/web-app-manifest-512x512.png +0 -0
- /package/dist/{standalone/public → public}/window.svg +0 -0
package/bin/taskmark.js
CHANGED
|
@@ -3,28 +3,36 @@ import { spawn } from "node:child_process"
|
|
|
3
3
|
import fs from "node:fs"
|
|
4
4
|
import http from "node:http"
|
|
5
5
|
import path from "node:path"
|
|
6
|
+
import { createRequire } from "node:module"
|
|
6
7
|
import { fileURLToPath } from "node:url"
|
|
7
8
|
|
|
8
9
|
import { resolveServeBoard } from "./lib/resolve-board.mjs"
|
|
10
|
+
import { startStaticServer } from "./lib/static-preview.mjs"
|
|
11
|
+
import { watchBoardMarkdown } from "./lib/watch-board-markdown.mjs"
|
|
9
12
|
|
|
10
13
|
const DEFAULT_PORT = 8275
|
|
11
14
|
const __dirname = path.dirname(fileURLToPath(import.meta.url))
|
|
12
15
|
const packageRoot = path.resolve(__dirname, "..")
|
|
16
|
+
const requireFromPackage = createRequire(path.join(packageRoot, "package.json"))
|
|
13
17
|
|
|
14
18
|
function printHelp() {
|
|
15
19
|
console.log(`Usage:
|
|
16
20
|
taskmark serve [options]
|
|
21
|
+
taskmark dev [options]
|
|
17
22
|
taskmark build [options]
|
|
23
|
+
taskmark preview [options]
|
|
18
24
|
|
|
19
25
|
Commands:
|
|
20
26
|
serve Start the prebuilt local UI server (default port ${DEFAULT_PORT})
|
|
27
|
+
dev Next.js development server with board markdown live reload
|
|
21
28
|
build Production static HTML export for Vercel / static hosting
|
|
29
|
+
preview Serve an existing static export (default: <board>/out)
|
|
22
30
|
|
|
23
31
|
Options:
|
|
24
|
-
--port, -p <n> Listen port
|
|
32
|
+
--port, -p <n> Listen port (default ${DEFAULT_PORT}; env PORT / TASKMARK_PORT)
|
|
25
33
|
--board <path> Board or product root (sets TASKMARK_BOARD)
|
|
26
|
-
--out <dir> Static output directory for build (default: <board>/out)
|
|
27
|
-
--no-open Do not open a browser (serve)
|
|
34
|
+
--out <dir> Static output directory for build/preview (default: <board>/out)
|
|
35
|
+
--no-open Do not open a browser (serve / preview / dev)
|
|
28
36
|
--help, -h Show help
|
|
29
37
|
|
|
30
38
|
Board resolution (same as the UI):
|
|
@@ -35,9 +43,11 @@ Board resolution (same as the UI):
|
|
|
35
43
|
|
|
36
44
|
Examples:
|
|
37
45
|
npm i @taskmark/ui --save && npx taskmark serve
|
|
46
|
+
npx taskmark dev --board .
|
|
38
47
|
npx taskmark build --board .
|
|
48
|
+
npm run preview
|
|
49
|
+
npx taskmark preview --port 9000
|
|
39
50
|
npx -p @taskmark/ui taskmark serve
|
|
40
|
-
npx taskmark serve --port 9000
|
|
41
51
|
TASKMARK_BOARD=/path/to/my-app/taskmark npx taskmark serve
|
|
42
52
|
`)
|
|
43
53
|
}
|
|
@@ -93,15 +103,73 @@ function resolvePort(raw) {
|
|
|
93
103
|
return n
|
|
94
104
|
}
|
|
95
105
|
|
|
96
|
-
function
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
100
|
-
|
|
101
|
-
|
|
102
|
-
|
|
106
|
+
function resolveNextBin() {
|
|
107
|
+
try {
|
|
108
|
+
return requireFromPackage.resolve("next/dist/bin/next")
|
|
109
|
+
} catch {
|
|
110
|
+
const fallback = path.join(
|
|
111
|
+
packageRoot,
|
|
112
|
+
"node_modules",
|
|
113
|
+
"next",
|
|
114
|
+
"dist",
|
|
115
|
+
"bin",
|
|
116
|
+
"next"
|
|
117
|
+
)
|
|
118
|
+
if (fs.existsSync(fallback)) return fallback
|
|
119
|
+
throw new Error(
|
|
120
|
+
"next binary not found. Reinstall @taskmark/ui (next is required for serve/dev)."
|
|
121
|
+
)
|
|
122
|
+
}
|
|
123
|
+
}
|
|
124
|
+
|
|
125
|
+
/**
|
|
126
|
+
* Ensure packageRoot/.next points at a usable production build.
|
|
127
|
+
* Published packages ship dist/prod-next (npm cannot pack nested node_modules
|
|
128
|
+
* used by Next standalone).
|
|
129
|
+
*/
|
|
130
|
+
function ensureProdNext() {
|
|
131
|
+
const nextDir = path.join(packageRoot, ".next")
|
|
132
|
+
const shipped = path.join(packageRoot, "dist", "prod-next")
|
|
133
|
+
const hasLocalServer = fs.existsSync(path.join(nextDir, "server"))
|
|
134
|
+
const hasShippedServer = fs.existsSync(path.join(shipped, "server"))
|
|
135
|
+
|
|
136
|
+
if (hasLocalServer) return nextDir
|
|
137
|
+
if (!hasShippedServer) {
|
|
138
|
+
throw new Error(`Prebuilt UI not found.
|
|
139
|
+
|
|
140
|
+
Expected ${shipped} (or a local .next/server from npm run build).
|
|
141
|
+
Reinstall @taskmark/ui or rebuild the package.`)
|
|
142
|
+
}
|
|
143
|
+
|
|
144
|
+
if (fs.existsSync(nextDir)) {
|
|
145
|
+
const st = fs.lstatSync(nextDir)
|
|
146
|
+
if (st.isSymbolicLink() || st.isDirectory()) {
|
|
147
|
+
fs.rmSync(nextDir, { recursive: true, force: true })
|
|
148
|
+
}
|
|
149
|
+
}
|
|
150
|
+
|
|
151
|
+
try {
|
|
152
|
+
const type = process.platform === "win32" ? "junction" : "dir"
|
|
153
|
+
fs.symlinkSync(shipped, nextDir, type)
|
|
154
|
+
} catch {
|
|
155
|
+
fs.cpSync(shipped, nextDir, { recursive: true })
|
|
103
156
|
}
|
|
104
|
-
return
|
|
157
|
+
return nextDir
|
|
158
|
+
}
|
|
159
|
+
|
|
160
|
+
function touchDevReloadToken() {
|
|
161
|
+
const tokenFile = path.join(
|
|
162
|
+
packageRoot,
|
|
163
|
+
"lib",
|
|
164
|
+
"taskmark",
|
|
165
|
+
"dev-reload-token.ts"
|
|
166
|
+
)
|
|
167
|
+
const stamp = String(Date.now())
|
|
168
|
+
fs.writeFileSync(
|
|
169
|
+
tokenFile,
|
|
170
|
+
`/**\n * Touched by \`taskmark dev\` when board markdown changes so Next Fast Refresh\n * re-runs server components that import this module.\n */\nexport const DEV_RELOAD_TOKEN = "${stamp}"\n`,
|
|
171
|
+
"utf8"
|
|
172
|
+
)
|
|
105
173
|
}
|
|
106
174
|
|
|
107
175
|
function openBrowser(url) {
|
|
@@ -151,8 +219,8 @@ function waitForServer(port, timeoutMs = 60_000) {
|
|
|
151
219
|
})
|
|
152
220
|
}
|
|
153
221
|
|
|
154
|
-
|
|
155
|
-
const resolved = resolveServeBoard(
|
|
222
|
+
function resolveBoardOrExit(boardArg, command) {
|
|
223
|
+
const resolved = resolveServeBoard(boardArg)
|
|
156
224
|
if (!resolved) {
|
|
157
225
|
console.error(`No Taskmark board found.
|
|
158
226
|
|
|
@@ -162,50 +230,126 @@ Looked for:
|
|
|
162
230
|
- cwd layouts: nested ./taskmark/ or dedicated *-taskmark root
|
|
163
231
|
|
|
164
232
|
Fix: cd into a product repo (with ./taskmark/) or a board root, or set TASKMARK_BOARD.
|
|
165
|
-
Then re-run: npx taskmark
|
|
166
|
-
(or: npx -p @taskmark/ui taskmark
|
|
233
|
+
Then re-run: npx taskmark ${command}
|
|
234
|
+
(or: npx -p @taskmark/ui taskmark ${command})`)
|
|
235
|
+
process.exit(1)
|
|
236
|
+
}
|
|
237
|
+
return resolved
|
|
238
|
+
}
|
|
239
|
+
|
|
240
|
+
function attachChildLifecycle(child, onShutdown) {
|
|
241
|
+
const shutdown = (signal) => {
|
|
242
|
+
onShutdown?.()
|
|
243
|
+
if (!child.killed) child.kill(signal)
|
|
244
|
+
}
|
|
245
|
+
process.on("SIGINT", () => shutdown("SIGINT"))
|
|
246
|
+
process.on("SIGTERM", () => shutdown("SIGTERM"))
|
|
247
|
+
child.on("exit", (code, signal) => {
|
|
248
|
+
onShutdown?.()
|
|
249
|
+
if (signal) process.exit(1)
|
|
250
|
+
process.exit(code ?? 0)
|
|
251
|
+
})
|
|
252
|
+
return shutdown
|
|
253
|
+
}
|
|
254
|
+
|
|
255
|
+
async function serve(args) {
|
|
256
|
+
const resolved = resolveBoardOrExit(args.board, "serve")
|
|
257
|
+
const port = resolvePort(args.port)
|
|
258
|
+
const url = `http://localhost:${port}`
|
|
259
|
+
const nextBin = resolveNextBin()
|
|
260
|
+
|
|
261
|
+
try {
|
|
262
|
+
ensureProdNext()
|
|
263
|
+
} catch (err) {
|
|
264
|
+
console.error(String(err?.message || err))
|
|
167
265
|
process.exit(1)
|
|
168
266
|
}
|
|
169
267
|
|
|
170
|
-
|
|
171
|
-
|
|
172
|
-
|
|
268
|
+
console.log(`Taskmark UI`)
|
|
269
|
+
console.log(` board: ${resolved.boardPath} (${resolved.source})`)
|
|
270
|
+
console.log(` listen: ${url}`)
|
|
271
|
+
|
|
272
|
+
const child = spawn(
|
|
273
|
+
process.execPath,
|
|
274
|
+
[nextBin, "start", "-H", "0.0.0.0", "-p", String(port)],
|
|
275
|
+
{
|
|
276
|
+
cwd: packageRoot,
|
|
277
|
+
env: {
|
|
278
|
+
...process.env,
|
|
279
|
+
PORT: String(port),
|
|
280
|
+
HOSTNAME: "0.0.0.0",
|
|
281
|
+
TASKMARK_BOARD: resolved.boardPath,
|
|
282
|
+
NODE_ENV: "production",
|
|
283
|
+
},
|
|
284
|
+
stdio: "inherit",
|
|
285
|
+
}
|
|
286
|
+
)
|
|
173
287
|
|
|
174
|
-
|
|
175
|
-
npm run build
|
|
288
|
+
const shutdown = attachChildLifecycle(child)
|
|
176
289
|
|
|
177
|
-
|
|
290
|
+
const hosted =
|
|
291
|
+
Boolean(process.env.VERCEL) ||
|
|
292
|
+
Boolean(process.env.NOW_REGION) ||
|
|
293
|
+
process.env.CI === "true"
|
|
294
|
+
const shouldOpen = args.open && !hosted
|
|
295
|
+
|
|
296
|
+
try {
|
|
297
|
+
await waitForServer(port)
|
|
298
|
+
if (shouldOpen) {
|
|
299
|
+
openBrowser(url)
|
|
300
|
+
} else {
|
|
301
|
+
console.log(`Ready: ${url}`)
|
|
302
|
+
}
|
|
303
|
+
} catch (err) {
|
|
304
|
+
console.error(String(err?.message || err))
|
|
305
|
+
shutdown("SIGTERM")
|
|
178
306
|
process.exit(1)
|
|
179
307
|
}
|
|
308
|
+
}
|
|
180
309
|
|
|
310
|
+
async function dev(args) {
|
|
311
|
+
const resolved = resolveBoardOrExit(args.board, "dev")
|
|
181
312
|
const port = resolvePort(args.port)
|
|
182
313
|
const url = `http://localhost:${port}`
|
|
183
|
-
const
|
|
314
|
+
const nextBin = resolveNextBin()
|
|
184
315
|
|
|
185
|
-
console.log(`Taskmark UI`)
|
|
316
|
+
console.log(`Taskmark UI (dev)`)
|
|
186
317
|
console.log(` board: ${resolved.boardPath} (${resolved.source})`)
|
|
187
318
|
console.log(` listen: ${url}`)
|
|
319
|
+
console.log(` watch: **/*.md under board`)
|
|
188
320
|
|
|
189
|
-
const child = spawn(
|
|
190
|
-
|
|
191
|
-
|
|
192
|
-
|
|
193
|
-
|
|
194
|
-
|
|
195
|
-
|
|
196
|
-
|
|
197
|
-
|
|
198
|
-
|
|
321
|
+
const child = spawn(
|
|
322
|
+
process.execPath,
|
|
323
|
+
[nextBin, "dev", "--webpack", "-H", "0.0.0.0", "-p", String(port)],
|
|
324
|
+
{
|
|
325
|
+
cwd: packageRoot,
|
|
326
|
+
env: {
|
|
327
|
+
...process.env,
|
|
328
|
+
PORT: String(port),
|
|
329
|
+
TASKMARK_BOARD: resolved.boardPath,
|
|
330
|
+
TASKMARK_CWD: resolved.boardPath,
|
|
331
|
+
NODE_ENV: "development",
|
|
332
|
+
},
|
|
333
|
+
stdio: "inherit",
|
|
334
|
+
}
|
|
335
|
+
)
|
|
199
336
|
|
|
200
|
-
|
|
201
|
-
|
|
202
|
-
|
|
203
|
-
|
|
204
|
-
|
|
337
|
+
let debounce = null
|
|
338
|
+
const stopWatch = watchBoardMarkdown(resolved.boardPath, () => {
|
|
339
|
+
if (debounce) clearTimeout(debounce)
|
|
340
|
+
debounce = setTimeout(() => {
|
|
341
|
+
try {
|
|
342
|
+
touchDevReloadToken()
|
|
343
|
+
console.log(`[taskmark] board markdown changed — refreshing`)
|
|
344
|
+
} catch (err) {
|
|
345
|
+
console.warn(`[taskmark] reload touch failed: ${err?.message || err}`)
|
|
346
|
+
}
|
|
347
|
+
}, 200)
|
|
348
|
+
})
|
|
205
349
|
|
|
206
|
-
child
|
|
207
|
-
|
|
208
|
-
|
|
350
|
+
const shutdown = attachChildLifecycle(child, () => {
|
|
351
|
+
stopWatch()
|
|
352
|
+
if (debounce) clearTimeout(debounce)
|
|
209
353
|
})
|
|
210
354
|
|
|
211
355
|
const hosted =
|
|
@@ -215,7 +359,7 @@ Or install a published build that includes dist/standalone.`)
|
|
|
215
359
|
const shouldOpen = args.open && !hosted
|
|
216
360
|
|
|
217
361
|
try {
|
|
218
|
-
await waitForServer(port)
|
|
362
|
+
await waitForServer(port, 120_000)
|
|
219
363
|
if (shouldOpen) {
|
|
220
364
|
openBrowser(url)
|
|
221
365
|
} else {
|
|
@@ -228,6 +372,55 @@ Or install a published build that includes dist/standalone.`)
|
|
|
228
372
|
}
|
|
229
373
|
}
|
|
230
374
|
|
|
375
|
+
async function preview(args) {
|
|
376
|
+
const callerCwd = process.env.INIT_CWD || process.cwd()
|
|
377
|
+
|
|
378
|
+
function resolveCallerPath(p) {
|
|
379
|
+
if (!p) return null
|
|
380
|
+
return path.isAbsolute(p) ? path.resolve(p) : path.resolve(callerCwd, p)
|
|
381
|
+
}
|
|
382
|
+
|
|
383
|
+
const boardArg = resolveCallerPath(args.board)
|
|
384
|
+
const resolved = resolveBoardOrExit(boardArg, "preview")
|
|
385
|
+
|
|
386
|
+
const outDir = args.out
|
|
387
|
+
? resolveCallerPath(args.out)
|
|
388
|
+
: path.join(resolved.boardPath, "out")
|
|
389
|
+
|
|
390
|
+
if (!outDir || !fs.existsSync(outDir) || !fs.statSync(outDir).isDirectory()) {
|
|
391
|
+
console.error(`Static export not found: ${outDir || "(missing)"}
|
|
392
|
+
|
|
393
|
+
Run a production build first:
|
|
394
|
+
npx taskmark build --board .
|
|
395
|
+
# or: npm run build
|
|
396
|
+
|
|
397
|
+
Then: npm run preview`)
|
|
398
|
+
process.exit(1)
|
|
399
|
+
}
|
|
400
|
+
|
|
401
|
+
const port = resolvePort(args.port)
|
|
402
|
+
const url = `http://localhost:${port}`
|
|
403
|
+
|
|
404
|
+
console.log(`Taskmark static preview`)
|
|
405
|
+
console.log(` board: ${resolved.boardPath} (${resolved.source})`)
|
|
406
|
+
console.log(` out: ${outDir}`)
|
|
407
|
+
console.log(` listen: ${url}`)
|
|
408
|
+
|
|
409
|
+
await startStaticServer({ root: outDir, port })
|
|
410
|
+
|
|
411
|
+
const hosted =
|
|
412
|
+
Boolean(process.env.VERCEL) ||
|
|
413
|
+
Boolean(process.env.NOW_REGION) ||
|
|
414
|
+
process.env.CI === "true"
|
|
415
|
+
const shouldOpen = args.open && !hosted
|
|
416
|
+
|
|
417
|
+
if (shouldOpen) {
|
|
418
|
+
openBrowser(url)
|
|
419
|
+
} else {
|
|
420
|
+
console.log(`Ready: ${url}`)
|
|
421
|
+
}
|
|
422
|
+
}
|
|
423
|
+
|
|
231
424
|
async function main() {
|
|
232
425
|
const args = parseArgs(process.argv.slice(2))
|
|
233
426
|
if (args.help || !args.command) {
|
|
@@ -243,16 +436,31 @@ async function main() {
|
|
|
243
436
|
}
|
|
244
437
|
return
|
|
245
438
|
}
|
|
439
|
+
if (args.command === "dev") {
|
|
440
|
+
try {
|
|
441
|
+
await dev(args)
|
|
442
|
+
} catch (err) {
|
|
443
|
+
console.error(String(err?.message || err))
|
|
444
|
+
process.exit(1)
|
|
445
|
+
}
|
|
446
|
+
return
|
|
447
|
+
}
|
|
448
|
+
if (args.command === "preview") {
|
|
449
|
+
try {
|
|
450
|
+
await preview(args)
|
|
451
|
+
} catch (err) {
|
|
452
|
+
console.error(String(err?.message || err))
|
|
453
|
+
process.exit(1)
|
|
454
|
+
}
|
|
455
|
+
return
|
|
456
|
+
}
|
|
246
457
|
if (args.command === "build") {
|
|
247
458
|
const buildScript = path.join(packageRoot, "scripts", "build-static.mjs")
|
|
248
|
-
// Resolve relative paths against the caller's cwd (npm/yarn script dir),
|
|
249
|
-
// not packageRoot — the child runs with cwd = @taskmark/ui.
|
|
250
459
|
const callerCwd = process.env.INIT_CWD || process.cwd()
|
|
251
460
|
const childArgs = [buildScript]
|
|
252
461
|
if (args.board) {
|
|
253
462
|
childArgs.push("--board", path.resolve(callerCwd, args.board))
|
|
254
463
|
} else {
|
|
255
|
-
// Prefer the invoke directory as the board when no --board flag.
|
|
256
464
|
childArgs.push("--board", callerCwd)
|
|
257
465
|
}
|
|
258
466
|
if (args.out) {
|
|
@@ -9,15 +9,13 @@ import type { DiscoveredProject } from "@/lib/taskmark/types"
|
|
|
9
9
|
type AppBarProps = {
|
|
10
10
|
projects: DiscoveredProject[]
|
|
11
11
|
activeProjectId: string
|
|
12
|
-
|
|
13
|
-
/** When true, workspace is env/cwd-bound — hide multi-master add. */
|
|
12
|
+
/** When true, workspace is env/cwd-bound — hide project switcher and add. */
|
|
14
13
|
autoconfig?: boolean
|
|
15
14
|
}
|
|
16
15
|
|
|
17
16
|
export function AppBar({
|
|
18
17
|
projects,
|
|
19
18
|
activeProjectId,
|
|
20
|
-
masterCount,
|
|
21
19
|
autoconfig = false,
|
|
22
20
|
}: AppBarProps) {
|
|
23
21
|
return (
|
|
@@ -49,42 +47,41 @@ export function AppBar({
|
|
|
49
47
|
</span>
|
|
50
48
|
</p>
|
|
51
49
|
<p className="truncate text-xs text-muted-foreground transition-transform duration-200 group-hover:translate-y-1">
|
|
52
|
-
|
|
53
|
-
{masterCount > 0
|
|
54
|
-
? ` · ${masterCount} workspace${masterCount === 1 ? "" : "s"}`
|
|
55
|
-
: ""}
|
|
50
|
+
Product memory for agent work
|
|
56
51
|
</p>
|
|
57
52
|
</div>
|
|
58
53
|
</div>
|
|
59
54
|
|
|
60
|
-
|
|
61
|
-
|
|
62
|
-
|
|
63
|
-
|
|
64
|
-
<label htmlFor="projectId" className="sr-only">
|
|
65
|
-
Active project
|
|
66
|
-
</label>
|
|
67
|
-
<select
|
|
68
|
-
id="projectId"
|
|
69
|
-
name="projectId"
|
|
70
|
-
defaultValue={activeProjectId}
|
|
71
|
-
onChange={(e) => {
|
|
72
|
-
e.currentTarget.form?.requestSubmit()
|
|
73
|
-
}}
|
|
74
|
-
className="max-w-[20rem] rounded border-2 border-border bg-input px-3 py-1.5 text-sm shadow-sm outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring"
|
|
55
|
+
{!autoconfig ? (
|
|
56
|
+
<form
|
|
57
|
+
action={selectActiveProject}
|
|
58
|
+
className="flex min-w-0 flex-wrap items-center gap-2"
|
|
75
59
|
>
|
|
76
|
-
|
|
77
|
-
|
|
78
|
-
|
|
79
|
-
|
|
80
|
-
|
|
81
|
-
|
|
82
|
-
|
|
83
|
-
|
|
84
|
-
|
|
85
|
-
|
|
86
|
-
|
|
87
|
-
|
|
60
|
+
<label htmlFor="projectId" className="sr-only">
|
|
61
|
+
Active project
|
|
62
|
+
</label>
|
|
63
|
+
<select
|
|
64
|
+
id="projectId"
|
|
65
|
+
name="projectId"
|
|
66
|
+
defaultValue={activeProjectId}
|
|
67
|
+
onChange={(e) => {
|
|
68
|
+
e.currentTarget.form?.requestSubmit()
|
|
69
|
+
}}
|
|
70
|
+
className="max-w-[20rem] rounded border-2 border-border bg-input px-3 py-1.5 text-sm shadow-sm outline-none focus-visible:outline-2 focus-visible:outline-offset-2 focus-visible:outline-ring"
|
|
71
|
+
>
|
|
72
|
+
{projects.map((project) => (
|
|
73
|
+
<option key={project.id} value={project.id}>
|
|
74
|
+
{projectOptionLabel(project, projects)}
|
|
75
|
+
</option>
|
|
76
|
+
))}
|
|
77
|
+
</select>
|
|
78
|
+
<noscript>
|
|
79
|
+
<Button type="submit" size="sm" variant="outline">
|
|
80
|
+
Switch project
|
|
81
|
+
</Button>
|
|
82
|
+
</noscript>
|
|
83
|
+
</form>
|
|
84
|
+
) : null}
|
|
88
85
|
|
|
89
86
|
{!autoconfig ? (
|
|
90
87
|
<form action={openAddProject}>
|
|
@@ -0,0 +1,49 @@
|
|
|
1
|
+
"use client"
|
|
2
|
+
|
|
3
|
+
import { useRouter } from "next/navigation"
|
|
4
|
+
import { useEffect, useRef } from "react"
|
|
5
|
+
|
|
6
|
+
/**
|
|
7
|
+
* In development, poll the board-reload SSE endpoint and soft-refresh RSC
|
|
8
|
+
* trees when markdown on disk changes.
|
|
9
|
+
*/
|
|
10
|
+
export function BoardDevReloader() {
|
|
11
|
+
const router = useRouter()
|
|
12
|
+
const lastAt = useRef(0)
|
|
13
|
+
|
|
14
|
+
useEffect(() => {
|
|
15
|
+
if (process.env.NODE_ENV !== "development") return
|
|
16
|
+
|
|
17
|
+
let closed = false
|
|
18
|
+
let source: EventSource | null = null
|
|
19
|
+
let retryTimer: ReturnType<typeof setTimeout> | null = null
|
|
20
|
+
|
|
21
|
+
const connect = () => {
|
|
22
|
+
if (closed) return
|
|
23
|
+
source = new EventSource("/api/taskmark-reload")
|
|
24
|
+
source.addEventListener("reload", (event) => {
|
|
25
|
+
const data = String((event as MessageEvent).data || "")
|
|
26
|
+
const at = Number.parseInt(data, 10)
|
|
27
|
+
if (Number.isFinite(at) && at <= lastAt.current) return
|
|
28
|
+
lastAt.current = Number.isFinite(at) ? at : Date.now()
|
|
29
|
+
router.refresh()
|
|
30
|
+
})
|
|
31
|
+
source.onerror = () => {
|
|
32
|
+
source?.close()
|
|
33
|
+
source = null
|
|
34
|
+
if (!closed) {
|
|
35
|
+
retryTimer = setTimeout(connect, 1500)
|
|
36
|
+
}
|
|
37
|
+
}
|
|
38
|
+
}
|
|
39
|
+
|
|
40
|
+
connect()
|
|
41
|
+
return () => {
|
|
42
|
+
closed = true
|
|
43
|
+
if (retryTimer) clearTimeout(retryTimer)
|
|
44
|
+
source?.close()
|
|
45
|
+
}
|
|
46
|
+
}, [router])
|
|
47
|
+
|
|
48
|
+
return null
|
|
49
|
+
}
|
|
@@ -33,6 +33,7 @@ import { usePaginatedRows } from "@/hooks/use-paginated-rows"
|
|
|
33
33
|
import { usePersistedHideCompleted } from "@/hooks/use-persisted-hide-completed"
|
|
34
34
|
import { useTableSort } from "@/hooks/use-table-sort"
|
|
35
35
|
import { cn } from "@/lib/utils"
|
|
36
|
+
import { displayFileName } from "@/lib/display-path"
|
|
36
37
|
import type { EpicSummary, ProjectEpicList } from "@/lib/taskmark/epic-types"
|
|
37
38
|
import { isGeneralEpic } from "@/lib/taskmark/general-epic"
|
|
38
39
|
import {
|
|
@@ -145,9 +146,6 @@ function ProjectEpicCard({
|
|
|
145
146
|
<Card>
|
|
146
147
|
<CardHeader>
|
|
147
148
|
<CardTitle className="font-head text-xl">{project.name}</CardTitle>
|
|
148
|
-
<CardDescription className="font-mono text-xs">
|
|
149
|
-
{project.boardPath}
|
|
150
|
-
</CardDescription>
|
|
151
149
|
{hasSourceRows ? (
|
|
152
150
|
<CardAction>
|
|
153
151
|
<TimeframeFilter
|
|
@@ -173,7 +171,7 @@ function ProjectEpicCard({
|
|
|
173
171
|
<ul className="mt-2 flex flex-col gap-1 font-mono text-xs text-muted-foreground">
|
|
174
172
|
{errors.map((err) => (
|
|
175
173
|
<li key={err.filePath}>
|
|
176
|
-
{err.filePath}: {err.message}
|
|
174
|
+
{displayFileName(err.filePath)}: {err.message}
|
|
177
175
|
</li>
|
|
178
176
|
))}
|
|
179
177
|
</ul>
|
|
@@ -13,8 +13,7 @@ type MarkdownContentProps = {
|
|
|
13
13
|
}
|
|
14
14
|
|
|
15
15
|
const proseClassName = cn(
|
|
16
|
-
"text-sm leading-relaxed text-foreground",
|
|
17
|
-
"[&>:first-child]:mt-0 [&>:last-child]:mb-0",
|
|
16
|
+
"tm-md text-sm leading-relaxed text-foreground",
|
|
18
17
|
"[&_p]:my-2",
|
|
19
18
|
"[&_h1]:mt-3 [&_h1]:mb-2 [&_h1]:font-head [&_h1]:text-lg [&_h1]:font-semibold",
|
|
20
19
|
"[&_h2]:mt-3 [&_h2]:mb-2 [&_h2]:font-head [&_h2]:text-base [&_h2]:font-semibold",
|
|
@@ -36,6 +36,7 @@ import { usePaginatedRows } from "@/hooks/use-paginated-rows"
|
|
|
36
36
|
import { usePersistedHideCompleted } from "@/hooks/use-persisted-hide-completed"
|
|
37
37
|
import { useTableSort } from "@/hooks/use-table-sort"
|
|
38
38
|
import { cn } from "@/lib/utils"
|
|
39
|
+
import { displayFileName } from "@/lib/display-path"
|
|
39
40
|
import type { EpicWorkItemsList } from "@/lib/taskmark/flat-work-item-types"
|
|
40
41
|
import {
|
|
41
42
|
DEFAULT_TIMEFRAME_FILTER,
|
|
@@ -155,7 +156,7 @@ export function OverallWorkItemsList({
|
|
|
155
156
|
<ul className="mt-2 flex flex-col gap-1 font-mono text-xs text-muted-foreground">
|
|
156
157
|
{errors.map((err) => (
|
|
157
158
|
<li key={`${err.filePath}:${err.message}`}>
|
|
158
|
-
{err.filePath}: {err.message}
|
|
159
|
+
{displayFileName(err.filePath)}: {err.message}
|
|
159
160
|
</li>
|
|
160
161
|
))}
|
|
161
162
|
</ul>
|
|
@@ -34,6 +34,7 @@ import { usePaginatedRows } from "@/hooks/use-paginated-rows"
|
|
|
34
34
|
import { usePersistedHideCompleted } from "@/hooks/use-persisted-hide-completed"
|
|
35
35
|
import { useTableSort } from "@/hooks/use-table-sort"
|
|
36
36
|
import { cn } from "@/lib/utils"
|
|
37
|
+
import { displayFileName } from "@/lib/display-path"
|
|
37
38
|
import type { EpicStoryList } from "@/lib/taskmark/story-types"
|
|
38
39
|
import {
|
|
39
40
|
DEFAULT_TIMEFRAME_FILTER,
|
|
@@ -158,7 +159,7 @@ export function StoryList({
|
|
|
158
159
|
<ul className="mt-2 flex flex-col gap-1 font-mono text-xs text-muted-foreground">
|
|
159
160
|
{errors.map((err) => (
|
|
160
161
|
<li key={`${err.filePath}:${err.message}`}>
|
|
161
|
-
{err.filePath}: {err.message}
|
|
162
|
+
{displayFileName(err.filePath)}: {err.message}
|
|
162
163
|
</li>
|
|
163
164
|
))}
|
|
164
165
|
</ul>
|
|
@@ -33,6 +33,7 @@ import { usePaginatedRows } from "@/hooks/use-paginated-rows"
|
|
|
33
33
|
import { usePersistedHideCompleted } from "@/hooks/use-persisted-hide-completed"
|
|
34
34
|
import { useTableSort } from "@/hooks/use-table-sort"
|
|
35
35
|
import type { StoryItemList } from "@/lib/taskmark/item-types"
|
|
36
|
+
import { displayFileName } from "@/lib/display-path"
|
|
36
37
|
import {
|
|
37
38
|
DEFAULT_TIMEFRAME_FILTER,
|
|
38
39
|
filterListRows,
|
|
@@ -154,7 +155,7 @@ export function TaskList({
|
|
|
154
155
|
<ul className="mt-2 flex flex-col gap-1 font-mono text-xs text-muted-foreground">
|
|
155
156
|
{errors.map((err) => (
|
|
156
157
|
<li key={`${err.filePath}:${err.message}`}>
|
|
157
|
-
{err.filePath}: {err.message}
|
|
158
|
+
{displayFileName(err.filePath)}: {err.message}
|
|
158
159
|
</li>
|
|
159
160
|
))}
|
|
160
161
|
</ul>
|
|
@@ -39,6 +39,7 @@ import {
|
|
|
39
39
|
loadWorkItemDetailFromSnapshot,
|
|
40
40
|
resolveWorkItemByIdFromSnapshot,
|
|
41
41
|
} from "@/lib/taskmark/snapshot-client"
|
|
42
|
+
import { displayFileName } from "@/lib/display-path"
|
|
42
43
|
|
|
43
44
|
const isStatic =
|
|
44
45
|
process.env.NEXT_PUBLIC_TASKMARK_STATIC === "1" ||
|
|
@@ -574,7 +575,7 @@ function WorkItemSheetProviderInner({
|
|
|
574
575
|
<p className="mt-1 text-muted-foreground">{state.message}</p>
|
|
575
576
|
{state.filePath ? (
|
|
576
577
|
<p className="mt-2 break-all font-mono text-xs text-muted-foreground">
|
|
577
|
-
{state.filePath}
|
|
578
|
+
{displayFileName(state.filePath)}
|
|
578
579
|
</p>
|
|
579
580
|
) : null}
|
|
580
581
|
</div>
|
|
@@ -598,13 +599,25 @@ function WorkItemSheetProviderInner({
|
|
|
598
599
|
)
|
|
599
600
|
}
|
|
600
601
|
|
|
602
|
+
/** Context while `useSearchParams` Suspense is pending — children must not render bare. */
|
|
603
|
+
const SUSPENSE_FALLBACK_SHEET: WorkItemSheetContextValue = {
|
|
604
|
+
openDetail: () => {},
|
|
605
|
+
openDetailById: () => {},
|
|
606
|
+
}
|
|
607
|
+
|
|
601
608
|
export function WorkItemSheetProvider({
|
|
602
609
|
children,
|
|
603
610
|
}: {
|
|
604
611
|
children: React.ReactNode
|
|
605
612
|
}) {
|
|
606
613
|
return (
|
|
607
|
-
<React.Suspense
|
|
614
|
+
<React.Suspense
|
|
615
|
+
fallback={
|
|
616
|
+
<WorkItemSheetContext.Provider value={SUSPENSE_FALLBACK_SHEET}>
|
|
617
|
+
{children}
|
|
618
|
+
</WorkItemSheetContext.Provider>
|
|
619
|
+
}
|
|
620
|
+
>
|
|
608
621
|
<WorkItemSheetProviderInner>{children}</WorkItemSheetProviderInner>
|
|
609
622
|
</React.Suspense>
|
|
610
623
|
)
|