@ondrej-svec/hog 1.15.0 → 1.16.0
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 +156 -4
- 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
|
@@ -2306,7 +2306,8 @@ function useKeyboard({
|
|
|
2306
2306
|
handleEnterFuzzyPicker,
|
|
2307
2307
|
handleEnterEditIssue,
|
|
2308
2308
|
handleUndo,
|
|
2309
|
-
handleToggleLog
|
|
2309
|
+
handleToggleLog,
|
|
2310
|
+
showDetailPanel
|
|
2310
2311
|
]
|
|
2311
2312
|
);
|
|
2312
2313
|
const inputActive = ui.state.mode === "normal" || ui.state.mode === "multiSelect" || ui.state.mode === "focus" || ui.state.mode === "overlay:detail";
|
|
@@ -6850,6 +6851,145 @@ Config written to ${CONFIG_DIR}/config.json`);
|
|
|
6850
6851
|
console.log(" hog task list # List TickTick tasks");
|
|
6851
6852
|
console.log(" hog config show # View configuration\n");
|
|
6852
6853
|
}
|
|
6854
|
+
async function runReposAdd(initialRepoName) {
|
|
6855
|
+
try {
|
|
6856
|
+
await runReposAddWizard(initialRepoName);
|
|
6857
|
+
} catch (error) {
|
|
6858
|
+
if (error instanceof Error && error.message.includes("User force closed")) {
|
|
6859
|
+
console.log("\nCancelled. No changes were made.");
|
|
6860
|
+
return;
|
|
6861
|
+
}
|
|
6862
|
+
throw error;
|
|
6863
|
+
}
|
|
6864
|
+
}
|
|
6865
|
+
async function runReposAddWizard(initialRepoName) {
|
|
6866
|
+
console.log("\n\u{1F417} hog config repos:add\n");
|
|
6867
|
+
const cfg = loadFullConfig();
|
|
6868
|
+
let repoName = initialRepoName;
|
|
6869
|
+
if (!repoName) {
|
|
6870
|
+
console.log("Fetching repositories...");
|
|
6871
|
+
const allRepos = listAllRepos();
|
|
6872
|
+
const configuredNames = new Set(cfg.repos.map((r) => r.name));
|
|
6873
|
+
const available = allRepos.filter((r) => !configuredNames.has(r.nameWithOwner));
|
|
6874
|
+
if (available.length === 0) {
|
|
6875
|
+
console.log(
|
|
6876
|
+
"No more repositories available to add. All accessible repos are already tracked."
|
|
6877
|
+
);
|
|
6878
|
+
return;
|
|
6879
|
+
}
|
|
6880
|
+
repoName = await select({
|
|
6881
|
+
message: "Select repository to add:",
|
|
6882
|
+
choices: available.map((r) => ({ name: r.nameWithOwner, value: r.nameWithOwner }))
|
|
6883
|
+
});
|
|
6884
|
+
}
|
|
6885
|
+
if (!validateRepoName(repoName)) {
|
|
6886
|
+
console.error("Invalid repo name. Use owner/repo format (e.g. myorg/myrepo).");
|
|
6887
|
+
process.exit(1);
|
|
6888
|
+
}
|
|
6889
|
+
if (findRepo(cfg, repoName)) {
|
|
6890
|
+
console.error(`Repo "${repoName}" is already configured.`);
|
|
6891
|
+
process.exit(1);
|
|
6892
|
+
}
|
|
6893
|
+
const [owner, name] = repoName.split("/");
|
|
6894
|
+
console.log(`
|
|
6895
|
+
Configuring ${repoName}...`);
|
|
6896
|
+
console.log(" Fetching GitHub Projects...");
|
|
6897
|
+
const projects = listOrgProjects(owner);
|
|
6898
|
+
let projectNumber;
|
|
6899
|
+
if (projects.length === 0) {
|
|
6900
|
+
console.log(" No GitHub Projects found. Enter project number manually.");
|
|
6901
|
+
const num = await input({ message: ` Project number for ${repoName}:` });
|
|
6902
|
+
projectNumber = Number.parseInt(num, 10);
|
|
6903
|
+
} else {
|
|
6904
|
+
projectNumber = await select({
|
|
6905
|
+
message: ` Select project for ${repoName}:`,
|
|
6906
|
+
choices: projects.map((p) => ({ name: `#${p.number} \u2014 ${p.title}`, value: p.number }))
|
|
6907
|
+
});
|
|
6908
|
+
}
|
|
6909
|
+
console.log(" Detecting status field...");
|
|
6910
|
+
const statusInfo = detectStatusField(owner, projectNumber);
|
|
6911
|
+
let statusFieldId;
|
|
6912
|
+
if (statusInfo) {
|
|
6913
|
+
statusFieldId = statusInfo.fieldId;
|
|
6914
|
+
console.log(` Found status field: ${statusFieldId}`);
|
|
6915
|
+
} else {
|
|
6916
|
+
console.log(" Could not auto-detect status field.");
|
|
6917
|
+
statusFieldId = await input({ message: " Enter status field ID manually:" });
|
|
6918
|
+
}
|
|
6919
|
+
console.log(" Detecting due date field...");
|
|
6920
|
+
let dueDateFieldId;
|
|
6921
|
+
const existingDateField = detectDateField(owner, projectNumber);
|
|
6922
|
+
if (existingDateField) {
|
|
6923
|
+
console.log(` Found date field: "${existingDateField.name}" (${existingDateField.id})`);
|
|
6924
|
+
const useDateField = await confirm({
|
|
6925
|
+
message: ` Use "${existingDateField.name}" for due dates?`,
|
|
6926
|
+
default: true
|
|
6927
|
+
});
|
|
6928
|
+
if (useDateField) {
|
|
6929
|
+
dueDateFieldId = existingDateField.id;
|
|
6930
|
+
}
|
|
6931
|
+
} else {
|
|
6932
|
+
console.log(" No due date field found.");
|
|
6933
|
+
const createField = await confirm({
|
|
6934
|
+
message: ' Create a "Due Date" field for this project?',
|
|
6935
|
+
default: false
|
|
6936
|
+
});
|
|
6937
|
+
if (createField) {
|
|
6938
|
+
console.log(' Creating "Due Date" field...');
|
|
6939
|
+
const newFieldId = createDateField(owner, projectNumber, "Due Date");
|
|
6940
|
+
if (newFieldId) {
|
|
6941
|
+
dueDateFieldId = newFieldId;
|
|
6942
|
+
console.log(` Created "Due Date" field (${newFieldId})`);
|
|
6943
|
+
} else {
|
|
6944
|
+
console.log(" Could not create field \u2014 due dates will be stored in issue body.");
|
|
6945
|
+
}
|
|
6946
|
+
}
|
|
6947
|
+
}
|
|
6948
|
+
const completionType = await select({
|
|
6949
|
+
message: " When a task is completed, what should happen on GitHub?",
|
|
6950
|
+
choices: [
|
|
6951
|
+
{ name: "Close the issue", value: "closeIssue" },
|
|
6952
|
+
{ name: "Add a label (e.g. review:pending)", value: "addLabel" },
|
|
6953
|
+
{ name: "Update project status column", value: "updateProjectStatus" }
|
|
6954
|
+
]
|
|
6955
|
+
});
|
|
6956
|
+
let completionAction;
|
|
6957
|
+
if (completionType === "addLabel") {
|
|
6958
|
+
const label = await input({ message: " Label to add:", default: "review:pending" });
|
|
6959
|
+
completionAction = { type: "addLabel", label };
|
|
6960
|
+
} else if (completionType === "updateProjectStatus") {
|
|
6961
|
+
const statusOptions = statusInfo?.options ?? [];
|
|
6962
|
+
let optionId;
|
|
6963
|
+
if (statusOptions.length > 0) {
|
|
6964
|
+
optionId = await select({
|
|
6965
|
+
message: " Status to set when completed:",
|
|
6966
|
+
choices: statusOptions.map((o) => ({ name: o.name, value: o.id }))
|
|
6967
|
+
});
|
|
6968
|
+
} else {
|
|
6969
|
+
optionId = await input({ message: " Status option ID to set:" });
|
|
6970
|
+
}
|
|
6971
|
+
completionAction = { type: "updateProjectStatus", optionId };
|
|
6972
|
+
} else {
|
|
6973
|
+
completionAction = { type: "closeIssue" };
|
|
6974
|
+
}
|
|
6975
|
+
const shortName2 = await input({
|
|
6976
|
+
message: ` Short name for ${repoName}:`,
|
|
6977
|
+
default: name
|
|
6978
|
+
});
|
|
6979
|
+
const newRepo = {
|
|
6980
|
+
name: repoName,
|
|
6981
|
+
shortName: shortName2,
|
|
6982
|
+
projectNumber,
|
|
6983
|
+
statusFieldId,
|
|
6984
|
+
...dueDateFieldId ? { dueDateFieldId } : {},
|
|
6985
|
+
completionAction
|
|
6986
|
+
};
|
|
6987
|
+
cfg.repos.push(newRepo);
|
|
6988
|
+
saveFullConfig(cfg);
|
|
6989
|
+
console.log(`
|
|
6990
|
+
Added ${shortName2} \u2192 ${repoName}`);
|
|
6991
|
+
console.log(" Run: hog board --live\n");
|
|
6992
|
+
}
|
|
6853
6993
|
|
|
6854
6994
|
// src/cli.ts
|
|
6855
6995
|
init_log_persistence();
|
|
@@ -7273,7 +7413,7 @@ function resolveProjectId(projectId) {
|
|
|
7273
7413
|
process.exit(1);
|
|
7274
7414
|
}
|
|
7275
7415
|
var program = new Command();
|
|
7276
|
-
program.name("hog").description("Personal command deck \u2014 unified task dashboard for GitHub Projects + TickTick").version("1.
|
|
7416
|
+
program.name("hog").description("Personal command deck \u2014 unified task dashboard for GitHub Projects + TickTick").version("1.16.0").option("--json", "Force JSON output").option("--human", "Force human-readable output").hook("preAction", (thisCommand) => {
|
|
7277
7417
|
const opts = thisCommand.opts();
|
|
7278
7418
|
if (opts.json) setFormat("json");
|
|
7279
7419
|
if (opts.human) setFormat("human");
|
|
@@ -7455,10 +7595,18 @@ config.command("repos").description("List configured repositories").action(() =>
|
|
|
7455
7595
|
}
|
|
7456
7596
|
}
|
|
7457
7597
|
});
|
|
7458
|
-
config.command("repos:add
|
|
7598
|
+
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
7599
|
"--completion-type <type>",
|
|
7460
7600
|
"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) => {
|
|
7601
|
+
).option("--completion-option-id <id>", "Option ID for updateProjectStatus").option("--completion-label <label>", "Label for addLabel").action(async (name, opts) => {
|
|
7602
|
+
if (!(opts.projectNumber && opts.statusFieldId)) {
|
|
7603
|
+
await runReposAdd(name);
|
|
7604
|
+
return;
|
|
7605
|
+
}
|
|
7606
|
+
if (!name) {
|
|
7607
|
+
console.error("Name argument required in non-interactive mode.");
|
|
7608
|
+
process.exit(1);
|
|
7609
|
+
}
|
|
7462
7610
|
if (!validateRepoName(name)) {
|
|
7463
7611
|
console.error("Invalid repo name. Use owner/repo format (e.g., myorg/myrepo)");
|
|
7464
7612
|
process.exit(1);
|
|
@@ -7469,6 +7617,10 @@ config.command("repos:add <name>").description("Add a repository to track (owner
|
|
|
7469
7617
|
process.exit(1);
|
|
7470
7618
|
}
|
|
7471
7619
|
const shortName2 = name.split("/")[1] ?? name;
|
|
7620
|
+
if (!opts.completionType) {
|
|
7621
|
+
console.error("--completion-type required in non-interactive mode");
|
|
7622
|
+
process.exit(1);
|
|
7623
|
+
}
|
|
7472
7624
|
let completionAction;
|
|
7473
7625
|
switch (opts.completionType) {
|
|
7474
7626
|
case "addLabel":
|