@gitset-dev/cli 2.1.0 → 2.2.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/index.js CHANGED
@@ -17,6 +17,8 @@ function showHelp() {
17
17
 
18
18
  ${theme.bold('First time?')} Run ${theme.accent('gitset config')} — an interactive wizard sets up your AI provider in under a minute.
19
19
 
20
+ ${theme.bold('Found a bug or have a suggestion?')} Run ${theme.accent('gitset feedback')} anytime.
21
+
20
22
  ${theme.bold('AI commands')} (use your own provider key):
21
23
  commit Generate a commit message from staged changes
22
24
  pr Generate a pull-request description from the branch diff
@@ -35,6 +37,7 @@ ${theme.bold('Local tools')} (no AI):
35
37
  status Show git + provider status
36
38
  template Manage local templates (~/.gitset/templates), edit <tool> to customize
37
39
  init Scaffold local templates
40
+ feedback Report a bug, suggest a feature, or share feedback
38
41
 
39
42
  ${theme.bold('Setup')}:
40
43
  config interactive setup wizard
@@ -125,6 +128,9 @@ Manage local templates in ~/.gitset/templates.
125
128
  path print the templates directory`,
126
129
  init: `Usage: gitset init
127
130
  Scaffold the local template directory.`,
131
+ feedback: `Usage: gitset feedback
132
+ Interactively submit a bug report, feature suggestion, or general feedback.
133
+ Filed as a GitHub issue in gitset-dev/gitset via your own \`gh\` auth.`,
128
134
  config: `Usage: gitset config [set|list|remove|theme|path]
129
135
  (no args) interactive setup wizard
130
136
  set interactive wizard, or: set <provider> --key <key> [--model m] [--base-url u] [--default]
@@ -200,6 +206,8 @@ async function main() {
200
206
  code = await require('./src/commands/labelspack').runLabelspackCommand(rest); break;
201
207
  case 'dependabot':
202
208
  code = (await require('./src/commands/dependabot-resolver')(null, rest)) || 0; break;
209
+ case 'feedback':
210
+ code = (await require('./src/commands/feedback')()) || 0; break;
203
211
 
204
212
  case 'auth': case 'verify': case 'logout':
205
213
  code = deprecatedAuth(command); break;
@@ -21,6 +21,8 @@ function create({ apiKey, model, timeoutMs = 60_000 }) {
21
21
  temperature: req.temperature ?? 0.7,
22
22
  ...(req.maxTokens ? { maxOutputTokens: req.maxTokens } : {}),
23
23
  ...(req.system ? { systemInstruction: req.system } : {}),
24
+
25
+ thinkingConfig: { thinkingBudget: req.thinkingBudget ?? 0 },
24
26
  };
25
27
  const ac = req.signal ? { abortSignal: req.signal } : {};
26
28
  return { config: cfg, http: { ...ac, timeout: timeoutMs } };
@@ -14,4 +14,11 @@ function dateAwarenessNote() {
14
14
  'content specifically and verifiably describes a past event.';
15
15
  }
16
16
 
17
- module.exports = { currentDateLine, dateAwarenessNote };
17
+ function constraintAdherenceNote() {
18
+ return 'If the input below contains explicit constraints or exclusions (e.g. "do not ' +
19
+ 'mention X", "do not name Y", a required format, a forbidden word), treat them as hard ' +
20
+ 'requirements — re-check your output against each one before finishing, not just your ' +
21
+ 'first draft.';
22
+ }
23
+
24
+ module.exports = { currentDateLine, dateAwarenessNote, constraintAdherenceNote };
@@ -2,7 +2,7 @@
2
2
  'use strict';
3
3
 
4
4
  const defaults = require('./defaults');
5
- const { dateAwarenessNote } = require('./context');
5
+ const { dateAwarenessNote, constraintAdherenceNote } = require('./context');
6
6
 
7
7
  let _cache = null;
8
8
 
@@ -63,7 +63,7 @@ function getPrompt(key, ctx = {}) {
63
63
  throw new Error(`Prompt "${key}" must return { system: string, user: string }`);
64
64
  }
65
65
 
66
- return { ...out, system: `${out.system}\n\n${dateAwarenessNote()}` };
66
+ return { ...out, system: `${out.system}\n\n${dateAwarenessNote()}\n\n${constraintAdherenceNote()}` };
67
67
  }
68
68
 
69
69
  function toAIRequest(key, ctx = {}, extra = {}) {
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@gitset-dev/cli",
3
- "version": "2.1.0",
3
+ "version": "2.2.0",
4
4
  "description": "Gitset CLI — drafts commits, PRs, issues, READMEs and release notes with your own AI key. Fully local: your code and keys never touch a Gitset server. Draft. Refine. Ship.",
5
5
  "type": "commonjs",
6
6
  "bin": {
@@ -0,0 +1,98 @@
1
+ const { execFileSync } = require('child_process');
2
+ const os = require('os');
3
+ const { log, askQuestion, selectOption } = require('../utils/ui');
4
+
5
+ const REPO = 'gitset-dev/gitset';
6
+
7
+ const TYPE_LABELS = {
8
+ bug: ['user-feedback', 'bug'],
9
+ suggestion: ['user-feedback', 'feature-request'],
10
+ qos: ['user-feedback'],
11
+ };
12
+
13
+ const TYPE_TITLES = {
14
+ bug: 'Bug Report',
15
+ suggestion: 'Feature Suggestion',
16
+ qos: 'Quality of Service Feedback',
17
+ };
18
+
19
+ function ghAvailable() {
20
+ try { execFileSync('gh', ['--version'], { stdio: 'ignore' }); return true; }
21
+ catch { return false; }
22
+ }
23
+
24
+ function ensureLabel(name, color, description) {
25
+ try {
26
+ execFileSync('gh', ['label', 'create', name, '--repo', REPO, '--color', color, '--description', description], { stdio: 'ignore' });
27
+ } catch { }
28
+ }
29
+
30
+ function buildBody(message, tool, version, includeSystemInfo) {
31
+ const lines = [message.trim(), ''];
32
+ if (includeSystemInfo) {
33
+ lines.push(
34
+ '<details>',
35
+ '<summary>Metadata</summary>',
36
+ '',
37
+ '- Source: cli',
38
+ tool ? `- Tool/command: ${tool}` : null,
39
+ `- Version: ${version}`,
40
+ `- OS: ${os.platform()}-${os.arch()}`,
41
+ '',
42
+ '</details>',
43
+ );
44
+ }
45
+ return lines.filter((l) => l !== null).join('\n');
46
+ }
47
+
48
+ module.exports = async function commandFeedback() {
49
+ console.log('\n=== Gitset Feedback ===\n');
50
+
51
+ if (!ghAvailable()) {
52
+ log('The `gh` CLI is required to submit feedback (https://cli.github.com).', 'red');
53
+ return 1;
54
+ }
55
+
56
+ const type = await selectOption('What kind of feedback would you like to share?', [
57
+ { label: 'Bug Report', value: 'bug' },
58
+ { label: 'Feature Suggestion', value: 'suggestion' },
59
+ { label: 'Quality of Service / General Feedback', value: 'qos' },
60
+ ]);
61
+
62
+ let title = '';
63
+ while (!title) {
64
+ title = (await askQuestion('Short title for your feedback: ')).slice(0, 120);
65
+ if (!title) log('A title is required.', 'red');
66
+ }
67
+
68
+ const tool = await askQuestion('Which tool or command does this relate to? (optional): ');
69
+
70
+ let message = '';
71
+ while (!message) {
72
+ message = await askQuestion('Please describe your feedback: ');
73
+ if (!message) log('A description is required.', 'red');
74
+ }
75
+
76
+ const version = require('../../package.json').version;
77
+ const consent = await askQuestion(`May we include your CLI version (${version}) and OS automatically? (Y/n): `);
78
+ const includeSystemInfo = consent.trim().toLowerCase() !== 'n';
79
+
80
+ ensureLabel('user-feedback', 'D4A5A5', 'Submitted via the in-app/CLI feedback tool (issue #20).');
81
+
82
+ const issueTitle = `[${TYPE_TITLES[type]}] ${title}`;
83
+ const body = buildBody(message, tool, version, includeSystemInfo);
84
+ const labels = TYPE_LABELS[type];
85
+
86
+ const args = ['issue', 'create', '--repo', REPO, '--title', issueTitle, '--body', body];
87
+ for (const l of labels) args.push('--label', l);
88
+
89
+ log('\nSubmitting feedback...', 'dim');
90
+ try {
91
+ const url = execFileSync('gh', args, { encoding: 'utf8' }).trim();
92
+ log(`\n✔ Feedback successfully submitted! View your issue here: ${url}`, 'green');
93
+ return 0;
94
+ } catch (e) {
95
+ log('Failed to submit feedback (is `gh` authenticated?).', 'red');
96
+ return 1;
97
+ }
98
+ };