@takemo101/mikan 0.0.5 → 0.0.7
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 +3 -1
- package/dist/bin.js +354 -138
- package/package.json +1 -1
package/README.md
CHANGED
|
@@ -2,6 +2,8 @@
|
|
|
2
2
|
|
|
3
3
|
mikan is a tiny local-first Issue board for AI-assisted development. It stores Issues as Markdown files under `.mikan/` and exposes the same board through a CLI, keyboard-first TUI, stdio MCP server, and polling watcher.
|
|
4
4
|
|
|
5
|
+
Manual: <https://takemo101.github.io/mikan/>
|
|
6
|
+
|
|
5
7
|
## Install
|
|
6
8
|
|
|
7
9
|
```sh
|
|
@@ -17,7 +19,7 @@ mikan is currently built for Bun-based execution. The npm package installs the `
|
|
|
17
19
|
|
|
18
20
|
- **Markdown source of truth**: each Issue is a file such as `.mikan/ready/MIK-001.md`.
|
|
19
21
|
- **Primitive CLI commands**: `init`, `add`, `list`, `show`, `update`, `move`, `append`, `github`, `tui`, `watch`, `mcp`, `skills`.
|
|
20
|
-
- **Keyboard TUI**: board-first flow with detail view, Note
|
|
22
|
+
- **Keyboard TUI**: board-first flow with detail view, Label/Note/Warning modals, Move shortcuts, and Archive confirmation.
|
|
21
23
|
- **MCP server**: stdio tools for agents: `get_board`, `list_issues`, `get_issue`, `create_issue`, `update_issue`, `move_issue`, `append_issue`, `mirror_issue_to_github`.
|
|
22
24
|
- **GitHub Mirror**: explicit one-way publication from local Markdown Issues to GitHub Issues.
|
|
23
25
|
- **Agent setup**: register the MCP server or install agent guidance for common AI agents.
|
package/dist/bin.js
CHANGED
|
@@ -100301,8 +100301,12 @@ function updateIssue(options) {
|
|
|
100301
100301
|
const target = findIssueById(options);
|
|
100302
100302
|
if (!target.ok)
|
|
100303
100303
|
return target;
|
|
100304
|
-
const
|
|
100305
|
-
const
|
|
100304
|
+
const existingLabels = target.value.issue.labels.map(String);
|
|
100305
|
+
const configuredLabelIds = new Set(options.config.labels.map((label) => label.id));
|
|
100306
|
+
const existingUnknownLabels = new Set(existingLabels.filter((label) => !configuredLabelIds.has(label)));
|
|
100307
|
+
const labels = options.labels ?? existingLabels;
|
|
100308
|
+
const labelsToValidate = options.preserveUnknownLabels ? labels.filter((label) => !existingUnknownLabels.has(label)) : labels;
|
|
100309
|
+
const labelsValidation = validateLabels(options.config, labelsToValidate);
|
|
100306
100310
|
if (!labelsValidation.ok)
|
|
100307
100311
|
return labelsValidation;
|
|
100308
100312
|
const dependenciesValidation = options.dependencies ? validateDependencies(options.dependencies) : undefined;
|
|
@@ -100798,9 +100802,18 @@ var labelSchema = exports_external.object({
|
|
|
100798
100802
|
id: nonEmptyString,
|
|
100799
100803
|
title: nonEmptyString
|
|
100800
100804
|
});
|
|
100805
|
+
var hookEntrySchema = exports_external.union([
|
|
100806
|
+
nonEmptyString,
|
|
100807
|
+
exports_external.object({
|
|
100808
|
+
command: nonEmptyString,
|
|
100809
|
+
when: exports_external.object({
|
|
100810
|
+
labels_include: exports_external.array(nonEmptyString).min(1).optional()
|
|
100811
|
+
}).optional()
|
|
100812
|
+
})
|
|
100813
|
+
]);
|
|
100801
100814
|
var hookSchema = exports_external.object({
|
|
100802
|
-
on_enter: exports_external.record(exports_external.string(), exports_external.array(
|
|
100803
|
-
on_transition: exports_external.record(exports_external.string(), exports_external.array(
|
|
100815
|
+
on_enter: exports_external.record(exports_external.string(), exports_external.array(hookEntrySchema)).optional(),
|
|
100816
|
+
on_transition: exports_external.record(exports_external.string(), exports_external.array(hookEntrySchema)).optional()
|
|
100804
100817
|
});
|
|
100805
100818
|
var githubSchema = exports_external.object({
|
|
100806
100819
|
repo: githubRepoSchema,
|
|
@@ -107386,27 +107399,38 @@ function coreError(code, message) {
|
|
|
107386
107399
|
|
|
107387
107400
|
// ../tui/src/index.ts
|
|
107388
107401
|
var import_react20 = __toESM(require_react(), 1);
|
|
107389
|
-
//
|
|
107402
|
+
// package.json
|
|
107390
107403
|
var package_default = {
|
|
107391
|
-
name: "@mikan
|
|
107392
|
-
version: "0.0.
|
|
107393
|
-
private:
|
|
107404
|
+
name: "@takemo101/mikan",
|
|
107405
|
+
version: "0.0.7",
|
|
107406
|
+
private: false,
|
|
107394
107407
|
type: "module",
|
|
107395
|
-
|
|
107396
|
-
|
|
107408
|
+
bin: {
|
|
107409
|
+
mikan: "dist/bin.js"
|
|
107410
|
+
},
|
|
107411
|
+
repository: {
|
|
107412
|
+
type: "git",
|
|
107413
|
+
url: "https://github.com/takemo101/mikan"
|
|
107414
|
+
},
|
|
107415
|
+
files: [
|
|
107416
|
+
"dist"
|
|
107417
|
+
],
|
|
107418
|
+
publishConfig: {
|
|
107419
|
+
access: "public"
|
|
107420
|
+
},
|
|
107421
|
+
optionalDependencies: {
|
|
107422
|
+
"@opentui/core-darwin-arm64": "0.3.0",
|
|
107423
|
+
"@opentui/core-darwin-x64": "0.3.0",
|
|
107424
|
+
"@opentui/core-linux-arm64": "0.3.0",
|
|
107425
|
+
"@opentui/core-linux-x64": "0.3.0",
|
|
107426
|
+
"@opentui/core-win32-arm64": "0.3.0",
|
|
107427
|
+
"@opentui/core-win32-x64": "0.3.0"
|
|
107397
107428
|
},
|
|
107398
107429
|
scripts: {
|
|
107399
|
-
build: "tsc -p ../../tsconfig.json --noEmit",
|
|
107430
|
+
build: "bun run build:dist && tsc -p ../../tsconfig.json --noEmit",
|
|
107431
|
+
"build:dist": "bun build ./src/bin.ts --target=bun --outdir=./dist --entry-naming=bin.js",
|
|
107400
107432
|
typecheck: "tsc -p ../../tsconfig.json --noEmit",
|
|
107401
107433
|
test: "bun test"
|
|
107402
|
-
},
|
|
107403
|
-
dependencies: {
|
|
107404
|
-
"@mikan/core": "workspace:*",
|
|
107405
|
-
"@mikan/github": "workspace:*",
|
|
107406
|
-
"@mikan/project-config": "workspace:*",
|
|
107407
|
-
"@opentui/core": "latest",
|
|
107408
|
-
"@opentui/react": "latest",
|
|
107409
|
-
react: "latest"
|
|
107410
107434
|
}
|
|
107411
107435
|
};
|
|
107412
107436
|
|
|
@@ -107446,9 +107470,9 @@ function footerText(mode) {
|
|
|
107446
107470
|
return "Modal | enter confirm | esc cancel | ? keys";
|
|
107447
107471
|
}
|
|
107448
107472
|
if (mode === "detail") {
|
|
107449
|
-
return "Detail | \u2191\u2193 scroll |
|
|
107473
|
+
return "Detail | \u2191\u2193 scroll | esc board | ? keys";
|
|
107450
107474
|
}
|
|
107451
|
-
return "Board | \u2191\u2193 card | \u2190\u2192 column | enter detail |
|
|
107475
|
+
return "Board | \u2191\u2193 card | \u2190\u2192 column | enter detail | ? keys";
|
|
107452
107476
|
}
|
|
107453
107477
|
|
|
107454
107478
|
// ../tui/src/selection.ts
|
|
@@ -107555,6 +107579,7 @@ function buildTuiModel(board, labels = [], githubRepo) {
|
|
|
107555
107579
|
})),
|
|
107556
107580
|
warnings: board.warnings.map(formatWarning),
|
|
107557
107581
|
...board.warnings.length > 0 ? { warningDetails: board.warnings.map(formatTuiWarning) } : {},
|
|
107582
|
+
labels: labels.map((label) => ({ id: label.id, title: label.title })),
|
|
107558
107583
|
labelTitles: Object.fromEntries(labels.map((label) => [label.id, label.title])),
|
|
107559
107584
|
githubRepo
|
|
107560
107585
|
};
|
|
@@ -107929,7 +107954,7 @@ function moveSelection(model, selection, direction, options = {}) {
|
|
|
107929
107954
|
message: undefined
|
|
107930
107955
|
};
|
|
107931
107956
|
}
|
|
107932
|
-
if (selection.detailOpen && !selection.moveOpen && !selection.noteOpen) {
|
|
107957
|
+
if (selection.detailOpen && !selection.moveOpen && !selection.noteOpen && !selection.labelOpen) {
|
|
107933
107958
|
if (direction === "up" || direction === "down") {
|
|
107934
107959
|
return {
|
|
107935
107960
|
...selection,
|
|
@@ -107950,6 +107975,9 @@ function moveSelection(model, selection, direction, options = {}) {
|
|
|
107950
107975
|
if (selection.githubConfirmOpen) {
|
|
107951
107976
|
return { ...selection, githubConfirmOpen: false };
|
|
107952
107977
|
}
|
|
107978
|
+
if (selection.labelOpen) {
|
|
107979
|
+
return { ...selection, labelOpen: false };
|
|
107980
|
+
}
|
|
107953
107981
|
if (selection.warningsOpen) {
|
|
107954
107982
|
return { ...selection, warningsOpen: false };
|
|
107955
107983
|
}
|
|
@@ -107957,7 +107985,8 @@ function moveSelection(model, selection, direction, options = {}) {
|
|
|
107957
107985
|
...selection,
|
|
107958
107986
|
detailOpen: false,
|
|
107959
107987
|
moveOpen: false,
|
|
107960
|
-
noteOpen: false
|
|
107988
|
+
noteOpen: false,
|
|
107989
|
+
labelOpen: false
|
|
107961
107990
|
};
|
|
107962
107991
|
}
|
|
107963
107992
|
if (direction === "move") {
|
|
@@ -107966,6 +107995,7 @@ function moveSelection(model, selection, direction, options = {}) {
|
|
|
107966
107995
|
archiveOpen: false,
|
|
107967
107996
|
detailOpen: false,
|
|
107968
107997
|
noteOpen: false,
|
|
107998
|
+
labelOpen: false,
|
|
107969
107999
|
moveOpen: true,
|
|
107970
108000
|
moveTargetIndex: 0
|
|
107971
108001
|
};
|
|
@@ -107976,15 +108006,31 @@ function moveSelection(model, selection, direction, options = {}) {
|
|
|
107976
108006
|
archiveOpen: false,
|
|
107977
108007
|
detailOpen: false,
|
|
107978
108008
|
moveOpen: false,
|
|
108009
|
+
labelOpen: false,
|
|
107979
108010
|
noteOpen: true
|
|
107980
108011
|
};
|
|
107981
108012
|
}
|
|
108013
|
+
if (direction === "edit-labels") {
|
|
108014
|
+
const card = model.columns[selection.columnIndex]?.cards[selection.cardIndex];
|
|
108015
|
+
const knownLabelIds = new Set((model.labels ?? []).map((label) => label.id));
|
|
108016
|
+
return {
|
|
108017
|
+
...selection,
|
|
108018
|
+
archiveOpen: false,
|
|
108019
|
+
githubConfirmOpen: false,
|
|
108020
|
+
moveOpen: false,
|
|
108021
|
+
noteOpen: false,
|
|
108022
|
+
labelOpen: true,
|
|
108023
|
+
labelFocusIndex: 0,
|
|
108024
|
+
labelDraftIds: card?.labels.filter((label) => knownLabelIds.has(label)) ?? []
|
|
108025
|
+
};
|
|
108026
|
+
}
|
|
107982
108027
|
if (direction === "archive") {
|
|
107983
108028
|
return {
|
|
107984
108029
|
...selection,
|
|
107985
108030
|
archiveOpen: true,
|
|
107986
108031
|
moveOpen: false,
|
|
107987
108032
|
noteOpen: false,
|
|
108033
|
+
labelOpen: false,
|
|
107988
108034
|
githubConfirmOpen: false
|
|
107989
108035
|
};
|
|
107990
108036
|
}
|
|
@@ -107994,6 +108040,7 @@ function moveSelection(model, selection, direction, options = {}) {
|
|
|
107994
108040
|
archiveOpen: false,
|
|
107995
108041
|
moveOpen: false,
|
|
107996
108042
|
noteOpen: false,
|
|
108043
|
+
labelOpen: false,
|
|
107997
108044
|
githubConfirmOpen: true
|
|
107998
108045
|
};
|
|
107999
108046
|
}
|
|
@@ -108025,6 +108072,27 @@ function getAdjacentMoveTarget(model, selection, direction) {
|
|
|
108025
108072
|
const column = model.columns[selection.columnIndex + offset];
|
|
108026
108073
|
return column ? { id: column.id, title: column.title } : undefined;
|
|
108027
108074
|
}
|
|
108075
|
+
function moveLabelFocus(model, selection, direction) {
|
|
108076
|
+
if (!selection.labelOpen)
|
|
108077
|
+
return selection;
|
|
108078
|
+
return {
|
|
108079
|
+
...selection,
|
|
108080
|
+
labelFocusIndex: clamp((selection.labelFocusIndex ?? 0) + (direction === "down" ? 1 : -1), 0, Math.max(0, (model.labels ?? []).length - 1))
|
|
108081
|
+
};
|
|
108082
|
+
}
|
|
108083
|
+
function toggleFocusedLabel(model, selection) {
|
|
108084
|
+
if (!selection.labelOpen)
|
|
108085
|
+
return selection;
|
|
108086
|
+
const label = (model.labels ?? [])[selection.labelFocusIndex ?? 0];
|
|
108087
|
+
if (!label)
|
|
108088
|
+
return selection;
|
|
108089
|
+
const current = new Set(selection.labelDraftIds ?? []);
|
|
108090
|
+
if (current.has(label.id))
|
|
108091
|
+
current.delete(label.id);
|
|
108092
|
+
else
|
|
108093
|
+
current.add(label.id);
|
|
108094
|
+
return { ...selection, labelDraftIds: [...current] };
|
|
108095
|
+
}
|
|
108028
108096
|
function applyNoteInput(selection, keyName2, shift = false) {
|
|
108029
108097
|
if (!selection.noteOpen || !keyName2)
|
|
108030
108098
|
return selection;
|
|
@@ -108041,7 +108109,7 @@ function applyNoteInput(selection, keyName2, shift = false) {
|
|
|
108041
108109
|
return { ...selection, noteDraft: `${selection.noteDraft ?? ""}${value}` };
|
|
108042
108110
|
}
|
|
108043
108111
|
function footerMode(selection) {
|
|
108044
|
-
if (selection.moveOpen || selection.noteOpen || selection.archiveOpen || selection.githubConfirmOpen) {
|
|
108112
|
+
if (selection.moveOpen || selection.noteOpen || selection.labelOpen || selection.archiveOpen || selection.githubConfirmOpen) {
|
|
108045
108113
|
return "modal";
|
|
108046
108114
|
}
|
|
108047
108115
|
return selection.detailOpen ? "detail" : "board";
|
|
@@ -108079,6 +108147,8 @@ function keyToTuiAction(keyName2, shift = false) {
|
|
|
108079
108147
|
return "move";
|
|
108080
108148
|
case "n":
|
|
108081
108149
|
return "append-note";
|
|
108150
|
+
case "e":
|
|
108151
|
+
return "edit-labels";
|
|
108082
108152
|
case "a":
|
|
108083
108153
|
return "archive";
|
|
108084
108154
|
case "g":
|
|
@@ -108129,6 +108199,29 @@ function buildNotePromptViewModel(model, selection) {
|
|
|
108129
108199
|
hint: "enter append esc cancel"
|
|
108130
108200
|
};
|
|
108131
108201
|
}
|
|
108202
|
+
function buildLabelPromptViewModel(model, selection) {
|
|
108203
|
+
const card = model.columns[selection.columnIndex]?.cards[selection.cardIndex];
|
|
108204
|
+
if (!card)
|
|
108205
|
+
return;
|
|
108206
|
+
const configuredLabels = model.labels ?? [];
|
|
108207
|
+
const draft = new Set(selection.labelDraftIds ?? card.labels);
|
|
108208
|
+
const known = new Set(configuredLabels.map((label) => label.id));
|
|
108209
|
+
return {
|
|
108210
|
+
title: `Edit Labels for ${card.id}`,
|
|
108211
|
+
focused: Boolean(selection.labelOpen),
|
|
108212
|
+
labels: configuredLabels.map((label, index2) => ({
|
|
108213
|
+
id: label.id,
|
|
108214
|
+
title: label.title,
|
|
108215
|
+
checked: draft.has(label.id),
|
|
108216
|
+
focused: index2 === (selection.labelFocusIndex ?? 0)
|
|
108217
|
+
})),
|
|
108218
|
+
unknownLabels: card.labels.filter((label) => !known.has(label)),
|
|
108219
|
+
...configuredLabels.length === 0 ? {
|
|
108220
|
+
emptyMessage: "No Labels configured. Add Labels in .mikan/config.yaml."
|
|
108221
|
+
} : {},
|
|
108222
|
+
hint: configuredLabels.length === 0 ? "esc close" : "space toggle enter save esc cancel"
|
|
108223
|
+
};
|
|
108224
|
+
}
|
|
108132
108225
|
function buildArchivePromptViewModel(model, selection) {
|
|
108133
108226
|
const card = model.columns[selection.columnIndex]?.cards[selection.cardIndex];
|
|
108134
108227
|
if (!card)
|
|
@@ -108155,118 +108248,7 @@ Local Markdown remains the source of truth.`,
|
|
|
108155
108248
|
};
|
|
108156
108249
|
}
|
|
108157
108250
|
|
|
108158
|
-
// ../tui/src/
|
|
108159
|
-
function MovePrompt(props) {
|
|
108160
|
-
const theme = props.theme ?? buildTuiTheme();
|
|
108161
|
-
return import_react3.default.createElement("box", {
|
|
108162
|
-
id: "move-modal-backdrop",
|
|
108163
|
-
style: modalBackdropStyle(theme)
|
|
108164
|
-
}, import_react3.default.createElement("box", {
|
|
108165
|
-
id: "move-prompt",
|
|
108166
|
-
title: "Move Issue",
|
|
108167
|
-
border: true,
|
|
108168
|
-
style: modalStyle(theme)
|
|
108169
|
-
}, import_react3.default.createElement("text", {
|
|
108170
|
-
content: renderMoveInteraction(props.model, props.selection).join(`
|
|
108171
|
-
`)
|
|
108172
|
-
})));
|
|
108173
|
-
}
|
|
108174
|
-
function NotePrompt(props) {
|
|
108175
|
-
const theme = props.theme ?? buildTuiTheme();
|
|
108176
|
-
return import_react3.default.createElement("box", {
|
|
108177
|
-
id: "note-modal-backdrop",
|
|
108178
|
-
style: modalBackdropStyle(theme)
|
|
108179
|
-
}, import_react3.default.createElement("box", {
|
|
108180
|
-
id: "note-prompt",
|
|
108181
|
-
title: "Append Note",
|
|
108182
|
-
border: true,
|
|
108183
|
-
style: modalStyle(theme)
|
|
108184
|
-
}, import_react3.default.createElement("text", {
|
|
108185
|
-
content: renderNoteInteraction(props.model, props.selection).join(`
|
|
108186
|
-
`)
|
|
108187
|
-
})));
|
|
108188
|
-
}
|
|
108189
|
-
function ArchivePrompt(props) {
|
|
108190
|
-
const theme = props.theme ?? buildTuiTheme();
|
|
108191
|
-
return import_react3.default.createElement("box", {
|
|
108192
|
-
id: "archive-modal-backdrop",
|
|
108193
|
-
style: modalBackdropStyle(theme)
|
|
108194
|
-
}, import_react3.default.createElement("box", {
|
|
108195
|
-
id: "archive-prompt",
|
|
108196
|
-
title: "Archive Issue",
|
|
108197
|
-
border: true,
|
|
108198
|
-
style: modalStyle(theme)
|
|
108199
|
-
}, import_react3.default.createElement("text", {
|
|
108200
|
-
content: renderArchiveInteraction(props.model, props.selection).join(`
|
|
108201
|
-
`)
|
|
108202
|
-
})));
|
|
108203
|
-
}
|
|
108204
|
-
function GitHubMirrorPrompt(props) {
|
|
108205
|
-
const theme = props.theme ?? buildTuiTheme();
|
|
108206
|
-
return import_react3.default.createElement("box", {
|
|
108207
|
-
id: "github-mirror-modal-backdrop",
|
|
108208
|
-
style: modalBackdropStyle(theme)
|
|
108209
|
-
}, import_react3.default.createElement("box", {
|
|
108210
|
-
id: "github-mirror-prompt",
|
|
108211
|
-
title: "GitHub Mirror",
|
|
108212
|
-
border: true,
|
|
108213
|
-
style: modalStyle(theme)
|
|
108214
|
-
}, import_react3.default.createElement("text", {
|
|
108215
|
-
content: renderGitHubMirrorInteraction(props.model, props.selection).join(`
|
|
108216
|
-
`)
|
|
108217
|
-
})));
|
|
108218
|
-
}
|
|
108219
|
-
function modalBackdropStyle(_theme) {
|
|
108220
|
-
return {
|
|
108221
|
-
alignItems: "center",
|
|
108222
|
-
flexDirection: "column",
|
|
108223
|
-
height: "100%",
|
|
108224
|
-
justifyContent: "center",
|
|
108225
|
-
left: 0,
|
|
108226
|
-
position: "absolute",
|
|
108227
|
-
top: 0,
|
|
108228
|
-
width: "100%",
|
|
108229
|
-
zIndex: 10
|
|
108230
|
-
};
|
|
108231
|
-
}
|
|
108232
|
-
function modalStyle(theme) {
|
|
108233
|
-
return {
|
|
108234
|
-
backgroundColor: theme.base.surface,
|
|
108235
|
-
borderColor: theme.interactive.focus,
|
|
108236
|
-
flexDirection: "column",
|
|
108237
|
-
padding: 1,
|
|
108238
|
-
width: "70%"
|
|
108239
|
-
};
|
|
108240
|
-
}
|
|
108241
|
-
function HelpPanel(props) {
|
|
108242
|
-
const theme = props.theme ?? buildTuiTheme();
|
|
108243
|
-
return import_react3.default.createElement("box", {
|
|
108244
|
-
id: "help-panel-backdrop",
|
|
108245
|
-
style: modalBackdropStyle(theme)
|
|
108246
|
-
}, import_react3.default.createElement("box", {
|
|
108247
|
-
id: "help-panel",
|
|
108248
|
-
title: "Key help",
|
|
108249
|
-
border: true,
|
|
108250
|
-
style: modalStyle(theme)
|
|
108251
|
-
}, import_react3.default.createElement("text", { content: renderKeyHelp().join(`
|
|
108252
|
-
`) })));
|
|
108253
|
-
}
|
|
108254
|
-
function WarningPanel(props) {
|
|
108255
|
-
const theme = props.theme ?? buildTuiTheme();
|
|
108256
|
-
return import_react3.default.createElement("box", {
|
|
108257
|
-
id: "warning-panel",
|
|
108258
|
-
title: "Warning details",
|
|
108259
|
-
border: true,
|
|
108260
|
-
style: {
|
|
108261
|
-
backgroundColor: theme.base.surface,
|
|
108262
|
-
borderColor: theme.feedback.warning,
|
|
108263
|
-
flexDirection: "column"
|
|
108264
|
-
}
|
|
108265
|
-
}, import_react3.default.createElement("text", {
|
|
108266
|
-
content: props.model.warnings.length > 0 ? props.model.warnings.map((warning) => `! ${warning}`).join(`
|
|
108267
|
-
`) : "No warnings"
|
|
108268
|
-
}));
|
|
108269
|
-
}
|
|
108251
|
+
// ../tui/src/prompt-text.ts
|
|
108270
108252
|
function renderMoveInteraction(model, selection) {
|
|
108271
108253
|
const view = buildMovePromptViewModel(model, selection);
|
|
108272
108254
|
if (!view)
|
|
@@ -108288,6 +108270,22 @@ function renderNoteInteraction(model, selection) {
|
|
|
108288
108270
|
view.hint
|
|
108289
108271
|
];
|
|
108290
108272
|
}
|
|
108273
|
+
function renderLabelInteraction(model, selection) {
|
|
108274
|
+
const view = buildLabelPromptViewModel(model, selection);
|
|
108275
|
+
if (!view)
|
|
108276
|
+
return ["Edit Labels", "No Issue selected"];
|
|
108277
|
+
if (view.emptyMessage) {
|
|
108278
|
+
return [view.title, "", view.emptyMessage, "", view.hint];
|
|
108279
|
+
}
|
|
108280
|
+
return [
|
|
108281
|
+
view.title,
|
|
108282
|
+
"",
|
|
108283
|
+
...view.labels.map((label) => `${label.focused ? "\u25B6" : " "} [${label.checked ? "x" : " "}] ${label.title}`),
|
|
108284
|
+
...view.unknownLabels.length > 0 ? ["", `Unknown Labels (read-only): ${view.unknownLabels.join(", ")}`] : [],
|
|
108285
|
+
"",
|
|
108286
|
+
view.hint
|
|
108287
|
+
];
|
|
108288
|
+
}
|
|
108291
108289
|
function renderArchiveInteraction(model, selection) {
|
|
108292
108290
|
const view = buildArchivePromptViewModel(model, selection);
|
|
108293
108291
|
if (!view)
|
|
@@ -108300,6 +108298,12 @@ function renderGitHubMirrorInteraction(model, selection) {
|
|
|
108300
108298
|
return ["GitHub Mirror", "No Issue selected"];
|
|
108301
108299
|
return [view.title, view.body, view.hint];
|
|
108302
108300
|
}
|
|
108301
|
+
function renderWarningDetails(model) {
|
|
108302
|
+
return [
|
|
108303
|
+
"Warning details",
|
|
108304
|
+
...model.warnings.length > 0 ? model.warnings.map((warning) => `! ${warning}`) : ["No warnings"]
|
|
108305
|
+
];
|
|
108306
|
+
}
|
|
108303
108307
|
function renderKeyHelp() {
|
|
108304
108308
|
return [
|
|
108305
108309
|
"Key help",
|
|
@@ -108310,6 +108314,7 @@ function renderKeyHelp() {
|
|
|
108310
108314
|
"H/L move Issue",
|
|
108311
108315
|
"m move menu",
|
|
108312
108316
|
"n append Note",
|
|
108317
|
+
"e edit Labels",
|
|
108313
108318
|
"a archive Issue",
|
|
108314
108319
|
"g GitHub Mirror",
|
|
108315
108320
|
"w warning details",
|
|
@@ -108318,6 +108323,113 @@ function renderKeyHelp() {
|
|
|
108318
108323
|
];
|
|
108319
108324
|
}
|
|
108320
108325
|
|
|
108326
|
+
// ../tui/src/modals.ts
|
|
108327
|
+
function MovePrompt(props) {
|
|
108328
|
+
return renderModalText({
|
|
108329
|
+
theme: props.theme,
|
|
108330
|
+
backdropId: "move-modal-backdrop",
|
|
108331
|
+
panelId: "move-prompt",
|
|
108332
|
+
title: "Move Issue",
|
|
108333
|
+
content: renderMoveInteraction(props.model, props.selection)
|
|
108334
|
+
});
|
|
108335
|
+
}
|
|
108336
|
+
function NotePrompt(props) {
|
|
108337
|
+
return renderModalText({
|
|
108338
|
+
theme: props.theme,
|
|
108339
|
+
backdropId: "note-modal-backdrop",
|
|
108340
|
+
panelId: "note-prompt",
|
|
108341
|
+
title: "Append Note",
|
|
108342
|
+
content: renderNoteInteraction(props.model, props.selection)
|
|
108343
|
+
});
|
|
108344
|
+
}
|
|
108345
|
+
function LabelPrompt(props) {
|
|
108346
|
+
return renderModalText({
|
|
108347
|
+
theme: props.theme,
|
|
108348
|
+
backdropId: "label-modal-backdrop",
|
|
108349
|
+
panelId: "label-prompt",
|
|
108350
|
+
title: "Edit Labels",
|
|
108351
|
+
content: renderLabelInteraction(props.model, props.selection)
|
|
108352
|
+
});
|
|
108353
|
+
}
|
|
108354
|
+
function ArchivePrompt(props) {
|
|
108355
|
+
return renderModalText({
|
|
108356
|
+
theme: props.theme,
|
|
108357
|
+
backdropId: "archive-modal-backdrop",
|
|
108358
|
+
panelId: "archive-prompt",
|
|
108359
|
+
title: "Archive Issue",
|
|
108360
|
+
content: renderArchiveInteraction(props.model, props.selection)
|
|
108361
|
+
});
|
|
108362
|
+
}
|
|
108363
|
+
function GitHubMirrorPrompt(props) {
|
|
108364
|
+
return renderModalText({
|
|
108365
|
+
theme: props.theme,
|
|
108366
|
+
backdropId: "github-mirror-modal-backdrop",
|
|
108367
|
+
panelId: "github-mirror-prompt",
|
|
108368
|
+
title: "GitHub Mirror",
|
|
108369
|
+
content: renderGitHubMirrorInteraction(props.model, props.selection)
|
|
108370
|
+
});
|
|
108371
|
+
}
|
|
108372
|
+
function renderModalText(options) {
|
|
108373
|
+
const theme = options.theme ?? buildTuiTheme();
|
|
108374
|
+
return import_react3.default.createElement("box", {
|
|
108375
|
+
id: options.backdropId,
|
|
108376
|
+
style: modalBackdropStyle(theme)
|
|
108377
|
+
}, import_react3.default.createElement("box", {
|
|
108378
|
+
id: options.panelId,
|
|
108379
|
+
title: options.title,
|
|
108380
|
+
border: true,
|
|
108381
|
+
style: {
|
|
108382
|
+
...modalStyle(theme),
|
|
108383
|
+
...options.panelStyle ?? {}
|
|
108384
|
+
}
|
|
108385
|
+
}, import_react3.default.createElement("text", {
|
|
108386
|
+
content: options.content.join(`
|
|
108387
|
+
`)
|
|
108388
|
+
})));
|
|
108389
|
+
}
|
|
108390
|
+
function modalBackdropStyle(_theme) {
|
|
108391
|
+
return {
|
|
108392
|
+
alignItems: "center",
|
|
108393
|
+
flexDirection: "column",
|
|
108394
|
+
height: "100%",
|
|
108395
|
+
justifyContent: "center",
|
|
108396
|
+
left: 0,
|
|
108397
|
+
position: "absolute",
|
|
108398
|
+
top: 0,
|
|
108399
|
+
width: "100%",
|
|
108400
|
+
zIndex: 10
|
|
108401
|
+
};
|
|
108402
|
+
}
|
|
108403
|
+
function modalStyle(theme) {
|
|
108404
|
+
return {
|
|
108405
|
+
backgroundColor: theme.base.surface,
|
|
108406
|
+
borderColor: theme.interactive.focus,
|
|
108407
|
+
flexDirection: "column",
|
|
108408
|
+
padding: 1,
|
|
108409
|
+
width: "70%"
|
|
108410
|
+
};
|
|
108411
|
+
}
|
|
108412
|
+
function HelpPanel(props) {
|
|
108413
|
+
return renderModalText({
|
|
108414
|
+
theme: props.theme,
|
|
108415
|
+
backdropId: "help-panel-backdrop",
|
|
108416
|
+
panelId: "help-panel",
|
|
108417
|
+
title: "Key help",
|
|
108418
|
+
content: renderKeyHelp()
|
|
108419
|
+
});
|
|
108420
|
+
}
|
|
108421
|
+
function WarningPanel(props) {
|
|
108422
|
+
const theme = props.theme ?? buildTuiTheme();
|
|
108423
|
+
return renderModalText({
|
|
108424
|
+
theme,
|
|
108425
|
+
backdropId: "warning-panel-backdrop",
|
|
108426
|
+
panelId: "warning-panel",
|
|
108427
|
+
title: "Warning details",
|
|
108428
|
+
content: renderWarningDetails(props.model).slice(1),
|
|
108429
|
+
panelStyle: { borderColor: theme.feedback.warning }
|
|
108430
|
+
});
|
|
108431
|
+
}
|
|
108432
|
+
|
|
108321
108433
|
// ../tui/src/mutations.ts
|
|
108322
108434
|
function refreshTuiModel(options) {
|
|
108323
108435
|
const selectedCard = options.model.columns[options.selection.columnIndex]?.cards[options.selection.cardIndex];
|
|
@@ -108336,6 +108448,9 @@ function refreshTuiModel(options) {
|
|
|
108336
108448
|
moveTargetIndex: stillSelected ? options.selection.moveTargetIndex : undefined,
|
|
108337
108449
|
noteOpen: stillSelected ? options.selection.noteOpen : false,
|
|
108338
108450
|
noteDraft: stillSelected ? options.selection.noteDraft : undefined,
|
|
108451
|
+
labelOpen: stillSelected ? options.selection.labelOpen : false,
|
|
108452
|
+
labelFocusIndex: stillSelected ? options.selection.labelFocusIndex : undefined,
|
|
108453
|
+
labelDraftIds: stillSelected ? options.selection.labelDraftIds : undefined,
|
|
108339
108454
|
message: options.selection.message,
|
|
108340
108455
|
archiveOpen: stillSelected ? options.selection.archiveOpen : false,
|
|
108341
108456
|
githubConfirmOpen: stillSelected ? options.selection.githubConfirmOpen : false,
|
|
@@ -108428,6 +108543,59 @@ function archiveSelectedIssue(options) {
|
|
|
108428
108543
|
selection: { ...result.selection, archiveOpen: false }
|
|
108429
108544
|
} : result;
|
|
108430
108545
|
}
|
|
108546
|
+
function updateSelectedIssueLabels(options) {
|
|
108547
|
+
const card = selectedCard(options.model, options.selection);
|
|
108548
|
+
if (!card) {
|
|
108549
|
+
return {
|
|
108550
|
+
ok: false,
|
|
108551
|
+
model: options.model,
|
|
108552
|
+
selection: { ...options.selection, labelOpen: false },
|
|
108553
|
+
message: "No Issue selected"
|
|
108554
|
+
};
|
|
108555
|
+
}
|
|
108556
|
+
const loaded = loadProjectConfig(options.cwd ?? process.cwd());
|
|
108557
|
+
if (!loaded.ok) {
|
|
108558
|
+
return {
|
|
108559
|
+
ok: false,
|
|
108560
|
+
model: options.model,
|
|
108561
|
+
selection: { ...options.selection, labelOpen: false },
|
|
108562
|
+
message: loaded.error.message
|
|
108563
|
+
};
|
|
108564
|
+
}
|
|
108565
|
+
const selectedKnown = new Set(options.selection.labelDraftIds ?? []);
|
|
108566
|
+
const configuredIds = loaded.value.config.labels.map((label) => label.id);
|
|
108567
|
+
const configuredSet = new Set(configuredIds);
|
|
108568
|
+
const knownLabels = configuredIds.filter((label) => selectedKnown.has(label));
|
|
108569
|
+
const unknownLabels = card.labels.filter((label) => !configuredSet.has(label));
|
|
108570
|
+
const updated = updateIssue({
|
|
108571
|
+
projectRoot: loaded.value.projectRoot,
|
|
108572
|
+
config: loaded.value.config,
|
|
108573
|
+
id: card.id,
|
|
108574
|
+
labels: [...knownLabels, ...unknownLabels],
|
|
108575
|
+
preserveUnknownLabels: true,
|
|
108576
|
+
now: options.now
|
|
108577
|
+
});
|
|
108578
|
+
if (!updated.ok) {
|
|
108579
|
+
return {
|
|
108580
|
+
ok: false,
|
|
108581
|
+
model: options.model,
|
|
108582
|
+
selection: { ...options.selection, labelOpen: false },
|
|
108583
|
+
message: updated.error.message
|
|
108584
|
+
};
|
|
108585
|
+
}
|
|
108586
|
+
const model = loadTuiModel(options.cwd);
|
|
108587
|
+
const selection = findSelectionByCardId(model, card.id) ?? clampSelection(model, options.selection);
|
|
108588
|
+
return {
|
|
108589
|
+
ok: true,
|
|
108590
|
+
model,
|
|
108591
|
+
selection: {
|
|
108592
|
+
...selection,
|
|
108593
|
+
detailOpen: options.selection.detailOpen,
|
|
108594
|
+
labelOpen: false
|
|
108595
|
+
},
|
|
108596
|
+
message: `${card.id} Labels updated`
|
|
108597
|
+
};
|
|
108598
|
+
}
|
|
108431
108599
|
async function beginSelectedIssueGitHubMirror(options) {
|
|
108432
108600
|
if (options.selection.githubBusy)
|
|
108433
108601
|
return githubAlreadyRunning(options);
|
|
@@ -108687,7 +108855,7 @@ function TuiAppView({
|
|
|
108687
108855
|
viewportHeight,
|
|
108688
108856
|
viewportWidth,
|
|
108689
108857
|
columns
|
|
108690
|
-
})), selection.moveOpen ? import_react20.default.createElement(MovePrompt, { model, selection, theme }) : undefined, selection.noteOpen ? import_react20.default.createElement(NotePrompt, { model, selection, theme }) : undefined, selection.archiveOpen ? import_react20.default.createElement(ArchivePrompt, { model, selection, theme }) : undefined, selection.githubConfirmOpen ? import_react20.default.createElement(GitHubMirrorPrompt, { model, selection, theme }) : undefined, selection.warningsOpen ? import_react20.default.createElement(WarningPanel, { model, theme }) : undefined, selection.helpOpen ? import_react20.default.createElement(HelpPanel, { theme }) : undefined, import_react20.default.createElement(Footer, {
|
|
108858
|
+
})), selection.moveOpen ? import_react20.default.createElement(MovePrompt, { model, selection, theme }) : undefined, selection.noteOpen ? import_react20.default.createElement(NotePrompt, { model, selection, theme }) : undefined, selection.labelOpen ? import_react20.default.createElement(LabelPrompt, { model, selection, theme }) : undefined, selection.archiveOpen ? import_react20.default.createElement(ArchivePrompt, { model, selection, theme }) : undefined, selection.githubConfirmOpen ? import_react20.default.createElement(GitHubMirrorPrompt, { model, selection, theme }) : undefined, selection.warningsOpen ? import_react20.default.createElement(WarningPanel, { model, theme }) : undefined, selection.helpOpen ? import_react20.default.createElement(HelpPanel, { theme }) : undefined, import_react20.default.createElement(Footer, {
|
|
108691
108859
|
message: selection.message,
|
|
108692
108860
|
mode: footerMode(selection),
|
|
108693
108861
|
theme
|
|
@@ -108820,6 +108988,35 @@ async function launchTui(options = {}) {
|
|
|
108820
108988
|
}
|
|
108821
108989
|
return;
|
|
108822
108990
|
}
|
|
108991
|
+
if (selection.labelOpen) {
|
|
108992
|
+
if (action === "help") {
|
|
108993
|
+
setSelection((current) => moveSelection(model, current, action));
|
|
108994
|
+
return;
|
|
108995
|
+
}
|
|
108996
|
+
if (action === "escape") {
|
|
108997
|
+
setSelection((current) => moveSelection(model, current, action));
|
|
108998
|
+
return;
|
|
108999
|
+
}
|
|
109000
|
+
if (action === "up" || action === "down") {
|
|
109001
|
+
setSelection((current) => moveLabelFocus(model, current, action));
|
|
109002
|
+
return;
|
|
109003
|
+
}
|
|
109004
|
+
if (key.name === "space") {
|
|
109005
|
+
setSelection((current) => toggleFocusedLabel(model, current));
|
|
109006
|
+
return;
|
|
109007
|
+
}
|
|
109008
|
+
if (action === "enter") {
|
|
109009
|
+
const result = updateSelectedIssueLabels({
|
|
109010
|
+
cwd: options.cwd,
|
|
109011
|
+
model,
|
|
109012
|
+
selection
|
|
109013
|
+
});
|
|
109014
|
+
setModel(result.model);
|
|
109015
|
+
setSelection({ ...result.selection, message: result.message });
|
|
109016
|
+
return;
|
|
109017
|
+
}
|
|
109018
|
+
return;
|
|
109019
|
+
}
|
|
108823
109020
|
if (!action)
|
|
108824
109021
|
return;
|
|
108825
109022
|
if (action === "quit") {
|
|
@@ -109180,7 +109377,10 @@ function fireHooks(loaded, issue2, fromStatus, toStatus, options) {
|
|
|
109180
109377
|
...hooks?.on_enter?.[toStatus] ?? [],
|
|
109181
109378
|
...hooks?.on_transition?.[`${fromStatus}->${toStatus}`] ?? []
|
|
109182
109379
|
];
|
|
109183
|
-
for (const
|
|
109380
|
+
for (const entry of commands2) {
|
|
109381
|
+
const command = hookCommandForIssue(entry, loaded, issue2, options);
|
|
109382
|
+
if (!command)
|
|
109383
|
+
continue;
|
|
109184
109384
|
const rendered = renderHookCommand(command, {
|
|
109185
109385
|
project_root: loaded.projectRoot,
|
|
109186
109386
|
issue_path: issue2.path,
|
|
@@ -109206,6 +109406,22 @@ function fireHooks(loaded, issue2, fromStatus, toStatus, options) {
|
|
|
109206
109406
|
}
|
|
109207
109407
|
}
|
|
109208
109408
|
}
|
|
109409
|
+
function hookCommandForIssue(entry, loaded, issue2, options) {
|
|
109410
|
+
if (typeof entry === "string")
|
|
109411
|
+
return entry;
|
|
109412
|
+
const labelsInclude = entry.when?.labels_include;
|
|
109413
|
+
if (!labelsInclude)
|
|
109414
|
+
return entry.command;
|
|
109415
|
+
const knownLabels = new Set(loaded.config.labels.map((label) => label.id));
|
|
109416
|
+
for (const label of labelsInclude) {
|
|
109417
|
+
if (!knownLabels.has(label)) {
|
|
109418
|
+
emitError(options, `hook skipped: ${String(issue2.issue.id)} references unknown label in hook filter: ${label}`);
|
|
109419
|
+
return;
|
|
109420
|
+
}
|
|
109421
|
+
}
|
|
109422
|
+
const issueLabels = new Set(issue2.issue.labels.map(String));
|
|
109423
|
+
return labelsInclude.every((label) => issueLabels.has(label)) ? entry.command : undefined;
|
|
109424
|
+
}
|
|
109209
109425
|
function recordGitHubMirrorPushFailure(projectRoot, issueId, message, options) {
|
|
109210
109426
|
appendHookFailure(projectRoot, {
|
|
109211
109427
|
timestamp: utcNow3(options.now),
|