@ggdna/dna-gg 0.1.2 → 0.3.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
@@ -14,6 +14,13 @@ publish.
14
14
  `dna/doc/guides/install-guide/install-gg-workspace-guide.md` — install
15
15
  `gg` and set up a workspace
16
16
 
17
+ ## CLAUDE.md
18
+
19
+ - `dna/CLAUDE.md` — points the agent to the `ai-dev-guide` and the
20
+ skills. helix writes it into the managed block of the consumer's
21
+ `CLAUDE.md` (`<!-- helix:claude_md:start/end -->`), everything outside
22
+ the block stays with the repo.
23
+
17
24
  ## Skills
18
25
 
19
26
  - `/ticket` — creates a ticket and adds the repos it needs
@@ -27,14 +34,25 @@ publish.
27
34
  - `dna/dot-github/workflows/quick_check.yaml` — the quick check pipeline
28
35
  every pull request has to pass
29
36
 
37
+ ## Scripts
38
+
39
+ - `dna/scripts/delete-feature-branch.js` — the one script this layer calls
40
+ itself, from `/cleanup`, with the two functions it imports:
41
+ `dna/scripts/functions/colors.js` and
42
+ `dna/scripts/functions/run-command.js`
43
+
44
+ These three files are byte-identical copies of their originals in
45
+ [dna_scripts](https://github.com/ggdna/dna_scripts). They are duplicated
46
+ on purpose so that this layer does not drag the whole script set into
47
+ every repo that only wants the gg workflow. A repo that wants the full
48
+ set lists `dna_scripts` as a layer of its own — the copies are identical,
49
+ so both layers together produce exactly the same files.
50
+
30
51
  ## Layers
31
52
 
32
53
  Builds on [dna_install](https://github.com/ggdna/dna_install) for the
33
- install overview, [dna_index](https://github.com/ggdna/dna_index) for the
34
- repo index every gg repo keeps, and
35
- [dna_scripts](https://github.com/ggdna/dna_scripts) for
36
- `setup-github-repo.js`, `rename-class.js`, `wait-for-pr.js` and
37
- `delete-feature-branch.js`, which the guides above call.
54
+ install overview and [dna_index](https://github.com/ggdna/dna_index) for
55
+ the repo index every gg repo keeps.
38
56
 
39
57
  It extends the `@tooling` section of the install overview through
40
58
  `dna/doc/guides/install-guide.overrides.md`: it adds `Install gg` and
package/dna/CLAUDE.md ADDED
@@ -0,0 +1,10 @@
1
+ # gg workflow
2
+
3
+ This repo is developed ticket by ticket with the `gg` CLI. Follow the
4
+ development guide, it tells you when to ask the user and which command
5
+ comes next:
6
+
7
+ @doc/guides/for-ai/ai-dev-guide.md
8
+
9
+ The steps are also available as skills: `/ticket`, `/commit`, `/push`,
10
+ `/publish`, `/cleanup`.
package/dna/_dna.json CHANGED
@@ -5,7 +5,12 @@
5
5
 
6
6
  // The parent DNAs. dna_install brings the install overview this layer
7
7
  // extends with the gg install guides, dna_index the index conventions
8
- // every gg repo follows, dna_scripts the node scripts this layer's
9
- // guides call. Parents first, this layer wins.
10
- "layers": ["dna_install", "dna_index", "dna_scripts"]
8
+ // every gg repo follows. Parents first, this layer wins.
9
+ //
10
+ // dna_scripts is deliberately not a parent: this layer calls exactly one
11
+ // of its scripts — `delete-feature-branch.js` from the /cleanup skill —
12
+ // and carries its own copy of it under dna/scripts/ instead. A consumer
13
+ // that wants the full script set lists dna_scripts itself; the copies
14
+ // here are byte-identical, so having both layers changes nothing.
15
+ "layers": ["dna_install", "dna_index"]
11
16
  }
@@ -5,9 +5,9 @@
5
5
  "name": "base",
6
6
  "package": "helix",
7
7
  "ecosystem": null,
8
- "resolvedVersion": "1.0.1",
8
+ "resolvedVersion": "1.6.1",
9
9
  "via": null,
10
- "hash": "0x705e486e88a93125"
10
+ "hash": "0x6883da335b415f9d"
11
11
  },
12
12
  {
13
13
  "name": "dna-install",
@@ -25,28 +25,21 @@
25
25
  "via": null,
26
26
  "hash": "0x1d92b0add37a1ac7"
27
27
  },
28
- {
29
- "name": "dna-scripts",
30
- "package": "@ggdna/dna-scripts",
31
- "ecosystem": "node",
32
- "resolvedVersion": "0.1.0",
33
- "via": null,
34
- "hash": "0x9ee08ef13ab4c8d3"
35
- },
36
28
  {
37
29
  "name": "self",
38
30
  "package": null,
39
31
  "ecosystem": null,
40
32
  "resolvedVersion": null,
41
33
  "via": null,
42
- "hash": "0xd5744033dd70c6a3"
34
+ "hash": "0x9f13019b84e4b029"
43
35
  }
44
36
  ],
45
37
  "claude": {
46
- "claudeMdInclude": null
38
+ "claudeMdInclude": null,
39
+ "claudeMdFromDna": true
47
40
  },
48
- "baseVersion": "1.0.1",
49
- "baseHash": "0x705e486e88a93125",
41
+ "baseVersion": "1.6.1",
42
+ "baseHash": "0x6883da335b415f9d",
50
43
  "instances": [
51
44
  {
52
45
  "path": ".claude/skills/cleanup/SKILL.md",
@@ -72,13 +65,9 @@
72
65
  "path": ".claude/skills/push/SKILL.md",
73
66
  "hash": "0x76c357ca9933317d"
74
67
  },
75
- {
76
- "path": ".claude/skills/scripts/SKILL.md",
77
- "hash": "0xa12593aa0af31ed2"
78
- },
79
68
  {
80
69
  "path": ".claude/skills/ticket/SKILL.md",
81
- "hash": "0xbc13efe6fa9af962"
70
+ "hash": "0xa86135ff5b7f5ddf"
82
71
  },
83
72
  {
84
73
  "path": ".github/workflows/quick_check.yaml",
@@ -94,7 +83,7 @@
94
83
  },
95
84
  {
96
85
  "path": "doc/guides/for-ai/ai-dev-guide.md",
97
- "hash": "0x3d2812a1dfb025cf"
86
+ "hash": "0x34d8b0200c0d657b"
98
87
  },
99
88
  {
100
89
  "path": "doc/guides/index-guide.md",
@@ -130,7 +119,7 @@
130
119
  },
131
120
  {
132
121
  "path": "doc/guides/install-guide/install-gg-workspace-guide.md",
133
- "hash": "0x846766914bb56a84"
122
+ "hash": "0xc06dc45d20e1bf79"
134
123
  },
135
124
  {
136
125
  "path": "doc/guides/install-guide/install-github-cli-guide.md",
@@ -148,14 +137,6 @@
148
137
  "path": "doc/guides/install-guide/install-vscode-guide.md",
149
138
  "hash": "0xa0da6a6877bb94c2"
150
139
  },
151
- {
152
- "path": "doc/guides/scripts-guide.md",
153
- "hash": "0x426857c389049083"
154
- },
155
- {
156
- "path": "doc/hello_world.md",
157
- "hash": "0x0903f7fc5224f6f1"
158
- },
159
140
  {
160
141
  "path": "doc/templates/index-template.jsonc",
161
142
  "hash": "0x16c3a8d50c72ed6d"
@@ -168,53 +149,9 @@
168
149
  "path": "scripts/functions/colors.js",
169
150
  "hash": "0xdfd97f3804665811"
170
151
  },
171
- {
172
- "path": "scripts/functions/current-branch.js",
173
- "hash": "0xb9ebbadf45893278"
174
- },
175
- {
176
- "path": "scripts/functions/directories.js",
177
- "hash": "0x148d4ebb8aa75523"
178
- },
179
- {
180
- "path": "scripts/functions/get-repo-urls.js",
181
- "hash": "0x4c7b3897973acec3"
182
- },
183
- {
184
- "path": "scripts/functions/get-version.js",
185
- "hash": "0xfe46316558755cf2"
186
- },
187
- {
188
- "path": "scripts/functions/is-clean-repo.js",
189
- "hash": "0x8aa95ca51d9d6517"
190
- },
191
- {
192
- "path": "scripts/functions/is-main-up-to-date.js",
193
- "hash": "0xe1ab1826d0ddd039"
194
- },
195
- {
196
- "path": "scripts/functions/pull-request-url.js",
197
- "hash": "0x5398755a61a59928"
198
- },
199
152
  {
200
153
  "path": "scripts/functions/run-command.js",
201
154
  "hash": "0x085b390fcb9256ab"
202
- },
203
- {
204
- "path": "scripts/functions/sync-folders.js",
205
- "hash": "0x4f83165fd92ec49d"
206
- },
207
- {
208
- "path": "scripts/rename-class.js",
209
- "hash": "0xa9daec4f3ea514b7"
210
- },
211
- {
212
- "path": "scripts/setup-github-repo.js",
213
- "hash": "0x5907588070a580ca"
214
- },
215
- {
216
- "path": "scripts/wait-for-pr.js",
217
- "hash": "0x1360c661984b78a8"
218
155
  }
219
156
  ]
220
157
  }
@@ -29,6 +29,23 @@ gg do create ticket dnaJiraPrefix-145 -m"Fix issue abc"
29
29
  cd tickets/dnaJiraPrefix-145
30
30
  ```
31
31
 
32
+ ## Choose the project management repo
33
+
34
+ Every ticket belongs to a project management (PM) repo. It holds the plans,
35
+ decisions and blog posts of a project, but no code.
36
+
37
+ Look at the `index.jsonc` of each repo in .ocean and find the PM repo the
38
+ ticket belongs to: its summary or domain talks about project management or
39
+ planning, not about code. If one fits, propose it to the user. If none fits,
40
+ ask the user which repo to use, or whether to create a new PM repo.
41
+
42
+ After the user's confirmation, add the PM repo to the ticket **before** any
43
+ other repo:
44
+
45
+ ```bash
46
+ gg do add pm_repo
47
+ ```
48
+
32
49
  ## Add git repositories
33
50
 
34
51
  Look at the `index.jsonc` of each repo in .ocean and decide which repos need to
@@ -40,6 +57,9 @@ Ask the user about this. Also explain to the user what you roughly want to
40
57
  change in which repo to implement the ticket and let them confirm that the
41
58
  corresponding repos are added to the ticket.
42
59
 
60
+ If the ticket is only planned (see below), the PM repo may be the only repo
61
+ of the ticket.
62
+
43
63
  After the user's confirmation, add the repos to the ticket:
44
64
 
45
65
  ```bash
@@ -52,9 +72,23 @@ gg do add repo1 repo2
52
72
  gg do code
53
73
  ```
54
74
 
55
- ## Implement
75
+ ## Plan (optional)
76
+
77
+ Ask the user whether the ticket is planned before it is implemented.
78
+
79
+ If yes, write the plan into the PM repo, following the guides of the PM repo:
80
+ the goal, the affected repos, the rough steps and open questions. Let the user
81
+ review the plan and revise it until they confirm it.
82
+
83
+ ## Implement (optional)
84
+
85
+ Ask the user whether the ticket is implemented now, or whether it is only
86
+ planned. Some tickets are only planned; the implementation follows in a later
87
+ ticket.
56
88
 
57
- Implement your features based on the guides
89
+ - Implement: implement your features based on the guides
90
+ - Plan only: skip this step. The following steps then apply to the PM repo
91
+ only.
58
92
 
59
93
  ## Commit
60
94
 
@@ -86,6 +120,7 @@ Afterwards load the review-light skill and execute it.
86
120
  - Create a blog post for the current ticket
87
121
  - Update the index.jsonc and README.md
88
122
  - Create the configuration for gg do publish
123
+ - If the ticket was only planned, publish the PM repo only
89
124
 
90
125
  Ask the user to run the following command **manually**:
91
126
 
@@ -21,6 +21,11 @@ cd ~/dev2
21
21
  gg do init workspace
22
22
  ```
23
23
 
24
+ This creates the `.ocean` folder and instantiates the latest `dna_gg` in
25
+ the workspace folder: the gg guides, the skills and the managed block of
26
+ `CLAUDE.md`. It is the same as running `gg dna init`, `gg dna add dna_gg`
27
+ and `gg dna build` by hand.
28
+
24
29
  ## Add your repositories
25
30
 
26
31
  ```bash
@@ -21,12 +21,25 @@ gg do create ticket DnaJiraPrefix-145 -m"Fix issue abc"
21
21
  cd tickets/DnaJiraPrefix-145
22
22
  ```
23
23
 
24
- ## 3. Choose the repos
24
+ ## 3. Choose the project management repo
25
+
26
+ Every ticket belongs to a project management (PM) repo: plans, decisions and
27
+ blog posts of a project, no code. Read the `index.md` of the repos in
28
+ `.ocean` and propose the PM repo the ticket belongs to. If none fits, ask
29
+ which repo to use or whether to create one.
30
+
31
+ After the confirmation, add it **before** any other repo:
32
+
33
+ ```bash
34
+ gg do add pm_repo
35
+ ```
36
+
37
+ ## 4. Choose the code repos
25
38
 
26
39
  Read the `index.md` of the candidate repos in `.ocean`. Tell the user which
27
40
  repos the ticket needs and what you roughly want to change in each one. If a
28
41
  part belongs to a domain that has no repo yet, say so and ask whether to
29
- create one.
42
+ create one. A ticket that is only planned may need no code repo at all.
30
43
 
31
44
  After the confirmation:
32
45
 
@@ -34,12 +47,19 @@ After the confirmation:
34
47
  gg do add repo1 repo2
35
48
  ```
36
49
 
37
- ## 4. Open the workspace
50
+ ## 5. Open the workspace
38
51
 
39
52
  ```bash
40
53
  gg do code
41
54
  ```
42
55
 
56
+ ## 6. Plan or implement
57
+
58
+ Ask the user whether the ticket is planned first. If yes, write the plan into
59
+ the PM repo and let the user confirm it. Then ask whether the ticket is
60
+ implemented now or only planned — in the latter case the ticket ends with
61
+ the PM repo alone.
62
+
43
63
  ## Important
44
64
 
45
65
  - Never add repos without confirmation. Rather too few than too many — more
@@ -0,0 +1,97 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) dnaCopyrightHolder
4
+ *
5
+ * Use of this source code is governed by terms that can be
6
+ * found in the LICENSE file in the root of this package.
7
+ */
8
+
9
+ import { gray, green, red, yellow } from './functions/colors.js';
10
+ import { runCommand } from './functions/run-command.js';
11
+
12
+ // Check for uncommitted changes
13
+ function hasUncommittedChanges() {
14
+ console.log(gray('Check for uncommitted changes'));
15
+ const status = runCommand('git status --porcelain');
16
+ return status.length > 0;
17
+ }
18
+
19
+ // Check for unpushed commits
20
+ function hasUnpushedCommits(branch) {
21
+ try {
22
+ console.log(gray('Check for unpushed commits'));
23
+ runCommand(`git rev-parse --abbrev-ref ${branch}@{u}`);
24
+ const ahead = runCommand(`git rev-list --count ${branch}@{u}..${branch}`);
25
+ return parseInt(ahead, 10) > 0;
26
+ } catch {
27
+ return true;
28
+ }
29
+ }
30
+
31
+ // Try a test merge into main and check if it introduces changes
32
+ function isBranchEffectivelyMerged(featureBranch) {
33
+ console.log(gray('Check if feature was fully merged'));
34
+
35
+ try {
36
+ runCommand(`git merge --no-commit --no-ff ${featureBranch}`);
37
+ const changed = hasUncommittedChanges();
38
+ runCommand('git merge --abort');
39
+ return !changed;
40
+ } catch {
41
+ try {
42
+ runCommand('git merge --abort');
43
+ } catch {}
44
+ return false;
45
+ }
46
+ }
47
+
48
+ try {
49
+ console.log(gray('Get current branch name'));
50
+ const currentBranch = runCommand('git rev-parse --abbrev-ref HEAD');
51
+
52
+ if (currentBranch === 'main') {
53
+ console.log(yellow('Please call this script from a feature branch.'));
54
+ process.exit(0);
55
+ }
56
+
57
+ if (hasUncommittedChanges()) {
58
+ console.error(red('❌ You have uncommitted changes.'));
59
+ console.error(
60
+ yellow('Please commit or stash your changes before continuing.'),
61
+ );
62
+ process.exit(1);
63
+ }
64
+
65
+ if (hasUnpushedCommits(currentBranch)) {
66
+ console.error(red('❌ You have unpushed commits.'));
67
+ console.error(yellow('Please push your branch before continuing.'));
68
+ process.exit(1);
69
+ }
70
+
71
+ console.log(gray(`Fetching and pulling 'main'...`));
72
+ runCommand('git fetch');
73
+ runCommand('git checkout main');
74
+ runCommand('git pull origin main');
75
+
76
+ const isMerged = isBranchEffectivelyMerged(currentBranch);
77
+
78
+ if (isMerged) {
79
+ runCommand(`git branch -d ${currentBranch}`);
80
+ console.log(green(`✅ Branch '${currentBranch}' has been deleted.`));
81
+ } else {
82
+ console.error(
83
+ red(`❌ Branch '${currentBranch}' is not merged into 'main'.`),
84
+ );
85
+ console.log(
86
+ yellow(`Please (create and) merge a pull request and try again.`),
87
+ );
88
+ runCommand(`git checkout ${currentBranch}`);
89
+ console.log(gray(`Switched back to '${currentBranch}'.`));
90
+ }
91
+ } catch (error) {
92
+ console.error(red(`Error: ${error.message}`));
93
+ try {
94
+ runCommand('git merge --abort');
95
+ } catch {}
96
+ process.exit(1);
97
+ }
@@ -0,0 +1,27 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) dnaCopyrightHolder
4
+ *
5
+ * Use of this source code is governed by terms that can be
6
+ * found in the LICENSE file in the root of this package.
7
+ */
8
+
9
+ export const red = (str) => `\x1b[31m${str}\x1b[0m`;
10
+ export const green = (str) => `\x1b[32m${str}\x1b[0m`;
11
+ export const yellow = (str) => `\x1b[33m${str}\x1b[0m`;
12
+ export const blue = (str) => `\x1b[34m${str}\x1b[0m`;
13
+ export const magenta = (str) => `\x1b[35m${str}\x1b[0m`;
14
+ export const cyan = (str) => `\x1b[36m${str}\x1b[0m`;
15
+ export const white = (str) => `\x1b[37m${str}\x1b[0m`;
16
+ export const black = (str) => `\x1b[30m${str}\x1b[0m`;
17
+ export const bgRed = (str) => `\x1b[41m${str}\x1b[0m`;
18
+ export const bgGreen = (str) => `\x1b[42m${str}\x1b[0m`;
19
+ export const bgYellow = (str) => `\x1b[43m${str}\x1b[0m`;
20
+ export const bgBlue = (str) => `\x1b[44m${str}\x1b[0m`;
21
+ export const bgMagenta = (str) => `\x1b[45m${str}\x1b[0m`;
22
+ export const bgCyan = (str) => `\x1b[46m${str}\x1b[0m`;
23
+ export const bgWhite = (str) => `\x1b[47m${str}\x1b[0m`;
24
+ export const bgBlack = (str) => `\x1b[40m${str}\x1b[0m`;
25
+ export const gray = (str) => `\x1b[90m${str}\x1b[0m`;
26
+ export const lightGray = (str) => `\x1b[37m${str}\x1b[0m`;
27
+ export const reset = (str) => `\x1b[0m${str}\x1b[0m`;
@@ -0,0 +1,22 @@
1
+ /**
2
+ * @license
3
+ * Copyright (c) dnaCopyrightHolder
4
+ *
5
+ * Use of this source code is governed by terms that can be
6
+ * found in the LICENSE file in the root of this package.
7
+ */
8
+
9
+ import { execSync } from 'child_process';
10
+ import { gray } from './colors.js';
11
+
12
+ // Execute a shell command and return trimmed output
13
+ // Execute a shell command and return trimmed output
14
+ export function runCommand(command, silent = true, logCommand = true) {
15
+ if (logCommand) {
16
+ console.log(gray(`${command}`));
17
+ }
18
+ return execSync(command, {
19
+ encoding: 'utf-8',
20
+ stdio: silent ? ['pipe', 'pipe', 'pipe'] : undefined,
21
+ }).trim();
22
+ }
package/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@ggdna/dna-gg",
3
- "version": "0.1.2",
3
+ "version": "0.3.0",
4
4
  "description": "DNA layer: gg CLI workflow guides, repo setup scripts and CI check",
5
5
  "keywords": [
6
6
  "dna",
@@ -29,18 +29,16 @@
29
29
  },
30
30
  "dependencies": {
31
31
  "@ggdna/dna-index": "^0.1.0",
32
- "@ggdna/dna-install": "^0.1.0",
33
- "@ggdna/dna-scripts": "^0.1.0"
32
+ "@ggdna/dna-install": "^0.1.0"
33
+ },
34
+ "devDependencies": {
35
+ "@types/node": "^26.5.0",
36
+ "prettier": "^3.9.6"
34
37
  },
35
38
  "scripts": {
36
39
  "test:dart": "dart test",
37
40
  "test": "pnpm run test:dart",
38
- "prepublishOnly": "pnpm run test",
39
41
  "format": "prettier --write .",
40
42
  "format:check": "prettier --check ."
41
- },
42
- "devDependencies": {
43
- "@types/node": "^26.2.0",
44
- "prettier": "^3.9.6"
45
43
  }
46
- }
44
+ }