@takemo101/mikan 0.0.6 → 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 +329 -124
- 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,
|
|
@@ -107389,7 +107402,7 @@ var import_react20 = __toESM(require_react(), 1);
|
|
|
107389
107402
|
// package.json
|
|
107390
107403
|
var package_default = {
|
|
107391
107404
|
name: "@takemo101/mikan",
|
|
107392
|
-
version: "0.0.
|
|
107405
|
+
version: "0.0.7",
|
|
107393
107406
|
private: false,
|
|
107394
107407
|
type: "module",
|
|
107395
107408
|
bin: {
|
|
@@ -107457,9 +107470,9 @@ function footerText(mode) {
|
|
|
107457
107470
|
return "Modal | enter confirm | esc cancel | ? keys";
|
|
107458
107471
|
}
|
|
107459
107472
|
if (mode === "detail") {
|
|
107460
|
-
return "Detail | \u2191\u2193 scroll |
|
|
107473
|
+
return "Detail | \u2191\u2193 scroll | esc board | ? keys";
|
|
107461
107474
|
}
|
|
107462
|
-
return "Board | \u2191\u2193 card | \u2190\u2192 column | enter detail |
|
|
107475
|
+
return "Board | \u2191\u2193 card | \u2190\u2192 column | enter detail | ? keys";
|
|
107463
107476
|
}
|
|
107464
107477
|
|
|
107465
107478
|
// ../tui/src/selection.ts
|
|
@@ -107566,6 +107579,7 @@ function buildTuiModel(board, labels = [], githubRepo) {
|
|
|
107566
107579
|
})),
|
|
107567
107580
|
warnings: board.warnings.map(formatWarning),
|
|
107568
107581
|
...board.warnings.length > 0 ? { warningDetails: board.warnings.map(formatTuiWarning) } : {},
|
|
107582
|
+
labels: labels.map((label) => ({ id: label.id, title: label.title })),
|
|
107569
107583
|
labelTitles: Object.fromEntries(labels.map((label) => [label.id, label.title])),
|
|
107570
107584
|
githubRepo
|
|
107571
107585
|
};
|
|
@@ -107940,7 +107954,7 @@ function moveSelection(model, selection, direction, options = {}) {
|
|
|
107940
107954
|
message: undefined
|
|
107941
107955
|
};
|
|
107942
107956
|
}
|
|
107943
|
-
if (selection.detailOpen && !selection.moveOpen && !selection.noteOpen) {
|
|
107957
|
+
if (selection.detailOpen && !selection.moveOpen && !selection.noteOpen && !selection.labelOpen) {
|
|
107944
107958
|
if (direction === "up" || direction === "down") {
|
|
107945
107959
|
return {
|
|
107946
107960
|
...selection,
|
|
@@ -107961,6 +107975,9 @@ function moveSelection(model, selection, direction, options = {}) {
|
|
|
107961
107975
|
if (selection.githubConfirmOpen) {
|
|
107962
107976
|
return { ...selection, githubConfirmOpen: false };
|
|
107963
107977
|
}
|
|
107978
|
+
if (selection.labelOpen) {
|
|
107979
|
+
return { ...selection, labelOpen: false };
|
|
107980
|
+
}
|
|
107964
107981
|
if (selection.warningsOpen) {
|
|
107965
107982
|
return { ...selection, warningsOpen: false };
|
|
107966
107983
|
}
|
|
@@ -107968,7 +107985,8 @@ function moveSelection(model, selection, direction, options = {}) {
|
|
|
107968
107985
|
...selection,
|
|
107969
107986
|
detailOpen: false,
|
|
107970
107987
|
moveOpen: false,
|
|
107971
|
-
noteOpen: false
|
|
107988
|
+
noteOpen: false,
|
|
107989
|
+
labelOpen: false
|
|
107972
107990
|
};
|
|
107973
107991
|
}
|
|
107974
107992
|
if (direction === "move") {
|
|
@@ -107977,6 +107995,7 @@ function moveSelection(model, selection, direction, options = {}) {
|
|
|
107977
107995
|
archiveOpen: false,
|
|
107978
107996
|
detailOpen: false,
|
|
107979
107997
|
noteOpen: false,
|
|
107998
|
+
labelOpen: false,
|
|
107980
107999
|
moveOpen: true,
|
|
107981
108000
|
moveTargetIndex: 0
|
|
107982
108001
|
};
|
|
@@ -107987,15 +108006,31 @@ function moveSelection(model, selection, direction, options = {}) {
|
|
|
107987
108006
|
archiveOpen: false,
|
|
107988
108007
|
detailOpen: false,
|
|
107989
108008
|
moveOpen: false,
|
|
108009
|
+
labelOpen: false,
|
|
107990
108010
|
noteOpen: true
|
|
107991
108011
|
};
|
|
107992
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
|
+
}
|
|
107993
108027
|
if (direction === "archive") {
|
|
107994
108028
|
return {
|
|
107995
108029
|
...selection,
|
|
107996
108030
|
archiveOpen: true,
|
|
107997
108031
|
moveOpen: false,
|
|
107998
108032
|
noteOpen: false,
|
|
108033
|
+
labelOpen: false,
|
|
107999
108034
|
githubConfirmOpen: false
|
|
108000
108035
|
};
|
|
108001
108036
|
}
|
|
@@ -108005,6 +108040,7 @@ function moveSelection(model, selection, direction, options = {}) {
|
|
|
108005
108040
|
archiveOpen: false,
|
|
108006
108041
|
moveOpen: false,
|
|
108007
108042
|
noteOpen: false,
|
|
108043
|
+
labelOpen: false,
|
|
108008
108044
|
githubConfirmOpen: true
|
|
108009
108045
|
};
|
|
108010
108046
|
}
|
|
@@ -108036,6 +108072,27 @@ function getAdjacentMoveTarget(model, selection, direction) {
|
|
|
108036
108072
|
const column = model.columns[selection.columnIndex + offset];
|
|
108037
108073
|
return column ? { id: column.id, title: column.title } : undefined;
|
|
108038
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
|
+
}
|
|
108039
108096
|
function applyNoteInput(selection, keyName2, shift = false) {
|
|
108040
108097
|
if (!selection.noteOpen || !keyName2)
|
|
108041
108098
|
return selection;
|
|
@@ -108052,7 +108109,7 @@ function applyNoteInput(selection, keyName2, shift = false) {
|
|
|
108052
108109
|
return { ...selection, noteDraft: `${selection.noteDraft ?? ""}${value}` };
|
|
108053
108110
|
}
|
|
108054
108111
|
function footerMode(selection) {
|
|
108055
|
-
if (selection.moveOpen || selection.noteOpen || selection.archiveOpen || selection.githubConfirmOpen) {
|
|
108112
|
+
if (selection.moveOpen || selection.noteOpen || selection.labelOpen || selection.archiveOpen || selection.githubConfirmOpen) {
|
|
108056
108113
|
return "modal";
|
|
108057
108114
|
}
|
|
108058
108115
|
return selection.detailOpen ? "detail" : "board";
|
|
@@ -108090,6 +108147,8 @@ function keyToTuiAction(keyName2, shift = false) {
|
|
|
108090
108147
|
return "move";
|
|
108091
108148
|
case "n":
|
|
108092
108149
|
return "append-note";
|
|
108150
|
+
case "e":
|
|
108151
|
+
return "edit-labels";
|
|
108093
108152
|
case "a":
|
|
108094
108153
|
return "archive";
|
|
108095
108154
|
case "g":
|
|
@@ -108140,6 +108199,29 @@ function buildNotePromptViewModel(model, selection) {
|
|
|
108140
108199
|
hint: "enter append esc cancel"
|
|
108141
108200
|
};
|
|
108142
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
|
+
}
|
|
108143
108225
|
function buildArchivePromptViewModel(model, selection) {
|
|
108144
108226
|
const card = model.columns[selection.columnIndex]?.cards[selection.cardIndex];
|
|
108145
108227
|
if (!card)
|
|
@@ -108166,118 +108248,7 @@ Local Markdown remains the source of truth.`,
|
|
|
108166
108248
|
};
|
|
108167
108249
|
}
|
|
108168
108250
|
|
|
108169
|
-
// ../tui/src/
|
|
108170
|
-
function MovePrompt(props) {
|
|
108171
|
-
const theme = props.theme ?? buildTuiTheme();
|
|
108172
|
-
return import_react3.default.createElement("box", {
|
|
108173
|
-
id: "move-modal-backdrop",
|
|
108174
|
-
style: modalBackdropStyle(theme)
|
|
108175
|
-
}, import_react3.default.createElement("box", {
|
|
108176
|
-
id: "move-prompt",
|
|
108177
|
-
title: "Move Issue",
|
|
108178
|
-
border: true,
|
|
108179
|
-
style: modalStyle(theme)
|
|
108180
|
-
}, import_react3.default.createElement("text", {
|
|
108181
|
-
content: renderMoveInteraction(props.model, props.selection).join(`
|
|
108182
|
-
`)
|
|
108183
|
-
})));
|
|
108184
|
-
}
|
|
108185
|
-
function NotePrompt(props) {
|
|
108186
|
-
const theme = props.theme ?? buildTuiTheme();
|
|
108187
|
-
return import_react3.default.createElement("box", {
|
|
108188
|
-
id: "note-modal-backdrop",
|
|
108189
|
-
style: modalBackdropStyle(theme)
|
|
108190
|
-
}, import_react3.default.createElement("box", {
|
|
108191
|
-
id: "note-prompt",
|
|
108192
|
-
title: "Append Note",
|
|
108193
|
-
border: true,
|
|
108194
|
-
style: modalStyle(theme)
|
|
108195
|
-
}, import_react3.default.createElement("text", {
|
|
108196
|
-
content: renderNoteInteraction(props.model, props.selection).join(`
|
|
108197
|
-
`)
|
|
108198
|
-
})));
|
|
108199
|
-
}
|
|
108200
|
-
function ArchivePrompt(props) {
|
|
108201
|
-
const theme = props.theme ?? buildTuiTheme();
|
|
108202
|
-
return import_react3.default.createElement("box", {
|
|
108203
|
-
id: "archive-modal-backdrop",
|
|
108204
|
-
style: modalBackdropStyle(theme)
|
|
108205
|
-
}, import_react3.default.createElement("box", {
|
|
108206
|
-
id: "archive-prompt",
|
|
108207
|
-
title: "Archive Issue",
|
|
108208
|
-
border: true,
|
|
108209
|
-
style: modalStyle(theme)
|
|
108210
|
-
}, import_react3.default.createElement("text", {
|
|
108211
|
-
content: renderArchiveInteraction(props.model, props.selection).join(`
|
|
108212
|
-
`)
|
|
108213
|
-
})));
|
|
108214
|
-
}
|
|
108215
|
-
function GitHubMirrorPrompt(props) {
|
|
108216
|
-
const theme = props.theme ?? buildTuiTheme();
|
|
108217
|
-
return import_react3.default.createElement("box", {
|
|
108218
|
-
id: "github-mirror-modal-backdrop",
|
|
108219
|
-
style: modalBackdropStyle(theme)
|
|
108220
|
-
}, import_react3.default.createElement("box", {
|
|
108221
|
-
id: "github-mirror-prompt",
|
|
108222
|
-
title: "GitHub Mirror",
|
|
108223
|
-
border: true,
|
|
108224
|
-
style: modalStyle(theme)
|
|
108225
|
-
}, import_react3.default.createElement("text", {
|
|
108226
|
-
content: renderGitHubMirrorInteraction(props.model, props.selection).join(`
|
|
108227
|
-
`)
|
|
108228
|
-
})));
|
|
108229
|
-
}
|
|
108230
|
-
function modalBackdropStyle(_theme) {
|
|
108231
|
-
return {
|
|
108232
|
-
alignItems: "center",
|
|
108233
|
-
flexDirection: "column",
|
|
108234
|
-
height: "100%",
|
|
108235
|
-
justifyContent: "center",
|
|
108236
|
-
left: 0,
|
|
108237
|
-
position: "absolute",
|
|
108238
|
-
top: 0,
|
|
108239
|
-
width: "100%",
|
|
108240
|
-
zIndex: 10
|
|
108241
|
-
};
|
|
108242
|
-
}
|
|
108243
|
-
function modalStyle(theme) {
|
|
108244
|
-
return {
|
|
108245
|
-
backgroundColor: theme.base.surface,
|
|
108246
|
-
borderColor: theme.interactive.focus,
|
|
108247
|
-
flexDirection: "column",
|
|
108248
|
-
padding: 1,
|
|
108249
|
-
width: "70%"
|
|
108250
|
-
};
|
|
108251
|
-
}
|
|
108252
|
-
function HelpPanel(props) {
|
|
108253
|
-
const theme = props.theme ?? buildTuiTheme();
|
|
108254
|
-
return import_react3.default.createElement("box", {
|
|
108255
|
-
id: "help-panel-backdrop",
|
|
108256
|
-
style: modalBackdropStyle(theme)
|
|
108257
|
-
}, import_react3.default.createElement("box", {
|
|
108258
|
-
id: "help-panel",
|
|
108259
|
-
title: "Key help",
|
|
108260
|
-
border: true,
|
|
108261
|
-
style: modalStyle(theme)
|
|
108262
|
-
}, import_react3.default.createElement("text", { content: renderKeyHelp().join(`
|
|
108263
|
-
`) })));
|
|
108264
|
-
}
|
|
108265
|
-
function WarningPanel(props) {
|
|
108266
|
-
const theme = props.theme ?? buildTuiTheme();
|
|
108267
|
-
return import_react3.default.createElement("box", {
|
|
108268
|
-
id: "warning-panel",
|
|
108269
|
-
title: "Warning details",
|
|
108270
|
-
border: true,
|
|
108271
|
-
style: {
|
|
108272
|
-
backgroundColor: theme.base.surface,
|
|
108273
|
-
borderColor: theme.feedback.warning,
|
|
108274
|
-
flexDirection: "column"
|
|
108275
|
-
}
|
|
108276
|
-
}, import_react3.default.createElement("text", {
|
|
108277
|
-
content: props.model.warnings.length > 0 ? props.model.warnings.map((warning) => `! ${warning}`).join(`
|
|
108278
|
-
`) : "No warnings"
|
|
108279
|
-
}));
|
|
108280
|
-
}
|
|
108251
|
+
// ../tui/src/prompt-text.ts
|
|
108281
108252
|
function renderMoveInteraction(model, selection) {
|
|
108282
108253
|
const view = buildMovePromptViewModel(model, selection);
|
|
108283
108254
|
if (!view)
|
|
@@ -108299,6 +108270,22 @@ function renderNoteInteraction(model, selection) {
|
|
|
108299
108270
|
view.hint
|
|
108300
108271
|
];
|
|
108301
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
|
+
}
|
|
108302
108289
|
function renderArchiveInteraction(model, selection) {
|
|
108303
108290
|
const view = buildArchivePromptViewModel(model, selection);
|
|
108304
108291
|
if (!view)
|
|
@@ -108311,6 +108298,12 @@ function renderGitHubMirrorInteraction(model, selection) {
|
|
|
108311
108298
|
return ["GitHub Mirror", "No Issue selected"];
|
|
108312
108299
|
return [view.title, view.body, view.hint];
|
|
108313
108300
|
}
|
|
108301
|
+
function renderWarningDetails(model) {
|
|
108302
|
+
return [
|
|
108303
|
+
"Warning details",
|
|
108304
|
+
...model.warnings.length > 0 ? model.warnings.map((warning) => `! ${warning}`) : ["No warnings"]
|
|
108305
|
+
];
|
|
108306
|
+
}
|
|
108314
108307
|
function renderKeyHelp() {
|
|
108315
108308
|
return [
|
|
108316
108309
|
"Key help",
|
|
@@ -108321,6 +108314,7 @@ function renderKeyHelp() {
|
|
|
108321
108314
|
"H/L move Issue",
|
|
108322
108315
|
"m move menu",
|
|
108323
108316
|
"n append Note",
|
|
108317
|
+
"e edit Labels",
|
|
108324
108318
|
"a archive Issue",
|
|
108325
108319
|
"g GitHub Mirror",
|
|
108326
108320
|
"w warning details",
|
|
@@ -108329,6 +108323,113 @@ function renderKeyHelp() {
|
|
|
108329
108323
|
];
|
|
108330
108324
|
}
|
|
108331
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
|
+
|
|
108332
108433
|
// ../tui/src/mutations.ts
|
|
108333
108434
|
function refreshTuiModel(options) {
|
|
108334
108435
|
const selectedCard = options.model.columns[options.selection.columnIndex]?.cards[options.selection.cardIndex];
|
|
@@ -108347,6 +108448,9 @@ function refreshTuiModel(options) {
|
|
|
108347
108448
|
moveTargetIndex: stillSelected ? options.selection.moveTargetIndex : undefined,
|
|
108348
108449
|
noteOpen: stillSelected ? options.selection.noteOpen : false,
|
|
108349
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,
|
|
108350
108454
|
message: options.selection.message,
|
|
108351
108455
|
archiveOpen: stillSelected ? options.selection.archiveOpen : false,
|
|
108352
108456
|
githubConfirmOpen: stillSelected ? options.selection.githubConfirmOpen : false,
|
|
@@ -108439,6 +108543,59 @@ function archiveSelectedIssue(options) {
|
|
|
108439
108543
|
selection: { ...result.selection, archiveOpen: false }
|
|
108440
108544
|
} : result;
|
|
108441
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
|
+
}
|
|
108442
108599
|
async function beginSelectedIssueGitHubMirror(options) {
|
|
108443
108600
|
if (options.selection.githubBusy)
|
|
108444
108601
|
return githubAlreadyRunning(options);
|
|
@@ -108698,7 +108855,7 @@ function TuiAppView({
|
|
|
108698
108855
|
viewportHeight,
|
|
108699
108856
|
viewportWidth,
|
|
108700
108857
|
columns
|
|
108701
|
-
})), 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, {
|
|
108702
108859
|
message: selection.message,
|
|
108703
108860
|
mode: footerMode(selection),
|
|
108704
108861
|
theme
|
|
@@ -108831,6 +108988,35 @@ async function launchTui(options = {}) {
|
|
|
108831
108988
|
}
|
|
108832
108989
|
return;
|
|
108833
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
|
+
}
|
|
108834
109020
|
if (!action)
|
|
108835
109021
|
return;
|
|
108836
109022
|
if (action === "quit") {
|
|
@@ -109191,7 +109377,10 @@ function fireHooks(loaded, issue2, fromStatus, toStatus, options) {
|
|
|
109191
109377
|
...hooks?.on_enter?.[toStatus] ?? [],
|
|
109192
109378
|
...hooks?.on_transition?.[`${fromStatus}->${toStatus}`] ?? []
|
|
109193
109379
|
];
|
|
109194
|
-
for (const
|
|
109380
|
+
for (const entry of commands2) {
|
|
109381
|
+
const command = hookCommandForIssue(entry, loaded, issue2, options);
|
|
109382
|
+
if (!command)
|
|
109383
|
+
continue;
|
|
109195
109384
|
const rendered = renderHookCommand(command, {
|
|
109196
109385
|
project_root: loaded.projectRoot,
|
|
109197
109386
|
issue_path: issue2.path,
|
|
@@ -109217,6 +109406,22 @@ function fireHooks(loaded, issue2, fromStatus, toStatus, options) {
|
|
|
109217
109406
|
}
|
|
109218
109407
|
}
|
|
109219
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
|
+
}
|
|
109220
109425
|
function recordGitHubMirrorPushFailure(projectRoot, issueId, message, options) {
|
|
109221
109426
|
appendHookFailure(projectRoot, {
|
|
109222
109427
|
timestamp: utcNow3(options.now),
|