skyboard-cli 0.1.1 → 0.1.3
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/dist/__tests__/auth-state.test.d.ts +1 -0
- package/dist/__tests__/auth-state.test.js +86 -0
- package/dist/__tests__/auth-state.test.js.map +1 -0
- package/dist/__tests__/card-ref.test.d.ts +1 -0
- package/dist/__tests__/card-ref.test.js +36 -0
- package/dist/__tests__/card-ref.test.js.map +1 -0
- package/dist/__tests__/column-match.test.d.ts +1 -0
- package/dist/__tests__/column-match.test.js +49 -0
- package/dist/__tests__/column-match.test.js.map +1 -0
- package/dist/__tests__/commands.test.d.ts +1 -0
- package/dist/__tests__/commands.test.js +243 -0
- package/dist/__tests__/commands.test.js.map +1 -0
- package/dist/__tests__/helpers.d.ts +50 -0
- package/dist/__tests__/helpers.js +135 -0
- package/dist/__tests__/helpers.js.map +1 -0
- package/dist/__tests__/materialize.test.d.ts +1 -0
- package/dist/__tests__/materialize.test.js +186 -0
- package/dist/__tests__/materialize.test.js.map +1 -0
- package/dist/__tests__/pds.test.d.ts +1 -0
- package/dist/__tests__/pds.test.js +80 -0
- package/dist/__tests__/pds.test.js.map +1 -0
- package/dist/commands/add.d.ts +1 -0
- package/dist/commands/add.js +41 -0
- package/dist/commands/add.js.map +1 -0
- package/dist/commands/boards.d.ts +3 -0
- package/dist/commands/boards.js +54 -0
- package/dist/commands/boards.js.map +1 -0
- package/dist/commands/cards.d.ts +7 -0
- package/dist/commands/cards.js +54 -0
- package/dist/commands/cards.js.map +1 -0
- package/dist/commands/cols.d.ts +4 -0
- package/dist/commands/cols.js +44 -0
- package/dist/commands/cols.js.map +1 -0
- package/dist/commands/comment.d.ts +4 -0
- package/dist/commands/comment.js +55 -0
- package/dist/commands/comment.js.map +1 -0
- package/dist/commands/edit.d.ts +7 -0
- package/dist/commands/edit.js +80 -0
- package/dist/commands/edit.js.map +1 -0
- package/dist/commands/login.d.ts +1 -0
- package/dist/commands/login.js +20 -0
- package/dist/commands/login.js.map +1 -0
- package/dist/commands/logout.d.ts +1 -0
- package/dist/commands/logout.js +14 -0
- package/dist/commands/logout.js.map +1 -0
- package/dist/commands/mv.d.ts +4 -0
- package/dist/commands/mv.js +74 -0
- package/dist/commands/mv.js.map +1 -0
- package/dist/commands/new.d.ts +6 -0
- package/dist/commands/new.js +72 -0
- package/dist/commands/new.js.map +1 -0
- package/dist/commands/rm.d.ts +5 -0
- package/dist/commands/rm.js +67 -0
- package/dist/commands/rm.js.map +1 -0
- package/dist/commands/show.d.ts +4 -0
- package/dist/commands/show.js +90 -0
- package/dist/commands/show.js.map +1 -0
- package/dist/commands/status.d.ts +3 -0
- package/dist/commands/status.js +71 -0
- package/dist/commands/status.js.map +1 -0
- package/dist/commands/use.d.ts +1 -0
- package/dist/commands/use.js +61 -0
- package/dist/commands/use.js.map +1 -0
- package/dist/commands/whoami.d.ts +3 -0
- package/dist/commands/whoami.js +23 -0
- package/dist/commands/whoami.js.map +1 -0
- package/dist/index.d.ts +2 -0
- package/dist/index.js +126 -0
- package/dist/index.js.map +1 -0
- package/dist/lib/auth.d.ts +28 -0
- package/dist/lib/auth.js +219 -0
- package/dist/lib/auth.js.map +1 -0
- package/dist/lib/card-ref.d.ts +7 -0
- package/dist/lib/card-ref.js +23 -0
- package/dist/lib/card-ref.js.map +1 -0
- package/dist/lib/column-match.d.ts +6 -0
- package/dist/lib/column-match.js +35 -0
- package/dist/lib/column-match.js.map +1 -0
- package/dist/lib/config.d.ts +32 -0
- package/dist/lib/config.js +153 -0
- package/dist/lib/config.js.map +1 -0
- package/dist/lib/display.d.ts +11 -0
- package/dist/lib/display.js +97 -0
- package/dist/lib/display.js.map +1 -0
- package/dist/lib/materialize.d.ts +2 -0
- package/dist/lib/materialize.js +111 -0
- package/dist/lib/materialize.js.map +1 -0
- package/dist/lib/pds.d.ts +26 -0
- package/dist/lib/pds.js +187 -0
- package/dist/lib/pds.js.map +1 -0
- package/dist/lib/permissions.d.ts +4 -0
- package/dist/lib/permissions.js +13 -0
- package/dist/lib/permissions.js.map +1 -0
- package/dist/lib/schemas.d.ts +209 -0
- package/dist/lib/schemas.js +82 -0
- package/dist/lib/schemas.js.map +1 -0
- package/dist/lib/tid.d.ts +9 -0
- package/dist/lib/tid.js +16 -0
- package/dist/lib/tid.js.map +1 -0
- package/dist/lib/types.d.ts +129 -0
- package/dist/lib/types.js +3 -0
- package/dist/lib/types.js.map +1 -0
- package/package.json +5 -2
|
@@ -0,0 +1,35 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* Match a column reference (name, prefix, or 1-based index) to a column.
|
|
3
|
+
* Throws with a helpful message if no match found.
|
|
4
|
+
*/
|
|
5
|
+
export function resolveColumn(ref, columns) {
|
|
6
|
+
const sorted = [...columns].sort((a, b) => a.order - b.order);
|
|
7
|
+
// Try numeric index (1-based)
|
|
8
|
+
const idx = parseInt(ref, 10);
|
|
9
|
+
if (!isNaN(idx) && idx >= 1 && idx <= sorted.length) {
|
|
10
|
+
return sorted[idx - 1];
|
|
11
|
+
}
|
|
12
|
+
// Try exact match (case-insensitive)
|
|
13
|
+
const exact = sorted.find((c) => c.name.toLowerCase() === ref.toLowerCase());
|
|
14
|
+
if (exact)
|
|
15
|
+
return exact;
|
|
16
|
+
// Try prefix match
|
|
17
|
+
const prefixMatches = sorted.filter((c) => c.name.toLowerCase().startsWith(ref.toLowerCase()));
|
|
18
|
+
if (prefixMatches.length === 1)
|
|
19
|
+
return prefixMatches[0];
|
|
20
|
+
if (prefixMatches.length > 1) {
|
|
21
|
+
const list = prefixMatches.map((c, i) => ` ${i + 1}. ${c.name}`).join("\n");
|
|
22
|
+
throw new Error(`Ambiguous column "${ref}". Matches:\n${list}`);
|
|
23
|
+
}
|
|
24
|
+
// Try substring match
|
|
25
|
+
const subMatches = sorted.filter((c) => c.name.toLowerCase().includes(ref.toLowerCase()));
|
|
26
|
+
if (subMatches.length === 1)
|
|
27
|
+
return subMatches[0];
|
|
28
|
+
if (subMatches.length > 1) {
|
|
29
|
+
const list = subMatches.map((c, i) => ` ${i + 1}. ${c.name}`).join("\n");
|
|
30
|
+
throw new Error(`Ambiguous column "${ref}". Matches:\n${list}`);
|
|
31
|
+
}
|
|
32
|
+
const allCols = sorted.map((c, i) => ` ${i + 1}. ${c.name}`).join("\n");
|
|
33
|
+
throw new Error(`No column matching "${ref}". Available columns:\n${allCols}`);
|
|
34
|
+
}
|
|
35
|
+
//# sourceMappingURL=column-match.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"column-match.js","sourceRoot":"","sources":["../../src/lib/column-match.ts"],"names":[],"mappings":"AAEA;;;GAGG;AACH,MAAM,UAAU,aAAa,CAC3B,GAAW,EACX,OAAiB;IAEjB,MAAM,MAAM,GAAG,CAAC,GAAG,OAAO,CAAC,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,KAAK,GAAG,CAAC,CAAC,KAAK,CAAC,CAAC;IAE9D,8BAA8B;IAC9B,MAAM,GAAG,GAAG,QAAQ,CAAC,GAAG,EAAE,EAAE,CAAC,CAAC;IAC9B,IAAI,CAAC,KAAK,CAAC,GAAG,CAAC,IAAI,GAAG,IAAI,CAAC,IAAI,GAAG,IAAI,MAAM,CAAC,MAAM,EAAE,CAAC;QACpD,OAAO,MAAM,CAAC,GAAG,GAAG,CAAC,CAAC,CAAC;IACzB,CAAC;IAED,qCAAqC;IACrC,MAAM,KAAK,GAAG,MAAM,CAAC,IAAI,CAAC,CAAC,CAAC,EAAE,EAAE,CAAC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,KAAK,GAAG,CAAC,WAAW,EAAE,CAAC,CAAC;IAC7E,IAAI,KAAK;QAAE,OAAO,KAAK,CAAC;IAExB,mBAAmB;IACnB,MAAM,aAAa,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CACxC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,UAAU,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CACnD,CAAC;IACF,IAAI,aAAa,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,aAAa,CAAC,CAAC,CAAC,CAAC;IACxD,IAAI,aAAa,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC7B,MAAM,IAAI,GAAG,aAAa,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC7E,MAAM,IAAI,KAAK,CAAC,qBAAqB,GAAG,gBAAgB,IAAI,EAAE,CAAC,CAAC;IAClE,CAAC;IAED,sBAAsB;IACtB,MAAM,UAAU,GAAG,MAAM,CAAC,MAAM,CAAC,CAAC,CAAC,EAAE,EAAE,CACrC,CAAC,CAAC,IAAI,CAAC,WAAW,EAAE,CAAC,QAAQ,CAAC,GAAG,CAAC,WAAW,EAAE,CAAC,CACjD,CAAC;IACF,IAAI,UAAU,CAAC,MAAM,KAAK,CAAC;QAAE,OAAO,UAAU,CAAC,CAAC,CAAC,CAAC;IAClD,IAAI,UAAU,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC1B,MAAM,IAAI,GAAG,UAAU,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;QAC1E,MAAM,IAAI,KAAK,CAAC,qBAAqB,GAAG,gBAAgB,IAAI,EAAE,CAAC,CAAC;IAClE,CAAC;IAED,MAAM,OAAO,GAAG,MAAM,CAAC,GAAG,CAAC,CAAC,CAAC,EAAE,CAAC,EAAE,EAAE,CAAC,KAAK,CAAC,GAAG,CAAC,KAAK,CAAC,CAAC,IAAI,EAAE,CAAC,CAAC,IAAI,CAAC,IAAI,CAAC,CAAC;IACzE,MAAM,IAAI,KAAK,CAAC,uBAAuB,GAAG,0BAA0B,OAAO,EAAE,CAAC,CAAC;AACjF,CAAC"}
|
|
@@ -0,0 +1,32 @@
|
|
|
1
|
+
export interface BoardRef {
|
|
2
|
+
did: string;
|
|
3
|
+
rkey: string;
|
|
4
|
+
name: string;
|
|
5
|
+
}
|
|
6
|
+
export interface Config {
|
|
7
|
+
defaultBoard?: BoardRef;
|
|
8
|
+
knownBoards: BoardRef[];
|
|
9
|
+
}
|
|
10
|
+
export declare function getConfigDir(): string;
|
|
11
|
+
export declare function getAuthDir(): string;
|
|
12
|
+
export declare function getStateDir(): string;
|
|
13
|
+
export declare function loadConfig(): Config;
|
|
14
|
+
export declare function saveConfig(config: Config): void;
|
|
15
|
+
export declare function setDefaultBoard(board: BoardRef): void;
|
|
16
|
+
export declare function getDefaultBoard(): BoardRef | undefined;
|
|
17
|
+
export declare function clearDefaultBoard(): void;
|
|
18
|
+
export declare function addKnownBoard(board: BoardRef): void;
|
|
19
|
+
export declare function writeStateFile(key: string, data: unknown): void;
|
|
20
|
+
export declare function readStateFile(key: string): unknown | undefined;
|
|
21
|
+
export declare function deleteStateFile(key: string): void;
|
|
22
|
+
export declare function writeSessionFile(sub: string, data: unknown): void;
|
|
23
|
+
export declare function readSessionFile(sub: string): unknown | undefined;
|
|
24
|
+
export declare function deleteSessionFile(sub: string): void;
|
|
25
|
+
export interface AuthInfo {
|
|
26
|
+
did: string;
|
|
27
|
+
handle: string;
|
|
28
|
+
service: string;
|
|
29
|
+
}
|
|
30
|
+
export declare function loadAuthInfo(): AuthInfo | null;
|
|
31
|
+
export declare function saveAuthInfo(info: AuthInfo): void;
|
|
32
|
+
export declare function clearAuthInfo(): void;
|
|
@@ -0,0 +1,153 @@
|
|
|
1
|
+
import { mkdirSync, readFileSync, writeFileSync, existsSync, unlinkSync } from "node:fs";
|
|
2
|
+
import { join } from "node:path";
|
|
3
|
+
import { homedir } from "node:os";
|
|
4
|
+
const CONFIG_DIR = join(homedir(), ".config", "skyboard");
|
|
5
|
+
const CONFIG_PATH = join(CONFIG_DIR, "config.json");
|
|
6
|
+
const AUTH_DIR = join(CONFIG_DIR, "auth");
|
|
7
|
+
const STATE_DIR = join(CONFIG_DIR, "state");
|
|
8
|
+
export function getConfigDir() {
|
|
9
|
+
return CONFIG_DIR;
|
|
10
|
+
}
|
|
11
|
+
export function getAuthDir() {
|
|
12
|
+
return AUTH_DIR;
|
|
13
|
+
}
|
|
14
|
+
export function getStateDir() {
|
|
15
|
+
return STATE_DIR;
|
|
16
|
+
}
|
|
17
|
+
function ensureConfigDir() {
|
|
18
|
+
mkdirSync(CONFIG_DIR, { recursive: true, mode: 0o700 });
|
|
19
|
+
}
|
|
20
|
+
function ensureAuthDir() {
|
|
21
|
+
ensureConfigDir();
|
|
22
|
+
mkdirSync(AUTH_DIR, { recursive: true, mode: 0o700 });
|
|
23
|
+
}
|
|
24
|
+
function ensureStateDir() {
|
|
25
|
+
ensureConfigDir();
|
|
26
|
+
mkdirSync(STATE_DIR, { recursive: true, mode: 0o700 });
|
|
27
|
+
}
|
|
28
|
+
export function loadConfig() {
|
|
29
|
+
ensureConfigDir();
|
|
30
|
+
if (!existsSync(CONFIG_PATH)) {
|
|
31
|
+
return { knownBoards: [] };
|
|
32
|
+
}
|
|
33
|
+
try {
|
|
34
|
+
const raw = readFileSync(CONFIG_PATH, "utf-8");
|
|
35
|
+
return JSON.parse(raw);
|
|
36
|
+
}
|
|
37
|
+
catch {
|
|
38
|
+
return { knownBoards: [] };
|
|
39
|
+
}
|
|
40
|
+
}
|
|
41
|
+
export function saveConfig(config) {
|
|
42
|
+
ensureConfigDir();
|
|
43
|
+
writeFileSync(CONFIG_PATH, JSON.stringify(config, null, 2), {
|
|
44
|
+
mode: 0o600,
|
|
45
|
+
});
|
|
46
|
+
}
|
|
47
|
+
export function setDefaultBoard(board) {
|
|
48
|
+
const config = loadConfig();
|
|
49
|
+
config.defaultBoard = board;
|
|
50
|
+
if (!config.knownBoards.some((b) => b.did === board.did && b.rkey === board.rkey)) {
|
|
51
|
+
config.knownBoards.push(board);
|
|
52
|
+
}
|
|
53
|
+
saveConfig(config);
|
|
54
|
+
}
|
|
55
|
+
export function getDefaultBoard() {
|
|
56
|
+
return loadConfig().defaultBoard;
|
|
57
|
+
}
|
|
58
|
+
export function clearDefaultBoard() {
|
|
59
|
+
const config = loadConfig();
|
|
60
|
+
delete config.defaultBoard;
|
|
61
|
+
saveConfig(config);
|
|
62
|
+
}
|
|
63
|
+
export function addKnownBoard(board) {
|
|
64
|
+
const config = loadConfig();
|
|
65
|
+
if (!config.knownBoards.some((b) => b.did === board.did && b.rkey === board.rkey)) {
|
|
66
|
+
config.knownBoards.push(board);
|
|
67
|
+
}
|
|
68
|
+
saveConfig(config);
|
|
69
|
+
}
|
|
70
|
+
// File-based state store for OAuth CSRF tokens
|
|
71
|
+
export function writeStateFile(key, data) {
|
|
72
|
+
ensureStateDir();
|
|
73
|
+
writeFileSync(join(STATE_DIR, `${key}.json`), JSON.stringify(data), {
|
|
74
|
+
mode: 0o600,
|
|
75
|
+
});
|
|
76
|
+
}
|
|
77
|
+
export function readStateFile(key) {
|
|
78
|
+
const path = join(STATE_DIR, `${key}.json`);
|
|
79
|
+
if (!existsSync(path))
|
|
80
|
+
return undefined;
|
|
81
|
+
try {
|
|
82
|
+
return JSON.parse(readFileSync(path, "utf-8"));
|
|
83
|
+
}
|
|
84
|
+
catch {
|
|
85
|
+
return undefined;
|
|
86
|
+
}
|
|
87
|
+
}
|
|
88
|
+
export function deleteStateFile(key) {
|
|
89
|
+
const path = join(STATE_DIR, `${key}.json`);
|
|
90
|
+
try {
|
|
91
|
+
unlinkSync(path);
|
|
92
|
+
}
|
|
93
|
+
catch {
|
|
94
|
+
// ignore
|
|
95
|
+
}
|
|
96
|
+
}
|
|
97
|
+
// File-based session store for OAuth sessions
|
|
98
|
+
export function writeSessionFile(sub, data) {
|
|
99
|
+
ensureAuthDir();
|
|
100
|
+
const filename = Buffer.from(sub).toString("base64url");
|
|
101
|
+
writeFileSync(join(AUTH_DIR, `${filename}.json`), JSON.stringify(data), {
|
|
102
|
+
mode: 0o600,
|
|
103
|
+
});
|
|
104
|
+
}
|
|
105
|
+
export function readSessionFile(sub) {
|
|
106
|
+
const filename = Buffer.from(sub).toString("base64url");
|
|
107
|
+
const path = join(AUTH_DIR, `${filename}.json`);
|
|
108
|
+
if (!existsSync(path))
|
|
109
|
+
return undefined;
|
|
110
|
+
try {
|
|
111
|
+
return JSON.parse(readFileSync(path, "utf-8"));
|
|
112
|
+
}
|
|
113
|
+
catch {
|
|
114
|
+
return undefined;
|
|
115
|
+
}
|
|
116
|
+
}
|
|
117
|
+
export function deleteSessionFile(sub) {
|
|
118
|
+
const filename = Buffer.from(sub).toString("base64url");
|
|
119
|
+
const path = join(AUTH_DIR, `${filename}.json`);
|
|
120
|
+
try {
|
|
121
|
+
unlinkSync(path);
|
|
122
|
+
}
|
|
123
|
+
catch {
|
|
124
|
+
// ignore
|
|
125
|
+
}
|
|
126
|
+
}
|
|
127
|
+
// Simple auth info storage (which DID is logged in)
|
|
128
|
+
const AUTH_INFO_PATH = join(CONFIG_DIR, "session.json");
|
|
129
|
+
export function loadAuthInfo() {
|
|
130
|
+
if (!existsSync(AUTH_INFO_PATH))
|
|
131
|
+
return null;
|
|
132
|
+
try {
|
|
133
|
+
return JSON.parse(readFileSync(AUTH_INFO_PATH, "utf-8"));
|
|
134
|
+
}
|
|
135
|
+
catch {
|
|
136
|
+
return null;
|
|
137
|
+
}
|
|
138
|
+
}
|
|
139
|
+
export function saveAuthInfo(info) {
|
|
140
|
+
ensureConfigDir();
|
|
141
|
+
writeFileSync(AUTH_INFO_PATH, JSON.stringify(info, null, 2), {
|
|
142
|
+
mode: 0o600,
|
|
143
|
+
});
|
|
144
|
+
}
|
|
145
|
+
export function clearAuthInfo() {
|
|
146
|
+
try {
|
|
147
|
+
unlinkSync(AUTH_INFO_PATH);
|
|
148
|
+
}
|
|
149
|
+
catch {
|
|
150
|
+
// ignore
|
|
151
|
+
}
|
|
152
|
+
}
|
|
153
|
+
//# sourceMappingURL=config.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"config.js","sourceRoot":"","sources":["../../src/lib/config.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
import type { MaterializedTask, Board, Column } from "./types.js";
|
|
2
|
+
export declare function formatDate(iso: string): string;
|
|
3
|
+
export declare function shortRkey(rkey: string): string;
|
|
4
|
+
export declare function formatTask(task: MaterializedTask, board: Board): string;
|
|
5
|
+
export declare function formatBoardHeader(board: Board): string;
|
|
6
|
+
export declare function formatColumnHeader(col: Column, taskCount: number): string;
|
|
7
|
+
export declare function printBoardCards(board: Board, tasks: MaterializedTask[], opts: {
|
|
8
|
+
column?: string;
|
|
9
|
+
label?: string;
|
|
10
|
+
search?: string;
|
|
11
|
+
}): void;
|
|
@@ -0,0 +1,97 @@
|
|
|
1
|
+
import chalk from "chalk";
|
|
2
|
+
export function formatDate(iso) {
|
|
3
|
+
const d = new Date(iso);
|
|
4
|
+
const now = new Date();
|
|
5
|
+
const diffMs = now.getTime() - d.getTime();
|
|
6
|
+
const diffDays = Math.floor(diffMs / (1000 * 60 * 60 * 24));
|
|
7
|
+
if (diffDays === 0) {
|
|
8
|
+
return d.toLocaleTimeString(undefined, { hour: "2-digit", minute: "2-digit" });
|
|
9
|
+
}
|
|
10
|
+
else if (diffDays < 7) {
|
|
11
|
+
return `${diffDays}d ago`;
|
|
12
|
+
}
|
|
13
|
+
else {
|
|
14
|
+
return d.toLocaleDateString(undefined, { month: "short", day: "numeric" });
|
|
15
|
+
}
|
|
16
|
+
}
|
|
17
|
+
export function shortRkey(rkey) {
|
|
18
|
+
return rkey.slice(0, 7);
|
|
19
|
+
}
|
|
20
|
+
export function formatTask(task, board) {
|
|
21
|
+
const col = board.columns.find((c) => c.id === task.effectiveColumnId);
|
|
22
|
+
const colName = col?.name ?? "?";
|
|
23
|
+
const labels = task.effectiveLabelIds
|
|
24
|
+
.map((id) => board.labels?.find((l) => l.id === id))
|
|
25
|
+
.filter(Boolean)
|
|
26
|
+
.map((l) => chalk.hex(l.color)(`[${l.name}]`))
|
|
27
|
+
.join(" ");
|
|
28
|
+
const ref = chalk.dim(shortRkey(task.rkey));
|
|
29
|
+
const title = task.effectiveTitle;
|
|
30
|
+
const date = chalk.dim(formatDate(task.lastModifiedAt));
|
|
31
|
+
let line = ` ${ref} ${title}`;
|
|
32
|
+
if (labels)
|
|
33
|
+
line += ` ${labels}`;
|
|
34
|
+
line += ` ${date}`;
|
|
35
|
+
return line;
|
|
36
|
+
}
|
|
37
|
+
export function formatBoardHeader(board) {
|
|
38
|
+
let header = chalk.bold(board.name);
|
|
39
|
+
if (board.description) {
|
|
40
|
+
header += chalk.dim(` ${board.description}`);
|
|
41
|
+
}
|
|
42
|
+
return header;
|
|
43
|
+
}
|
|
44
|
+
export function formatColumnHeader(col, taskCount) {
|
|
45
|
+
return `\n${chalk.bold.underline(col.name)} ${chalk.dim(`(${taskCount})`)}`;
|
|
46
|
+
}
|
|
47
|
+
export function printBoardCards(board, tasks, opts) {
|
|
48
|
+
// Sort columns by order
|
|
49
|
+
const sortedColumns = [...board.columns].sort((a, b) => a.order - b.order);
|
|
50
|
+
for (const col of sortedColumns) {
|
|
51
|
+
// Filter tasks for this column
|
|
52
|
+
let colTasks = tasks.filter((t) => t.effectiveColumnId === col.id);
|
|
53
|
+
// Apply filters
|
|
54
|
+
if (opts.column && !matchesColumn(col, opts.column, sortedColumns))
|
|
55
|
+
continue;
|
|
56
|
+
if (opts.label) {
|
|
57
|
+
const label = board.labels?.find((l) => l.name.toLowerCase().includes(opts.label.toLowerCase()));
|
|
58
|
+
if (label) {
|
|
59
|
+
colTasks = colTasks.filter((t) => t.effectiveLabelIds.includes(label.id));
|
|
60
|
+
}
|
|
61
|
+
else {
|
|
62
|
+
colTasks = [];
|
|
63
|
+
}
|
|
64
|
+
}
|
|
65
|
+
if (opts.search) {
|
|
66
|
+
const s = opts.search.toLowerCase();
|
|
67
|
+
colTasks = colTasks.filter((t) => t.effectiveTitle.toLowerCase().includes(s) ||
|
|
68
|
+
(t.effectiveDescription?.toLowerCase().includes(s) ?? false));
|
|
69
|
+
}
|
|
70
|
+
// Sort by position
|
|
71
|
+
colTasks.sort((a, b) => a.effectivePosition.localeCompare(b.effectivePosition));
|
|
72
|
+
console.log(formatColumnHeader(col, colTasks.length));
|
|
73
|
+
if (colTasks.length === 0) {
|
|
74
|
+
console.log(chalk.dim(" (empty)"));
|
|
75
|
+
}
|
|
76
|
+
else {
|
|
77
|
+
for (const task of colTasks) {
|
|
78
|
+
console.log(formatTask(task, board));
|
|
79
|
+
}
|
|
80
|
+
}
|
|
81
|
+
}
|
|
82
|
+
}
|
|
83
|
+
function matchesColumn(col, query, allColumns) {
|
|
84
|
+
// Check numeric index (1-based)
|
|
85
|
+
const idx = parseInt(query, 10);
|
|
86
|
+
if (!isNaN(idx) && idx >= 1 && idx <= allColumns.length) {
|
|
87
|
+
return allColumns[idx - 1].id === col.id;
|
|
88
|
+
}
|
|
89
|
+
// Check exact match (case-insensitive)
|
|
90
|
+
if (col.name.toLowerCase() === query.toLowerCase())
|
|
91
|
+
return true;
|
|
92
|
+
// Check prefix match
|
|
93
|
+
if (col.name.toLowerCase().startsWith(query.toLowerCase()))
|
|
94
|
+
return true;
|
|
95
|
+
return false;
|
|
96
|
+
}
|
|
97
|
+
//# sourceMappingURL=display.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"display.js","sourceRoot":"","sources":["../../src/lib/display.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,111 @@
|
|
|
1
|
+
// Synced from ../src/lib/materialize.ts
|
|
2
|
+
import { buildAtUri, TASK_COLLECTION } from "./tid.js";
|
|
3
|
+
import { generateKeyBetween } from "fractional-indexing";
|
|
4
|
+
import { isTrusted } from "./permissions.js";
|
|
5
|
+
const MUTABLE_FIELDS = [
|
|
6
|
+
"title",
|
|
7
|
+
"description",
|
|
8
|
+
"columnId",
|
|
9
|
+
"position",
|
|
10
|
+
"labelIds",
|
|
11
|
+
];
|
|
12
|
+
function orderToPosition(order) {
|
|
13
|
+
if (order === undefined || order === null)
|
|
14
|
+
return generateKeyBetween(null, null);
|
|
15
|
+
const clamped = Math.min(Math.max(0, order), 10_000);
|
|
16
|
+
let pos = null;
|
|
17
|
+
for (let i = 0; i <= clamped; i++) {
|
|
18
|
+
pos = generateKeyBetween(pos, null);
|
|
19
|
+
}
|
|
20
|
+
return pos;
|
|
21
|
+
}
|
|
22
|
+
export function materializeTasks(tasks, ops, ownerTrustedDids, currentUserDid, boardOwnerDid) {
|
|
23
|
+
const seenTasks = new Set();
|
|
24
|
+
const uniqueTasks = tasks.filter((task) => {
|
|
25
|
+
const key = `${task.did}:${task.rkey}`;
|
|
26
|
+
if (seenTasks.has(key))
|
|
27
|
+
return false;
|
|
28
|
+
seenTasks.add(key);
|
|
29
|
+
return true;
|
|
30
|
+
});
|
|
31
|
+
const opsByTask = new Map();
|
|
32
|
+
for (const op of ops) {
|
|
33
|
+
const list = opsByTask.get(op.targetTaskUri) || [];
|
|
34
|
+
list.push(op);
|
|
35
|
+
opsByTask.set(op.targetTaskUri, list);
|
|
36
|
+
}
|
|
37
|
+
return uniqueTasks.map((task) => {
|
|
38
|
+
const taskUri = buildAtUri(task.did, TASK_COLLECTION, task.rkey);
|
|
39
|
+
const taskOps = opsByTask.get(taskUri) || [];
|
|
40
|
+
const appliedOps = [];
|
|
41
|
+
for (const op of taskOps) {
|
|
42
|
+
if (op.did === boardOwnerDid ||
|
|
43
|
+
op.did === task.did ||
|
|
44
|
+
op.did === currentUserDid ||
|
|
45
|
+
isTrusted(op.did, boardOwnerDid, ownerTrustedDids)) {
|
|
46
|
+
appliedOps.push(op);
|
|
47
|
+
}
|
|
48
|
+
}
|
|
49
|
+
const fieldStates = {};
|
|
50
|
+
for (const field of MUTABLE_FIELDS) {
|
|
51
|
+
let value = task[field];
|
|
52
|
+
if (field === "position" && !value) {
|
|
53
|
+
value = orderToPosition(task.order);
|
|
54
|
+
}
|
|
55
|
+
fieldStates[field] = {
|
|
56
|
+
value,
|
|
57
|
+
timestamp: task.createdAt,
|
|
58
|
+
author: task.did,
|
|
59
|
+
};
|
|
60
|
+
}
|
|
61
|
+
const sortedOps = [...appliedOps].sort((a, b) => a.createdAt.localeCompare(b.createdAt));
|
|
62
|
+
for (const op of sortedOps) {
|
|
63
|
+
for (const field of MUTABLE_FIELDS) {
|
|
64
|
+
const opValue = op.fields[field];
|
|
65
|
+
if (opValue !== undefined) {
|
|
66
|
+
const current = fieldStates[field];
|
|
67
|
+
if (op.createdAt > current.timestamp) {
|
|
68
|
+
fieldStates[field] = {
|
|
69
|
+
value: opValue,
|
|
70
|
+
timestamp: op.createdAt,
|
|
71
|
+
author: op.did,
|
|
72
|
+
};
|
|
73
|
+
}
|
|
74
|
+
}
|
|
75
|
+
}
|
|
76
|
+
}
|
|
77
|
+
let lastModifiedBy = task.did;
|
|
78
|
+
let lastModifiedAt = task.updatedAt || task.createdAt;
|
|
79
|
+
for (const field of MUTABLE_FIELDS) {
|
|
80
|
+
if (fieldStates[field].timestamp > lastModifiedAt) {
|
|
81
|
+
lastModifiedAt = fieldStates[field].timestamp;
|
|
82
|
+
lastModifiedBy = fieldStates[field].author;
|
|
83
|
+
}
|
|
84
|
+
}
|
|
85
|
+
return {
|
|
86
|
+
rkey: task.rkey,
|
|
87
|
+
did: task.did,
|
|
88
|
+
title: task.title,
|
|
89
|
+
description: task.description,
|
|
90
|
+
columnId: task.columnId,
|
|
91
|
+
boardUri: task.boardUri,
|
|
92
|
+
position: task.position,
|
|
93
|
+
labelIds: task.labelIds,
|
|
94
|
+
order: task.order,
|
|
95
|
+
createdAt: task.createdAt,
|
|
96
|
+
updatedAt: task.updatedAt,
|
|
97
|
+
sourceTask: task,
|
|
98
|
+
appliedOps,
|
|
99
|
+
pendingOps: [],
|
|
100
|
+
effectiveTitle: fieldStates.title.value,
|
|
101
|
+
effectiveDescription: fieldStates.description.value,
|
|
102
|
+
effectiveColumnId: fieldStates.columnId.value,
|
|
103
|
+
effectivePosition: fieldStates.position.value,
|
|
104
|
+
effectiveLabelIds: fieldStates.labelIds.value ?? [],
|
|
105
|
+
ownerDid: task.did,
|
|
106
|
+
lastModifiedBy,
|
|
107
|
+
lastModifiedAt,
|
|
108
|
+
};
|
|
109
|
+
});
|
|
110
|
+
}
|
|
111
|
+
//# sourceMappingURL=materialize.js.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"materialize.js","sourceRoot":"","sources":["../../src/lib/materialize.ts"],"names":[],"mappings":"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"}
|
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import type { Agent } from "@atproto/api";
|
|
2
|
+
import type { Board, Trust, Comment } from "./types.js";
|
|
3
|
+
import type { MaterializedTask } from "./types.js";
|
|
4
|
+
/**
|
|
5
|
+
* Fetch a single board record from the appview.
|
|
6
|
+
*/
|
|
7
|
+
export declare function fetchBoardFromAppview(ownerDid: string, rkey: string): Promise<Board | null>;
|
|
8
|
+
/**
|
|
9
|
+
* Fetch all boards from the authenticated user's PDS (using Agent).
|
|
10
|
+
*/
|
|
11
|
+
export declare function fetchMyBoards(agent: Agent, did: string): Promise<Board[]>;
|
|
12
|
+
export interface BoardData {
|
|
13
|
+
board: Board;
|
|
14
|
+
tasks: MaterializedTask[];
|
|
15
|
+
trusts: Trust[];
|
|
16
|
+
comments: Comment[];
|
|
17
|
+
allParticipants: string[];
|
|
18
|
+
}
|
|
19
|
+
/**
|
|
20
|
+
* Fetch all data for a board from the appview (single HTTP request).
|
|
21
|
+
*/
|
|
22
|
+
export declare function fetchBoardData(boardDid: string, boardRkey: string, currentUserDid: string): Promise<BoardData | null>;
|
|
23
|
+
/**
|
|
24
|
+
* Resolve a handle to a DID.
|
|
25
|
+
*/
|
|
26
|
+
export declare function resolveHandle(handle: string): Promise<string | null>;
|