trekoon 0.3.1 → 0.3.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/.agents/skills/trekoon/SKILL.md +127 -15
- package/.agents/skills/trekoon/reference/execution-with-team.md +213 -0
- package/.agents/skills/trekoon/reference/execution.md +210 -0
- package/.agents/skills/trekoon/reference/planning.md +244 -0
- package/README.md +30 -11
- package/docs/ai-agents.md +59 -26
- package/docs/quickstart.md +19 -0
- package/package.json +3 -3
- package/src/board/assets/app.js +5 -0
- package/src/board/assets/components/EpicsOverview.js +13 -0
- package/src/board/assets/components/Workspace.js +27 -12
- package/src/board/assets/components/helpers.js +3 -2
- package/src/board/assets/runtime/delegation.js +69 -1
- package/src/board/assets/state/actions.js +27 -1
- package/src/board/assets/state/store.js +37 -8
- package/src/board/assets/state/utils.js +43 -1
- package/src/board/assets/styles/board.css +68 -0
- package/src/commands/arg-parser.ts +10 -0
- package/src/commands/help.ts +25 -8
- package/src/commands/skills.ts +450 -179
- package/src/runtime/cli-shell.ts +5 -0
|
@@ -1,3 +1,5 @@
|
|
|
1
|
+
import { isValidTransition } from "../state/utils.js";
|
|
2
|
+
|
|
1
3
|
/**
|
|
2
4
|
* Event delegation system for the board runtime.
|
|
3
5
|
*
|
|
@@ -89,6 +91,31 @@ export function createDelegation(rootElement, actions) {
|
|
|
89
91
|
return;
|
|
90
92
|
}
|
|
91
93
|
|
|
94
|
+
// -- Status filter pills ---------------------------------------------------
|
|
95
|
+
const epicFilterEl = target.closest("[data-toggle-epic-status-filter]");
|
|
96
|
+
if (epicFilterEl) {
|
|
97
|
+
actions.toggleEpicStatusFilter(epicFilterEl.dataset.toggleEpicStatusFilter);
|
|
98
|
+
return;
|
|
99
|
+
}
|
|
100
|
+
|
|
101
|
+
const taskFilterEl = target.closest("[data-toggle-task-status-filter]");
|
|
102
|
+
if (taskFilterEl) {
|
|
103
|
+
actions.toggleTaskStatusFilter(taskFilterEl.dataset.toggleTaskStatusFilter);
|
|
104
|
+
return;
|
|
105
|
+
}
|
|
106
|
+
|
|
107
|
+
const resetEpicFilterEl = target.closest("[data-reset-epic-filter]");
|
|
108
|
+
if (resetEpicFilterEl) {
|
|
109
|
+
actions.resetEpicFilter();
|
|
110
|
+
return;
|
|
111
|
+
}
|
|
112
|
+
|
|
113
|
+
const resetTaskFilterEl = target.closest("[data-reset-task-filter]");
|
|
114
|
+
if (resetTaskFilterEl) {
|
|
115
|
+
actions.resetTaskFilter();
|
|
116
|
+
return;
|
|
117
|
+
}
|
|
118
|
+
|
|
92
119
|
// -- Navigation -----------------------------------------------------------
|
|
93
120
|
|
|
94
121
|
const navEl = target.closest("[data-nav]");
|
|
@@ -276,6 +303,15 @@ export function createDelegation(rootElement, actions) {
|
|
|
276
303
|
// ---------------------------------------------------------------------------
|
|
277
304
|
// Drag-and-drop delegation
|
|
278
305
|
// ---------------------------------------------------------------------------
|
|
306
|
+
let draggedTaskStatus = null;
|
|
307
|
+
|
|
308
|
+
function cleanupDragFeedback() {
|
|
309
|
+
draggedTaskStatus = null;
|
|
310
|
+
for (const el of rootElement.querySelectorAll(".board-drop-valid, .board-drop-invalid")) {
|
|
311
|
+
el.classList.remove("board-drop-valid", "board-drop-invalid");
|
|
312
|
+
}
|
|
313
|
+
}
|
|
314
|
+
|
|
279
315
|
function handleDragstart(event) {
|
|
280
316
|
const draggable = event.target.closest("[data-draggable-task]");
|
|
281
317
|
if (!draggable) return;
|
|
@@ -290,11 +326,28 @@ export function createDelegation(rootElement, actions) {
|
|
|
290
326
|
|
|
291
327
|
event.dataTransfer?.setData("text/task-id", taskId);
|
|
292
328
|
event.dataTransfer?.setData("text/plain", taskId);
|
|
329
|
+
draggedTaskStatus = actions.getTaskStatus(taskId);
|
|
293
330
|
}
|
|
294
331
|
|
|
295
332
|
function handleDragover(event) {
|
|
296
|
-
|
|
333
|
+
const column = event.target.closest("[data-drop-status]");
|
|
334
|
+
if (!column) return;
|
|
335
|
+
|
|
336
|
+
const targetStatus = column.dataset.dropStatus;
|
|
337
|
+
if (draggedTaskStatus && isValidTransition(draggedTaskStatus, targetStatus)) {
|
|
297
338
|
event.preventDefault();
|
|
339
|
+
column.classList.add("board-drop-valid");
|
|
340
|
+
column.classList.remove("board-drop-invalid");
|
|
341
|
+
} else if (draggedTaskStatus && targetStatus !== draggedTaskStatus) {
|
|
342
|
+
column.classList.add("board-drop-invalid");
|
|
343
|
+
column.classList.remove("board-drop-valid");
|
|
344
|
+
}
|
|
345
|
+
}
|
|
346
|
+
|
|
347
|
+
function handleDragleave(event) {
|
|
348
|
+
const column = event.target.closest("[data-drop-status]");
|
|
349
|
+
if (column && !column.contains(event.relatedTarget)) {
|
|
350
|
+
column.classList.remove("board-drop-valid", "board-drop-invalid");
|
|
298
351
|
}
|
|
299
352
|
}
|
|
300
353
|
|
|
@@ -309,7 +362,18 @@ export function createDelegation(rootElement, actions) {
|
|
|
309
362
|
event.dataTransfer?.getData("text/task-id") ||
|
|
310
363
|
event.dataTransfer?.getData("text/plain");
|
|
311
364
|
const nextStatus = column.dataset.dropStatus;
|
|
365
|
+
|
|
366
|
+
if (draggedTaskStatus && !isValidTransition(draggedTaskStatus, nextStatus)) {
|
|
367
|
+
cleanupDragFeedback();
|
|
368
|
+
return;
|
|
369
|
+
}
|
|
370
|
+
|
|
312
371
|
actions.dropTaskStatus(taskId, nextStatus);
|
|
372
|
+
cleanupDragFeedback();
|
|
373
|
+
}
|
|
374
|
+
|
|
375
|
+
function handleDragend() {
|
|
376
|
+
cleanupDragFeedback();
|
|
313
377
|
}
|
|
314
378
|
|
|
315
379
|
// ---------------------------------------------------------------------------
|
|
@@ -321,7 +385,9 @@ export function createDelegation(rootElement, actions) {
|
|
|
321
385
|
rootElement.addEventListener("submit", handleSubmit);
|
|
322
386
|
rootElement.addEventListener("dragstart", handleDragstart);
|
|
323
387
|
rootElement.addEventListener("dragover", handleDragover);
|
|
388
|
+
rootElement.addEventListener("dragleave", handleDragleave);
|
|
324
389
|
rootElement.addEventListener("drop", handleDrop);
|
|
390
|
+
rootElement.addEventListener("dragend", handleDragend);
|
|
325
391
|
rootElement.addEventListener("keydown", handleDelegatedKeydown);
|
|
326
392
|
window.addEventListener("keydown", handleKeydown);
|
|
327
393
|
|
|
@@ -335,7 +401,9 @@ export function createDelegation(rootElement, actions) {
|
|
|
335
401
|
rootElement.removeEventListener("submit", handleSubmit);
|
|
336
402
|
rootElement.removeEventListener("dragstart", handleDragstart);
|
|
337
403
|
rootElement.removeEventListener("dragover", handleDragover);
|
|
404
|
+
rootElement.removeEventListener("dragleave", handleDragleave);
|
|
338
405
|
rootElement.removeEventListener("drop", handleDrop);
|
|
406
|
+
rootElement.removeEventListener("dragend", handleDragend);
|
|
339
407
|
rootElement.removeEventListener("keydown", handleDelegatedKeydown);
|
|
340
408
|
window.removeEventListener("keydown", handleKeydown);
|
|
341
409
|
};
|
|
@@ -1,5 +1,5 @@
|
|
|
1
1
|
import { copyTextToClipboard } from "../runtime/clipboard.js";
|
|
2
|
-
import { orderEpicsNewestFirst } from "./store.js";
|
|
2
|
+
import { DEFAULT_STATUS_FILTER, orderEpicsNewestFirst } from "./store.js";
|
|
3
3
|
|
|
4
4
|
function cloneSnapshot(snapshot) {
|
|
5
5
|
if (typeof structuredClone === "function") {
|
|
@@ -404,6 +404,10 @@ export function createBoardActions(options) {
|
|
|
404
404
|
removeDependency(sourceId, dependsOnId) {
|
|
405
405
|
api.removeDependency(sourceId, dependsOnId, (snapshot) => removeDependencyInSnapshot(snapshot, sourceId, dependsOnId, normalizeSnapshot));
|
|
406
406
|
},
|
|
407
|
+
getTaskStatus(taskId) {
|
|
408
|
+
const task = getTaskById(taskId);
|
|
409
|
+
return task?.status ?? null;
|
|
410
|
+
},
|
|
407
411
|
dropTaskStatus(taskId, nextStatus) {
|
|
408
412
|
const task = getTaskById(taskId);
|
|
409
413
|
if (!task || !nextStatus || task.status === nextStatus) {
|
|
@@ -426,6 +430,28 @@ export function createBoardActions(options) {
|
|
|
426
430
|
cascadeEpicStatusInSnapshot(snapshot, epicId, normalizedStatus, normalizeSnapshot),
|
|
427
431
|
);
|
|
428
432
|
},
|
|
433
|
+
toggleEpicStatusFilter(status) {
|
|
434
|
+
const current = store.epicStatusFilter || { ...DEFAULT_STATUS_FILTER };
|
|
435
|
+
store.epicStatusFilter = { ...current, [status]: !current[status] };
|
|
436
|
+
persist();
|
|
437
|
+
rerender();
|
|
438
|
+
},
|
|
439
|
+
toggleTaskStatusFilter(status) {
|
|
440
|
+
const current = store.taskStatusFilter || { ...DEFAULT_STATUS_FILTER };
|
|
441
|
+
store.taskStatusFilter = { ...current, [status]: !current[status] };
|
|
442
|
+
persist();
|
|
443
|
+
rerender();
|
|
444
|
+
},
|
|
445
|
+
resetEpicFilter() {
|
|
446
|
+
store.epicStatusFilter = { ...DEFAULT_STATUS_FILTER };
|
|
447
|
+
persist();
|
|
448
|
+
rerender();
|
|
449
|
+
},
|
|
450
|
+
resetTaskFilter() {
|
|
451
|
+
store.taskStatusFilter = { ...DEFAULT_STATUS_FILTER };
|
|
452
|
+
persist();
|
|
453
|
+
rerender();
|
|
454
|
+
},
|
|
429
455
|
handleKeydown(event) {
|
|
430
456
|
const boardState = getBoardState();
|
|
431
457
|
const activeElement = document.activeElement;
|
|
@@ -9,6 +9,18 @@ function normalizeSearch(value) {
|
|
|
9
9
|
|
|
10
10
|
// --- Persistence helpers ---
|
|
11
11
|
|
|
12
|
+
export const DEFAULT_STATUS_FILTER = { todo: true, blocked: true, in_progress: true, done: false };
|
|
13
|
+
|
|
14
|
+
function readStatusFilter(raw) {
|
|
15
|
+
if (typeof raw !== "object" || raw === null) return { ...DEFAULT_STATUS_FILTER };
|
|
16
|
+
return {
|
|
17
|
+
todo: typeof raw.todo === "boolean" ? raw.todo : DEFAULT_STATUS_FILTER.todo,
|
|
18
|
+
blocked: typeof raw.blocked === "boolean" ? raw.blocked : DEFAULT_STATUS_FILTER.blocked,
|
|
19
|
+
in_progress: typeof raw.in_progress === "boolean" ? raw.in_progress : DEFAULT_STATUS_FILTER.in_progress,
|
|
20
|
+
done: typeof raw.done === "boolean" ? raw.done : DEFAULT_STATUS_FILTER.done,
|
|
21
|
+
};
|
|
22
|
+
}
|
|
23
|
+
|
|
12
24
|
export function readStoredState() {
|
|
13
25
|
try {
|
|
14
26
|
return JSON.parse(localStorage.getItem(STATE_STORAGE_KEY) || "{}");
|
|
@@ -77,13 +89,25 @@ export function orderEpicsNewestFirst(epics) {
|
|
|
77
89
|
|
|
78
90
|
// --- Derived state selectors ---
|
|
79
91
|
|
|
92
|
+
/** Recently-done epics stay visible for 24h even when the "done" filter is off. */
|
|
93
|
+
const DONE_GRACE_PERIOD_MS = 86400000;
|
|
94
|
+
|
|
80
95
|
const selectVisibleEpics = createSelector(
|
|
81
|
-
(s) => [s.snapshot?.epics, s.searchQuery],
|
|
82
|
-
(epics, searchQuery) => {
|
|
96
|
+
(s) => [s.snapshot?.epics, s.searchQuery, s.epicStatusFilter],
|
|
97
|
+
(epics, searchQuery, epicStatusFilter) => {
|
|
83
98
|
if (!epics) return [];
|
|
99
|
+
const now = Date.now();
|
|
100
|
+
const filtered = epics.filter((epic) => {
|
|
101
|
+
if (epic.status === "done") {
|
|
102
|
+
if (!epicStatusFilter.done && (now - epic.updatedAt) > DONE_GRACE_PERIOD_MS) return false;
|
|
103
|
+
} else if (!epicStatusFilter[epic.status]) {
|
|
104
|
+
return false;
|
|
105
|
+
}
|
|
106
|
+
return true;
|
|
107
|
+
});
|
|
84
108
|
const matchingEpics = searchQuery.length === 0
|
|
85
|
-
?
|
|
86
|
-
:
|
|
109
|
+
? filtered
|
|
110
|
+
: filtered.filter((epic) => epic.searchText.includes(searchQuery));
|
|
87
111
|
|
|
88
112
|
return orderEpicsNewestFirst(matchingEpics);
|
|
89
113
|
},
|
|
@@ -100,11 +124,12 @@ const selectTasksInScope = createSelector(
|
|
|
100
124
|
);
|
|
101
125
|
|
|
102
126
|
const selectVisibleTasks = createSelector(
|
|
103
|
-
(s) => [selectTasksInScope(s), s.searchQuery],
|
|
104
|
-
(tasksInScope, searchQuery) => {
|
|
127
|
+
(s) => [selectTasksInScope(s), s.searchQuery, s.taskStatusFilter],
|
|
128
|
+
(tasksInScope, searchQuery, taskStatusFilter) => {
|
|
129
|
+
const filtered = tasksInScope.filter((task) => taskStatusFilter[task.status]);
|
|
105
130
|
return searchQuery.length === 0
|
|
106
|
-
?
|
|
107
|
-
:
|
|
131
|
+
? filtered
|
|
132
|
+
: filtered.filter((task) => task.searchText.includes(searchQuery));
|
|
108
133
|
},
|
|
109
134
|
);
|
|
110
135
|
|
|
@@ -287,6 +312,8 @@ export function createStore(initialSnapshot, options = {}) {
|
|
|
287
312
|
notice: null,
|
|
288
313
|
isMutating: false,
|
|
289
314
|
notesPanelOpen: storedState.notesPanelOpen === true,
|
|
315
|
+
epicStatusFilter: readStatusFilter(storedState.epicStatusFilter),
|
|
316
|
+
taskStatusFilter: readStatusFilter(storedState.taskStatusFilter),
|
|
290
317
|
};
|
|
291
318
|
|
|
292
319
|
/** @type {Set<(state: object) => void>} */
|
|
@@ -306,6 +333,8 @@ export function createStore(initialSnapshot, options = {}) {
|
|
|
306
333
|
view: state.view,
|
|
307
334
|
selectedTaskId: state.selectedTaskId,
|
|
308
335
|
notesPanelOpen: state.notesPanelOpen,
|
|
336
|
+
epicStatusFilter: state.epicStatusFilter,
|
|
337
|
+
taskStatusFilter: state.taskStatusFilter,
|
|
309
338
|
});
|
|
310
339
|
}
|
|
311
340
|
|
|
@@ -143,7 +143,7 @@ export function normalizeSnapshot(rawSnapshot) {
|
|
|
143
143
|
id: epicId,
|
|
144
144
|
title: String(epic.title ?? "Untitled epic"),
|
|
145
145
|
description: String(epic.description ?? "").replace(/\\n/g, "\n"),
|
|
146
|
-
status: String(epic.status ?? "todo"),
|
|
146
|
+
status: normalizeStatus(String(epic.status ?? "todo")),
|
|
147
147
|
createdAt: Number(epic.createdAt ?? Date.now()),
|
|
148
148
|
updatedAt: Number(epic.updatedAt ?? epic.createdAt ?? Date.now()),
|
|
149
149
|
taskIds: epicTasks.map((task) => task.id),
|
|
@@ -220,3 +220,45 @@ export function escapeHtml(value) {
|
|
|
220
220
|
.replaceAll(">", ">")
|
|
221
221
|
.replaceAll('"', """);
|
|
222
222
|
}
|
|
223
|
+
|
|
224
|
+
/**
|
|
225
|
+
* Valid status transitions mirroring the backend state machine (src/domain/types.ts).
|
|
226
|
+
* @type {Map<string, Set<string>>}
|
|
227
|
+
*/
|
|
228
|
+
export const VALID_TRANSITIONS = new Map([
|
|
229
|
+
["todo", new Set(["in_progress", "blocked"])],
|
|
230
|
+
["in_progress", new Set(["done", "blocked"])],
|
|
231
|
+
["blocked", new Set(["in_progress", "todo"])],
|
|
232
|
+
["done", new Set(["in_progress"])],
|
|
233
|
+
]);
|
|
234
|
+
|
|
235
|
+
/**
|
|
236
|
+
* Get the list of statuses a node can transition to from its current status.
|
|
237
|
+
* @param {string} currentStatus
|
|
238
|
+
* @returns {string[]}
|
|
239
|
+
*/
|
|
240
|
+
export function getValidTargets(currentStatus) {
|
|
241
|
+
const targets = VALID_TRANSITIONS.get(currentStatus);
|
|
242
|
+
return targets ? Array.from(targets) : [];
|
|
243
|
+
}
|
|
244
|
+
|
|
245
|
+
/**
|
|
246
|
+
* Check whether transitioning from one status to another is valid.
|
|
247
|
+
* @param {string} from
|
|
248
|
+
* @param {string} to
|
|
249
|
+
* @returns {boolean}
|
|
250
|
+
*/
|
|
251
|
+
export function isValidTransition(from, to) {
|
|
252
|
+
const targets = VALID_TRANSITIONS.get(from);
|
|
253
|
+
return targets ? targets.has(to) : false;
|
|
254
|
+
}
|
|
255
|
+
|
|
256
|
+
/**
|
|
257
|
+
* Return the current status plus all valid targets, useful for populating
|
|
258
|
+
* status select dropdowns.
|
|
259
|
+
* @param {string} currentStatus
|
|
260
|
+
* @returns {string[]}
|
|
261
|
+
*/
|
|
262
|
+
export function getSelectableStatuses(currentStatus) {
|
|
263
|
+
return [currentStatus, ...getValidTargets(currentStatus)];
|
|
264
|
+
}
|
|
@@ -1929,3 +1929,71 @@ textarea,
|
|
|
1929
1929
|
.\!px-2 { padding-inline: 0.5rem !important; }
|
|
1930
1930
|
.\!text-xs { font-size: 0.75rem !important; line-height: 1rem !important; }
|
|
1931
1931
|
.\!min-h-0 { min-height: 0 !important; }
|
|
1932
|
+
|
|
1933
|
+
/* --- Drag-and-drop transition feedback --- */
|
|
1934
|
+
.board-drop-valid {
|
|
1935
|
+
outline: 2px solid var(--board-accent);
|
|
1936
|
+
outline-offset: -2px;
|
|
1937
|
+
background: rgba(var(--board-accent-rgb, 99, 102, 241), 0.06);
|
|
1938
|
+
}
|
|
1939
|
+
|
|
1940
|
+
.board-drop-invalid {
|
|
1941
|
+
outline: 2px dashed rgba(239, 68, 68, 0.4);
|
|
1942
|
+
outline-offset: -2px;
|
|
1943
|
+
opacity: 0.6;
|
|
1944
|
+
cursor: not-allowed;
|
|
1945
|
+
}
|
|
1946
|
+
|
|
1947
|
+
/* --- Filter pills --- */
|
|
1948
|
+
.board-filter-bar {
|
|
1949
|
+
display: flex;
|
|
1950
|
+
flex-wrap: wrap;
|
|
1951
|
+
align-items: center;
|
|
1952
|
+
gap: 0.375rem;
|
|
1953
|
+
margin-top: 0.75rem;
|
|
1954
|
+
}
|
|
1955
|
+
|
|
1956
|
+
.board-filter-pill {
|
|
1957
|
+
display: inline-flex;
|
|
1958
|
+
align-items: center;
|
|
1959
|
+
gap: 0.25rem;
|
|
1960
|
+
padding: 0.25rem 0.75rem;
|
|
1961
|
+
border-radius: 9999px;
|
|
1962
|
+
border: 1px solid var(--board-border);
|
|
1963
|
+
background: var(--board-surface-2);
|
|
1964
|
+
color: var(--board-text-muted);
|
|
1965
|
+
font-size: 0.6875rem;
|
|
1966
|
+
font-weight: 600;
|
|
1967
|
+
text-transform: uppercase;
|
|
1968
|
+
letter-spacing: 0.14em;
|
|
1969
|
+
cursor: pointer;
|
|
1970
|
+
transition: opacity 0.2s, border-color 0.2s, background 0.2s;
|
|
1971
|
+
user-select: none;
|
|
1972
|
+
}
|
|
1973
|
+
|
|
1974
|
+
.board-filter-pill:hover {
|
|
1975
|
+
border-color: var(--board-border-strong);
|
|
1976
|
+
background: rgba(255, 255, 255, 0.08);
|
|
1977
|
+
}
|
|
1978
|
+
|
|
1979
|
+
.board-filter-pill:focus-visible {
|
|
1980
|
+
outline: none;
|
|
1981
|
+
box-shadow: 0 0 0 2px var(--board-border-strong);
|
|
1982
|
+
}
|
|
1983
|
+
|
|
1984
|
+
.board-filter-pill--active {
|
|
1985
|
+
opacity: 1;
|
|
1986
|
+
}
|
|
1987
|
+
|
|
1988
|
+
.board-filter-pill--inactive {
|
|
1989
|
+
opacity: 0.4;
|
|
1990
|
+
}
|
|
1991
|
+
|
|
1992
|
+
.board-filter-pill--reset {
|
|
1993
|
+
color: var(--board-accent);
|
|
1994
|
+
border-color: var(--board-accent);
|
|
1995
|
+
}
|
|
1996
|
+
|
|
1997
|
+
.board-filter-pill--reset:hover {
|
|
1998
|
+
background: rgba(var(--board-accent-rgb, 99, 102, 241), 0.1);
|
|
1999
|
+
}
|
|
@@ -42,6 +42,7 @@ export interface ParsedCompactFields {
|
|
|
42
42
|
}
|
|
43
43
|
|
|
44
44
|
const LONG_PREFIX = "--";
|
|
45
|
+
const SHORT_FLAG_PATTERN = /^-([A-Za-z])$/u;
|
|
45
46
|
|
|
46
47
|
export function parseArgs(args: readonly string[]): ParsedArgs {
|
|
47
48
|
const positional: string[] = [];
|
|
@@ -57,6 +58,15 @@ export function parseArgs(args: readonly string[]): ParsedArgs {
|
|
|
57
58
|
continue;
|
|
58
59
|
}
|
|
59
60
|
|
|
61
|
+
// Short flag: single dash + single letter (e.g. -g).
|
|
62
|
+
const shortMatch = SHORT_FLAG_PATTERN.exec(token);
|
|
63
|
+
if (shortMatch) {
|
|
64
|
+
const key: string = shortMatch[1]!;
|
|
65
|
+
flags.add(key);
|
|
66
|
+
providedOptions.push(key);
|
|
67
|
+
continue;
|
|
68
|
+
}
|
|
69
|
+
|
|
60
70
|
if (!token.startsWith(LONG_PREFIX)) {
|
|
61
71
|
positional.push(token);
|
|
62
72
|
continue;
|
package/src/commands/help.ts
CHANGED
|
@@ -30,7 +30,8 @@ const ROOT_HELP = [
|
|
|
30
30
|
" migrate Migration status and rollback commands",
|
|
31
31
|
" session One-call agent orientation (diagnostics + sync + next task)",
|
|
32
32
|
" sync Cross-branch sync commands",
|
|
33
|
-
" skills
|
|
33
|
+
" skills Skill install/update/link (local and global)",
|
|
34
|
+
" update Alias for skills update",
|
|
34
35
|
].join("\n");
|
|
35
36
|
|
|
36
37
|
const INIT_HELP = [
|
|
@@ -385,31 +386,46 @@ const SESSION_HELP = [
|
|
|
385
386
|
const SKILLS_HELP = [
|
|
386
387
|
"Usage:",
|
|
387
388
|
" trekoon skills install [--link --editor opencode|claude|pi] [--to <path>] [--allow-outside-repo]",
|
|
389
|
+
" trekoon skills install -g|--global [--editor opencode|claude|pi]",
|
|
388
390
|
" trekoon skills update",
|
|
389
391
|
"",
|
|
390
392
|
"Purpose:",
|
|
391
|
-
" Install or refresh the
|
|
393
|
+
" Install or refresh the Trekoon skill asset locally or globally.",
|
|
392
394
|
"",
|
|
393
|
-
"
|
|
394
|
-
" -
|
|
395
|
-
"
|
|
395
|
+
"Local install behavior (default):",
|
|
396
|
+
" - Creates a directory symlink at <cwd>/.agents/skills/trekoon pointing to",
|
|
397
|
+
" the bundled package source, so the skill always matches the installed version.",
|
|
396
398
|
" - Use --link to also create an editor symlink named 'trekoon'.",
|
|
397
399
|
" - --editor is required when --link is used (opencode|claude|pi).",
|
|
398
400
|
" - --to overrides the symlink root for --link only.",
|
|
399
401
|
" - Without --allow-outside-repo, link targets must resolve inside repo.",
|
|
400
402
|
" - --allow-outside-repo requires --link and disables that boundary check.",
|
|
401
403
|
"",
|
|
404
|
+
"Global install behavior (-g|--global):",
|
|
405
|
+
" - Creates a global anchor symlink at ~/.agents/skills/trekoon pointing to",
|
|
406
|
+
" the bundled package source.",
|
|
407
|
+
" - Creates per-editor symlinks under each editor's global skills directory",
|
|
408
|
+
" (~/.claude/skills/, ~/.config/opencode/skills/, ~/.pi/skills/).",
|
|
409
|
+
" - Use --editor to install for a single editor only.",
|
|
410
|
+
"",
|
|
402
411
|
"Update behavior:",
|
|
403
|
-
" -
|
|
404
|
-
" -
|
|
405
|
-
" - Skips
|
|
412
|
+
" - Probes and repairs both global and local anchor/editor symlinks.",
|
|
413
|
+
" - Reports per-entry status: ok, repointed, created, migrated, skipped.",
|
|
414
|
+
" - Skips entries that are not installed; creates local editor links when",
|
|
415
|
+
" the editor config dir exists.",
|
|
416
|
+
"",
|
|
417
|
+
"Alias:",
|
|
418
|
+
" trekoon update → trekoon skills update",
|
|
406
419
|
"",
|
|
407
420
|
"Examples:",
|
|
408
421
|
" trekoon skills install",
|
|
422
|
+
" trekoon skills install -g",
|
|
423
|
+
" trekoon skills install --global --editor claude",
|
|
409
424
|
" trekoon skills install --link --editor opencode",
|
|
410
425
|
" trekoon skills install --link --editor claude --to .claude/skills",
|
|
411
426
|
" trekoon skills install --link --editor pi --to ../shared/skills --allow-outside-repo",
|
|
412
427
|
" trekoon skills update",
|
|
428
|
+
" trekoon update",
|
|
413
429
|
].join("\n");
|
|
414
430
|
|
|
415
431
|
const COMMAND_HELP: Record<string, string> = {
|
|
@@ -426,6 +442,7 @@ const COMMAND_HELP: Record<string, string> = {
|
|
|
426
442
|
migrate: MIGRATE_HELP,
|
|
427
443
|
sync: SYNC_HELP,
|
|
428
444
|
skills: SKILLS_HELP,
|
|
445
|
+
update: "Usage: trekoon update [--json|--toon]\n\nAlias for: trekoon skills update\n\nProbes and repairs all installed global and local skill symlinks.",
|
|
429
446
|
help: "Usage: trekoon help [command] [--json|--toon]",
|
|
430
447
|
};
|
|
431
448
|
|