@taskmark/ui 0.2.5 → 0.2.6

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.
Files changed (50) hide show
  1. package/README.md +32 -7
  2. package/app/setup/page.tsx +4 -1
  3. package/bin/lib/resolve-board.mjs +50 -1
  4. package/bin/taskmark.js +139 -30
  5. package/dist/prod-next/BUILD_ID +1 -1
  6. package/dist/prod-next/build-manifest.json +2 -2
  7. package/dist/prod-next/prerender-manifest.json +24 -0
  8. package/dist/prod-next/server/app/_global-error.html +1 -1
  9. package/dist/prod-next/server/app/_global-error.rsc +1 -1
  10. package/dist/prod-next/server/app/_global-error.segments/_full.segment.rsc +1 -1
  11. package/dist/prod-next/server/app/_global-error.segments/_global-error/__PAGE__.segment.rsc +1 -1
  12. package/dist/prod-next/server/app/_global-error.segments/_global-error.segment.rsc +1 -1
  13. package/dist/prod-next/server/app/_global-error.segments/_head.segment.rsc +1 -1
  14. package/dist/prod-next/server/app/_global-error.segments/_index.segment.rsc +1 -1
  15. package/dist/prod-next/server/app/_global-error.segments/_tree.segment.rsc +1 -1
  16. package/dist/prod-next/server/app/_not-found.html +1 -1
  17. package/dist/prod-next/server/app/_not-found.rsc +1 -1
  18. package/dist/prod-next/server/app/_not-found.segments/_full.segment.rsc +1 -1
  19. package/dist/prod-next/server/app/_not-found.segments/_head.segment.rsc +1 -1
  20. package/dist/prod-next/server/app/_not-found.segments/_index.segment.rsc +1 -1
  21. package/dist/prod-next/server/app/_not-found.segments/_not-found/__PAGE__.segment.rsc +1 -1
  22. package/dist/prod-next/server/app/_not-found.segments/_not-found.segment.rsc +1 -1
  23. package/dist/prod-next/server/app/_not-found.segments/_tree.segment.rsc +1 -1
  24. package/dist/prod-next/server/app/api/taskmark-reload/route.js +1 -1
  25. package/dist/prod-next/server/app/board/page.js +1 -1
  26. package/dist/prod-next/server/app/page.js +1 -1
  27. package/dist/prod-next/server/app/setup/page.js +1 -1
  28. package/dist/prod-next/server/app/setup.html +1 -0
  29. package/dist/prod-next/server/app/setup.meta +17 -0
  30. package/dist/prod-next/server/app/setup.rsc +22 -0
  31. package/dist/prod-next/server/app/setup.segments/_full.segment.rsc +22 -0
  32. package/dist/prod-next/server/app/setup.segments/_head.segment.rsc +6 -0
  33. package/dist/prod-next/server/app/setup.segments/_index.segment.rsc +8 -0
  34. package/dist/prod-next/server/app/setup.segments/_tree.segment.rsc +5 -0
  35. package/dist/prod-next/server/app/setup.segments/setup/__PAGE__.segment.rsc +6 -0
  36. package/dist/prod-next/server/app/setup.segments/setup.segment.rsc +5 -0
  37. package/dist/prod-next/server/chunks/490.js +2 -2
  38. package/dist/prod-next/server/chunks/616.js +1 -1
  39. package/dist/prod-next/server/middleware-build-manifest.js +1 -1
  40. package/dist/prod-next/server/pages/404.html +1 -1
  41. package/dist/prod-next/server/pages/500.html +1 -1
  42. package/dist/public/taskmark-snapshot.json +1 -1
  43. package/lib/taskmark/autoconfig.ts +54 -3
  44. package/lib/taskmark/discover.ts +2 -1
  45. package/lib/taskmark/workspace-mode.ts +24 -0
  46. package/lib/taskmark/workspace.ts +5 -2
  47. package/package.json +4 -2
  48. package/public/taskmark-snapshot.json +1 -1
  49. /package/dist/prod-next/static/{wbcgYS3Jw87KqhnA9ttOL → sAWr5ATVuqk6Wqs18kAWs}/_buildManifest.js +0 -0
  50. /package/dist/prod-next/static/{wbcgYS3Jw87KqhnA9ttOL → sAWr5ATVuqk6Wqs18kAWs}/_ssgManifest.js +0 -0
@@ -7,8 +7,13 @@ import {
7
7
  discoverTaskmarkProjects,
8
8
  } from "@/lib/taskmark/discover"
9
9
  import type { DiscoveredProject } from "@/lib/taskmark/types"
10
+ import { isWorkspaceMode } from "@/lib/taskmark/workspace-mode"
10
11
 
11
- export type AutoconfigSource = "env_board" | "env_master" | "cwd"
12
+ export type AutoconfigSource =
13
+ | "env_board"
14
+ | "env_master"
15
+ | "cwd"
16
+ | "sibling"
12
17
 
13
18
  export type AutoconfigWorkspace = {
14
19
  source: AutoconfigSource
@@ -84,13 +89,54 @@ export function cwdCandidates(): string[] {
84
89
  return out
85
90
  }
86
91
 
92
+ /**
93
+ * Multi-git: product repo beside `<parentBasename>-taskmark` (or unique sibling).
94
+ */
95
+ export function resolveSiblingDedicatedBoard(fromDir: string): string | null {
96
+ const resolved = path.resolve(fromDir)
97
+ const parent = path.dirname(resolved)
98
+ const parentName = path.basename(parent)
99
+ const preferred = path.join(parent, `${parentName}-taskmark`)
100
+ const preferredBoard = resolveBoardAtPath(preferred)
101
+ if (preferredBoard) return preferredBoard
102
+
103
+ let entries: fs.Dirent[]
104
+ try {
105
+ entries = fs.readdirSync(parent, { withFileTypes: true })
106
+ } catch {
107
+ return null
108
+ }
109
+
110
+ const boards: string[] = []
111
+ for (const entry of entries) {
112
+ if (!entry.isDirectory() || !entry.name.endsWith("-taskmark")) continue
113
+ const board = resolveBoardAtPath(path.join(parent, entry.name))
114
+ if (board) boards.push(board)
115
+ }
116
+ if (boards.length === 0) return null
117
+ if (boards.length === 1) return boards[0]
118
+
119
+ const cwdBase = path.basename(resolved)
120
+ const parts = cwdBase.split("-").filter(Boolean)
121
+ for (let i = parts.length - 1; i >= 1; i--) {
122
+ const prefix = parts.slice(0, i).join("-")
123
+ const hit = boards.find((b) => path.basename(b) === `${prefix}-taskmark`)
124
+ if (hit) return hit
125
+ }
126
+
127
+ return null
128
+ }
129
+
87
130
  /**
88
131
  * Resolve a zero-config workspace without cookies.
89
132
  *
90
- * Precedence: TASKMARK_BOARD → TASKMARK_MASTER → cwd layouts.
91
- * Returns null when nothing valid is found (caller should use cookie setup).
133
+ * Precedence: TASKMARK_BOARD → TASKMARK_MASTER → cwd layouts → sibling *-taskmark.
134
+ * Returns null when nothing valid is found (caller should use cookie setup),
135
+ * or when workspace mode asked for the multi-project picker instead of a bind.
92
136
  */
93
137
  export function resolveAutoconfigWorkspace(): AutoconfigWorkspace | null {
138
+ if (isWorkspaceMode()) return null
139
+
94
140
  const boardEnv = readEnvPath("TASKMARK_BOARD")
95
141
  if (boardEnv) {
96
142
  const board = resolveBoardAtPath(boardEnv)
@@ -114,5 +160,10 @@ export function resolveAutoconfigWorkspace(): AutoconfigWorkspace | null {
114
160
  if (board) return workspaceFromBoard(board, "cwd")
115
161
  }
116
162
 
163
+ for (const candidate of cwdCandidates()) {
164
+ const sibling = resolveSiblingDedicatedBoard(candidate)
165
+ if (sibling) return workspaceFromBoard(sibling, "sibling")
166
+ }
167
+
117
168
  return null
118
169
  }
@@ -129,7 +129,8 @@ export function discoverTaskmarkProjects(
129
129
  for (const entry of entries) {
130
130
  if (!entry.isDirectory()) continue
131
131
  if (shouldSkipDir(entry.name)) continue
132
- if (entry.name === "taskmark") continue
132
+ // A real `<dir>/taskmark` board already returned above, so a folder named
133
+ // "taskmark" here is an ordinary directory (e.g. a workspace root).
133
134
  visit(path.join(dir, entry.name), depth + 1)
134
135
  }
135
136
  }
@@ -0,0 +1,24 @@
1
+ import path from "node:path"
2
+
3
+ /**
4
+ * Workspace (multi-project) mode — `taskmark` / `taskmark open` / `--workspace`.
5
+ *
6
+ * Board-bound commands (`serve`, `dev`) auto-config a single board from env or
7
+ * cwd. Workspace mode turns that off so the cookie-based master folders and the
8
+ * app bar project picker drive which board is shown.
9
+ */
10
+ export function isWorkspaceMode(): boolean {
11
+ const raw = process.env.TASKMARK_WORKSPACE?.trim().toLowerCase()
12
+ return raw === "1" || raw === "true"
13
+ }
14
+
15
+ /** Directory `taskmark` was invoked from; seeds the setup wizard input. */
16
+ export function workspaceStartPath(): string {
17
+ for (const raw of [
18
+ process.env.TASKMARK_WORKSPACE_ROOT,
19
+ process.env.INIT_CWD,
20
+ ]) {
21
+ if (raw && raw.trim()) return path.resolve(raw.trim())
22
+ }
23
+ return ""
24
+ }
@@ -1,4 +1,7 @@
1
- import { resolveAutoconfigWorkspace } from "@/lib/taskmark/autoconfig"
1
+ import {
2
+ resolveAutoconfigWorkspace,
3
+ type AutoconfigSource,
4
+ } from "@/lib/taskmark/autoconfig"
2
5
  import { discoverTaskmarkProjectsFromMasters } from "@/lib/taskmark/discover"
3
6
  import { validateMasterFolder } from "@/lib/taskmark/validate"
4
7
  import type { DiscoveredProject } from "@/lib/taskmark/types"
@@ -7,7 +10,7 @@ export type ConfiguredWorkspace = {
7
10
  masters: string[]
8
11
  projects: DiscoveredProject[]
9
12
  /** How the workspace was resolved; null means cookie/manual masters. */
10
- source: "env_board" | "env_master" | "cwd" | "cookies" | null
13
+ source: AutoconfigSource | "cookies" | null
11
14
  /** When true, UI is locked to the auto-bound board(s) (skip setup). */
12
15
  autoconfig: boolean
13
16
  }
package/package.json CHANGED
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "@taskmark/ui",
3
- "version": "0.2.5",
4
- "description": "Local Taskmark board UI — install in a board folder and run `npx taskmark serve`, `npx taskmark dev`, or `npx taskmark build`",
3
+ "version": "0.2.6",
4
+ "description": "Taskmark board UI — run globally for setup/project picker, or install in a board folder to open that board with `npx taskmark`",
5
5
  "private": false,
6
6
  "type": "module",
7
7
  "bin": {
@@ -33,6 +33,8 @@
33
33
  },
34
34
  "scripts": {
35
35
  "dev": "node ./bin/taskmark.js dev",
36
+ "dev:workspace": "node ./bin/taskmark.js dev --workspace",
37
+ "open": "node ./bin/taskmark.js open",
36
38
  "build": "next build --webpack && node scripts/prepare-standalone.mjs",
37
39
  "build:static": "node scripts/build-static.mjs",
38
40
  "start": "next start",