sequant 1.18.0 → 1.20.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.
@@ -1,7 +1,7 @@
1
1
  {
2
2
  "name": "sequant",
3
3
  "description": "Structured workflow system for Claude Code - GitHub issue resolution with spec, exec, test, and QA phases",
4
- "version": "1.18.0",
4
+ "version": "1.20.0",
5
5
  "author": {
6
6
  "name": "sequant-io",
7
7
  "email": "hello@sequant.io"
package/README.md CHANGED
@@ -49,7 +49,7 @@ Or step-by-step:
49
49
  - Git (for worktree-based isolation)
50
50
 
51
51
  **For npm installation:**
52
- - Node.js 18+
52
+ - Node.js 20+
53
53
 
54
54
  **Optional MCP servers (enhanced features):**
55
55
  - `chrome-devtools` — enables `/test` for browser-based UI testing
package/dist/bin/cli.js CHANGED
@@ -45,6 +45,7 @@ import { dashboardCommand } from "../src/commands/dashboard.js";
45
45
  import { stateInitCommand, stateRebuildCommand, stateCleanCommand, } from "../src/commands/state.js";
46
46
  import { syncCommand, areSkillsOutdated } from "../src/commands/sync.js";
47
47
  import { mergeCommand } from "../src/commands/merge.js";
48
+ import { conventionsCommand } from "../src/commands/conventions.js";
48
49
  import { getManifest } from "../src/lib/manifest.js";
49
50
  const program = new Command();
50
51
  // Handle --no-color before parsing
@@ -159,6 +160,12 @@ program
159
160
  .option("--json", "Output as JSON")
160
161
  .option("-v, --verbose", "Enable verbose output")
161
162
  .action(mergeCommand);
163
+ program
164
+ .command("conventions")
165
+ .description("View and manage codebase conventions")
166
+ .option("--detect", "Re-run convention detection")
167
+ .option("--reset", "Clear detected conventions (keep manual)")
168
+ .action(conventionsCommand);
162
169
  program
163
170
  .command("logs")
164
171
  .description("View and analyze workflow run logs")
@@ -0,0 +1,9 @@
1
+ /**
2
+ * sequant conventions - View and manage codebase conventions
3
+ */
4
+ interface ConventionsOptions {
5
+ detect?: boolean;
6
+ reset?: boolean;
7
+ }
8
+ export declare function conventionsCommand(options: ConventionsOptions): Promise<void>;
9
+ export {};
@@ -0,0 +1,61 @@
1
+ /**
2
+ * sequant conventions - View and manage codebase conventions
3
+ */
4
+ import chalk from "chalk";
5
+ import { detectAndSaveConventions, loadConventions, formatConventions, CONVENTIONS_PATH, } from "../lib/conventions-detector.js";
6
+ import { fileExists, writeFile } from "../lib/fs.js";
7
+ export async function conventionsCommand(options) {
8
+ if (options.reset) {
9
+ await handleReset();
10
+ return;
11
+ }
12
+ if (options.detect) {
13
+ await handleDetect();
14
+ return;
15
+ }
16
+ // Default: show current conventions
17
+ await handleShow();
18
+ }
19
+ async function handleDetect() {
20
+ console.log(chalk.blue("Detecting codebase conventions..."));
21
+ const result = await detectAndSaveConventions(process.cwd());
22
+ const count = Object.keys(result.detected).length;
23
+ console.log(chalk.green(`\nDetected ${count} conventions:`));
24
+ console.log(formatConventions(result));
25
+ console.log(chalk.gray(`\nSaved to ${CONVENTIONS_PATH}`));
26
+ }
27
+ async function handleReset() {
28
+ const existing = await loadConventions();
29
+ if (!existing) {
30
+ console.log(chalk.yellow("No conventions file found. Nothing to reset."));
31
+ return;
32
+ }
33
+ // Keep manual entries, clear detected
34
+ const reset = {
35
+ detected: {},
36
+ manual: existing.manual,
37
+ detectedAt: "",
38
+ };
39
+ await writeFile(CONVENTIONS_PATH, JSON.stringify(reset, null, 2));
40
+ console.log(chalk.green("Detected conventions cleared. Manual entries preserved."));
41
+ if (Object.keys(existing.manual).length > 0) {
42
+ console.log(chalk.gray("\nManual entries kept:"));
43
+ for (const [key, value] of Object.entries(existing.manual)) {
44
+ console.log(chalk.gray(` ${key}: ${value}`));
45
+ }
46
+ }
47
+ }
48
+ async function handleShow() {
49
+ if (!(await fileExists(CONVENTIONS_PATH))) {
50
+ console.log(chalk.yellow("No conventions detected yet."));
51
+ console.log(chalk.gray("Run 'sequant conventions --detect' or 'sequant init' to detect conventions."));
52
+ return;
53
+ }
54
+ const conventions = await loadConventions();
55
+ if (!conventions) {
56
+ console.log(chalk.yellow("Could not read conventions file."));
57
+ return;
58
+ }
59
+ console.log(formatConventions(conventions));
60
+ console.log(chalk.gray(`\nEdit ${CONVENTIONS_PATH} to add manual overrides.`));
61
+ }
@@ -9,6 +9,7 @@ import { copyTemplates } from "../lib/templates.js";
9
9
  import { createManifest } from "../lib/manifest.js";
10
10
  import { saveConfig } from "../lib/config.js";
11
11
  import { createDefaultSettings } from "../lib/settings.js";
12
+ import { detectAndSaveConventions } from "../lib/conventions-detector.js";
12
13
  import { fileExists, ensureDir, readFile, writeFile } from "../lib/fs.js";
13
14
  import { commandExists, isGhAuthenticated, getInstallHint, } from "../lib/system.js";
14
15
  import { shouldUseInteractiveMode, getNonInteractiveReason, } from "../lib/tty.js";
@@ -347,6 +348,17 @@ export async function initCommand(options) {
347
348
  settingsSpinner.start();
348
349
  await createDefaultSettings();
349
350
  settingsSpinner.succeed("Created default settings");
351
+ // Detect codebase conventions
352
+ const conventionsSpinner = ui.spinner("Detecting codebase conventions...");
353
+ conventionsSpinner.start();
354
+ try {
355
+ const conventions = await detectAndSaveConventions(process.cwd());
356
+ const count = Object.keys(conventions.detected).length;
357
+ conventionsSpinner.succeed(`Detected ${count} codebase conventions`);
358
+ }
359
+ catch {
360
+ conventionsSpinner.warn("Could not detect conventions (non-blocking)");
361
+ }
350
362
  // Copy templates (with symlinks for scripts unless --no-symlinks)
351
363
  const templatesSpinner = ui.spinner("Copying templates...");
352
364
  templatesSpinner.start();
@@ -0,0 +1,62 @@
1
+ /**
2
+ * Codebase conventions detector
3
+ *
4
+ * Deterministic detection of observable codebase patterns.
5
+ * No AI/ML — just file scanning and pattern matching.
6
+ */
7
+ /** Path to conventions file */
8
+ export declare const CONVENTIONS_PATH = ".sequant/conventions.json";
9
+ /**
10
+ * A single detected convention
11
+ */
12
+ export interface Convention {
13
+ /** Machine-readable key */
14
+ key: string;
15
+ /** Human-readable label */
16
+ label: string;
17
+ /** Detected value */
18
+ value: string;
19
+ /** How it was detected */
20
+ source: "detected" | "manual";
21
+ /** What evidence triggered detection */
22
+ evidence?: string;
23
+ }
24
+ /**
25
+ * Full conventions file schema
26
+ */
27
+ export interface ConventionsFile {
28
+ /** Auto-detected conventions */
29
+ detected: Record<string, string>;
30
+ /** User-provided overrides */
31
+ manual: Record<string, string>;
32
+ /** When detection was last run */
33
+ detectedAt: string;
34
+ }
35
+ /**
36
+ * Run all convention detectors
37
+ */
38
+ export declare function detectConventions(projectRoot: string): Promise<Convention[]>;
39
+ /**
40
+ * Load existing conventions file
41
+ */
42
+ export declare function loadConventions(): Promise<ConventionsFile | null>;
43
+ /**
44
+ * Save conventions, preserving manual entries
45
+ */
46
+ export declare function saveConventions(detected: Convention[]): Promise<ConventionsFile>;
47
+ /**
48
+ * Get merged conventions (manual overrides detected)
49
+ */
50
+ export declare function getMergedConventions(file: ConventionsFile): Record<string, string>;
51
+ /**
52
+ * Format conventions for display
53
+ */
54
+ export declare function formatConventions(file: ConventionsFile): string;
55
+ /**
56
+ * Detect and save conventions in one call
57
+ */
58
+ export declare function detectAndSaveConventions(projectRoot: string): Promise<ConventionsFile>;
59
+ /**
60
+ * Format conventions as context for AI skills
61
+ */
62
+ export declare function formatConventionsForContext(file: ConventionsFile): string;