create-quiver 0.17.0 → 0.17.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/CHANGELOG.md CHANGED
@@ -40,6 +40,10 @@ All notable changes to this project will be documented in this file.
40
40
  - CLI output now follows the shared Quiver palette and hierarchy while keeping `--json`, CI, no-TTY, and `--no-color` output clean.
41
41
  - Command docs now cover human-vs-machine output, selectors, Doctor output, and cross-platform usage.
42
42
 
43
+ ### Fixed
44
+
45
+ - `ai analyze-project` now shows human TTY progress while provider analysis runs and reports schema validation issues with actionable detail.
46
+
43
47
  ## [0.14.1] - 2026-05-26
44
48
 
45
49
  ### Added
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "create-quiver",
3
- "version": "0.17.0",
3
+ "version": "0.17.1",
4
4
  "private": false,
5
5
  "description": "Quiver CLI for scaffolding projects from the packaged template",
6
6
  "license": "MIT",
@@ -165,6 +165,46 @@ function limitList(items, maxItems = 30) {
165
165
  };
166
166
  }
167
167
 
168
+ function formatAnalyzeProjectIssues(issues = [], maxIssues = 8) {
169
+ const list = Array.isArray(issues) ? issues : [];
170
+ const visible = list.slice(0, maxIssues);
171
+ const lines = visible.map((issue) => {
172
+ const location = issue.path || 'analysis';
173
+ const code = issue.issue || 'invalid';
174
+ const message = issue.message || 'Invalid provider analysis output.';
175
+ return `- ${location}: ${code} - ${message}`;
176
+ });
177
+ const hidden = list.length - visible.length;
178
+ if (hidden > 0) {
179
+ lines.push(`- ... ${hidden} more issue${hidden === 1 ? '' : 's'}`);
180
+ }
181
+ return lines;
182
+ }
183
+
184
+ function enhanceAnalyzeProjectAnalysisError(error) {
185
+ if (!error || error.code !== 'AI_ANALYZE_PROJECT_INVALID') {
186
+ return error;
187
+ }
188
+
189
+ const issueLines = formatAnalyzeProjectIssues(error.issues);
190
+ if (issueLines.length === 0) {
191
+ return error;
192
+ }
193
+
194
+ const wrapped = new Error([
195
+ error.message,
196
+ 'Issues:',
197
+ ...issueLines,
198
+ 'Next safe step: inspect the selected evidence with `npx create-quiver ai analyze-project --deep --dry-run --json`, then rerun live. If provider drift repeats, reduce --max-files or --max-bytes.',
199
+ ].join('\n'));
200
+ wrapped.name = error.name;
201
+ wrapped.code = error.code;
202
+ wrapped.cause = error;
203
+ wrapped.issues = error.issues;
204
+ wrapped.details = error.issues;
205
+ return wrapped;
206
+ }
207
+
168
208
  function formatAnalyzeProjectFileLine(file) {
169
209
  const details = [];
170
210
  if (Array.isArray(file.signals) && file.signals.length > 0) {
@@ -1883,6 +1923,9 @@ async function runAnalyzeProject(repoRoot, options = {}) {
1883
1923
  const runtimeProfile = resolveRuntimeAgentProfile(repoRoot, role, options, DEFAULT_PLAN_PROVIDER);
1884
1924
  const provider = runtimeProfile.provider;
1885
1925
  const timeoutMs = normalizeTimeout(options.timeout);
1926
+ const ux = createCommandUx(options);
1927
+ const showProgress = shouldShowHumanProgress(ux, options);
1928
+ const progressTranslator = createTranslator(options.language);
1886
1929
  const promptPackage = buildAnalyzeProjectPrompt({
1887
1930
  analysisPlan: report,
1888
1931
  repoRoot,
@@ -1893,6 +1936,17 @@ async function runAnalyzeProject(repoRoot, options = {}) {
1893
1936
  const promptLimit = assertProviderPromptWithinLimit(prompt, options.promptLimitOptions || {});
1894
1937
  const privacyPreflight = promptPackage.privacyPreflight;
1895
1938
 
1939
+ writeProgressChecks(
1940
+ ux,
1941
+ showProgress,
1942
+ plannerProgressTitle(progressTranslator.t('ai.planner.progress.analyze_project'), runtimeProfile, options),
1943
+ [
1944
+ progressTranslator.t('ai.planner.progress.reading_base_docs'),
1945
+ progressTranslator.t('ai.planner.progress.detecting_structure'),
1946
+ progressTranslator.t('ai.planner.progress.preparing_prompt'),
1947
+ ],
1948
+ );
1949
+
1896
1950
  if (!privacyPreflight.ok) {
1897
1951
  const error = new Error(formatError('ai analyze-project privacy preflight failed; provider execution was blocked before sending repository content.'));
1898
1952
  error.code = 'AI_ANALYZE_PROJECT_PRIVACY_PREFLIGHT_FAILED';
@@ -1931,18 +1985,25 @@ async function runAnalyzeProject(repoRoot, options = {}) {
1931
1985
 
1932
1986
  let result;
1933
1987
  try {
1934
- result = await (options.runProviderFn || runProvider)(provider, {
1935
- prompt,
1936
- cwd: repoRoot,
1937
- timeoutMs,
1938
- dryRun: false,
1939
- probe: options.probe,
1940
- spawn: options.spawn,
1941
- tempRoot: options.tempRoot,
1942
- tempFileName: options.tempFileName,
1943
- tempFilePrefix: options.tempFilePrefix,
1944
- ...runtimeModelExecutionOptions(runtimeProfile, options),
1945
- enforceModelSelection: false,
1988
+ result = await runProviderWithProgress({
1989
+ ux,
1990
+ enabled: showProgress,
1991
+ message: progressTranslator.t('ai.planner.progress.running_agent'),
1992
+ successMessage: progressTranslator.t('ai.planner.progress.agent_finished'),
1993
+ failureMessage: progressTranslator.t('ai.planner.progress.agent_failed'),
1994
+ run: () => (options.runProviderFn || runProvider)(provider, {
1995
+ prompt,
1996
+ cwd: repoRoot,
1997
+ timeoutMs,
1998
+ dryRun: false,
1999
+ probe: options.probe,
2000
+ spawn: options.spawn,
2001
+ tempRoot: options.tempRoot,
2002
+ tempFileName: options.tempFileName,
2003
+ tempFilePrefix: options.tempFilePrefix,
2004
+ ...runtimeModelExecutionOptions(runtimeProfile, options),
2005
+ enforceModelSelection: false,
2006
+ }),
1946
2007
  });
1947
2008
  } catch (error) {
1948
2009
  throw annotateProviderError(error, 'analyze-project');
@@ -1953,10 +2014,15 @@ async function runAnalyzeProject(repoRoot, options = {}) {
1953
2014
  }
1954
2015
 
1955
2016
  const clean = extractCleanProviderOutput(result, { prompt, projectRoot: repoRoot });
1956
- const parsed = parseAnalyzeProjectOutput(clean.cleanOutput, {
1957
- selectedFiles: report.selected_files,
1958
- promptFiles: promptPackage.files,
1959
- });
2017
+ let parsed;
2018
+ try {
2019
+ parsed = parseAnalyzeProjectOutput(clean.cleanOutput, {
2020
+ selectedFiles: report.selected_files,
2021
+ promptFiles: promptPackage.files,
2022
+ });
2023
+ } catch (error) {
2024
+ throw enhanceAnalyzeProjectAnalysisError(error);
2025
+ }
1960
2026
  const completedReport = {
1961
2027
  ...report,
1962
2028
  provider,
@@ -272,6 +272,7 @@ module.exports = {
272
272
  'ai.plan.with_planner_already_active': 'Planner mode: already active for ai plan; --with-planner is accepted for UX consistency.',
273
273
  'ai.planner.progress.agent_failed': 'Agent failed',
274
274
  'ai.planner.progress.agent_finished': 'Agent finished',
275
+ 'ai.planner.progress.analyze_project': 'Analyzing project',
275
276
  'ai.planner.progress.detecting_structure': 'Detecting structure',
276
277
  'ai.planner.progress.onboarding': 'Running onboarding',
277
278
  'ai.planner.progress.plan': 'Running plan {phase}',
@@ -387,6 +387,7 @@ module.exports = {
387
387
  'ai.plan.with_planner_already_active': 'Modo planner: ya esta activo para ai plan; --with-planner se acepta por consistencia de UX.',
388
388
  'ai.planner.progress.agent_failed': 'Fallo el agente',
389
389
  'ai.planner.progress.agent_finished': 'Agente finalizado',
390
+ 'ai.planner.progress.analyze_project': 'Analizando proyecto',
390
391
  'ai.planner.progress.detecting_structure': 'Detectando estructura',
391
392
  'ai.planner.progress.onboarding': 'Ejecutando onboarding',
392
393
  'ai.planner.progress.plan': 'Ejecutando plan {phase}',