@bragduck/cli 2.38.1 → 2.39.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.
@@ -63,7 +63,7 @@ var init_constants = __esm({
63
63
  CLIENT_ID: "kJlsd66DLTnENE8p7Ru2JwqZg1Sie4yZ",
64
64
  AUTH_URL: "https://auth.atlassian.com/authorize",
65
65
  AUDIENCE: "api.atlassian.com",
66
- SCOPES: "read:jira-work read:jira-user read:page:confluence read:confluence-user offline_access read:me",
66
+ SCOPES: "read:jira-work read:jira-user read:confluence-content.all read:confluence-user offline_access",
67
67
  ACCESSIBLE_RESOURCES_URL: "https://api.atlassian.com/oauth/token/accessible-resources",
68
68
  API_GATEWAY_URL: "https://api.atlassian.com"
69
69
  };
@@ -104,6 +104,11 @@ var init_constants = __esm({
104
104
  ORGANISATIONS: {
105
105
  LIST: "/v1/users/{userId}/organisations"
106
106
  },
107
+ STORIES: {
108
+ LIST: "/v1/users/{userId}/stories",
109
+ CREATE: "/v1/users/{userId}/stories",
110
+ DELETE: "/v1/users/{userId}/stories/{storyId}"
111
+ },
107
112
  VERSION: "/v1/cli/version",
108
113
  /**
109
114
  * @deprecated Use BRAGS.REFINE instead
@@ -1622,6 +1627,70 @@ var init_api_service = __esm({
1622
1627
  throw _error;
1623
1628
  }
1624
1629
  }
1630
+ /**
1631
+ * List user's stories
1632
+ */
1633
+ async listStories(userId, params = {}) {
1634
+ const { page = 1, perPage = 20, search, competency, orgId } = params;
1635
+ logger.debug(`Listing stories: page=${page}, perPage=${perPage}`);
1636
+ try {
1637
+ const queryParams = new URLSearchParams6({
1638
+ page: page.toString(),
1639
+ perPage: perPage.toString()
1640
+ });
1641
+ if (search) queryParams.append("search", search);
1642
+ if (competency) queryParams.append("competency", competency);
1643
+ if (orgId) queryParams.append("orgId", orgId);
1644
+ const url = `${API_ENDPOINTS.STORIES.LIST.replace("{userId}", userId)}?${queryParams.toString()}`;
1645
+ const response = await this.makeRequest(url, {
1646
+ method: "GET"
1647
+ });
1648
+ logger.debug(
1649
+ `Successfully fetched ${response.items.length} stories (total: ${response.total})`
1650
+ );
1651
+ return response;
1652
+ } catch (_error) {
1653
+ logger.debug("Failed to list stories");
1654
+ throw _error;
1655
+ }
1656
+ }
1657
+ /**
1658
+ * Create a story
1659
+ */
1660
+ async createStory(userId, body) {
1661
+ logger.debug(`Creating story: ${body.title}`);
1662
+ try {
1663
+ const url = API_ENDPOINTS.STORIES.CREATE.replace("{userId}", userId);
1664
+ const response = await this.makeRequest(url, {
1665
+ method: "POST",
1666
+ body
1667
+ });
1668
+ logger.debug(`Successfully created story: ${response.id}`);
1669
+ return response;
1670
+ } catch (_error) {
1671
+ logger.debug("Failed to create story");
1672
+ throw _error;
1673
+ }
1674
+ }
1675
+ /**
1676
+ * Delete a story (soft delete)
1677
+ */
1678
+ async deleteStory(userId, storyId) {
1679
+ logger.debug(`Deleting story: ${storyId}`);
1680
+ try {
1681
+ const url = API_ENDPOINTS.STORIES.DELETE.replace("{userId}", userId).replace(
1682
+ "{storyId}",
1683
+ storyId
1684
+ );
1685
+ await this.makeRequest(url, {
1686
+ method: "DELETE"
1687
+ });
1688
+ logger.debug(`Successfully deleted story: ${storyId}`);
1689
+ } catch (_error) {
1690
+ logger.debug("Failed to delete story");
1691
+ throw _error;
1692
+ }
1693
+ }
1625
1694
  /**
1626
1695
  * List user's organisations
1627
1696
  */
@@ -1891,6 +1960,19 @@ var AtlassianAuthService = class {
1891
1960
  callbackResult = await resultPromise;
1892
1961
  } catch (error) {
1893
1962
  storageService.deleteOAuthState();
1963
+ const rawMessage = error?.message ?? String(error);
1964
+ if (/invalid_scope/i.test(rawMessage)) {
1965
+ throw new AtlassianError(
1966
+ "Atlassian rejected the requested scopes. The app must list all of these classic scopes: read:jira-work, read:jira-user, read:confluence-content.all, read:confluence-user, offline_access.",
1967
+ { originalError: rawMessage }
1968
+ );
1969
+ }
1970
+ if (/redirect_uri|invalid_request/i.test(rawMessage)) {
1971
+ throw new AtlassianError(
1972
+ "Atlassian rejected the redirect URI. All of http://127.0.0.1:8000/callback through http://127.0.0.1:8004/callback must be registered in the Atlassian app callback URL list.",
1973
+ { originalError: rawMessage }
1974
+ );
1975
+ }
1894
1976
  throw error;
1895
1977
  }
1896
1978
  storageService.deleteOAuthState();
@@ -5957,6 +6039,12 @@ async function promptConfirm(message, defaultValue = true) {
5957
6039
  default: defaultValue
5958
6040
  });
5959
6041
  }
6042
+ async function promptInput(message, defaultValue) {
6043
+ return await input2({
6044
+ message,
6045
+ default: defaultValue
6046
+ });
6047
+ }
5960
6048
  async function promptDaysToScan(defaultDays = 30) {
5961
6049
  const choices = [
5962
6050
  { name: "1 day", value: "1", description: "Last 24 hours" },
@@ -6204,6 +6292,13 @@ function createFetchSpinner(text) {
6204
6292
  spinner: "bouncingBar"
6205
6293
  });
6206
6294
  }
6295
+ function createWriteSpinner(text) {
6296
+ return ora({
6297
+ text,
6298
+ color: "cyan",
6299
+ spinner: "dots"
6300
+ });
6301
+ }
6207
6302
  function createValidateSpinner(text) {
6208
6303
  return ora({
6209
6304
  text,
@@ -6226,6 +6321,15 @@ function updateStepSpinner(spinner, currentStep, totalSteps, text) {
6226
6321
  function fetchingBragsSpinner() {
6227
6322
  return createFetchSpinner("Fetching your brags...");
6228
6323
  }
6324
+ function fetchingStoriesSpinner() {
6325
+ return createFetchSpinner("Fetching your stories...");
6326
+ }
6327
+ function creatingStorySpinner() {
6328
+ return createWriteSpinner("Creating story...");
6329
+ }
6330
+ function deletingStorySpinner() {
6331
+ return createWriteSpinner("Deleting story...");
6332
+ }
6229
6333
  function succeedSpinner(spinner, text) {
6230
6334
  if (text) {
6231
6335
  spinner.succeed(colors.success(text));
@@ -6522,6 +6626,7 @@ async function syncSingleRepository(repo, days, sortOption, scanMode, orgId, opt
6522
6626
  );
6523
6627
  createSpinner.start();
6524
6628
  const createRequest = {
6629
+ mode: options.turbo ? "turbo" : "manual",
6525
6630
  brags: acceptedBrags.map((refined, index) => {
6526
6631
  const originalCommit = selectedCommits[index];
6527
6632
  const repoTag = repo.name;
@@ -6950,6 +7055,7 @@ async function syncSingleService(sourceType, options, TOTAL_STEPS, sharedDays, s
6950
7055
  );
6951
7056
  createSpinner.start();
6952
7057
  const createRequest = {
7058
+ mode: options.turbo ? "turbo" : "manual",
6953
7059
  brags: acceptedBrags.map((refined, index) => {
6954
7060
  const originalCommit = selectedCommits[index];
6955
7061
  const isGitSource = sourceType === "github" || sourceType === "gitlab" || sourceType === "bitbucket" || sourceType === "atlassian";
@@ -7667,13 +7773,15 @@ function formatBragsTable(brags) {
7667
7773
  return table.toString() + (links ? "\n\n" + links : "");
7668
7774
  }
7669
7775
  function formatBragLinks(brags) {
7670
- const lines = brags.filter((brag) => brag.url || brag.goalIds && brag.goalIds.length > 0).map((brag) => {
7776
+ const lines = brags.filter((brag) => brag.url || brag.keyResultIds && brag.keyResultIds.length > 0).map((brag) => {
7671
7777
  const parts = [` ${colors.white(brag.title)}`];
7672
7778
  if (brag.url) {
7673
7779
  parts.push(` ${colors.info(brag.url)}`);
7674
7780
  }
7675
- if (brag.goalIds && brag.goalIds.length > 0) {
7676
- parts.push(` ${colors.dim("Linked to key result:")} ${colors.primary(brag.goalIds[0])}`);
7781
+ if (brag.keyResultIds && brag.keyResultIds.length > 0) {
7782
+ parts.push(
7783
+ ` ${colors.dim("Linked to key result:")} ${colors.primary(brag.keyResultIds[0])}`
7784
+ );
7677
7785
  }
7678
7786
  return parts.join("\n");
7679
7787
  });
@@ -7685,9 +7793,9 @@ function formatBragsOneline(brags) {
7685
7793
  const date = formatDate(brag.date);
7686
7794
  const urlLine = brag.url ? `
7687
7795
  ${colors.info(brag.url)}` : "";
7688
- const goalLine = brag.goalIds && brag.goalIds.length > 0 ? `
7689
- ${colors.dim("Linked to key result:")} ${colors.primary(brag.goalIds[0])}` : "";
7690
- return `${colors.highlight(date)} ${colors.white(brag.title)}${urlLine}${goalLine}`;
7796
+ const keyResultLine = brag.keyResultIds && brag.keyResultIds.length > 0 ? `
7797
+ ${colors.dim("Linked to key result:")} ${colors.primary(brag.keyResultIds[0])}` : "";
7798
+ return `${colors.highlight(date)} ${colors.white(brag.title)}${urlLine}${keyResultLine}`;
7691
7799
  }).join("\n");
7692
7800
  }
7693
7801
  function truncateText(text, maxLength) {
@@ -7717,14 +7825,338 @@ function getErrorHint2(error) {
7717
7825
  return "Try running with DEBUG=* for more information";
7718
7826
  }
7719
7827
 
7828
+ // src/commands/story.ts
7829
+ init_esm_shims();
7830
+ init_api_service();
7831
+ init_auth_service();
7832
+ import boxen8 from "boxen";
7833
+ import Table3 from "cli-table3";
7834
+ init_logger();
7835
+ async function storyCommand(subcommand, idOrOptions, _options) {
7836
+ switch (subcommand) {
7837
+ case "list":
7838
+ case "ls":
7839
+ await storyListCommand(idOrOptions || {});
7840
+ break;
7841
+ case "create":
7842
+ case "add":
7843
+ await storyCreateCommand(idOrOptions || {});
7844
+ break;
7845
+ case "delete":
7846
+ case "rm":
7847
+ if (typeof idOrOptions === "string") {
7848
+ await storyDeleteCommand(idOrOptions);
7849
+ } else {
7850
+ logger.log("");
7851
+ logger.log(
7852
+ boxen8(
7853
+ formatErrorMessage("Missing story ID", "Usage: bragduck story delete <id>"),
7854
+ boxStyles.error
7855
+ )
7856
+ );
7857
+ process.exit(1);
7858
+ }
7859
+ break;
7860
+ default:
7861
+ logger.log("");
7862
+ logger.log(
7863
+ boxen8(
7864
+ colors.primary("Story Commands") + `
7865
+
7866
+ ${theme.command("bragduck story list")} List your interview stories
7867
+ ${theme.command("bragduck story create")} Create a new STAR story
7868
+ ${theme.command("bragduck story delete")} Delete a story by ID
7869
+
7870
+ ` + colors.dim("Aliases: ls, add, rm"),
7871
+ { ...boxStyles.info, padding: 1 }
7872
+ )
7873
+ );
7874
+ break;
7875
+ }
7876
+ }
7877
+ async function storyListCommand(options) {
7878
+ logger.log("");
7879
+ try {
7880
+ const isAuthenticated = await ensureAuthenticated();
7881
+ if (!isAuthenticated) {
7882
+ process.exit(1);
7883
+ }
7884
+ const subSpinner = createValidateSpinner("Checking subscription...");
7885
+ subSpinner.start();
7886
+ let subscriptionStatus;
7887
+ try {
7888
+ subscriptionStatus = await apiService.getSubscriptionStatus();
7889
+ } catch (error) {
7890
+ failSpinner(subSpinner, "Failed to check subscription");
7891
+ throw error;
7892
+ }
7893
+ if (subscriptionStatus.tier === "FREE") {
7894
+ failSpinner(subSpinner, "Free plan \u2014 upgrade to use the CLI");
7895
+ showUpgradeMessage();
7896
+ return;
7897
+ }
7898
+ subSpinner.stop();
7899
+ const userInfo = authService.getUserInfo();
7900
+ if (!userInfo) {
7901
+ logger.log(boxen8(formatErrorMessage("Could not retrieve user info"), boxStyles.error));
7902
+ process.exit(1);
7903
+ }
7904
+ const perPage = options.limit || 20;
7905
+ const spinner = fetchingStoriesSpinner();
7906
+ spinner.start();
7907
+ const response = await apiService.listStories(userInfo.id, {
7908
+ perPage,
7909
+ search: options.search,
7910
+ competency: options.competency
7911
+ });
7912
+ if (response.items.length === 0) {
7913
+ failSpinner(spinner, "No stories found");
7914
+ logger.log("");
7915
+ if (options.search || options.competency) {
7916
+ logger.info("Try adjusting your filters or run without filters to see all stories");
7917
+ } else {
7918
+ logger.info(
7919
+ theme.secondary("Run ") + theme.command("bragduck story create") + theme.secondary(" to create your first interview story")
7920
+ );
7921
+ }
7922
+ return;
7923
+ }
7924
+ succeedSpinner(spinner, `Found ${response.total} stor${response.total > 1 ? "ies" : "y"}`);
7925
+ showCommandHeader(userInfo);
7926
+ logger.log("");
7927
+ logger.log(formatStoriesTable(response.items));
7928
+ logger.log("");
7929
+ if (response.total > response.items.length) {
7930
+ logger.info(`Showing ${response.items.length} of ${response.total} total stories`);
7931
+ logger.log("");
7932
+ }
7933
+ if (options.search || options.competency) {
7934
+ const filterInfo = [];
7935
+ if (options.search) filterInfo.push(`search: "${options.search}"`);
7936
+ if (options.competency) filterInfo.push(`competency: ${options.competency}`);
7937
+ logger.info(theme.info(`Filters applied: ${filterInfo.join(", ")}`));
7938
+ logger.log("");
7939
+ }
7940
+ } catch (error) {
7941
+ const err = error;
7942
+ logger.log("");
7943
+ logger.log(boxen8(formatErrorMessage(err.message, getErrorHint3(err)), boxStyles.error));
7944
+ process.exit(1);
7945
+ }
7946
+ }
7947
+ async function storyCreateCommand(options) {
7948
+ logger.log("");
7949
+ try {
7950
+ const isAuthenticated = await ensureAuthenticated();
7951
+ if (!isAuthenticated) {
7952
+ process.exit(1);
7953
+ }
7954
+ const subSpinner = createValidateSpinner("Checking subscription...");
7955
+ subSpinner.start();
7956
+ let subscriptionStatus;
7957
+ try {
7958
+ subscriptionStatus = await apiService.getSubscriptionStatus();
7959
+ } catch (error) {
7960
+ failSpinner(subSpinner, "Failed to check subscription");
7961
+ throw error;
7962
+ }
7963
+ if (subscriptionStatus.tier === "FREE") {
7964
+ failSpinner(subSpinner, "Free plan \u2014 upgrade to use the CLI");
7965
+ showUpgradeMessage();
7966
+ return;
7967
+ }
7968
+ subSpinner.stop();
7969
+ const userInfo = authService.getUserInfo();
7970
+ if (!userInfo) {
7971
+ logger.log(boxen8(formatErrorMessage("Could not retrieve user info"), boxStyles.error));
7972
+ process.exit(1);
7973
+ }
7974
+ logger.log(
7975
+ boxen8(
7976
+ colors.primary("Create Interview Story") + "\n\n" + colors.dim("Use the STAR format to structure your story:\n") + colors.dim("Situation, Task, Action, Result"),
7977
+ { ...boxStyles.info, padding: 1 }
7978
+ )
7979
+ );
7980
+ logger.log("");
7981
+ const title = options.title || await promptInput("Story title (short summary):");
7982
+ if (!title.trim()) {
7983
+ logger.log(theme.error("Title is required"));
7984
+ process.exit(1);
7985
+ }
7986
+ const situation = await promptInput("Situation (context and background):");
7987
+ if (!situation.trim()) {
7988
+ logger.log(theme.error("Situation is required"));
7989
+ process.exit(1);
7990
+ }
7991
+ const task = await promptInput("Task (your responsibility or challenge):");
7992
+ if (!task.trim()) {
7993
+ logger.log(theme.error("Task is required"));
7994
+ process.exit(1);
7995
+ }
7996
+ const action = await promptInput("Action (what you did):");
7997
+ if (!action.trim()) {
7998
+ logger.log(theme.error("Action is required"));
7999
+ process.exit(1);
8000
+ }
8001
+ const result = await promptInput("Result (outcome and impact):");
8002
+ if (!result.trim()) {
8003
+ logger.log(theme.error("Result is required"));
8004
+ process.exit(1);
8005
+ }
8006
+ const competenciesInput = await promptInput(
8007
+ "Competencies (comma-separated, e.g. leadership, system design):",
8008
+ ""
8009
+ );
8010
+ const competencies = competenciesInput ? competenciesInput.split(",").map((c) => c.trim()).filter(Boolean) : [];
8011
+ let orgId;
8012
+ try {
8013
+ const orgsResponse = await apiService.listUserOrganisations(userInfo.id);
8014
+ if (orgsResponse.items.length > 0) {
8015
+ const selectedOrg = await promptSelectOrganisationWithDefault(orgsResponse.items);
8016
+ if (selectedOrg) {
8017
+ orgId = selectedOrg;
8018
+ }
8019
+ }
8020
+ } catch {
8021
+ logger.debug("Failed to fetch organisations, skipping org selection");
8022
+ }
8023
+ logger.log("");
8024
+ logger.log(
8025
+ boxen8(
8026
+ colors.primary("Preview") + `
8027
+
8028
+ ${theme.label("Title")} ${colors.white(title)}
8029
+
8030
+ ${theme.label("Situation")} ${colors.white(situation)}
8031
+
8032
+ ${theme.label("Task")} ${colors.white(task)}
8033
+
8034
+ ${theme.label("Action")} ${colors.white(action)}
8035
+
8036
+ ${theme.label("Result")} ${colors.white(result)}
8037
+
8038
+ ${theme.label("Competencies")} ${competencies.length > 0 ? colors.primary(competencies.join(", ")) : colors.dim("none")}`,
8039
+ { ...boxStyles.info, padding: 1 }
8040
+ )
8041
+ );
8042
+ logger.log("");
8043
+ const shouldCreate = await promptConfirm("Create this story?", true);
8044
+ if (!shouldCreate) {
8045
+ logger.log(theme.secondary("Story creation cancelled"));
8046
+ return;
8047
+ }
8048
+ const spinner = creatingStorySpinner();
8049
+ spinner.start();
8050
+ const body = {
8051
+ title,
8052
+ situation,
8053
+ task,
8054
+ action,
8055
+ result,
8056
+ competencies,
8057
+ source: "cli"
8058
+ };
8059
+ if (orgId) {
8060
+ body.orgId = orgId;
8061
+ }
8062
+ const story = await apiService.createStory(userInfo.id, body);
8063
+ succeedSpinner(spinner, `Story created: "${story.title}"`);
8064
+ logger.log("");
8065
+ } catch (error) {
8066
+ const err = error;
8067
+ logger.log("");
8068
+ logger.log(boxen8(formatErrorMessage(err.message, getErrorHint3(err)), boxStyles.error));
8069
+ process.exit(1);
8070
+ }
8071
+ }
8072
+ async function storyDeleteCommand(storyId) {
8073
+ logger.log("");
8074
+ try {
8075
+ const isAuthenticated = await ensureAuthenticated();
8076
+ if (!isAuthenticated) {
8077
+ process.exit(1);
8078
+ }
8079
+ const userInfo = authService.getUserInfo();
8080
+ if (!userInfo) {
8081
+ logger.log(boxen8(formatErrorMessage("Could not retrieve user info"), boxStyles.error));
8082
+ process.exit(1);
8083
+ }
8084
+ const shouldDelete = await promptConfirm(`Delete story ${storyId}?`, false);
8085
+ if (!shouldDelete) {
8086
+ logger.log(theme.secondary("Deletion cancelled"));
8087
+ return;
8088
+ }
8089
+ const spinner = deletingStorySpinner();
8090
+ spinner.start();
8091
+ await apiService.deleteStory(userInfo.id, storyId);
8092
+ succeedSpinner(spinner, "Story deleted");
8093
+ logger.log("");
8094
+ } catch (error) {
8095
+ const err = error;
8096
+ logger.log("");
8097
+ logger.log(boxen8(formatErrorMessage(err.message, getErrorHint3(err)), boxStyles.error));
8098
+ process.exit(1);
8099
+ }
8100
+ }
8101
+ function formatStoriesTable(stories) {
8102
+ const table = new Table3({
8103
+ head: [
8104
+ colors.primary("ID"),
8105
+ colors.primary("Title"),
8106
+ colors.primary("Competencies"),
8107
+ colors.primary("Updated")
8108
+ ],
8109
+ colWidths: [12, 35, 30, 14],
8110
+ wordWrap: true,
8111
+ style: tableStyles.default.style
8112
+ });
8113
+ stories.forEach((story) => {
8114
+ const competencies = story.competencies.length > 0 ? story.competencies.join(", ") : colors.dim("none");
8115
+ const updated = formatDate(story.updatedAt);
8116
+ table.push([
8117
+ colors.dim(story.id),
8118
+ colors.white(story.title),
8119
+ colors.primary(competencies),
8120
+ colors.highlight(updated)
8121
+ ]);
8122
+ });
8123
+ return table.toString();
8124
+ }
8125
+ function showUpgradeMessage() {
8126
+ logger.log("");
8127
+ logger.log(
8128
+ boxen8(
8129
+ theme.warning("CLI Access Requires Subscription") + "\n\nThe BragDuck CLI is available for Plus and Pro subscribers.\nUpgrade now to unlock:\n\n \u2022 List and manage your interview stories\n \u2022 Create STAR-format stories from the terminal\n \u2022 Automatic work item scanning\n\n" + colors.highlight("Upgrade at: https://bragduck.com/app/settings/plans"),
8130
+ {
8131
+ ...boxStyles.warning,
8132
+ padding: 1,
8133
+ margin: 1
8134
+ }
8135
+ )
8136
+ );
8137
+ logger.log("");
8138
+ }
8139
+ function getErrorHint3(error) {
8140
+ if (error.name === "TokenExpiredError" || error.name === "AuthenticationError") {
8141
+ return 'Run "bragduck auth login" to login again';
8142
+ }
8143
+ if (error.name === "NetworkError") {
8144
+ return "Check your internet connection and try again";
8145
+ }
8146
+ if (error.name === "ApiError") {
8147
+ return "The server might be experiencing issues. Try again later";
8148
+ }
8149
+ return "Try running with DEBUG=* for more information";
8150
+ }
8151
+
7720
8152
  // src/commands/config.ts
7721
8153
  init_esm_shims();
7722
8154
  init_storage_service();
7723
8155
  init_logger();
7724
8156
  init_constants();
7725
- import boxen8 from "boxen";
8157
+ import boxen9 from "boxen";
7726
8158
  import chalk6 from "chalk";
7727
- import Table3 from "cli-table3";
8159
+ import Table4 from "cli-table3";
7728
8160
  init_errors();
7729
8161
  var VALID_CONFIG_KEYS = Object.values(CONFIG_KEYS);
7730
8162
  async function configCommand(subcommand, key, value) {
@@ -7758,7 +8190,7 @@ async function configCommand(subcommand, key, value) {
7758
8190
  const err = error;
7759
8191
  logger.log("");
7760
8192
  logger.log(
7761
- boxen8(formatErrorMessage(err.message, getConfigHint(err)), {
8193
+ boxen9(formatErrorMessage(err.message, getConfigHint(err)), {
7762
8194
  padding: 1,
7763
8195
  margin: 1,
7764
8196
  borderStyle: "round",
@@ -7778,7 +8210,7 @@ async function handleListConfig() {
7778
8210
  confluenceInstance: storageService.getConfig("confluenceInstance"),
7779
8211
  gitlabInstance: storageService.getConfig("gitlabInstance")
7780
8212
  };
7781
- const table = new Table3({
8213
+ const table = new Table4({
7782
8214
  head: [chalk6.cyan("Key"), chalk6.cyan("Value"), chalk6.cyan("Default")],
7783
8215
  colWidths: [25, 40, 40],
7784
8216
  wordWrap: true,
@@ -7852,7 +8284,7 @@ async function handleSetConfig(key, value) {
7852
8284
  const typedValue = validateAndConvertValue(key, value);
7853
8285
  storageService.setConfig(key, typedValue);
7854
8286
  logger.log(
7855
- boxen8(
8287
+ boxen9(
7856
8288
  `${chalk6.green.bold("\u2713 Configuration updated")}
7857
8289
 
7858
8290
  ${chalk6.white(key)}: ${chalk6.yellow(String(typedValue))}`,
@@ -7984,6 +8416,18 @@ program.command("list").description("List your existing brags").option("-l, --li
7984
8416
  process.exit(1);
7985
8417
  }
7986
8418
  });
8419
+ program.command("story [subcommand] [id]").description("Manage interview stories (subcommands: list, create, delete)").option("-l, --limit <number>", "Number of stories to display", (val) => parseInt(val, 10), 20).option("-s, --search <query>", "Search stories by keyword").option("-c, --competency <competency>", "Filter by competency").option("-t, --title <title>", "Story title (for create)").action(async (subcommand, id, options) => {
8420
+ try {
8421
+ if (subcommand === "delete" || subcommand === "rm") {
8422
+ await storyCommand(subcommand, id, options);
8423
+ } else {
8424
+ await storyCommand(subcommand, options);
8425
+ }
8426
+ } catch (error) {
8427
+ console.error(error);
8428
+ process.exit(1);
8429
+ }
8430
+ });
7987
8431
  program.command("logout").description("Clear stored credentials").action(async () => {
7988
8432
  try {
7989
8433
  await logoutCommand();