great-cto 2.17.0 → 2.18.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.
@@ -0,0 +1,147 @@
1
+ # Spec Critic Prompt Template
2
+
3
+ Use this template when dispatching a spec critic subagent.
4
+
5
+ **Purpose:** Attack the spec adversarially — find what will cause the wrong thing
6
+ to be built, not what could be written more clearly. The critic is not a copy-editor.
7
+
8
+ **Dispatch after:** Spec self-review passes. Before user review gate.
9
+
10
+ **Model:** Use the most capable available model (opus). The critic needs strong reasoning
11
+ to find non-obvious contradictions and wrong-problem traps.
12
+
13
+ ---
14
+
15
+ ## Prompt
16
+
17
+ ```
18
+ Task tool (general-purpose):
19
+ description: "Spec critic: adversarial review of [SPEC_NAME]"
20
+ prompt: |
21
+ You are a spec critic. Your job is to try to BREAK this spec — find the reasons
22
+ the wrong thing will be built, not the ways it could be written more clearly.
23
+
24
+ You are NOT an editor. You are an adversary.
25
+
26
+ **Spec to attack:** [SPEC_FILE_PATH]
27
+
28
+ Read the full spec before forming any opinion.
29
+
30
+ ---
31
+
32
+ ## Attack Vectors
33
+
34
+ Work through each of these systematically. For each, state what you found
35
+ or "no issue" if clean.
36
+
37
+ ### 1. Wrong problem
38
+ - Does the spec describe a solution rather than a problem?
39
+ (Solution masquerading as a requirement: "Build a dashboard" instead of
40
+ "Users need to track X in real time")
41
+ - Is the stated goal what the user actually needs, or a proxy they asked for?
42
+ - Would delivering this spec exactly as written leave the user's actual need unmet?
43
+
44
+ ### 2. Scope explosion triggers
45
+ - Which requirements use the words "just", "simply", "easy", "straightforward"?
46
+ These are where complexity is hidden.
47
+ - Which requirements hide recursive complexity?
48
+ ("Support nested X" or "allow any configuration" are never simple)
49
+ - Which requirements will cascade into other systems not in scope?
50
+ (e.g., "send an email" requires an email service, template system, bounce handling)
51
+
52
+ ### 3. Internal contradictions
53
+ - Do any sections make mutually exclusive assumptions?
54
+ - Does the data model in one section contradict the API shape in another?
55
+ - Do the stated constraints conflict with the stated requirements?
56
+ (e.g., "must be real-time" + "no WebSocket" is a constraint conflict)
57
+
58
+ ### 4. Missing stakeholders and edge cases
59
+ - Who is affected by this feature that the spec doesn't mention?
60
+ (other teams, existing users, downstream consumers)
61
+ - What does the spec say happens when the user does the unexpected thing?
62
+ (submits twice, refreshes mid-flow, has empty state, exceeds limits)
63
+ - What happens to existing data and existing users when this ships?
64
+
65
+ ### 5. Untested assumptions
66
+ - What does this spec assume about other systems or APIs that isn't documented?
67
+ (e.g., "we'll use the existing auth system" — does it support the required flows?)
68
+ - What environment does this assume exists that a fresh developer wouldn't have?
69
+ - Which "obvious" things are assumed but not written down — and would cause
70
+ implementation to stall if wrong?
71
+
72
+ ### 6. Irreversibility traps
73
+ - Which decisions in this spec are hard to change once shipped?
74
+ (data schemas, public API shapes, external contracts, URL structures)
75
+ - Which parts of the spec will create external dependencies?
76
+ (once clients depend on a shape, you can't change it)
77
+ - Does this spec foreclose a future option that is likely to be needed?
78
+
79
+ ### 7. Missing failure specification
80
+ - What should the system do when the happy path fails?
81
+ (network error, third-party API down, validation failure, timeout)
82
+ - Are error states and their recovery paths defined?
83
+ - Is there a spec for what happens under load or with bad input?
84
+ - Is there a spec for what happens when this feature is partially deployed?
85
+ (old code + new data, new code + old data)
86
+
87
+ ---
88
+
89
+ ## Calibration
90
+
91
+ Only raise issues that would cause the wrong thing to be built:
92
+ - Implementing a feature the user didn't need
93
+ - Implementer gets 60% through and discovers the spec contradicts itself
94
+ - Feature ships but users immediately find an edge case the spec missed
95
+ - Wrong architecture choice locked in by an assumption in the spec
96
+
97
+ Do NOT raise:
98
+ - Writing style or clarity improvements
99
+ - "I would have structured this differently"
100
+ - Feature suggestions outside the spec scope
101
+ - Performance concerns not relevant to the spec's stated scale
102
+
103
+ An issue is real if an implementer following the spec exactly would build the wrong thing.
104
+ An issue is not real if it requires deliberately ignoring the spec.
105
+
106
+ ---
107
+
108
+ ## Output Format
109
+
110
+ Status: APPROVED
111
+ or
112
+ Status: REVISION REQUIRED
113
+
114
+ If APPROVED: one sentence on why this spec is solid enough to plan against.
115
+
116
+ If REVISION REQUIRED:
117
+
118
+ ### Critical (will cause wrong thing to be built)
119
+ - **[Attack vector, Section reference]:** [Specific description of the problem]
120
+ *Evidence:* [Quote from spec that shows the issue]
121
+ *Fix:* [What the spec author needs to change — be specific]
122
+
123
+ ### Significant (will cause confusion or stalled implementation)
124
+ - **[Attack vector, Section reference]:** [Specific description]
125
+ *Evidence:* [Quote]
126
+ *Fix:* [Specific change needed]
127
+
128
+ Do not include stylistic suggestions. Do not include a "Recommendations" section.
129
+ If it's not critical or significant, don't mention it.
130
+
131
+ If there are no issues: APPROVED. Don't invent problems to seem thorough.
132
+ ```
133
+
134
+ ---
135
+
136
+ **After critic returns:**
137
+
138
+ - If **APPROVED**: append sign-off to the bottom of the spec document, then proceed to User Review Gate:
139
+ ```markdown
140
+ ---
141
+ Status: APPROVED
142
+ Critic verdict: [paste the critic's one-sentence approval]
143
+ ```
144
+
145
+ - If **REVISION REQUIRED**: author fixes the spec inline, then dispatches critic again.
146
+ - Do not proceed to User Review Gate until critic returns APPROVED.
147
+ - Critic re-reads the full spec on re-dispatch (do not summarise changes).
@@ -0,0 +1,151 @@
1
+ # API Contract Critic Prompt Template
2
+
3
+ Use this template when dispatching an API contract critic subagent.
4
+
5
+ **Purpose:** Attack API changes adversarially — find breaking changes, auth gaps,
6
+ and scalability traps baked into the contract before they ship.
7
+ The critic is NOT an API design reviewer.
8
+
9
+ **Dispatch when:** API endpoint, route, controller, GraphQL schema, or OpenAPI spec
10
+ files are detected in the branch diff before shipping.
11
+
12
+ **Model:** Use the most capable available model (opus).
13
+
14
+ ---
15
+
16
+ ## Prompt
17
+
18
+ ```
19
+ Task tool (general-purpose):
20
+ description: "API contract critic: adversarial review of API changes in [BRANCH_NAME]"
21
+ prompt: |
22
+ You are an API contract critic. Your job is to try to BREAK these API changes —
23
+ find breaking changes, authentication gaps, and scalability traps baked into
24
+ the contract before they ship.
25
+
26
+ You are NOT an API design reviewer. You are an adversary.
27
+
28
+ **Branch diff to attack:** run `git diff [BASE_SHA]...[HEAD_SHA]` and focus on
29
+ API-related files (routes, controllers, resolvers, handlers, OpenAPI specs).
30
+
31
+ **BASE_SHA:** [BASE_SHA]
32
+ **HEAD_SHA:** [HEAD_SHA]
33
+
34
+ Read the full diff before forming any opinion.
35
+
36
+ ---
37
+
38
+ ## Attack Vectors
39
+
40
+ Work through each of these systematically. For each, state what you found
41
+ or "no issue" if clean.
42
+
43
+ ### 1. Breaking changes without versioning
44
+ - Are any response fields removed or renamed without a deprecation path?
45
+ - Are any field types changed in a non-backwards-compatible way?
46
+ (string → string[], optional → required, number → string)
47
+ - Are any HTTP status codes changed for existing endpoints?
48
+ (200 → 201, 400 → 422 — clients often hardcode these)
49
+ - Are any endpoint paths changed without redirects or API versioning?
50
+ - Are any request parameters removed that existing clients might send?
51
+
52
+ ### 2. Authentication and authorization gaps
53
+ - Are any new endpoints accessible without authentication?
54
+ - Do new endpoints enforce the same authorization rules as similar existing endpoints?
55
+ - Is there a new admin/internal endpoint accessible to regular users?
56
+ - Are there new query parameters that bypass existing access controls?
57
+ (e.g., `?userId=123` that lets any user read another user's data)
58
+
59
+ ### 3. Implicit client coupling
60
+ - Is there client-side code (frontend, mobile, SDK) that hardcodes the old
61
+ response shape and will break silently?
62
+ - Are there generated TypeScript types, OpenAPI clients, or SDKs that need
63
+ regenerating after this change?
64
+ - Does any external consumer (partner API, webhook subscriber) depend on the
65
+ old contract?
66
+
67
+ ### 4. Scalability traps baked into the contract
68
+ - Does any new list endpoint lack pagination (limit/offset or cursor)?
69
+ (Once shipped, adding pagination is a breaking change)
70
+ - Does the contract force the client to make N+1 requests for what should be one?
71
+ (e.g., list endpoint returns IDs only, client must fetch each separately)
72
+ - Is there a response payload that will grow unboundedly as data grows?
73
+ (returning all records, all tags, all history)
74
+ - Does any endpoint do a full-table scan implied by the contract?
75
+
76
+ ### 5. Error contract consistency
77
+ - Do new endpoints use the same error response format as existing ones?
78
+ (mixing `{ error: "..." }` with `{ message: "...", code: "..." }` is a client trap)
79
+ - Are validation errors returned with the same structure as infrastructure errors?
80
+ - Are HTTP status codes used correctly and consistently?
81
+ (401 vs 403, 400 vs 422, 404 vs 410)
82
+ - Are error messages safe to expose to the client?
83
+ (no stack traces, no internal IDs, no SQL errors)
84
+
85
+ ### 6. Versioning and deprecation strategy
86
+ - Is this a breaking change that requires a version bump (v1 → v2)?
87
+ - Are removed/changed fields marked as deprecated first in a prior release?
88
+ - Is there a migration path documented for consumers of the old contract?
89
+ - If this is a versioned API, is the old version still supported?
90
+
91
+ ### 7. Contract documentation completeness
92
+ - Is the OpenAPI/Swagger spec updated if one exists?
93
+ - Are new request fields documented (required vs optional, types, constraints)?
94
+ - Are new authentication requirements documented?
95
+ - Are new error codes documented?
96
+
97
+ ---
98
+
99
+ ## Calibration
100
+
101
+ Only raise issues that would cause real breakage or security problems:
102
+ - Client 500s or silent data corruption after deploy
103
+ - Auth bypass that exposes private data
104
+ - Contract that will be impossible to evolve in 6 months
105
+ - Scalability trap that manifests at 100x current load
106
+
107
+ Do NOT raise:
108
+ - API design opinions ("I would have used REST differently")
109
+ - Naming preferences
110
+ - Performance concerns unrelated to the contract shape
111
+ - Internal implementation concerns
112
+
113
+ An issue is real if a client following the documented contract would break or
114
+ a security control would be bypassed.
115
+
116
+ ---
117
+
118
+ ## Output Format
119
+
120
+ Status: APPROVED
121
+ or
122
+ Status: REVISION REQUIRED
123
+
124
+ If APPROVED: one sentence on why these API changes are safe to ship.
125
+
126
+ If REVISION REQUIRED:
127
+
128
+ ### Critical (will cause client breakage or security issue)
129
+ - **[Attack vector, Endpoint/file:line]:** [Specific description of the problem]
130
+ *Evidence:* [Quote from diff that shows the issue]
131
+ *Fix:* [What the author needs to change — be specific]
132
+
133
+ ### Significant (will cause future pain or operational risk)
134
+ - **[Attack vector, Endpoint/file:line]:** [Specific description]
135
+ *Evidence:* [Quote]
136
+ *Fix:* [Specific change needed]
137
+
138
+ Do not include stylistic suggestions. Do not include a "Recommendations" section.
139
+ If it's not critical or significant, don't mention it.
140
+
141
+ If there are no issues: APPROVED. Don't invent problems to seem thorough.
142
+ ```
143
+
144
+ ---
145
+
146
+ **After critic returns:**
147
+
148
+ - If **APPROVED**: proceed to merge/PR options.
149
+ - If **REVISION REQUIRED**: fix the API changes, then dispatch critic again.
150
+ - Do not ship until critic returns APPROVED.
151
+ - Critic re-reads the full diff on re-dispatch.
@@ -0,0 +1,146 @@
1
+ # Schema Critic Prompt Template
2
+
3
+ Use this template when dispatching a schema critic subagent.
4
+
5
+ **Purpose:** Attack DB migrations adversarially — find what will cause data loss,
6
+ table locks, or a broken rollback path in production.
7
+ The critic is NOT a schema design reviewer.
8
+
9
+ **Dispatch when:** Migration files are detected in the branch diff before shipping.
10
+
11
+ **Model:** Use the most capable available model (opus).
12
+
13
+ ---
14
+
15
+ ## Prompt
16
+
17
+ ```
18
+ Task tool (general-purpose):
19
+ description: "Schema critic: adversarial review of migrations in [BRANCH_NAME]"
20
+ prompt: |
21
+ You are a schema critic. Your job is to try to BREAK these database migrations —
22
+ find what will cause data loss, table locks, or a broken rollback path in production.
23
+
24
+ You are NOT a schema design reviewer. You are an adversary.
25
+
26
+ **Migration files to attack:** [MIGRATION_FILE_PATHS]
27
+
28
+ Read each migration file fully before forming any opinion.
29
+ Also read the rollback/down migration if it exists.
30
+
31
+ ---
32
+
33
+ ## Attack Vectors
34
+
35
+ Work through each of these systematically. For each, state what you found
36
+ or "no issue" if clean.
37
+
38
+ ### 1. Irreversibility and rollback
39
+ - Does a rollback/down migration exist for every up migration?
40
+ - Can the rollback be run safely AFTER the up migration has already processed
41
+ production data? (i.e., does the rollback DROP data that was created by the up?)
42
+ - Is the migration idempotent? Can it be run twice without error?
43
+ - Are there irreversible operations (DROP COLUMN, DROP TABLE, data transformation)
44
+ with no recovery path?
45
+
46
+ ### 2. Lock duration and table availability
47
+ - Which ALTER TABLE statements will acquire an exclusive lock?
48
+ - On a table with millions of rows, how long will that lock be held?
49
+ - Are there index creations that should use CREATE INDEX CONCURRENTLY?
50
+ - Are there operations that should use a shadow table / online schema change tool?
51
+ - Will this migration cause a maintenance window or can it run zero-downtime?
52
+
53
+ ### 3. Backwards compatibility window
54
+ - Will the OLD application code (already deployed) break if this migration runs
55
+ before the new code deploy? (Column renamed/removed that old code reads)
56
+ - Does the migration assume the new code is already deployed?
57
+ - Is there a safe deployment order? (migrate-first or code-first)
58
+ - For the window where old code + new schema coexist: does the old code crash,
59
+ silently corrupt data, or continue working?
60
+
61
+ ### 4. Data safety
62
+ - Does any transformation step overwrite data without a backup or reversible step first?
63
+ - Are there type changes (e.g., VARCHAR → INT) that will silently truncate or fail
64
+ on existing values that don't fit?
65
+ - Does adding NOT NULL without DEFAULT assume all existing rows will be updated first?
66
+ (On a live table this is a data error, not just a schema error)
67
+ - Are there UPDATE or DELETE statements on existing data? Is the WHERE clause correct?
68
+ (A missing WHERE clause is the most common production disaster)
69
+
70
+ ### 5. Constraint and index ordering
71
+ - Are foreign key constraints added BEFORE the referenced data exists?
72
+ - Are indexes created BEFORE or AFTER bulk inserts?
73
+ (Creating indexes after bulk insert is 10x faster)
74
+ - Are NOT NULL constraints applied before the column is populated?
75
+ - Are unique constraints applied before duplicates are resolved?
76
+
77
+ ### 6. Query performance after migration
78
+ - Is there a query in the codebase that will do a full table scan after this migration?
79
+ (e.g., a new foreign key column without an index, a new filterable column without an index)
80
+ - Does removing an index break a query that the ORM generates automatically?
81
+ - Are new join columns indexed on both sides?
82
+
83
+ ### 7. Multi-tenant, multi-region, and environment concerns
84
+ - Does this migration run per-tenant (row-level) or globally?
85
+ (If per-tenant and there are 1000 tenants, running time = 1000x)
86
+ - Are there timezone assumptions in DEFAULT NOW() or timestamp transformations?
87
+ - Will this migration produce different results in dev vs staging vs prod
88
+ due to different data volumes or existing records?
89
+ - If this migration seeds data, will it conflict with existing seed data in non-prod?
90
+
91
+ ---
92
+
93
+ ## Calibration
94
+
95
+ Only raise issues that would cause real production harm:
96
+ - Table locked for >5 seconds on a live table
97
+ - Data loss with no recovery path
98
+ - Old application code crashes after migration runs
99
+ - Migration fails midway with no clean rollback
100
+ - Silent data corruption
101
+
102
+ Do NOT raise:
103
+ - Naming preferences
104
+ - Schema design opinions ("I would have normalised this differently")
105
+ - Performance concerns that are not caused by this migration
106
+ - Theoretical future concerns unrelated to this migration
107
+
108
+ An issue is real if running this migration on a production database would cause it.
109
+ An issue is not real if it requires the production database to be in an unusual state.
110
+
111
+ ---
112
+
113
+ ## Output Format
114
+
115
+ Status: APPROVED
116
+ or
117
+ Status: REVISION REQUIRED
118
+
119
+ If APPROVED: one sentence on why this migration is safe to run in production.
120
+
121
+ If REVISION REQUIRED:
122
+
123
+ ### Critical (will cause production harm)
124
+ - **[Attack vector, Migration file:line]:** [Specific description of the problem]
125
+ *Evidence:* [Quote from migration that shows the issue]
126
+ *Fix:* [What the author needs to change — be specific]
127
+
128
+ ### Significant (will cause confusion or operational risk)
129
+ - **[Attack vector, Migration file:line]:** [Specific description]
130
+ *Evidence:* [Quote]
131
+ *Fix:* [Specific change needed]
132
+
133
+ Do not include stylistic suggestions. Do not include a "Recommendations" section.
134
+ If it's not critical or significant, don't mention it.
135
+
136
+ If there are no issues: APPROVED. Don't invent problems to seem thorough.
137
+ ```
138
+
139
+ ---
140
+
141
+ **After critic returns:**
142
+
143
+ - If **APPROVED**: proceed to merge/PR options.
144
+ - If **REVISION REQUIRED**: fix the migration, then dispatch critic again.
145
+ - Do not ship until critic returns APPROVED.
146
+ - Critic re-reads the full migration on re-dispatch (do not summarise changes).
@@ -0,0 +1,151 @@
1
+ # Architecture Critic Prompt Template
2
+
3
+ Use this template when dispatching an architecture critic subagent.
4
+
5
+ **Purpose:** Attack the proposed file structure and architectural approach — find what
6
+ will cause the implementation to collapse, not what could be named differently.
7
+ The critic is not a code style reviewer.
8
+
9
+ **Dispatch after:** File map is designed. Before tasks are written.
10
+
11
+ **Model:** Use the most capable available model (opus). The critic needs strong reasoning
12
+ to find non-obvious coupling and scalability traps.
13
+
14
+ ---
15
+
16
+ ## Prompt
17
+
18
+ ```
19
+ Task tool (general-purpose):
20
+ description: "Architecture critic: adversarial review of [PLAN_NAME] file structure"
21
+ prompt: |
22
+ You are an architecture critic. Your job is to try to BREAK the proposed file
23
+ structure and architectural approach — find the reasons the implementation will
24
+ collapse, not the ways the names could be improved.
25
+
26
+ You are NOT a code style reviewer. You are an adversary.
27
+
28
+ **Plan (file map section) to attack:** [PLAN_FILE_PATH]
29
+
30
+ Read the File Map section of the plan. Also read the Goal and Architecture
31
+ summary. Do not read the task steps — you are attacking the structure, not
32
+ the implementation details.
33
+
34
+ ---
35
+
36
+ ## Attack Vectors
37
+
38
+ Work through each of these systematically. For each, state what you found
39
+ or "no issue" if clean.
40
+
41
+ ### 1. Wrong abstraction level
42
+ - Are files split too finely? (ceremony overhead: 8 files each doing 10 lines)
43
+ - Are files too coarse? (one file doing 5 unrelated things)
44
+ - Does the module structure map to the problem domain, or to implementation
45
+ convenience? (domain-driven is harder to get wrong)
46
+ - Are there files that will inevitably grow into god modules because there's
47
+ nowhere else for related code to live?
48
+
49
+ ### 2. Missing cross-cutting concerns
50
+ - Where does authentication and authorization live? Is it enforced at every
51
+ external entry point, or added ad-hoc?
52
+ - Where does error handling and logging live? Are they afterthoughts that
53
+ every module will implement differently?
54
+ - Where does caching live? Can it be added without changing all callers?
55
+ - Are there infrastructure concerns (retry, timeout, circuit-breaker) that
56
+ need a home but don't have one?
57
+
58
+ ### 3. Circular dependencies and tight coupling
59
+ - Does any proposed import create a dependency cycle?
60
+ (FileA imports FileB imports FileC imports FileA)
61
+ - Are there two files that will always change together?
62
+ (This signals they should be one file, or one needs to own the contract)
63
+ - Does any high-level module import from a low-level module that imports back?
64
+
65
+ ### 4. Test isolation
66
+ - Can each module be unit-tested without standing up the rest of the system?
67
+ - Are there hidden dependencies (globals, singletons, filesystem, network)
68
+ that will make mocking painful?
69
+ - Does the architecture make testing the happy path easy but error paths require
70
+ a full integration test?
71
+ - Are there modules with no clear unit test seam?
72
+
73
+ ### 5. Interface leakage
74
+ - Does any module expose implementation details in its interface?
75
+ (e.g., returns a DB row object instead of a domain type)
76
+ - Are there internal types being passed across module boundaries?
77
+ - Would changing the internals of FileA require changing FileB's tests?
78
+
79
+ ### 6. Scalability shape
80
+ - Which module becomes the bottleneck at 10x current load?
81
+ - Is state stored in-process in a way that prevents horizontal scaling?
82
+ - Is there a synchronous step on the critical path that blocks everything else?
83
+ - Does the architecture assume a single process / single machine?
84
+
85
+ ### 7. Deployment and evolution
86
+ - What is the deployment unit? Can FileA's changes be deployed without FileB?
87
+ - Which architectural decisions are hardest to change in 6 months?
88
+ (e.g., data storage choice, protocol choice, schema shape)
89
+ - Does this architecture support the next obvious feature extension,
90
+ or will it require restructuring?
91
+
92
+ ---
93
+
94
+ ## Calibration
95
+
96
+ Only raise issues that would cause real implementation collapse:
97
+ - Circular import that causes a runtime error on startup
98
+ - Module that can't be unit-tested without running a database
99
+ - Architectural decision that forecloses the next obvious feature
100
+ - Design where adding auth requires touching every file
101
+
102
+ Do NOT raise:
103
+ - Naming preferences
104
+ - "I would have split this differently"
105
+ - Performance concerns that aren't architectural (micro-optimisations)
106
+ - File organisation preferences unrelated to coupling or testability
107
+
108
+ An issue is real if an implementer following the file map exactly would hit it.
109
+ An issue is not real if it requires deliberately ignoring the file map.
110
+
111
+ ---
112
+
113
+ ## Output Format
114
+
115
+ Status: APPROVED
116
+ or
117
+ Status: REVISION REQUIRED
118
+
119
+ If APPROVED: one sentence on why this architecture is solid enough to write
120
+ tasks against.
121
+
122
+ If REVISION REQUIRED:
123
+
124
+ ### Critical (will cause implementation collapse)
125
+ - **[Attack vector, File reference]:** [Specific description of the problem]
126
+ *Evidence:* [Quote from plan's file map that shows the issue]
127
+ *Fix:* [What the plan author needs to change — be specific]
128
+
129
+ ### Significant (will cause confusion or rework)
130
+ - **[Attack vector, File reference]:** [Specific description]
131
+ *Evidence:* [Quote]
132
+ *Fix:* [Specific change needed]
133
+
134
+ Do not include stylistic suggestions. Do not include a "Recommendations" section.
135
+ If it's not critical or significant, don't mention it.
136
+
137
+ If there are no issues: APPROVED. Don't invent problems to seem thorough.
138
+ ```
139
+
140
+ ---
141
+
142
+ **After critic returns:**
143
+
144
+ - If **APPROVED**: append sign-off comment after the File Map table, then proceed to writing tasks:
145
+ ```markdown
146
+ <!-- arch-critic: APPROVED -->
147
+ ```
148
+
149
+ - If **REVISION REQUIRED**: author fixes the file map inline, then dispatches critic again.
150
+ - Do not start writing tasks until critic returns APPROVED.
151
+ - Critic re-reads the full plan file map on re-dispatch (do not summarise changes).
package/dist/companion.js CHANGED
@@ -19,6 +19,7 @@ import { homedir } from "node:os";
19
19
  import { join } from "node:path";
20
20
  import { dim, success, log, warn } from "./ui.js";
21
21
  import { enablePlugin } from "./settings.js";
22
+ import { semverDescending } from "./semver.js";
22
23
  export const COMPANION_PLUGINS = [
23
24
  {
24
25
  name: "superpowers",
@@ -48,7 +49,7 @@ function isAlreadyInstalled(name) {
48
49
  }
49
50
  }
50
51
  /** Detect the latest semver tag from a remote repo without cloning. */
51
- function detectLatestTag(repoUrl) {
52
+ export function detectLatestTag(repoUrl) {
52
53
  try {
53
54
  const out = execFileSync("git", ["ls-remote", "--tags", repoUrl], {
54
55
  encoding: "utf-8",
@@ -59,16 +60,7 @@ function detectLatestTag(repoUrl) {
59
60
  .split("\n")
60
61
  .map((line) => line.match(/refs\/tags\/v?([0-9]+\.[0-9]+\.[0-9]+)(?!\^)/)?.[1])
61
62
  .filter((t) => !!t)
62
- .sort((a, b) => {
63
- const pa = a.split(".").map(Number);
64
- const pb = b.split(".").map(Number);
65
- for (let i = 0; i < 3; i++) {
66
- const d = (pb[i] ?? 0) - (pa[i] ?? 0);
67
- if (d !== 0)
68
- return d;
69
- }
70
- return 0;
71
- });
63
+ .sort(semverDescending);
72
64
  return tags[0] ?? null;
73
65
  }
74
66
  catch {
package/dist/main.js CHANGED
@@ -99,6 +99,8 @@ function parseArgs(argv) {
99
99
  args.command = "report";
100
100
  else if (a === "leash")
101
101
  args.command = "leash";
102
+ else if (a === "upgrade")
103
+ args.command = "upgrade";
102
104
  // Slash-commands surfaced as CLI subcommands so users get a clear hint
103
105
  // instead of a confusing usage error. These work only in the chat plugin.
104
106
  else if (a === "start" || a === "audit" || a === "inbox" || a === "digest" ||
@@ -366,6 +368,7 @@ ${bold("Usage:")}
366
368
  npx great-cto mcp [--sse --port N]
367
369
  npx great-cto adapt [--dry-run]
368
370
  npx great-cto serve [--port 3142]
371
+ npx great-cto upgrade [superpowers|beads] Re-clone companions to latest tag + re-apply overlays
369
372
  npx great-cto help
370
373
  npx great-cto version
371
374
 
@@ -379,6 +382,12 @@ ${bold("Register:")}
379
382
  (auto-discovered after /audit or /start, but
380
383
  run this if the project doesn't appear in board)
381
384
 
385
+ ${bold("Upgrade:")}
386
+ great-cto upgrade Upgrade superpowers + beads to latest, re-apply critic overlays
387
+ great-cto upgrade superpowers Upgrade superpowers only
388
+ great-cto upgrade beads Upgrade beads only
389
+ ${dim("(Safe to run any time — idempotent if already on latest)")}
390
+
382
391
  ${bold("Scan (AI-security):")}
383
392
  great-cto scan AI-specific scan of cwd (OWASP LLM Top 10)
384
393
  great-cto scan ./src --severity high Filter by minimum severity
@@ -681,6 +690,12 @@ async function runInit(args) {
681
690
  warn(` install manually: claude plugin install github.com/obra/${r.name === "superpowers" ? "superpowers" : ""} or github.com/steveyegge/beads`);
682
691
  }
683
692
  }
693
+ // Apply bundled critic overlays (idempotent — skips already-applied changes)
694
+ try {
695
+ const { applyOverlays } = await import("./overlay.js");
696
+ applyOverlays();
697
+ }
698
+ catch { /* best-effort — overlay failure must not block init */ }
684
699
  }
685
700
  // ── 4c. bootstrap skills catalog (v1.0.140+) ─────────────
686
701
  // Clone external skill repos + run skill-discover.sh so agents have
@@ -867,6 +882,38 @@ async function tryInstallLeash(forceUpdate = false) {
867
882
  warn("llm-leash install failed — run `great-cto leash install` manually later");
868
883
  }
869
884
  }
885
+ async function runUpgrade(rawArgv) {
886
+ const { upgradePlugin, upgradeAll } = await import("./upgrade.js");
887
+ const { COMPANION_PLUGINS } = await import("./companion.js");
888
+ // Optional positional: great-cto upgrade [plugin-name]
889
+ const upgradeIdx = rawArgv.indexOf("upgrade");
890
+ const pluginArg = upgradeIdx >= 0 ? rawArgv[upgradeIdx + 1] : undefined;
891
+ const targetPlugin = pluginArg && !pluginArg.startsWith("--") ? pluginArg : undefined;
892
+ let results;
893
+ if (targetPlugin) {
894
+ const plugin = COMPANION_PLUGINS.find((p) => p.name === targetPlugin);
895
+ if (!plugin) {
896
+ error(`unknown plugin '${targetPlugin}'. Valid: ${COMPANION_PLUGINS.map((p) => p.name).join(", ")}`);
897
+ return 2;
898
+ }
899
+ results = [await upgradePlugin(plugin)];
900
+ }
901
+ else {
902
+ results = await upgradeAll();
903
+ }
904
+ for (const r of results) {
905
+ if (r.status === "upgraded") {
906
+ success(`${r.name} ${r.fromVersion} → ${r.toVersion}`);
907
+ }
908
+ else if (r.status === "already_latest") {
909
+ log(` ${dim(`${r.name} ${r.toVersion} already at latest (overlays re-applied)`)}`);
910
+ }
911
+ else {
912
+ warn(`${r.name} skipped — ${r.reason ?? "unknown reason"}`);
913
+ }
914
+ }
915
+ return 0;
916
+ }
870
917
  async function main() {
871
918
  const rawArgv = process.argv.slice(2);
872
919
  const args = parseArgs(rawArgv);
@@ -1005,6 +1052,16 @@ async function main() {
1005
1052
  process.exit(2);
1006
1053
  }
1007
1054
  }
1055
+ if (args.command === "upgrade") {
1056
+ try {
1057
+ const code = await runUpgrade(rawArgv);
1058
+ process.exit(code);
1059
+ }
1060
+ catch (e) {
1061
+ error(e.message);
1062
+ process.exit(2);
1063
+ }
1064
+ }
1008
1065
  if (args.command === "chat-only-hint") {
1009
1066
  const tried = args._slashTried || "<command>";
1010
1067
  error(`'${tried}' is a chat slash command, not a CLI subcommand.`);
@@ -0,0 +1,227 @@
1
+ /**
2
+ * overlay.ts — applies great-cto bundled critic overlays to the installed
3
+ * superpowers plugin.
4
+ *
5
+ * Two idempotent operations:
6
+ * 1. Copy 4 critic prompt files from package assets into superpowers cache
7
+ * 2. Patch 3 upstream SKILL.md files (detect → skip if already applied)
8
+ *
9
+ * Called after every superpowers install and from `great-cto upgrade`.
10
+ */
11
+ import { existsSync, readFileSync, writeFileSync, copyFileSync, mkdirSync, readdirSync, } from "node:fs";
12
+ import { join, dirname } from "node:path";
13
+ import { fileURLToPath } from "node:url";
14
+ import { homedir } from "node:os";
15
+ import { semverDescending } from "./semver.js";
16
+ export const CRITIC_ASSETS = [
17
+ {
18
+ assetRelPath: "brainstorming/spec-critic-prompt.md",
19
+ skillRelPath: "skills/brainstorming/spec-critic-prompt.md",
20
+ },
21
+ {
22
+ assetRelPath: "writing-plans/arch-critic-prompt.md",
23
+ skillRelPath: "skills/writing-plans/arch-critic-prompt.md",
24
+ },
25
+ {
26
+ assetRelPath: "finishing-a-development-branch/schema-critic-prompt.md",
27
+ skillRelPath: "skills/finishing-a-development-branch/schema-critic-prompt.md",
28
+ },
29
+ {
30
+ assetRelPath: "finishing-a-development-branch/api-critic-prompt.md",
31
+ skillRelPath: "skills/finishing-a-development-branch/api-critic-prompt.md",
32
+ },
33
+ ];
34
+ export const SKILL_PATCHES = [
35
+ // ── brainstorming/SKILL.md ─────────────────────────────────────────────
36
+ // Insert spec-critic dispatch block immediately before the User Review Gate section.
37
+ // Anchor: "\n\n**User Review Gate:**" — this section header is stable across
38
+ // upstream versions regardless of what precedes it in the Self-Review section.
39
+ {
40
+ skillRelPath: "skills/brainstorming/SKILL.md",
41
+ detectString: "spec-critic-prompt.md",
42
+ searchString: "\n\n**User Review Gate:**",
43
+ replaceWith: "\n\n" +
44
+ "**After self-review passes, dispatch spec critic:**\n\n" +
45
+ "Dispatch the spec-critic subagent (`./spec-critic-prompt.md`) now.\n" +
46
+ "Substitute all placeholders before dispatching:\n" +
47
+ "- Replace `[SPEC_FILE_PATH]` with the absolute path to the saved spec document\n" +
48
+ "- Replace `[SPEC_NAME]` in the description field with the spec filename (e.g., `2026-05-22-auth-design`)\n\n" +
49
+ "- If REVISION REQUIRED: fix each issue inline, re-dispatch (critic re-reads full spec, not just diff)\n" +
50
+ "- If APPROVED: append `Status: APPROVED` sign-off to the spec document, proceed to User Review Gate\n\n" +
51
+ "Do not proceed to the user review gate until the critic returns APPROVED.\n\n" +
52
+ "**User Review Gate:**",
53
+ },
54
+ // ── writing-plans/SKILL.md ─────────────────────────────────────────────
55
+ // Insert Architecture Critic section before Bite-Sized Task Granularity.
56
+ {
57
+ skillRelPath: "skills/writing-plans/SKILL.md",
58
+ detectString: "arch-critic-prompt.md",
59
+ searchString: "## Bite-Sized Task Granularity",
60
+ replaceWith: "## Architecture Critic\n\n" +
61
+ "After designing the File Map, dispatch an architecture critic subagent using `./arch-critic-prompt.md`.\n" +
62
+ "When dispatching, substitute all placeholders:\n" +
63
+ "- Replace `[PLAN_FILE_PATH]` with the absolute path to the plan document\n" +
64
+ "- Replace `[PLAN_NAME]` in the description field with the plan filename\n\n" +
65
+ "**The critic's job is adversarial:** find coupling traps, missing cross-cutting concerns,\n" +
66
+ "circular dependencies, and untestable designs that would cause the implementation to collapse.\n" +
67
+ "The critic is NOT a naming reviewer — stylistic feedback is noise.\n\n" +
68
+ "**Dispatch:** Use model `opus`.\n\n" +
69
+ "**If critic returns REVISION REQUIRED:**\n" +
70
+ "- Fix the file map inline in the plan document\n" +
71
+ "- Re-dispatch the critic (it re-reads the full file map, not just the diff)\n" +
72
+ "- Repeat until APPROVED\n\n" +
73
+ "**If critic returns APPROVED:** append `<!-- arch-critic: APPROVED -->` as a comment\n" +
74
+ "after the File Map table, then proceed to writing bite-sized tasks.\n\n" +
75
+ "**Do not write tasks until the architecture critic approves.** Structural errors found\n" +
76
+ "after tasks are written cascade into every task — far cheaper to catch at the file map stage.\n\n" +
77
+ "## Bite-Sized Task Granularity",
78
+ },
79
+ // ── finishing-a-development-branch/SKILL.md ────────────────────────────
80
+ // Insert Step 1.5 Pre-Ship Critics between Step 1 (tests) and Step 2 (base branch).
81
+ {
82
+ skillRelPath: "skills/finishing-a-development-branch/SKILL.md",
83
+ detectString: "schema-critic-prompt.md",
84
+ searchString: "**If tests pass:** Continue to Step 2.\n\n### Step 2:",
85
+ replaceWith: "**If tests pass:** Continue to Step 1.5.\n\n" +
86
+ "### Step 1.5: Pre-Ship Critics\n\n" +
87
+ "Before presenting merge/PR options, check whether the branch contains schema or API changes\n" +
88
+ "that require adversarial review.\n\n" +
89
+ "**Detect migration files** (checks only actual migration/schema files, not docs about them):\n" +
90
+ "```bash\n" +
91
+ "BASE=$(git merge-base HEAD main 2>/dev/null || git merge-base HEAD master)\n" +
92
+ "git diff --name-only \"$BASE\" HEAD \\\n" +
93
+ " | grep -E \"^(db/migrate/|migrations/|database/migrations/|.*\\.sql$)\" | head -20\n" +
94
+ "```\n\n" +
95
+ "If any files match, confirm with a brief list before dispatching:\n" +
96
+ "```\n" +
97
+ "Detected migration files: [list]. Run schema critic? (y to proceed, n to skip)\n" +
98
+ "```\n\n" +
99
+ "If confirmed → **dispatch schema critic:** use `./schema-critic-prompt.md`.\n" +
100
+ "Substitute all placeholders: `[MIGRATION_FILE_PATHS]` = list of detected files,\n" +
101
+ "`[BRANCH_NAME]` = current branch name (`git branch --show-current`).\n\n" +
102
+ "- If REVISION REQUIRED: fix the migration, re-dispatch (critic re-reads full migration)\n" +
103
+ "- If APPROVED: proceed\n\n" +
104
+ "**Detect API contract files** (routes, controllers, GraphQL, OpenAPI specs only — not test files):\n" +
105
+ "```bash\n" +
106
+ "BASE=$(git merge-base HEAD main 2>/dev/null || git merge-base HEAD master)\n" +
107
+ "git diff --name-only \"$BASE\" HEAD \\\n" +
108
+ " | grep -E \"^(src/routes/|src/controllers/|src/resolvers/|app/controllers/|api/|graphql/schema)\" \\\n" +
109
+ " | grep -v '__tests__\\|\\.test\\.\\|\\.spec\\.' | head -20\n" +
110
+ "```\n\n" +
111
+ "If any files match, confirm with a brief list before dispatching:\n" +
112
+ "```\n" +
113
+ "Detected API files: [list]. Run API contract critic? (y to proceed, n to skip)\n" +
114
+ "```\n\n" +
115
+ "If confirmed → **dispatch API contract critic:** use `./api-critic-prompt.md`.\n" +
116
+ "Substitute all placeholders: `[BASE_SHA]` = output of `git merge-base HEAD main`,\n" +
117
+ "`[HEAD_SHA]` = output of `git rev-parse HEAD`, `[BRANCH_NAME]` = `git branch --show-current`.\n\n" +
118
+ "- If REVISION REQUIRED: fix the API changes, re-dispatch\n" +
119
+ "- If APPROVED: proceed\n\n" +
120
+ "**If neither detected or both skipped:** proceed to Step 2 directly.\n\n" +
121
+ "**Do not proceed to Step 2 until all dispatched critics return APPROVED.**\n\n" +
122
+ "### Step 2:",
123
+ },
124
+ ];
125
+ /** Returns the assets/skills directory path, relative to the compiled dist/ output. */
126
+ export function getAssetsDir() {
127
+ const here = dirname(fileURLToPath(import.meta.url));
128
+ // dist/overlay.js → ../assets/skills/
129
+ return join(here, "..", "assets", "skills");
130
+ }
131
+ /**
132
+ * Returns the path to the highest installed superpowers version directory, or null.
133
+ * Sorts by semver descending so the latest version wins when multiple exist.
134
+ */
135
+ export function findSuperpowersDir() {
136
+ const base = join(homedir(), ".claude", "plugins", "cache", "local", "superpowers");
137
+ if (!existsSync(base))
138
+ return null;
139
+ try {
140
+ const versions = readdirSync(base)
141
+ .filter((v) => v.trim() !== "")
142
+ .sort(semverDescending);
143
+ return versions.length > 0 ? join(base, versions[0]) : null;
144
+ }
145
+ catch {
146
+ return null;
147
+ }
148
+ }
149
+ /**
150
+ * Copy 4 critic prompt files from the bundled assets into the superpowers
151
+ * cache. Always overwrites — the asset is the source of truth.
152
+ */
153
+ export function copyCriticFiles(superpowersDir, assetsDir) {
154
+ const copied = [];
155
+ const skipped = [];
156
+ for (const asset of CRITIC_ASSETS) {
157
+ const src = join(assetsDir, asset.assetRelPath);
158
+ const dest = join(superpowersDir, asset.skillRelPath);
159
+ if (!existsSync(src)) {
160
+ skipped.push(`${asset.assetRelPath} (asset missing)`);
161
+ continue;
162
+ }
163
+ mkdirSync(dirname(dest), { recursive: true });
164
+ copyFileSync(src, dest);
165
+ copied.push(asset.skillRelPath);
166
+ }
167
+ return { copied, skipped };
168
+ }
169
+ /**
170
+ * Apply 3 idempotent patches to upstream SKILL.md files.
171
+ * Each patch checks for its `detectString` first — if present, the patch is
172
+ * already applied and the file is skipped. If the `searchString` anchor is
173
+ * not found (upstream changed significantly), a warning is emitted and the
174
+ * file is skipped rather than corrupted.
175
+ */
176
+ export function patchSkillFiles(superpowersDir) {
177
+ const patched = [];
178
+ const skipped = [];
179
+ const warnings = [];
180
+ for (const patch of SKILL_PATCHES) {
181
+ const filePath = join(superpowersDir, patch.skillRelPath);
182
+ if (!existsSync(filePath)) {
183
+ warnings.push(`${patch.skillRelPath} not found — skipping patch`);
184
+ continue;
185
+ }
186
+ const content = readFileSync(filePath, "utf-8");
187
+ if (content.includes(patch.detectString)) {
188
+ skipped.push(patch.skillRelPath);
189
+ continue;
190
+ }
191
+ if (!content.includes(patch.searchString)) {
192
+ warnings.push(`${patch.skillRelPath} — anchor string not found (upstream may have changed); skipping`);
193
+ continue;
194
+ }
195
+ writeFileSync(filePath, content.replace(patch.searchString, patch.replaceWith), "utf-8");
196
+ patched.push(patch.skillRelPath);
197
+ }
198
+ return { patched, skipped, warnings };
199
+ }
200
+ /**
201
+ * Apply all overlays to the installed superpowers plugin.
202
+ *
203
+ * @param superpowersDirOverride - Pass an explicit path (used by `upgrade` command).
204
+ * Defaults to auto-detecting the installed superpowers version directory.
205
+ */
206
+ export function applyOverlays(superpowersDirOverride) {
207
+ const dir = superpowersDirOverride ?? findSuperpowersDir();
208
+ const assetsDir = getAssetsDir();
209
+ if (!dir) {
210
+ return {
211
+ superpowersDir: null,
212
+ copiedFiles: [],
213
+ patchedFiles: [],
214
+ skippedFiles: [],
215
+ warnings: ["superpowers not installed — skipping overlay"],
216
+ };
217
+ }
218
+ const { copied, skipped: skippedCopy } = copyCriticFiles(dir, assetsDir);
219
+ const { patched, skipped: skippedPatch, warnings } = patchSkillFiles(dir);
220
+ return {
221
+ superpowersDir: dir,
222
+ copiedFiles: copied,
223
+ patchedFiles: patched,
224
+ skippedFiles: [...skippedCopy, ...skippedPatch],
225
+ warnings,
226
+ };
227
+ }
package/dist/semver.js ADDED
@@ -0,0 +1,12 @@
1
+ /** Shared semver utilities. */
2
+ /** Compare two semver strings descending (highest first). */
3
+ export function semverDescending(a, b) {
4
+ const pa = a.split(".").map((n) => parseInt(n, 10) || 0);
5
+ const pb = b.split(".").map((n) => parseInt(n, 10) || 0);
6
+ for (let i = 0; i < 3; i++) {
7
+ const d = (pb[i] ?? 0) - (pa[i] ?? 0);
8
+ if (d !== 0)
9
+ return d;
10
+ }
11
+ return 0;
12
+ }
@@ -0,0 +1,111 @@
1
+ /**
2
+ * upgrade.ts — force re-clone companion plugins to their latest semver tag,
3
+ * then re-apply great-cto overlays.
4
+ *
5
+ * `great-cto upgrade [plugin]`
6
+ * plugin: "superpowers" | "beads" | undefined → all
7
+ */
8
+ import { existsSync, readdirSync, rmSync } from "node:fs";
9
+ import { homedir } from "node:os";
10
+ import { join } from "node:path";
11
+ import { COMPANION_PLUGINS, installCompanionPlugin, detectLatestTag } from "./companion.js";
12
+ import { applyOverlays } from "./overlay.js";
13
+ import { semverDescending } from "./semver.js";
14
+ function getPluginCacheDir(name) {
15
+ return join(homedir(), ".claude", "plugins", "cache", "local", name);
16
+ }
17
+ /** Returns the highest installed semver version for a plugin, or null. */
18
+ function getInstalledVersion(name) {
19
+ const base = getPluginCacheDir(name);
20
+ if (!existsSync(base))
21
+ return null;
22
+ try {
23
+ const versions = readdirSync(base)
24
+ .filter((v) => v.trim() !== "")
25
+ .sort(semverDescending);
26
+ return versions.length > 0 ? versions[0] : null;
27
+ }
28
+ catch {
29
+ return null;
30
+ }
31
+ }
32
+ /**
33
+ * Force-upgrade a single companion plugin to its latest semver tag.
34
+ * If already on the latest tag, re-applies overlays and returns `already_latest`.
35
+ */
36
+ export async function upgradePlugin(plugin) {
37
+ const { name, repoUrl } = plugin;
38
+ const currentVersion = getInstalledVersion(name);
39
+ const latestTag = detectLatestTag(repoUrl);
40
+ const latestVersion = latestTag ?? "main";
41
+ // Already on latest — just re-apply overlays in case they were missing
42
+ if (currentVersion && currentVersion === latestVersion) {
43
+ if (name === "superpowers") {
44
+ applyOverlays(join(getPluginCacheDir(name), currentVersion));
45
+ }
46
+ return { name, status: "already_latest", fromVersion: currentVersion, toVersion: latestVersion };
47
+ }
48
+ // Remove ALL existing version directories so installCompanionPlugin's
49
+ // isAlreadyInstalled guard always returns null and the clone proceeds fresh.
50
+ const cacheDir = getPluginCacheDir(name);
51
+ if (existsSync(cacheDir)) {
52
+ try {
53
+ const existingVersions = readdirSync(cacheDir).filter((v) => v.trim() !== "");
54
+ for (const v of existingVersions) {
55
+ rmSync(join(cacheDir, v), { recursive: true, force: true });
56
+ }
57
+ }
58
+ catch (e) {
59
+ return {
60
+ name,
61
+ status: "skipped",
62
+ fromVersion: currentVersion ?? "—",
63
+ toVersion: latestVersion,
64
+ reason: `failed to remove old versions: ${e.message}`,
65
+ };
66
+ }
67
+ }
68
+ // Re-install via companion installer (handles clone + settings enable).
69
+ // All version dirs were removed above, so isAlreadyInstalled returns null
70
+ // and the clone always proceeds fresh.
71
+ const result = installCompanionPlugin(plugin);
72
+ if (result.status === "skipped") {
73
+ return {
74
+ name,
75
+ status: "skipped",
76
+ fromVersion: currentVersion ?? "—",
77
+ toVersion: latestVersion,
78
+ reason: result.reason,
79
+ };
80
+ }
81
+ // "installed" | "already_present" → plugin is present; apply overlays
82
+ if (name === "superpowers") {
83
+ const newDir = join(getPluginCacheDir(name), result.version);
84
+ applyOverlays(newDir);
85
+ }
86
+ return {
87
+ name,
88
+ status: "upgraded",
89
+ fromVersion: currentVersion ?? "—",
90
+ toVersion: result.version,
91
+ };
92
+ }
93
+ /** Upgrade all companion plugins. Never throws — best-effort for each. */
94
+ export async function upgradeAll() {
95
+ const results = [];
96
+ for (const plugin of COMPANION_PLUGINS) {
97
+ try {
98
+ results.push(await upgradePlugin(plugin));
99
+ }
100
+ catch (e) {
101
+ results.push({
102
+ name: plugin.name,
103
+ status: "skipped",
104
+ fromVersion: "—",
105
+ toVersion: "—",
106
+ reason: e.message,
107
+ });
108
+ }
109
+ }
110
+ return results;
111
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "great-cto",
3
- "version": "2.17.0",
3
+ "version": "2.18.0",
4
4
  "description": "One command install for the great_cto Claude Code plugin. Auto-detects your stack, picks the right archetype, bootstraps PROJECT.md.",
5
5
  "keywords": [
6
6
  "claude-code",
@@ -69,6 +69,7 @@
69
69
  "files": [
70
70
  "index.mjs",
71
71
  "dist/",
72
+ "assets/",
72
73
  "agentshield-rules/",
73
74
  "postinstall.mjs",
74
75
  "README.md"