@zaowu-labs/cli 1.0.2 → 1.0.5

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.
Files changed (60) hide show
  1. package/dist/args.d.ts.map +1 -1
  2. package/dist/args.js +10 -13
  3. package/dist/args.js.map +1 -1
  4. package/dist/command-contracts.d.ts +7 -0
  5. package/dist/command-contracts.d.ts.map +1 -1
  6. package/dist/command-contracts.js +57 -36
  7. package/dist/command-contracts.js.map +1 -1
  8. package/dist/handler-utils.d.ts +17 -2
  9. package/dist/handler-utils.d.ts.map +1 -1
  10. package/dist/handler-utils.js +34 -1
  11. package/dist/handler-utils.js.map +1 -1
  12. package/dist/handlers/ai-handlers.d.ts.map +1 -1
  13. package/dist/handlers/ai-handlers.js +28 -20
  14. package/dist/handlers/ai-handlers.js.map +1 -1
  15. package/dist/handlers/auto-handlers.d.ts.map +1 -1
  16. package/dist/handlers/auto-handlers.js +3 -7
  17. package/dist/handlers/auto-handlers.js.map +1 -1
  18. package/dist/handlers/config-handlers.d.ts.map +1 -1
  19. package/dist/handlers/config-handlers.js +12 -21
  20. package/dist/handlers/config-handlers.js.map +1 -1
  21. package/dist/handlers/data-handlers.d.ts.map +1 -1
  22. package/dist/handlers/data-handlers.js +6 -9
  23. package/dist/handlers/data-handlers.js.map +1 -1
  24. package/dist/handlers/dev-handlers.d.ts.map +1 -1
  25. package/dist/handlers/dev-handlers.js +144 -182
  26. package/dist/handlers/dev-handlers.js.map +1 -1
  27. package/dist/handlers/doc-handlers.d.ts.map +1 -1
  28. package/dist/handlers/doc-handlers.js +12 -8
  29. package/dist/handlers/doc-handlers.js.map +1 -1
  30. package/dist/handlers/plugin-handlers.d.ts.map +1 -1
  31. package/dist/handlers/plugin-handlers.js +21 -26
  32. package/dist/handlers/plugin-handlers.js.map +1 -1
  33. package/dist/option-registry.d.ts +16 -0
  34. package/dist/option-registry.d.ts.map +1 -0
  35. package/dist/option-registry.js +84 -0
  36. package/dist/option-registry.js.map +1 -0
  37. package/dist/option-validation.d.ts.map +1 -1
  38. package/dist/option-validation.js +1 -48
  39. package/dist/option-validation.js.map +1 -1
  40. package/dist/root-doctor.d.ts.map +1 -1
  41. package/dist/root-doctor.js +2 -3
  42. package/dist/root-doctor.js.map +1 -1
  43. package/dist/root-help.d.ts +1 -2
  44. package/dist/root-help.d.ts.map +1 -1
  45. package/dist/root-help.js +7 -13
  46. package/dist/root-help.js.map +1 -1
  47. package/dist/root-init.d.ts +2 -1
  48. package/dist/root-init.d.ts.map +1 -1
  49. package/dist/root-init.js +7 -8
  50. package/dist/root-init.js.map +1 -1
  51. package/dist/run.d.ts +0 -1
  52. package/dist/run.d.ts.map +1 -1
  53. package/dist/run.js +42 -24
  54. package/dist/run.js.map +1 -1
  55. package/dist/system-command.d.ts +2 -0
  56. package/dist/system-command.d.ts.map +1 -1
  57. package/dist/system-command.js +2 -1
  58. package/dist/system-command.js.map +1 -1
  59. package/dist/version.js +1 -1
  60. package/package.json +11 -11
@@ -1,5 +1,5 @@
1
1
  import { findConfigPathOrThrow, getResolvedConfigValue, loadResolvedConfig, migrateResolvedConfig, setResolvedConfigValue, validateResolvedConfig, } from '@zaowu-labs/config';
2
- import { assertOperationPlanFingerprint, createContentOperationSubjects, createOperationPlan, formatOperationPlan, hasFlag, requireSecondTarget, requireTarget, result, withOperationPlan, } from '../handler-utils.js';
2
+ import { assertOperationPlanFingerprint, createContentOperationSubjects, createOperationPlan, formatLabeledList, formatOperationPlan, hasFlag, requireSecondTarget, requireTarget, result, withOperationPlan, } from '../handler-utils.js';
3
3
  export const handleConfigPath = async (_args, context) => {
4
4
  const filePath = await findConfigPathOrThrow(context.cwd);
5
5
  const payload = {
@@ -18,7 +18,7 @@ export const handleConfigShow = async (_args, context) => {
18
18
  config: resolved.config,
19
19
  };
20
20
  const human = [
21
- 'ZaoWu Config',
21
+ 'ZaoWu Config Show',
22
22
  '',
23
23
  `File: ${resolved.filePath}`,
24
24
  `Project: ${resolved.config.project.name}`,
@@ -37,9 +37,7 @@ export const handleConfigValidate = async (_args, context) => {
37
37
  `Status: ${validation.status}`,
38
38
  `File: ${validation.filePath}`,
39
39
  '',
40
- validation.warnings.length > 0
41
- ? ['Warnings:', ...validation.warnings.map((warning) => `- ${warning}`)].join('\n')
42
- : 'Warnings: none',
40
+ formatLabeledList('Warnings', validation.warnings),
43
41
  ].join('\n');
44
42
  return result(context, validation, human);
45
43
  };
@@ -58,10 +56,11 @@ export const handleConfigSet = async (args, context) => {
58
56
  const key = requireTarget(args, 'zw config set');
59
57
  const value = requireSecondTarget(args, 'zw config set', 'value');
60
58
  const isGlobal = hasFlag(context.parsed, '--global');
61
- const preview = await setResolvedConfigValue(key, value, {
62
- cwd: context.cwd,
63
- global: isGlobal,
64
- });
59
+ // One options object for both the preview and the confirmed call: the
60
+ // fingerprint the user confirms is computed from the preview, so the two
61
+ // calls must be structurally unable to drift apart.
62
+ const setOptions = { cwd: context.cwd, global: isGlobal };
63
+ const preview = await setResolvedConfigValue(key, value, setOptions);
65
64
  const operationPlan = createOperationPlan({
66
65
  risk: 'medium',
67
66
  confirmationRequired: !context.yes,
@@ -77,11 +76,7 @@ export const handleConfigSet = async (args, context) => {
77
76
  });
78
77
  assertOperationPlanFingerprint(context, operationPlan);
79
78
  const updated = context.yes
80
- ? await setResolvedConfigValue(key, value, {
81
- cwd: context.cwd,
82
- yes: true,
83
- global: isGlobal,
84
- })
79
+ ? await setResolvedConfigValue(key, value, { ...setOptions, yes: true })
85
80
  : preview;
86
81
  const human = [
87
82
  'ZaoWu Config Set',
@@ -100,9 +95,8 @@ export const handleConfigSet = async (args, context) => {
100
95
  return result(context, withOperationPlan(updated, operationPlan), human);
101
96
  };
102
97
  export const handleConfigMigrate = async (_args, context) => {
103
- const preview = await migrateResolvedConfig({
104
- cwd: context.cwd,
105
- });
98
+ const migrateOptions = { cwd: context.cwd };
99
+ const preview = await migrateResolvedConfig(migrateOptions);
106
100
  const operationPlan = createOperationPlan({
107
101
  risk: 'medium',
108
102
  confirmationRequired: preview.changed && !context.yes,
@@ -116,10 +110,7 @@ export const handleConfigMigrate = async (_args, context) => {
116
110
  });
117
111
  assertOperationPlanFingerprint(context, operationPlan);
118
112
  const migrated = context.yes && preview.changed
119
- ? await migrateResolvedConfig({
120
- cwd: context.cwd,
121
- yes: true,
122
- })
113
+ ? await migrateResolvedConfig({ ...migrateOptions, yes: true })
123
114
  : preview;
124
115
  const human = [
125
116
  'ZaoWu Config Migrate',
@@ -1 +1 @@
1
- {"version":3,"file":"config-handlers.js","sourceRoot":"","sources":["../../src/handlers/config-handlers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"config-handlers.js","sourceRoot":"","sources":["../../src/handlers/config-handlers.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"data-handlers.d.ts","sourceRoot":"","sources":["../../src/handlers/data-handlers.ts"],"names":[],"mappings":"AAQA,OAAO,EAYL,KAAK,mBAAmB,EACzB,MAAM,qBAAqB,CAAC;AAE7B,eAAO,MAAM,iBAAiB,EAAE,mBAgB/B,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,mBAkB/B,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,mBA8D7B,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,mBAgB9B,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,mBAgB9B,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,mBAY9B,CAAC"}
1
+ {"version":3,"file":"data-handlers.d.ts","sourceRoot":"","sources":["../../src/handlers/data-handlers.ts"],"names":[],"mappings":"AAQA,OAAO,EAYL,KAAK,mBAAmB,EACzB,MAAM,qBAAqB,CAAC;AAE7B,eAAO,MAAM,iBAAiB,EAAE,mBAgB/B,CAAC;AAEF,eAAO,MAAM,iBAAiB,EAAE,mBAkB/B,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,mBA2D7B,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,mBAgB9B,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,mBAgB9B,CAAC;AAEF,eAAO,MAAM,gBAAgB,EAAE,mBAY9B,CAAC"}
@@ -35,10 +35,11 @@ export const handleDataClean = async (args, context) => {
35
35
  const target = requireTarget(args, 'zw data clean');
36
36
  const outputPath = getValue(context.parsed, '--output');
37
37
  const sheet = getValue(context.parsed, '--sheet');
38
- const preview = await cleanData(target, {
39
- outputPath,
40
- sheet,
41
- });
38
+ // One options object for both the preview and the confirmed call: the
39
+ // fingerprint the user confirms is computed from the preview, so the two
40
+ // calls must be structurally unable to drift apart.
41
+ const cleanOptions = { outputPath, sheet };
42
+ const preview = await cleanData(target, cleanOptions);
42
43
  const operationPlan = createOperationPlan({
43
44
  risk: preview.outputPath ? 'medium' : 'low',
44
45
  confirmationRequired: Boolean(preview.outputPath && !context.yes),
@@ -53,11 +54,7 @@ export const handleDataClean = async (args, context) => {
53
54
  });
54
55
  assertOperationPlanFingerprint(context, operationPlan);
55
56
  const cleaned = context.yes && preview.outputPath
56
- ? await cleanData(target, {
57
- outputPath,
58
- sheet,
59
- yes: true,
60
- })
57
+ ? await cleanData(target, { ...cleanOptions, yes: true })
61
58
  : preview;
62
59
  const confirmCommand = preview.outputPath && !context.yes
63
60
  ? formatConfirmCommand([
@@ -1 +1 @@
1
- {"version":3,"file":"data-handlers.js","sourceRoot":"","sources":["../../src/handlers/data-handlers.ts"],"names":[],"mappings":"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"}
1
+ {"version":3,"file":"data-handlers.js","sourceRoot":"","sources":["../../src/handlers/data-handlers.ts"],"names":[],"mappings":"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"}
@@ -1 +1 @@
1
- {"version":3,"file":"dev-handlers.d.ts","sourceRoot":"","sources":["../../src/handlers/dev-handlers.ts"],"names":[],"mappings":"AAiBA,OAAO,EAYL,KAAK,mBAAmB,EAGzB,MAAM,qBAAqB,CAAC;AAsF7B,eAAO,MAAM,eAAe,EAAE,mBA4E7B,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,mBA0H7B,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,mBA2B7B,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,mBA6C3B,CAAC"}
1
+ {"version":3,"file":"dev-handlers.d.ts","sourceRoot":"","sources":["../../src/handlers/dev-handlers.ts"],"names":[],"mappings":"AAYA,OAAO,EAcL,KAAK,mBAAmB,EAIzB,MAAM,qBAAqB,CAAC;AA2F7B,eAAO,MAAM,eAAe,EAAE,mBA2E7B,CAAC;AAgBF,eAAO,MAAM,eAAe,EAAE,mBAuF7B,CAAC;AAEF,eAAO,MAAM,eAAe,EAAE,mBA2B7B,CAAC;AAEF,eAAO,MAAM,aAAa,EAAE,mBA+C3B,CAAC"}
@@ -1,153 +1,153 @@
1
- import { askAI, resolveAIModel, resolveAIProviderNetworkTarget, validateAIProviderConfig, } from '@zaowu-labs/ai';
2
- import { loadResolvedConfig } from '@zaowu-labs/config';
3
- import { getDevStatus, isDevFindingCategory, isDevFindingPriority, isDevFindingSeverity, previewDevCommit, reviewDevChanges, syncDevRepo, } from '@zaowu-labs/dev';
4
- import { assertOperationPlanFingerprint, createOperationPlan, formatCounts, formatFinding, formatList, formatOperationPlan, getValue, hasFlag, result, withOperationPlan, ZaoWuError, } from '../handler-utils.js';
5
- const getAiReviewOrCommit = async (context, prompt) => {
6
- let providerId = getValue(context.parsed, '--provider');
7
- if (!providerId) {
8
- try {
9
- const config = await loadResolvedConfig(context.cwd);
10
- providerId = config.config.ai.provider ?? undefined;
11
- }
12
- catch {
13
- // ignore — fall back to default provider
14
- }
15
- }
16
- const requestedModel = getValue(context.parsed, '--model');
17
- const providerValidation = validateAIProviderConfig(providerId);
18
- const provider = providerValidation.provider;
19
- const resolvedModel = resolveAIModel(provider, { model: requestedModel });
20
- if (provider.network && !context.yes) {
21
- throw new ZaoWuError({
22
- code: 'AI_NETWORK_CONFIRMATION_REQUIRED',
23
- message: 'Network AI request requires confirmation.',
24
- why: `The AI-assisted dev command sends diff context to the network provider \`${provider.id}\`.`,
25
- fix: 'Run the command with the `--yes` flag to confirm sending the diff context.',
26
- });
27
- }
28
- const response = await askAI({
29
- prompt,
30
- provider: providerId,
31
- model: requestedModel,
32
- allowNetwork: context.yes,
33
- });
34
- return {
35
- output: response.output,
36
- providerId: provider.id,
37
- modelName: resolvedModel,
38
- };
39
- };
40
- const getGitDiffText = (commandRunner, cwd, gitArgs) => {
41
- let diffText = '';
1
+ import { askAI } from '@zaowu-labs/ai';
2
+ import { applyDevAiCommitSuggestion, buildDevAiCommitPrompt, buildDevAiReviewPrompt, getDevStatus, parseDevAiReviewFindings, previewDevCommit, reviewDevChanges, syncDevRepo, } from '@zaowu-labs/dev';
3
+ import { assertOperationPlanFingerprint, createContentOperationSubjects, createOperationPlan, formatConfirmCommand, formatCounts, formatFinding, formatList, formatOperationPlan, hasFlag, resolveAiProvider, result, withOperationPlan, ZaoWuError, } from '../handler-utils.js';
4
+ const getGitDiffText = (context, gitArgs) => {
42
5
  try {
43
- diffText = commandRunner('git', gitArgs, { cwd });
6
+ return context.commandRunner('git', gitArgs, { cwd: context.cwd });
44
7
  }
45
8
  catch {
46
9
  // ignore — diff may be empty
10
+ return '';
47
11
  }
48
- if (diffText.length > 100000) {
49
- diffText = diffText.slice(0, 100000) + '\n... [truncated] ...';
50
- }
51
- return diffText;
52
12
  };
53
- const buildAiOperationPlan = (providerId, reviewUsesWorktree, isReview) => {
54
- const provider = validateAIProviderConfig(providerId).provider;
55
- const networkTarget = provider.network ? resolveAIProviderNetworkTarget(providerId) : undefined;
56
- const actionName = isReview ? 'review' : 'suggestion';
13
+ /**
14
+ * Operation plan for an AI-assisted dev command. The exact prompt (instructions
15
+ * plus the truncated diff) is folded into the plan subjects, so the preview
16
+ * fingerprint only authorizes a confirmed run that sends identical content —
17
+ * a diff staged between preview and confirm invalidates the plan.
18
+ */
19
+ const buildAiOperationPlan = (ai, prompt, context, options) => {
20
+ const actionName = options.isReview ? 'review' : 'suggestion';
57
21
  return createOperationPlan({
58
- risk: provider.network ? 'medium' : 'low',
59
- reads: isReview
60
- ? reviewUsesWorktree
22
+ risk: ai.provider.network ? 'medium' : 'low',
23
+ confirmationRequired: ai.provider.network && !context.yes,
24
+ subjects: [
25
+ `ai:${ai.providerId}`,
26
+ `model:${ai.resolvedModel}`,
27
+ ...createContentOperationSubjects(prompt),
28
+ ],
29
+ reads: options.isReview
30
+ ? options.reviewUsesWorktree
61
31
  ? ['working-tree git diff', 'untracked git file list']
62
32
  : ['staged git diff']
63
33
  : ['staged git diff', 'staged git diff hunks'],
64
- executes: isReview
65
- ? reviewUsesWorktree
34
+ executes: options.isReview
35
+ ? options.reviewUsesWorktree
66
36
  ? ['git diff', 'git ls-files --others --exclude-standard']
67
37
  : ['git diff --cached']
68
38
  : ['git diff --cached'],
69
- network: networkTarget ? [networkTarget] : [],
70
- secrets: provider.requiredEnv,
71
- notes: [`AI ${actionName} was generated using the ${providerId} provider.`],
39
+ network: ai.networkTarget ? [ai.networkTarget] : [],
40
+ secrets: ai.provider.requiredEnv,
41
+ notes: [
42
+ ai.provider.network
43
+ ? `AI ${actionName} sends the diff context to the ${ai.providerId} provider and requires --yes.`
44
+ : `AI ${actionName} was generated using the ${ai.providerId} provider.`,
45
+ ],
72
46
  });
73
47
  };
48
+ const buildAiConfirmCommand = (commandParts, ai, operationPlan) => formatConfirmCommand([
49
+ ...commandParts,
50
+ '--ai',
51
+ '--provider',
52
+ ai.providerId,
53
+ ...(ai.requestedModel ? ['--model', ai.requestedModel] : []),
54
+ '--yes',
55
+ '--plan-fingerprint',
56
+ operationPlan.fingerprint,
57
+ ]);
58
+ const formatAiPreviewHuman = (title, ai, operationPlan, confirmCommand) => [
59
+ title,
60
+ '',
61
+ 'Status: preview',
62
+ `Provider: ${ai.providerId} (${ai.provider.name})`,
63
+ `Model: ${ai.resolvedModel}`,
64
+ `Endpoint: ${ai.networkTarget ?? 'local'}`,
65
+ '',
66
+ formatOperationPlan(operationPlan),
67
+ '',
68
+ 'No provider request was sent.',
69
+ '',
70
+ 'To send exactly this AI request, run:',
71
+ ` ${confirmCommand}`,
72
+ ].join('\n');
74
73
  export const handleDevCommit = async (_args, context) => {
75
74
  const preview = previewDevCommit(context.commandRunner, { cwd: context.cwd });
75
+ let payload = preview;
76
76
  let operationPlan = createOperationPlan({
77
77
  risk: 'low',
78
78
  reads: ['staged git diff', 'staged git diff hunks'],
79
79
  executes: ['git diff --cached'],
80
80
  notes: ['No Git state is modified.'],
81
81
  });
82
- if (context.parsed.flags.has('--ai')) {
83
- const diffText = getGitDiffText(context.commandRunner, context.cwd, ['diff', '--cached']);
84
- const prompt = [
85
- 'Generate a Conventional Commit message for the following staged changes.',
86
- 'Follow the Conventional Commits specification (e.g. feat(scope): message).',
87
- 'Respond ONLY with the commit message, including a title and an optional body/footer.',
88
- '',
89
- 'Changes:',
90
- diffText,
91
- ].join('\n');
92
- const aiResponse = await getAiReviewOrCommit(context, prompt);
93
- const lines = aiResponse.output
94
- .split(/\r?\n/)
95
- .map((l) => l.trim())
96
- .filter(Boolean);
97
- const title = lines[0] || preview.suggestion.title;
98
- const body = lines.slice(1);
99
- const match = /^([a-z0-9]+)(?:\(([^)]+)\))?:\s*(.+)$/i.exec(title);
100
- const type = match?.[1] || preview.suggestion.type;
101
- const scope = match?.[2] || preview.suggestion.scope;
102
- const subject = match?.[3] || preview.suggestion.subject;
103
- preview.suggestion = {
104
- type,
105
- scope,
106
- subject,
107
- title,
108
- body: body.length > 0 ? body : preview.suggestion.body,
109
- };
110
- preview.message = title;
111
- operationPlan = buildAiOperationPlan(aiResponse.providerId, false, false);
82
+ if (hasFlag(context.parsed, '--ai')) {
83
+ const diffText = getGitDiffText(context, ['diff', '--cached']);
84
+ const prompt = buildDevAiCommitPrompt(diffText);
85
+ const ai = await resolveAiProvider(context);
86
+ operationPlan = buildAiOperationPlan(ai, prompt, context, {
87
+ isReview: false,
88
+ reviewUsesWorktree: false,
89
+ });
90
+ if (ai.provider.network && !context.yes) {
91
+ const confirmCommand = buildAiConfirmCommand(['zw', 'dev', 'commit'], ai, operationPlan);
92
+ const human = formatAiPreviewHuman('ZaoWu Dev Commit', ai, operationPlan, confirmCommand);
93
+ return result(context, withOperationPlan({ ...preview, status: 'preview' }, operationPlan), human);
94
+ }
95
+ // The fingerprint must be verified before any provider request is sent.
96
+ assertOperationPlanFingerprint(context, operationPlan);
97
+ const response = await askAI({
98
+ prompt,
99
+ provider: ai.providerId,
100
+ model: ai.requestedModel,
101
+ allowNetwork: context.yes,
102
+ });
103
+ payload = applyDevAiCommitSuggestion(preview, response.output);
104
+ }
105
+ else {
106
+ assertOperationPlanFingerprint(context, operationPlan);
112
107
  }
113
- assertOperationPlanFingerprint(context, operationPlan);
114
108
  const human = [
115
109
  'ZaoWu Dev Commit',
116
110
  '',
117
111
  'No Git state was modified.',
118
112
  '',
119
- `Files: ${preview.summary.files.length}`,
120
- `Changes: +${preview.summary.additions}/-${preview.summary.deletions}`,
113
+ `Files: ${payload.summary.files.length}`,
114
+ `Changes: +${payload.summary.additions}/-${payload.summary.deletions}`,
121
115
  '',
122
116
  'Categories:',
123
- formatCounts(preview.summary.categories),
117
+ formatCounts(payload.summary.categories),
124
118
  '',
125
119
  'Suggested commit:',
126
- preview.message,
120
+ payload.message,
127
121
  '',
128
122
  'Suggested body:',
129
- formatList(preview.suggestion.body),
123
+ formatList(payload.suggestion.body),
130
124
  '',
131
125
  'Findings:',
132
- ...(preview.findings.length > 0
133
- ? preview.findings.map((finding) => formatFinding(finding))
126
+ ...(payload.findings.length > 0
127
+ ? payload.findings.map((finding) => formatFinding(finding))
134
128
  : ['- none']),
135
129
  '',
136
130
  'Recommended checks:',
137
- formatList(preview.recommendedChecks),
131
+ formatList(payload.recommendedChecks),
138
132
  '',
139
133
  formatOperationPlan(operationPlan),
140
134
  ].join('\n');
141
- return result(context, withOperationPlan(preview, operationPlan), human);
135
+ return result(context, withOperationPlan(payload, operationPlan), human);
136
+ };
137
+ const resolveReviewMode = (context) => {
138
+ if (hasFlag(context.parsed, '--staged')) {
139
+ return { mode: 'staged', modeFlags: ['--staged'] };
140
+ }
141
+ if (hasFlag(context.parsed, '--worktree')) {
142
+ return { mode: 'worktree', modeFlags: ['--worktree'] };
143
+ }
144
+ return { mode: 'auto', modeFlags: [] };
142
145
  };
143
146
  export const handleDevReview = async (_args, context) => {
144
- const mode = context.parsed.flags.has('--staged')
145
- ? 'staged'
146
- : context.parsed.flags.has('--worktree')
147
- ? 'worktree'
148
- : 'auto';
147
+ const { mode, modeFlags } = resolveReviewMode(context);
149
148
  const review = reviewDevChanges(context.commandRunner, { cwd: context.cwd, mode });
150
149
  const reviewUsesWorktree = review.source === 'working-tree';
150
+ let payload = review;
151
151
  let operationPlan = createOperationPlan({
152
152
  risk: 'low',
153
153
  reads: reviewUsesWorktree
@@ -158,100 +158,60 @@ export const handleDevReview = async (_args, context) => {
158
158
  : ['git diff --cached'],
159
159
  notes: ['No Git state is modified.'],
160
160
  });
161
- if (context.parsed.flags.has('--ai')) {
161
+ if (hasFlag(context.parsed, '--ai')) {
162
162
  const gitArgs = reviewUsesWorktree ? ['diff'] : ['diff', '--cached'];
163
- const diffText = getGitDiffText(context.commandRunner, context.cwd, gitArgs);
164
- const prompt = [
165
- 'Perform a code review of the following Git changes.',
166
- 'Find potential security vulnerabilities, performance issues, architectural flaws, bugs, or test gaps.',
167
- 'Format your review as a JSON array of finding objects, like this:',
168
- '[',
169
- ' {',
170
- ' "severity": "info" | "warning",',
171
- ' "priority": "low" | "medium" | "high",',
172
- ' "category": "security" | "performance" | "quality" | "test" | "filesystem" | "network" | "git",',
173
- ' "title": "Short title",',
174
- ' "detail": "Detailed explanation of the issue and fix.",',
175
- ' "filePath": "relative/path/to/file",',
176
- ' "line": 123,',
177
- ' "hunkHeader": "@@ ... @@"',
178
- ' }',
179
- ']',
180
- 'Respond ONLY with the JSON array. Do not wrap in markdown code blocks.',
181
- '',
182
- 'Changes:',
183
- diffText,
184
- ].join('\n');
185
- const aiResponse = await getAiReviewOrCommit(context, prompt);
186
- let cleanOutput = aiResponse.output.trim();
187
- if (cleanOutput.startsWith('```')) {
188
- cleanOutput = cleanOutput.replace(/^```[a-z]*\r?\n/, '').replace(/\r?\n```$/, '');
189
- }
190
- let aiFindings = [];
191
- let isParsedArray = false;
192
- try {
193
- const parsed = JSON.parse(cleanOutput);
194
- if (Array.isArray(parsed)) {
195
- aiFindings = parsed;
196
- isParsedArray = true;
197
- }
198
- }
199
- catch {
200
- // Fall back to wrapping the raw AI output as a plain-text summary finding.
201
- }
202
- if (!isParsedArray) {
203
- aiFindings = [
204
- {
205
- severity: 'info',
206
- priority: 'medium',
207
- category: 'quality',
208
- title: 'AI Code Review Summary',
209
- detail: aiResponse.output.trim(),
210
- },
211
- ];
212
- }
213
- for (const item of aiFindings) {
214
- const finding = item && typeof item === 'object' ? item : {};
215
- review.findings.push({
216
- severity: isDevFindingSeverity(finding.severity) ? finding.severity : 'info',
217
- priority: isDevFindingPriority(finding.priority) ? finding.priority : 'medium',
218
- category: isDevFindingCategory(finding.category) ? finding.category : 'quality',
219
- title: typeof finding.title === 'string' ? finding.title : 'AI Review',
220
- detail: typeof finding.detail === 'string' ? finding.detail : '',
221
- filePath: typeof finding.filePath === 'string' ? finding.filePath : undefined,
222
- line: Number.isInteger(finding.line) && Number(finding.line) > 0
223
- ? Number(finding.line)
224
- : undefined,
225
- hunkHeader: typeof finding.hunkHeader === 'string' ? finding.hunkHeader : undefined,
226
- });
163
+ const diffText = getGitDiffText(context, gitArgs);
164
+ const prompt = buildDevAiReviewPrompt(diffText);
165
+ const ai = await resolveAiProvider(context);
166
+ operationPlan = buildAiOperationPlan(ai, prompt, context, {
167
+ isReview: true,
168
+ reviewUsesWorktree,
169
+ });
170
+ if (ai.provider.network && !context.yes) {
171
+ const confirmCommand = buildAiConfirmCommand(['zw', 'dev', 'review', ...modeFlags], ai, operationPlan);
172
+ const human = formatAiPreviewHuman('ZaoWu Dev Review', ai, operationPlan, confirmCommand);
173
+ return result(context, withOperationPlan({ ...review, status: 'preview' }, operationPlan), human);
227
174
  }
228
- operationPlan = buildAiOperationPlan(aiResponse.providerId, reviewUsesWorktree, true);
175
+ // The fingerprint must be verified before any provider request is sent.
176
+ assertOperationPlanFingerprint(context, operationPlan);
177
+ const response = await askAI({
178
+ prompt,
179
+ provider: ai.providerId,
180
+ model: ai.requestedModel,
181
+ allowNetwork: context.yes,
182
+ });
183
+ payload = {
184
+ ...review,
185
+ findings: [...review.findings, ...parseDevAiReviewFindings(response.output)],
186
+ };
187
+ }
188
+ else {
189
+ assertOperationPlanFingerprint(context, operationPlan);
229
190
  }
230
- assertOperationPlanFingerprint(context, operationPlan);
231
191
  const human = [
232
192
  'ZaoWu Dev Review',
233
193
  '',
234
- `Source: ${review.source}`,
235
- `Files: ${review.summary.files.length}`,
236
- `Changes: +${review.summary.additions}/-${review.summary.deletions}`,
194
+ `Source: ${payload.source}`,
195
+ `Files: ${payload.summary.files.length}`,
196
+ `Changes: +${payload.summary.additions}/-${payload.summary.deletions}`,
237
197
  '',
238
198
  'Categories:',
239
- formatCounts(review.summary.categories),
199
+ formatCounts(payload.summary.categories),
240
200
  '',
241
201
  'Findings:',
242
- ...review.findings.map((finding) => formatFinding(finding)),
202
+ ...payload.findings.map((finding) => formatFinding(finding)),
243
203
  '',
244
204
  'Diff hunks:',
245
- ...(review.diffHunks.length > 0
246
- ? review.diffHunks.map((hunk) => `- ${hunk.filePath} ${hunk.header}: +${hunk.addedLines}/-${hunk.removedLines}`)
205
+ ...(payload.diffHunks.length > 0
206
+ ? payload.diffHunks.map((hunk) => `- ${hunk.filePath} ${hunk.header}: +${hunk.addedLines}/-${hunk.removedLines}`)
247
207
  : ['- none']),
248
208
  '',
249
209
  'Recommended checks:',
250
- formatList(review.recommendedChecks),
210
+ formatList(payload.recommendedChecks),
251
211
  '',
252
212
  formatOperationPlan(operationPlan),
253
213
  ].join('\n');
254
- return result(context, withOperationPlan(review, operationPlan), human);
214
+ return result(context, withOperationPlan(payload, operationPlan), human);
255
215
  };
256
216
  export const handleDevStatus = async (_args, context) => {
257
217
  const status = getDevStatus(context.commandRunner, { cwd: context.cwd });
@@ -297,13 +257,15 @@ export const handleDevSync = async (_args, context) => {
297
257
  : preview;
298
258
  const operationPlan = syncResult.operationPlan ?? preview.operationPlan;
299
259
  const requiresDiscardLocal = operationPlan.notes.some((note) => note.includes('Confirmed sync requires both --yes and --discard-local'));
300
- const confirmCommand = [
301
- 'zw dev sync',
260
+ const confirmCommand = formatConfirmCommand([
261
+ 'zw',
262
+ 'dev',
263
+ 'sync',
302
264
  '--yes',
303
265
  ...(requiresDiscardLocal ? ['--discard-local'] : []),
304
266
  '--plan-fingerprint',
305
267
  operationPlan.fingerprint,
306
- ].join(' ');
268
+ ]);
307
269
  const human = [
308
270
  'ZaoWu Dev Sync',
309
271
  '',