@jnyross/code-factory 1.0.0 → 1.1.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/README.md CHANGED
@@ -1,88 +1,116 @@
1
1
  # Code Factory Template
2
2
 
3
- A private-first template for running Ryan Carson-style "Ralph" autonomous loops with local CLI tooling and flat-rate subscriptions.
4
-
5
- ## Zero-API Cost Principle
6
- This template is built to avoid extra API token costs:
7
- - Use local CLI agents (Claude Code CLI, Cursor Ultra agent mode, Antigravity, GLM coding plan, Minimax coding plan, ChatGPT Pro workflows).
8
- - Do not add direct token-billed API calls in repository scripts.
9
- - Keep all automation in repo-native shell scripts and CI.
3
+ Code Factory is a repo control-plane for autonomous coding + deterministic review.
4
+
5
+ This template implements the full pattern:
6
+ - one machine-readable contract
7
+ - risk-policy gate before expensive CI fanout
8
+ - current-head SHA review discipline
9
+ - canonical rerun comment dedupe
10
+ - bot-only thread auto-resolve after clean rerun
11
+ - browser evidence verification for UI/user-flow changes
12
+ - incident -> harness-gap loop with weekly metrics
13
+
14
+ ## Contract (single source of truth)
15
+ All control-plane policy lives in `ARCHITECTURE.yaml` under `control_plane`:
16
+ - `riskTierRules`
17
+ - `mergePolicy`
18
+ - `docsDriftRules`
19
+ - `reviewAgent`
20
+ - `browserEvidence`
21
+ - `harnessGapLoop`
22
+
23
+ ## Workflow Order
24
+ `Control Plane` workflow (`.github/workflows/preflight.yml`) runs jobs in this order:
25
+ 1. `risk-policy-gate`
26
+ 2. fanout: `CI Pipeline`, `harness-smoke`, `Browser Evidence`
27
+ 3. `risk-policy-finalize`
28
+
29
+ `Code Review Agent` workflow (`.github/workflows/auto-review.yml`) runs in parallel and is enforced by SHA-aware policy checks.
30
+
31
+ ## SHA Discipline and Reruns
32
+ `scripts/control-plane/risk-policy-gate.mjs` enforces:
33
+ - review check must be for current PR head SHA
34
+ - stale review state is rejected
35
+ - actionable findings in review summary comment fail the gate
36
+ - canonical rerun request comment is deduped by marker + `sha:<head>`
37
+
38
+ ## Browser Evidence
39
+ For UI-sensitive paths, `Browser Evidence` requires a valid manifest:
40
+ - path: `harness/browser-evidence/manifest.json`
41
+ - freshness window and required flows defined in `ARCHITECTURE.yaml`
42
+
43
+ Generate/update evidence manifest:
44
+ ```bash
45
+ npm run harness:ui:capture-browser-evidence
46
+ npm run harness:ui:verify-browser-evidence
47
+ ```
10
48
 
11
- ## Core Loop Files
12
- - `ARCHITECTURE.yaml`: Machine-readable architecture contract.
13
- - `AGENTS.md`: Shared autonomous loop policy.
14
- - `prd.json`: Task queue for agents.
15
- - `progress.txt`: Append-only execution journal.
49
+ ## Harness Gap Loop
50
+ `harness-gap-loop` workflow:
51
+ - creates a `harness-gap` issue when a `production-regression` issue appears
52
+ - runs weekly metrics (`npm run harness:weekly-metrics`)
16
53
 
17
- ## Tool Rule Files
18
- - `.cursorrules`: Cursor Ultra native behavior.
19
- - `CLAUDE.md`: Claude Code CLI behavior.
20
- - `.agent/rules/CodeFactory.md`: Antigravity/GLM/Minimax behavior.
21
- - `prompt_template.txt`: ChatGPT Pro project-manager prompt.
22
-
23
- ## Local Runner
24
- `ralph.sh` is rewritten to use local CLI tools only.
25
-
26
- Runner behavior:
27
- 1. Reads next open task from `prd.json`.
28
- 2. Invokes a local agent CLI for implementation (`codex` by default).
29
- 3. Runs preflight checks:
30
- - `npm run typecheck`
31
- - `npm run lint`
32
- - `npm test`
33
- 4. Appends progress to `progress.txt`.
34
- 5. Marks task done only when preflight passes.
35
-
36
- Engine selection:
37
- - Default: `codex` (`AGENT_ENGINE=codex`).
38
- - Claude: `AGENT_ENGINE=claude`.
39
- - OpenCode: `AGENT_ENGINE=opencode` (defaults to `minimax-coding-plan/MiniMax-M2.5`).
40
- - Custom CLI: `AGENT_ENGINE=custom AGENT_CMD='<your command>'`.
41
-
42
- Examples:
54
+ ## Local Command Set
43
55
  ```bash
44
- ./ralph.sh --once
45
- AGENT_ENGINE=claude ./ralph.sh --once
46
- AGENT_ENGINE=opencode ./ralph.sh --once
47
- OPENCODE_MODEL=minimax-coding-plan/MiniMax-M2.5 AGENT_ENGINE=opencode ./ralph.sh --once
48
- AGENT_ENGINE=custom AGENT_CMD='your-cli --non-interactive -' ./ralph.sh --once
56
+ npm run typecheck
57
+ npm test
58
+ npm run build:ci --if-present
59
+ npm run harness:legal-chat:smoke
60
+ npm run harness:ui:capture-browser-evidence
61
+ npm run harness:ui:verify-browser-evidence
62
+ npm run harness:risk-tier
63
+ npm run harness:weekly-metrics
49
64
  ```
50
65
 
51
- Preflight directory selection:
52
- - First choice: repository root.
53
- - Fallback: `flowchart/` (included in this base template).
54
- - Override with `PROJECT_DIR=/path/to/app`.
55
-
56
- ## CI Safety Layer
57
- - `.github/workflows/preflight.yml`
58
- - Labels risky PRs as `high-risk` when touching paths like `db/`, `auth/`, or `infra/`.
59
- - Runs typecheck/lint/tests in root or fallback `flowchart/`.
60
- - `.github/workflows/auto-review.yml`
61
- - Adds or updates a secondary agent-review comment on PRs.
66
+ ## Agent Loop Files
67
+ - `ARCHITECTURE.yaml`
68
+ - `AGENTS.md`
69
+ - `prd.json`
70
+ - `progress.txt`
62
71
 
63
- ## New Project Bootstrap
64
- Use the CLI to create a fresh repo from this template with clean git history.
72
+ ## Tool Rule Files
73
+ - `.cursorrules`
74
+ - `CLAUDE.md`
75
+ - `.agent/rules/CodeFactory.md`
76
+ - `prompt_template.txt`
77
+ - `chatgpt_architecture_prd_prompt.txt`
78
+ - `chatgpt_prd_format_prompt.txt`
79
+
80
+ ## CLI Install
81
+ ```bash
82
+ npm install -g @jnyross/code-factory
83
+ ```
65
84
 
66
- Example:
85
+ ## Create a New Project
86
+ Local only:
67
87
  ```bash
68
88
  code-factory my-next-app ~/Projects
69
89
  ```
70
90
 
71
- Global install:
91
+ Create + push GitHub repo in one command:
72
92
  ```bash
73
- npm install -g @jnyross/code-factory
93
+ code-factory my-next-app ~/Projects --github --private
94
+ ```
95
+
96
+ Examples:
97
+ ```bash
98
+ code-factory my-next-app --github --owner my-org --repo my-org/my-next-app --public
74
99
  ```
75
100
 
76
101
  Compatibility alias:
77
102
  - `new-project` points to the same CLI command as `code-factory`.
78
103
 
79
- ## Suggested Working Loop
80
- 1. Copy `prd.json.example` to `prd.json` (already present in this template).
81
- 2. Add real tasks to `prd.json`.
82
- 3. Run `./ralph.sh --once` for a single task cycle or `./ralph.sh` for looped operation.
83
- 4. Review `progress.txt` after each run.
84
- 5. Open PR and require preflight workflow success before merge.
104
+ ## Ralph Runner
105
+ `ralph.sh` supports:
106
+ - `codex` (default)
107
+ - `claude`
108
+ - `opencode` (default model `minimax-coding-plan/MiniMax-M2.5`)
109
+ - `custom`
85
110
 
86
- ## Notes
87
- - This template assumes a Node/TypeScript project with `typecheck`, `lint`, and `test` scripts.
88
- - If you use different commands, update `ralph.sh`, `ARCHITECTURE.yaml`, and workflow files together.
111
+ Examples:
112
+ ```bash
113
+ ./ralph.sh --once
114
+ AGENT_ENGINE=claude ./ralph.sh --once
115
+ AGENT_ENGINE=opencode ./ralph.sh --once
116
+ ```
@@ -5,62 +5,184 @@ import { existsSync, rmSync } from "node:fs";
5
5
  import { resolve } from "node:path";
6
6
  import process from "node:process";
7
7
 
8
- const TEMPLATE_URL =
8
+ const DEFAULT_TEMPLATE_URL =
9
9
  process.env.CODE_FACTORY_TEMPLATE_URL ??
10
10
  "https://github.com/jnyross/code-factory-template.git";
11
11
 
12
12
  function usage(exitCode = 0) {
13
13
  console.log(`Usage:
14
- code-factory <project-name> [destination-directory]
15
- code-factory new <project-name> [destination-directory]
14
+ code-factory <project-name> [destination-directory] [options]
15
+ code-factory new <project-name> [destination-directory] [options]
16
+
17
+ Options:
18
+ --github Create and push a new GitHub repo via gh CLI
19
+ --public Use public visibility for --github
20
+ --private Use private visibility for --github (default)
21
+ --owner <owner> GitHub owner/org for --github (defaults to gh auth user)
22
+ --repo <name|owner/name>
23
+ GitHub repo name override (default: slugified project name)
24
+ --template-url <url> Override template repository URL for this run
25
+ -h, --help Show help
16
26
 
17
27
  Examples:
18
28
  code-factory my-app
19
29
  code-factory "Youth Reg Response Platform" ~/Software_Projects
20
-
21
- Environment:
22
- CODE_FACTORY_TEMPLATE_URL Override template repository URL
30
+ code-factory my-app ~/Software_Projects --github --private
31
+ code-factory my-app --github --owner my-org --repo my-org/my-app
23
32
  `);
24
33
  process.exit(exitCode);
25
34
  }
26
35
 
27
- function run(cmd, args) {
28
- execFileSync(cmd, args, { stdio: "inherit" });
36
+ function run(cmd, args, cwd) {
37
+ execFileSync(cmd, args, { stdio: "inherit", cwd });
29
38
  }
30
39
 
31
- const rawArgs = process.argv.slice(2);
32
-
33
- if (rawArgs.length === 0 || rawArgs.includes("-h") || rawArgs.includes("--help")) {
34
- usage(0);
40
+ function runCapture(cmd, args, cwd) {
41
+ return execFileSync(cmd, args, {
42
+ stdio: ["ignore", "pipe", "pipe"],
43
+ cwd,
44
+ encoding: "utf8"
45
+ }).trim();
35
46
  }
36
47
 
37
- let args = rawArgs;
38
- if (args[0] === "new") {
39
- args = args.slice(1);
48
+ function slugify(name) {
49
+ return name
50
+ .toLowerCase()
51
+ .trim()
52
+ .replace(/[^a-z0-9]+/g, "-")
53
+ .replace(/^-+|-+$/g, "")
54
+ .replace(/-{2,}/g, "-")
55
+ .slice(0, 80);
40
56
  }
41
57
 
42
- if (args.length < 1 || args.length > 2) {
43
- usage(1);
58
+ function parseArgs(rawArgs) {
59
+ const options = {
60
+ github: false,
61
+ visibility: "private",
62
+ owner: null,
63
+ repo: null,
64
+ templateUrl: DEFAULT_TEMPLATE_URL
65
+ };
66
+
67
+ let args = [...rawArgs];
68
+ if (args[0] === "new") {
69
+ args = args.slice(1);
70
+ }
71
+
72
+ const positional = [];
73
+
74
+ for (let index = 0; index < args.length; index += 1) {
75
+ const arg = args[index];
76
+
77
+ if (arg === "--github") {
78
+ options.github = true;
79
+ continue;
80
+ }
81
+
82
+ if (arg === "--public") {
83
+ options.visibility = "public";
84
+ continue;
85
+ }
86
+
87
+ if (arg === "--private") {
88
+ options.visibility = "private";
89
+ continue;
90
+ }
91
+
92
+ if (arg === "--owner") {
93
+ options.owner = args[index + 1] ?? null;
94
+ index += 1;
95
+ continue;
96
+ }
97
+
98
+ if (arg === "--repo") {
99
+ options.repo = args[index + 1] ?? null;
100
+ index += 1;
101
+ continue;
102
+ }
103
+
104
+ if (arg === "--template-url") {
105
+ options.templateUrl = args[index + 1] ?? DEFAULT_TEMPLATE_URL;
106
+ index += 1;
107
+ continue;
108
+ }
109
+
110
+ if (arg === "-h" || arg === "--help") {
111
+ usage(0);
112
+ }
113
+
114
+ if (arg.startsWith("--")) {
115
+ console.error(`Unknown option: ${arg}`);
116
+ usage(1);
117
+ }
118
+
119
+ positional.push(arg);
120
+ }
121
+
122
+ if (positional.length < 1 || positional.length > 2) {
123
+ usage(1);
124
+ }
125
+
126
+ return {
127
+ projectName: positional[0],
128
+ destinationDir: positional[1] ?? process.cwd(),
129
+ options
130
+ };
44
131
  }
45
132
 
46
- const projectName = args[0];
47
- const destinationDir = args[1] ?? process.cwd();
48
- const targetPath = resolve(destinationDir, projectName);
133
+ function deriveGitHubRepo(projectName, options) {
134
+ if (options.repo && options.repo.includes("/")) {
135
+ const [owner, repo] = options.repo.split("/");
136
+ return { owner, repo };
137
+ }
49
138
 
50
- if (existsSync(targetPath)) {
51
- console.error(`Target already exists: ${targetPath}`);
52
- process.exit(1);
139
+ const repo = options.repo ?? slugify(projectName);
140
+ if (!repo) {
141
+ throw new Error("Could not derive GitHub repository name from project name.");
142
+ }
143
+
144
+ const owner = options.owner ?? runCapture("gh", ["api", "user", "-q", ".login"]);
145
+ if (!owner) {
146
+ throw new Error("Unable to determine GitHub owner. Pass --owner.");
147
+ }
148
+
149
+ return { owner, repo };
53
150
  }
54
151
 
55
- try {
56
- run("git", ["clone", TEMPLATE_URL, targetPath]);
152
+ function createProject(projectName, destinationDir, options) {
153
+ const targetPath = resolve(destinationDir, projectName);
154
+
155
+ if (existsSync(targetPath)) {
156
+ throw new Error(`Target already exists: ${targetPath}`);
157
+ }
158
+
159
+ run("git", ["clone", options.templateUrl, targetPath]);
57
160
  rmSync(resolve(targetPath, ".git"), { recursive: true, force: true });
58
161
  run("git", ["-C", targetPath, "init", "-q"]);
59
162
  run("git", ["-C", targetPath, "add", "."]);
60
163
  run("git", ["-C", targetPath, "commit", "-q", "-m", "Initial commit from Code Factory template"]);
61
164
 
165
+ if (options.github) {
166
+ const { owner, repo } = deriveGitHubRepo(projectName, options);
167
+ const fullRepo = `${owner}/${repo}`;
168
+ const visibilityFlag = options.visibility === "public" ? "--public" : "--private";
169
+
170
+ run("gh", ["repo", "create", fullRepo, visibilityFlag, "--source", targetPath, "--remote", "origin", "--push"]);
171
+ console.log(`GitHub repo created: https://github.com/${fullRepo}`);
172
+ }
173
+
62
174
  console.log("Your new Code Factory project is ready!");
63
175
  console.log(`Path: ${targetPath}`);
176
+ }
177
+
178
+ try {
179
+ const rawArgs = process.argv.slice(2);
180
+ if (rawArgs.length === 0) {
181
+ usage(0);
182
+ }
183
+
184
+ const { projectName, destinationDir, options } = parseArgs(rawArgs);
185
+ createProject(projectName, destinationDir, options);
64
186
  } catch (error) {
65
187
  const message = error instanceof Error ? error.message : String(error);
66
188
  console.error(`code-factory failed: ${message}`);
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@jnyross/code-factory",
3
- "version": "1.0.0",
3
+ "version": "1.1.0",
4
4
  "description": "Bootstrap new repos from the Code Factory template.",
5
5
  "type": "module",
6
6
  "license": "MIT",
@@ -24,11 +24,21 @@
24
24
  "code-factory": "bin/code-factory.mjs",
25
25
  "new-project": "bin/code-factory.mjs"
26
26
  },
27
+ "scripts": {
28
+ "harness:risk-tier": "node scripts/control-plane/risk-tier.mjs",
29
+ "harness:legal-chat:smoke": "node scripts/control-plane/harness-smoke.mjs",
30
+ "harness:ui:capture-browser-evidence": "node scripts/control-plane/capture-browser-evidence.mjs",
31
+ "harness:ui:verify-browser-evidence": "node scripts/control-plane/verify-browser-evidence.mjs",
32
+ "harness:weekly-metrics": "node scripts/control-plane/weekly-metrics.mjs"
33
+ },
27
34
  "files": [
28
35
  "bin",
29
36
  "README.md",
30
37
  "LICENSE"
31
38
  ],
39
+ "dependencies": {
40
+ "yaml": "^2.8.1"
41
+ },
32
42
  "engines": {
33
43
  "node": ">=18"
34
44
  },