@gamflaz/opencode-todolist 1.0.5 → 1.0.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.
- package/README.md +32 -31
- package/dist/icons/{convert.js → svg-icon.js} +1 -1
- package/dist/tui/todo-panel.js +742 -0
- package/package.json +1 -1
- package/dist/icons/capabilities.d.ts +0 -9
- package/dist/icons/capabilities.js +0 -15
- package/dist/icons/convert.d.ts +0 -7
- package/dist/icons/icons.d.ts +0 -4
- package/dist/icons/icons.js +0 -14
- package/dist/icons/svg-icon.jsx +0 -37
- package/dist/schema/status.schema.d.ts +0 -16
- package/dist/schema/status.schema.js +0 -14
- package/dist/schema/store.schema.d.ts +0 -19
- package/dist/schema/store.schema.js +0 -20
- package/dist/schema/todo.schema.d.ts +0 -281
- package/dist/schema/todo.schema.js +0 -112
- package/dist/skills/skill.d.ts +0 -24
- package/dist/skills/skill.js +0 -153
- package/dist/store/errors.d.ts +0 -3
- package/dist/store/errors.js +0 -6
- package/dist/store/store.d.ts +0 -145
- package/dist/store/store.js +0 -445
- package/dist/todo/display.d.ts +0 -21
- package/dist/todo/display.js +0 -53
- package/dist/todo/hint.d.ts +0 -16
- package/dist/todo/hint.js +0 -187
- package/dist/todo/todo.d.ts +0 -63
- package/dist/todo/todo.js +0 -188
- package/dist/todo/update.d.ts +0 -35
- package/dist/todo/update.js +0 -140
- package/dist/tui/todo-panel.jsx +0 -503
- package/dist/tui.jsx +0 -20
package/dist/skills/skill.js
DELETED
|
@@ -1,153 +0,0 @@
|
|
|
1
|
-
import { Skill } from "@opencode/plugin";
|
|
2
|
-
import fs from "node:fs";
|
|
3
|
-
import path from "node:path";
|
|
4
|
-
import { fileURLToPath } from "node:url";
|
|
5
|
-
const unquote = (value) => {
|
|
6
|
-
const v = value.trim();
|
|
7
|
-
const quoted = /^(["'])([\s\S]*)\1$/.exec(v);
|
|
8
|
-
return quoted ? (quoted[2] ?? v) : v;
|
|
9
|
-
};
|
|
10
|
-
export function parseSkillMarkdown(input) {
|
|
11
|
-
const raw = input.replace(/^\uFEFF/, "");
|
|
12
|
-
const match = /^---\r?\n([\s\S]*?)\r?\n---(?:\r?\n|$)/.exec(raw);
|
|
13
|
-
if (!match)
|
|
14
|
-
return { body: raw.trim() };
|
|
15
|
-
const parsed = { body: raw.slice(match[0].length).trim() };
|
|
16
|
-
const lines = (match[1] ?? "").split(/\r?\n/);
|
|
17
|
-
let inMetadata = false;
|
|
18
|
-
for (let i = 0; i < lines.length; i++) {
|
|
19
|
-
const line = lines[i];
|
|
20
|
-
if (!line || !line.trim() || line.trimStart().startsWith("#"))
|
|
21
|
-
continue;
|
|
22
|
-
const separator = line.indexOf(":");
|
|
23
|
-
if (separator === -1)
|
|
24
|
-
continue;
|
|
25
|
-
const key = line.slice(0, separator).trim();
|
|
26
|
-
let value = unquote(line.slice(separator + 1));
|
|
27
|
-
if (/^\s/.test(line)) {
|
|
28
|
-
if (inMetadata && value)
|
|
29
|
-
(parsed.metadata ??= {})[key] = value;
|
|
30
|
-
continue;
|
|
31
|
-
}
|
|
32
|
-
inMetadata = key.toLowerCase() === "metadata";
|
|
33
|
-
if (/^[>|][+-]?$/.test(value)) {
|
|
34
|
-
const folded = value.startsWith(">");
|
|
35
|
-
const block = [];
|
|
36
|
-
while (i + 1 < lines.length &&
|
|
37
|
-
(!lines[i + 1]?.trim() || /^\s/.test(lines[i + 1] ?? ""))) {
|
|
38
|
-
block.push((lines[++i] ?? "").trim());
|
|
39
|
-
}
|
|
40
|
-
value = block.filter(Boolean).join(folded ? " " : "\n");
|
|
41
|
-
}
|
|
42
|
-
if (!value)
|
|
43
|
-
continue;
|
|
44
|
-
switch (key.toLowerCase()) {
|
|
45
|
-
case "name":
|
|
46
|
-
parsed.name = value;
|
|
47
|
-
break;
|
|
48
|
-
case "description":
|
|
49
|
-
parsed.description = value;
|
|
50
|
-
break;
|
|
51
|
-
case "license":
|
|
52
|
-
parsed.license = value;
|
|
53
|
-
break;
|
|
54
|
-
case "compatibility":
|
|
55
|
-
parsed.compatibility = value;
|
|
56
|
-
break;
|
|
57
|
-
}
|
|
58
|
-
}
|
|
59
|
-
return parsed;
|
|
60
|
-
}
|
|
61
|
-
export function parseSkillFile(file) {
|
|
62
|
-
try {
|
|
63
|
-
return parseSkillMarkdown(fs.readFileSync(file, "utf8"));
|
|
64
|
-
}
|
|
65
|
-
catch {
|
|
66
|
-
return null;
|
|
67
|
-
}
|
|
68
|
-
}
|
|
69
|
-
export function getSkillsDirectory() {
|
|
70
|
-
const moduleDir = path.dirname(fileURLToPath(import.meta.url));
|
|
71
|
-
const candidates = [path.resolve(moduleDir, "..", "..", "skills")];
|
|
72
|
-
return candidates.find((dir) => fs.existsSync(dir)) ?? candidates[0] ?? "";
|
|
73
|
-
}
|
|
74
|
-
function isDirectoryEntry(dir, entry) {
|
|
75
|
-
if (entry.isDirectory())
|
|
76
|
-
return true;
|
|
77
|
-
if (!entry.isSymbolicLink())
|
|
78
|
-
return false;
|
|
79
|
-
try {
|
|
80
|
-
return fs.statSync(path.join(dir, entry.name)).isDirectory();
|
|
81
|
-
}
|
|
82
|
-
catch {
|
|
83
|
-
return false;
|
|
84
|
-
}
|
|
85
|
-
}
|
|
86
|
-
export function readSkills(dir = getSkillsDirectory()) {
|
|
87
|
-
try {
|
|
88
|
-
return fs.readdirSync(dir, { withFileTypes: true }).flatMap((entry) => {
|
|
89
|
-
const isDir = isDirectoryEntry(dir, entry);
|
|
90
|
-
const candidates = isDir
|
|
91
|
-
? [
|
|
92
|
-
path.join(dir, entry.name, "SKILL.md"),
|
|
93
|
-
path.join(dir, entry.name, `${entry.name}.md`),
|
|
94
|
-
]
|
|
95
|
-
: path.extname(entry.name) === ".md"
|
|
96
|
-
? [path.join(dir, entry.name)]
|
|
97
|
-
: [];
|
|
98
|
-
for (const file of candidates) {
|
|
99
|
-
const parsed = parseSkillFile(file);
|
|
100
|
-
if (!parsed)
|
|
101
|
-
continue;
|
|
102
|
-
const id = isDir ? entry.name : path.basename(entry.name, ".md");
|
|
103
|
-
return [
|
|
104
|
-
{
|
|
105
|
-
id,
|
|
106
|
-
name: parsed.name || id,
|
|
107
|
-
description: parsed.description,
|
|
108
|
-
license: parsed.license,
|
|
109
|
-
compatibility: parsed.compatibility,
|
|
110
|
-
metadata: parsed.metadata,
|
|
111
|
-
path: file,
|
|
112
|
-
content: parsed.body,
|
|
113
|
-
},
|
|
114
|
-
];
|
|
115
|
-
}
|
|
116
|
-
return [];
|
|
117
|
-
});
|
|
118
|
-
}
|
|
119
|
-
catch {
|
|
120
|
-
return [];
|
|
121
|
-
}
|
|
122
|
-
}
|
|
123
|
-
export async function registerTodoSkills(ctx) {
|
|
124
|
-
const debug = process.env.TODO_HINT_DEBUG === "1";
|
|
125
|
-
try {
|
|
126
|
-
const skills = readSkills();
|
|
127
|
-
if (skills.length === 0) {
|
|
128
|
-
if (debug) {
|
|
129
|
-
console.error("[todo] no skills found in", getSkillsDirectory());
|
|
130
|
-
}
|
|
131
|
-
return;
|
|
132
|
-
}
|
|
133
|
-
await ctx.skill.transform((editor) => {
|
|
134
|
-
for (const skill of skills) {
|
|
135
|
-
editor.add(Skill.Info.make({
|
|
136
|
-
id: skill.id,
|
|
137
|
-
name: skill.name,
|
|
138
|
-
path: skill.path,
|
|
139
|
-
content: skill.content,
|
|
140
|
-
autoinvoke: skill.metadata?.["opencode/autoinvoke"] !== "false",
|
|
141
|
-
...(skill.description ? { description: skill.description } : {}),
|
|
142
|
-
}));
|
|
143
|
-
}
|
|
144
|
-
});
|
|
145
|
-
if (debug) {
|
|
146
|
-
console.error("[todo] skills registered:", skills.map((s) => s.id).join(", "));
|
|
147
|
-
}
|
|
148
|
-
}
|
|
149
|
-
catch (error) {
|
|
150
|
-
if (debug)
|
|
151
|
-
console.error("[todo] skill registration failed", error);
|
|
152
|
-
}
|
|
153
|
-
}
|
package/dist/store/errors.d.ts
DELETED
package/dist/store/errors.js
DELETED
package/dist/store/store.d.ts
DELETED
|
@@ -1,145 +0,0 @@
|
|
|
1
|
-
import { type TodoRootItem } from "../schema/todo.schema";
|
|
2
|
-
/**
|
|
3
|
-
* Environment/OS context used to resolve storage locations. All fields are
|
|
4
|
-
* optional so callers (and tests) can simulate any platform on any host.
|
|
5
|
-
*/
|
|
6
|
-
export interface PlatformContext {
|
|
7
|
-
platform?: NodeJS.Platform;
|
|
8
|
-
env?: Record<string, string | undefined>;
|
|
9
|
-
home?: string;
|
|
10
|
-
}
|
|
11
|
-
export interface TodoData {
|
|
12
|
-
version: number;
|
|
13
|
-
todos: TodoRootItem[];
|
|
14
|
-
created_at: string;
|
|
15
|
-
updated_at: string;
|
|
16
|
-
}
|
|
17
|
-
/**
|
|
18
|
-
* Per-session todo persistence.
|
|
19
|
-
*
|
|
20
|
-
* Layout (per session):
|
|
21
|
-
* <base>/s_<hash>/todos/todos-<timestamp>.json todo payload (latest wins)
|
|
22
|
-
* <base>/s_<hash>/todos/version monotonically increasing version
|
|
23
|
-
* <base>/s_<hash>/todos/id hashed session folder name
|
|
24
|
-
* <base>/s_<hash>/todos/todos.lock cross-process lock
|
|
25
|
-
* <base>/s_<hash>/todos/hint-marker.json hint injection marker
|
|
26
|
-
*/
|
|
27
|
-
export declare class TodoStore {
|
|
28
|
-
private readonly ctx;
|
|
29
|
-
private static readonly SESSION_ID_PATTERN;
|
|
30
|
-
private static readonly FILE_PREFIX;
|
|
31
|
-
private static readonly FILE_SUFFIX;
|
|
32
|
-
constructor(ctx?: PlatformContext);
|
|
33
|
-
static isMissingFile(error: unknown): boolean;
|
|
34
|
-
static normalizeSessionID(sessionID: string): string;
|
|
35
|
-
/**
|
|
36
|
-
* Deterministic cryptographic hash of sessionID.
|
|
37
|
-
* Produces an opaque 32-character hexadecimal folder name prefixed with "s_".
|
|
38
|
-
* Prevents raw sessionIDs from leaking in the filesystem structure.
|
|
39
|
-
*/
|
|
40
|
-
static hashSessionID(sessionID: string): string;
|
|
41
|
-
private static setPrivateMode;
|
|
42
|
-
private get env();
|
|
43
|
-
private get platform();
|
|
44
|
-
private joinForPlatform;
|
|
45
|
-
/**
|
|
46
|
-
* Cross-platform home directory resolution.
|
|
47
|
-
*
|
|
48
|
-
* `os.homedir()` already adapts to the OS, but it can return an empty string
|
|
49
|
-
* in stripped environments, and Windows shells sometimes expose a
|
|
50
|
-
* POSIX-style `HOME` (e.g. Git Bash `/c/Users/...`). We therefore prefer the
|
|
51
|
-
* canonical variable for the running platform before falling back.
|
|
52
|
-
*
|
|
53
|
-
* @see {@link https://nodejs.org/api/os.html#oshomedir}
|
|
54
|
-
*/
|
|
55
|
-
resolveHomeDir(): string;
|
|
56
|
-
/**
|
|
57
|
-
* Platform-native base directory for user configuration/data.
|
|
58
|
-
*
|
|
59
|
-
* - Windows : `%APPDATA%` (fallback `%LOCALAPPDATA%` → `~/AppData/Roaming`)
|
|
60
|
-
* - macOS : `~/Library/Application Support`
|
|
61
|
-
* - Linux : `$XDG_CONFIG_HOME` (fallback `~/.config`)
|
|
62
|
-
*
|
|
63
|
-
* `XDG_CONFIG_HOME` is honored first on every platform so users who prefer an
|
|
64
|
-
* XDG layout (including those running OpenCode's own convention) can force it.
|
|
65
|
-
*/
|
|
66
|
-
resolveConfigHome(): string;
|
|
67
|
-
/**
|
|
68
|
-
* Base directory that stores per-session todo folders.
|
|
69
|
-
*
|
|
70
|
-
* Priority:
|
|
71
|
-
* 1. `OPENCODE_TODOS_DIR` — explicit plugin override (tests/tooling).
|
|
72
|
-
* 2. The user's home directory + `.opencode/sessions`.
|
|
73
|
-
*/
|
|
74
|
-
resolveTodosBaseDir(): string;
|
|
75
|
-
/** Base directory for all sessions (replaces the old `TODOS_DIRECTORY` const). */
|
|
76
|
-
get todosRoot(): string;
|
|
77
|
-
getSessionDirectory(sessionID: string): string;
|
|
78
|
-
getTodosDirectory(sessionID?: string): string;
|
|
79
|
-
getTodoLockPath(sessionID: string): string;
|
|
80
|
-
getHintMarkerPath(sessionID: string): string;
|
|
81
|
-
getSessionIDFilePath(sessionID: string): string;
|
|
82
|
-
getVersionFilePath(sessionID: string): string;
|
|
83
|
-
getTodoFilePath(sessionID: string): string;
|
|
84
|
-
readTodos(sessionID: string): Promise<TodoRootItem[]>;
|
|
85
|
-
readTodosSync(sessionID: string): TodoRootItem[];
|
|
86
|
-
readTodoData(sessionID: string): TodoData | null;
|
|
87
|
-
writeTodos(sessionID: string, todos: TodoRootItem[]): Promise<void>;
|
|
88
|
-
updateTodos(sessionID: string, update: (todos: TodoRootItem[]) => TodoRootItem[]): Promise<TodoRootItem[]>;
|
|
89
|
-
private scanTodoFiles;
|
|
90
|
-
private listSessionFiles;
|
|
91
|
-
private readVersionFile;
|
|
92
|
-
private static parseTodoFile;
|
|
93
|
-
/** Shared error policy for readTodos / readTodosSync. */
|
|
94
|
-
private recoverFromReadError;
|
|
95
|
-
private writeTextAtomically;
|
|
96
|
-
private writeJsonAtomically;
|
|
97
|
-
private migrateFlatTodoFiles;
|
|
98
|
-
}
|
|
99
|
-
export declare const getTodosDirectory: (sessionID?: string) => string;
|
|
100
|
-
export declare const hashSessionID: (sessionID: string) => string;
|
|
101
|
-
export declare const readTodos: (sessionID: string) => Promise<{
|
|
102
|
-
id: number;
|
|
103
|
-
content: string;
|
|
104
|
-
status: "cancelled" | "completed" | "error" | "in_progress" | "pending";
|
|
105
|
-
priority?: "high" | "low" | "medium" | undefined;
|
|
106
|
-
note?: string | undefined;
|
|
107
|
-
children?: {
|
|
108
|
-
id: number;
|
|
109
|
-
content: string;
|
|
110
|
-
status: "cancelled" | "completed" | "error" | "in_progress" | "pending";
|
|
111
|
-
priority?: "high" | "low" | "medium" | undefined;
|
|
112
|
-
note?: string | undefined;
|
|
113
|
-
}[] | undefined;
|
|
114
|
-
}[]>;
|
|
115
|
-
export declare const readTodosSync: (sessionID: string) => {
|
|
116
|
-
id: number;
|
|
117
|
-
content: string;
|
|
118
|
-
status: "cancelled" | "completed" | "error" | "in_progress" | "pending";
|
|
119
|
-
priority?: "high" | "low" | "medium" | undefined;
|
|
120
|
-
note?: string | undefined;
|
|
121
|
-
children?: {
|
|
122
|
-
id: number;
|
|
123
|
-
content: string;
|
|
124
|
-
status: "cancelled" | "completed" | "error" | "in_progress" | "pending";
|
|
125
|
-
priority?: "high" | "low" | "medium" | undefined;
|
|
126
|
-
note?: string | undefined;
|
|
127
|
-
}[] | undefined;
|
|
128
|
-
}[];
|
|
129
|
-
export declare const writeTodos: (sessionID: string, todos: TodoRootItem[]) => Promise<void>;
|
|
130
|
-
export declare const updateTodos: (sessionID: string, update: (todos: TodoRootItem[]) => TodoRootItem[]) => Promise<{
|
|
131
|
-
id: number;
|
|
132
|
-
content: string;
|
|
133
|
-
status: "cancelled" | "completed" | "error" | "in_progress" | "pending";
|
|
134
|
-
priority?: "high" | "low" | "medium" | undefined;
|
|
135
|
-
note?: string | undefined;
|
|
136
|
-
children?: {
|
|
137
|
-
id: number;
|
|
138
|
-
content: string;
|
|
139
|
-
status: "cancelled" | "completed" | "error" | "in_progress" | "pending";
|
|
140
|
-
priority?: "high" | "low" | "medium" | undefined;
|
|
141
|
-
note?: string | undefined;
|
|
142
|
-
}[] | undefined;
|
|
143
|
-
}[]>;
|
|
144
|
-
export declare const readTodoData: (sessionID: string) => TodoData | null;
|
|
145
|
-
export declare const getHintMarkerPath: (sessionID: string) => string;
|