@ondrej-svec/hog 1.15.0 → 1.16.1
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- package/dist/cli.js +179 -25
- package/dist/cli.js.map +1 -1
- package/dist/fetch-worker.js.map +1 -1
- package/package.json +1 -1
package/dist/cli.js
CHANGED
|
@@ -2149,6 +2149,29 @@ function useKeyboard({
|
|
|
2149
2149
|
if (handleErrorAction("dismiss")) return;
|
|
2150
2150
|
}
|
|
2151
2151
|
if (input2 === "r" && handleErrorAction("retry")) return;
|
|
2152
|
+
if (ui.canAct || ui.state.mode === "overlay:detail") {
|
|
2153
|
+
if (input2 === "y") {
|
|
2154
|
+
handleCopyLink();
|
|
2155
|
+
return;
|
|
2156
|
+
}
|
|
2157
|
+
if (input2 === "o") {
|
|
2158
|
+
handleSlack();
|
|
2159
|
+
return;
|
|
2160
|
+
}
|
|
2161
|
+
if (input2 === "c") {
|
|
2162
|
+
if (selectedIssue) {
|
|
2163
|
+
multiSelect.clear();
|
|
2164
|
+
ui.enterComment();
|
|
2165
|
+
}
|
|
2166
|
+
return;
|
|
2167
|
+
}
|
|
2168
|
+
if (input2 === "e") {
|
|
2169
|
+
if (selectedIssue) {
|
|
2170
|
+
handleEnterEditIssue();
|
|
2171
|
+
}
|
|
2172
|
+
return;
|
|
2173
|
+
}
|
|
2174
|
+
}
|
|
2152
2175
|
if (ui.canAct) {
|
|
2153
2176
|
const digit = parseInt(input2, 10);
|
|
2154
2177
|
if (!Number.isNaN(digit) && digit >= 0 && digit <= 4) {
|
|
@@ -2173,14 +2196,6 @@ function useKeyboard({
|
|
|
2173
2196
|
refresh();
|
|
2174
2197
|
return;
|
|
2175
2198
|
}
|
|
2176
|
-
if (input2 === "o") {
|
|
2177
|
-
handleSlack();
|
|
2178
|
-
return;
|
|
2179
|
-
}
|
|
2180
|
-
if (input2 === "y") {
|
|
2181
|
-
handleCopyLink();
|
|
2182
|
-
return;
|
|
2183
|
-
}
|
|
2184
2199
|
if (input2 === "p") {
|
|
2185
2200
|
handlePick();
|
|
2186
2201
|
return;
|
|
@@ -2197,13 +2212,6 @@ function useKeyboard({
|
|
|
2197
2212
|
handleToggleLog();
|
|
2198
2213
|
return;
|
|
2199
2214
|
}
|
|
2200
|
-
if (input2 === "c") {
|
|
2201
|
-
if (selectedIssue) {
|
|
2202
|
-
multiSelect.clear();
|
|
2203
|
-
ui.enterComment();
|
|
2204
|
-
}
|
|
2205
|
-
return;
|
|
2206
|
-
}
|
|
2207
2215
|
if (input2 === "m") {
|
|
2208
2216
|
if (selectedIssue && selectedRepoStatusOptionsLength > 0) {
|
|
2209
2217
|
multiSelect.clear();
|
|
@@ -2241,12 +2249,6 @@ function useKeyboard({
|
|
|
2241
2249
|
handleEnterFuzzyPicker();
|
|
2242
2250
|
return;
|
|
2243
2251
|
}
|
|
2244
|
-
if (input2 === "e") {
|
|
2245
|
-
if (selectedIssue) {
|
|
2246
|
-
handleEnterEditIssue();
|
|
2247
|
-
}
|
|
2248
|
-
return;
|
|
2249
|
-
}
|
|
2250
2252
|
if (input2 === " ") {
|
|
2251
2253
|
const id = nav.selectedId;
|
|
2252
2254
|
if (id) {
|
|
@@ -2306,7 +2308,8 @@ function useKeyboard({
|
|
|
2306
2308
|
handleEnterFuzzyPicker,
|
|
2307
2309
|
handleEnterEditIssue,
|
|
2308
2310
|
handleUndo,
|
|
2309
|
-
handleToggleLog
|
|
2311
|
+
handleToggleLog,
|
|
2312
|
+
showDetailPanel
|
|
2310
2313
|
]
|
|
2311
2314
|
);
|
|
2312
2315
|
const inputActive = ui.state.mode === "normal" || ui.state.mode === "multiSelect" || ui.state.mode === "focus" || ui.state.mode === "overlay:detail";
|
|
@@ -6850,6 +6853,145 @@ Config written to ${CONFIG_DIR}/config.json`);
|
|
|
6850
6853
|
console.log(" hog task list # List TickTick tasks");
|
|
6851
6854
|
console.log(" hog config show # View configuration\n");
|
|
6852
6855
|
}
|
|
6856
|
+
async function runReposAdd(initialRepoName) {
|
|
6857
|
+
try {
|
|
6858
|
+
await runReposAddWizard(initialRepoName);
|
|
6859
|
+
} catch (error) {
|
|
6860
|
+
if (error instanceof Error && error.message.includes("User force closed")) {
|
|
6861
|
+
console.log("\nCancelled. No changes were made.");
|
|
6862
|
+
return;
|
|
6863
|
+
}
|
|
6864
|
+
throw error;
|
|
6865
|
+
}
|
|
6866
|
+
}
|
|
6867
|
+
async function runReposAddWizard(initialRepoName) {
|
|
6868
|
+
console.log("\n\u{1F417} hog config repos:add\n");
|
|
6869
|
+
const cfg = loadFullConfig();
|
|
6870
|
+
let repoName = initialRepoName;
|
|
6871
|
+
if (!repoName) {
|
|
6872
|
+
console.log("Fetching repositories...");
|
|
6873
|
+
const allRepos = listAllRepos();
|
|
6874
|
+
const configuredNames = new Set(cfg.repos.map((r) => r.name));
|
|
6875
|
+
const available = allRepos.filter((r) => !configuredNames.has(r.nameWithOwner));
|
|
6876
|
+
if (available.length === 0) {
|
|
6877
|
+
console.log(
|
|
6878
|
+
"No more repositories available to add. All accessible repos are already tracked."
|
|
6879
|
+
);
|
|
6880
|
+
return;
|
|
6881
|
+
}
|
|
6882
|
+
repoName = await select({
|
|
6883
|
+
message: "Select repository to add:",
|
|
6884
|
+
choices: available.map((r) => ({ name: r.nameWithOwner, value: r.nameWithOwner }))
|
|
6885
|
+
});
|
|
6886
|
+
}
|
|
6887
|
+
if (!validateRepoName(repoName)) {
|
|
6888
|
+
console.error("Invalid repo name. Use owner/repo format (e.g. myorg/myrepo).");
|
|
6889
|
+
process.exit(1);
|
|
6890
|
+
}
|
|
6891
|
+
if (findRepo(cfg, repoName)) {
|
|
6892
|
+
console.error(`Repo "${repoName}" is already configured.`);
|
|
6893
|
+
process.exit(1);
|
|
6894
|
+
}
|
|
6895
|
+
const [owner, name] = repoName.split("/");
|
|
6896
|
+
console.log(`
|
|
6897
|
+
Configuring ${repoName}...`);
|
|
6898
|
+
console.log(" Fetching GitHub Projects...");
|
|
6899
|
+
const projects = listOrgProjects(owner);
|
|
6900
|
+
let projectNumber;
|
|
6901
|
+
if (projects.length === 0) {
|
|
6902
|
+
console.log(" No GitHub Projects found. Enter project number manually.");
|
|
6903
|
+
const num = await input({ message: ` Project number for ${repoName}:` });
|
|
6904
|
+
projectNumber = Number.parseInt(num, 10);
|
|
6905
|
+
} else {
|
|
6906
|
+
projectNumber = await select({
|
|
6907
|
+
message: ` Select project for ${repoName}:`,
|
|
6908
|
+
choices: projects.map((p) => ({ name: `#${p.number} \u2014 ${p.title}`, value: p.number }))
|
|
6909
|
+
});
|
|
6910
|
+
}
|
|
6911
|
+
console.log(" Detecting status field...");
|
|
6912
|
+
const statusInfo = detectStatusField(owner, projectNumber);
|
|
6913
|
+
let statusFieldId;
|
|
6914
|
+
if (statusInfo) {
|
|
6915
|
+
statusFieldId = statusInfo.fieldId;
|
|
6916
|
+
console.log(` Found status field: ${statusFieldId}`);
|
|
6917
|
+
} else {
|
|
6918
|
+
console.log(" Could not auto-detect status field.");
|
|
6919
|
+
statusFieldId = await input({ message: " Enter status field ID manually:" });
|
|
6920
|
+
}
|
|
6921
|
+
console.log(" Detecting due date field...");
|
|
6922
|
+
let dueDateFieldId;
|
|
6923
|
+
const existingDateField = detectDateField(owner, projectNumber);
|
|
6924
|
+
if (existingDateField) {
|
|
6925
|
+
console.log(` Found date field: "${existingDateField.name}" (${existingDateField.id})`);
|
|
6926
|
+
const useDateField = await confirm({
|
|
6927
|
+
message: ` Use "${existingDateField.name}" for due dates?`,
|
|
6928
|
+
default: true
|
|
6929
|
+
});
|
|
6930
|
+
if (useDateField) {
|
|
6931
|
+
dueDateFieldId = existingDateField.id;
|
|
6932
|
+
}
|
|
6933
|
+
} else {
|
|
6934
|
+
console.log(" No due date field found.");
|
|
6935
|
+
const createField = await confirm({
|
|
6936
|
+
message: ' Create a "Due Date" field for this project?',
|
|
6937
|
+
default: false
|
|
6938
|
+
});
|
|
6939
|
+
if (createField) {
|
|
6940
|
+
console.log(' Creating "Due Date" field...');
|
|
6941
|
+
const newFieldId = createDateField(owner, projectNumber, "Due Date");
|
|
6942
|
+
if (newFieldId) {
|
|
6943
|
+
dueDateFieldId = newFieldId;
|
|
6944
|
+
console.log(` Created "Due Date" field (${newFieldId})`);
|
|
6945
|
+
} else {
|
|
6946
|
+
console.log(" Could not create field \u2014 due dates will be stored in issue body.");
|
|
6947
|
+
}
|
|
6948
|
+
}
|
|
6949
|
+
}
|
|
6950
|
+
const completionType = await select({
|
|
6951
|
+
message: " When a task is completed, what should happen on GitHub?",
|
|
6952
|
+
choices: [
|
|
6953
|
+
{ name: "Close the issue", value: "closeIssue" },
|
|
6954
|
+
{ name: "Add a label (e.g. review:pending)", value: "addLabel" },
|
|
6955
|
+
{ name: "Update project status column", value: "updateProjectStatus" }
|
|
6956
|
+
]
|
|
6957
|
+
});
|
|
6958
|
+
let completionAction;
|
|
6959
|
+
if (completionType === "addLabel") {
|
|
6960
|
+
const label = await input({ message: " Label to add:", default: "review:pending" });
|
|
6961
|
+
completionAction = { type: "addLabel", label };
|
|
6962
|
+
} else if (completionType === "updateProjectStatus") {
|
|
6963
|
+
const statusOptions = statusInfo?.options ?? [];
|
|
6964
|
+
let optionId;
|
|
6965
|
+
if (statusOptions.length > 0) {
|
|
6966
|
+
optionId = await select({
|
|
6967
|
+
message: " Status to set when completed:",
|
|
6968
|
+
choices: statusOptions.map((o) => ({ name: o.name, value: o.id }))
|
|
6969
|
+
});
|
|
6970
|
+
} else {
|
|
6971
|
+
optionId = await input({ message: " Status option ID to set:" });
|
|
6972
|
+
}
|
|
6973
|
+
completionAction = { type: "updateProjectStatus", optionId };
|
|
6974
|
+
} else {
|
|
6975
|
+
completionAction = { type: "closeIssue" };
|
|
6976
|
+
}
|
|
6977
|
+
const shortName2 = await input({
|
|
6978
|
+
message: ` Short name for ${repoName}:`,
|
|
6979
|
+
default: name
|
|
6980
|
+
});
|
|
6981
|
+
const newRepo = {
|
|
6982
|
+
name: repoName,
|
|
6983
|
+
shortName: shortName2,
|
|
6984
|
+
projectNumber,
|
|
6985
|
+
statusFieldId,
|
|
6986
|
+
...dueDateFieldId ? { dueDateFieldId } : {},
|
|
6987
|
+
completionAction
|
|
6988
|
+
};
|
|
6989
|
+
cfg.repos.push(newRepo);
|
|
6990
|
+
saveFullConfig(cfg);
|
|
6991
|
+
console.log(`
|
|
6992
|
+
Added ${shortName2} \u2192 ${repoName}`);
|
|
6993
|
+
console.log(" Run: hog board --live\n");
|
|
6994
|
+
}
|
|
6853
6995
|
|
|
6854
6996
|
// src/cli.ts
|
|
6855
6997
|
init_log_persistence();
|
|
@@ -7273,7 +7415,7 @@ function resolveProjectId(projectId) {
|
|
|
7273
7415
|
process.exit(1);
|
|
7274
7416
|
}
|
|
7275
7417
|
var program = new Command();
|
|
7276
|
-
program.name("hog").description("Personal command deck \u2014 unified task dashboard for GitHub Projects + TickTick").version("1.
|
|
7418
|
+
program.name("hog").description("Personal command deck \u2014 unified task dashboard for GitHub Projects + TickTick").version("1.16.1").option("--json", "Force JSON output").option("--human", "Force human-readable output").hook("preAction", (thisCommand) => {
|
|
7277
7419
|
const opts = thisCommand.opts();
|
|
7278
7420
|
if (opts.json) setFormat("json");
|
|
7279
7421
|
if (opts.human) setFormat("human");
|
|
@@ -7455,10 +7597,18 @@ config.command("repos").description("List configured repositories").action(() =>
|
|
|
7455
7597
|
}
|
|
7456
7598
|
}
|
|
7457
7599
|
});
|
|
7458
|
-
config.command("repos:add
|
|
7600
|
+
config.command("repos:add [name]").description("Add a repository to track (interactive wizard, or pass flags for scripted use)").option("--project-number <n>", "GitHub project number (skips interactive prompt)").option("--status-field-id <id>", "Project status field ID (skips interactive prompt)").option(
|
|
7459
7601
|
"--completion-type <type>",
|
|
7460
7602
|
"Completion action: addLabel, updateProjectStatus, closeIssue"
|
|
7461
|
-
).option("--completion-option-id <id>", "Option ID for updateProjectStatus").option("--completion-label <label>", "Label for addLabel").action((name, opts) => {
|
|
7603
|
+
).option("--completion-option-id <id>", "Option ID for updateProjectStatus").option("--completion-label <label>", "Label for addLabel").action(async (name, opts) => {
|
|
7604
|
+
if (!(opts.projectNumber && opts.statusFieldId)) {
|
|
7605
|
+
await runReposAdd(name);
|
|
7606
|
+
return;
|
|
7607
|
+
}
|
|
7608
|
+
if (!name) {
|
|
7609
|
+
console.error("Name argument required in non-interactive mode.");
|
|
7610
|
+
process.exit(1);
|
|
7611
|
+
}
|
|
7462
7612
|
if (!validateRepoName(name)) {
|
|
7463
7613
|
console.error("Invalid repo name. Use owner/repo format (e.g., myorg/myrepo)");
|
|
7464
7614
|
process.exit(1);
|
|
@@ -7469,6 +7619,10 @@ config.command("repos:add <name>").description("Add a repository to track (owner
|
|
|
7469
7619
|
process.exit(1);
|
|
7470
7620
|
}
|
|
7471
7621
|
const shortName2 = name.split("/")[1] ?? name;
|
|
7622
|
+
if (!opts.completionType) {
|
|
7623
|
+
console.error("--completion-type required in non-interactive mode");
|
|
7624
|
+
process.exit(1);
|
|
7625
|
+
}
|
|
7472
7626
|
let completionAction;
|
|
7473
7627
|
switch (opts.completionType) {
|
|
7474
7628
|
case "addLabel":
|