@ggdna/dna-gg 1.2.0 → 1.4.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
|
@@ -52,10 +52,12 @@ All skills of this layer are prefixed with `gg-`:
|
|
|
52
52
|
prompts wait in `~/.claude/pm-prompts/sessions/` and are committed to the
|
|
53
53
|
branch `prompts` of that repo when a session starts or ends, under
|
|
54
54
|
`doc/prompts/<first name>/<yyyy-mm>/<yyyy-mm-dd>_<repo>_<session>.md`.
|
|
55
|
-
The first name comes from
|
|
56
|
-
|
|
57
|
-
|
|
58
|
-
|
|
55
|
+
The first name comes from `doc/team/people.md` there, found by the git
|
|
56
|
+
user name: a first name equal to it or to its first word, or a `Git`
|
|
57
|
+
line listing it. An unknown name goes to `doc/prompts/_unknown/`. No
|
|
58
|
+
e-mail address is read or written; the commits carry the neutral author
|
|
59
|
+
`pm-prompts`. Only the prompts are kept, never the answers; tokens and
|
|
60
|
+
passwords are replaced by `[redacted]`. No working tree is touched: the commit is built in a bare
|
|
59
61
|
cache below `~/.claude/pm-prompts/repos/`. Needs `node` and `git`; a
|
|
60
62
|
failure never stops a prompt and ends up in
|
|
61
63
|
`~/.claude/pm-prompts/sync.log`.
|
package/dna/_generated.json
CHANGED
|
@@ -39,7 +39,7 @@
|
|
|
39
39
|
"ecosystem": null,
|
|
40
40
|
"resolvedVersion": null,
|
|
41
41
|
"via": null,
|
|
42
|
-
"hash": "
|
|
42
|
+
"hash": "0xcda6ccaeb5d52dd1"
|
|
43
43
|
}
|
|
44
44
|
],
|
|
45
45
|
"claude": {
|
|
@@ -59,7 +59,7 @@
|
|
|
59
59
|
},
|
|
60
60
|
{
|
|
61
61
|
"path": ".claude/hooks/pm-prompts.mjs",
|
|
62
|
-
"hash": "
|
|
62
|
+
"hash": "0xf4266eea17b3b9c1"
|
|
63
63
|
},
|
|
64
64
|
{
|
|
65
65
|
"path": ".claude/settings.json",
|
|
@@ -107,7 +107,7 @@
|
|
|
107
107
|
},
|
|
108
108
|
{
|
|
109
109
|
"path": "doc/guides/develop-guide.md",
|
|
110
|
-
"hash": "
|
|
110
|
+
"hash": "0xed4328d138fe76ef"
|
|
111
111
|
},
|
|
112
112
|
{
|
|
113
113
|
"path": "doc/guides/develop-without-ai-guide.md",
|
|
@@ -115,7 +115,7 @@
|
|
|
115
115
|
},
|
|
116
116
|
{
|
|
117
117
|
"path": "doc/guides/for-ai/ai-dev-guide.md",
|
|
118
|
-
"hash": "
|
|
118
|
+
"hash": "0xb6eecdb4c7a1ebe8"
|
|
119
119
|
},
|
|
120
120
|
{
|
|
121
121
|
"path": "doc/guides/index-guide.md",
|
|
@@ -47,6 +47,8 @@ Use the following skills in Claude
|
|
|
47
47
|
When the repo belongs to a project management repo, every prompt you write
|
|
48
48
|
to Claude Code is kept there, under `doc/prompts/<your first name>/` on the
|
|
49
49
|
branch `prompts`. Only the prompts, not the answers. Tokens and passwords
|
|
50
|
-
are replaced by `[redacted]`. Your first name comes from
|
|
51
|
-
`doc/team/people.md` in the project management repo
|
|
52
|
-
|
|
50
|
+
are replaced by `[redacted]`. Your first name comes from
|
|
51
|
+
`doc/team/people.md` in the project management repo: the person whose
|
|
52
|
+
first name is your git user name or its first word, or whose `Git` line
|
|
53
|
+
lists your git user name. Otherwise your prompts land in
|
|
54
|
+
`doc/prompts/_unknown/`. Your e-mail address never goes there.
|
|
@@ -169,7 +169,9 @@ ticket.
|
|
|
169
169
|
[Describe every repo in its own terms](#describe-every-repo-in-its-own-terms)).
|
|
170
170
|
Keep every repo in its scope while you code: stop and propose a split,
|
|
171
171
|
a new repo or a move as soon as code does not fit (see
|
|
172
|
-
[Keep every repo in its scope](#keep-every-repo-in-its-scope))
|
|
172
|
+
[Keep every repo in its scope](#keep-every-repo-in-its-scope)).
|
|
173
|
+
Before each change, if the repo has `doc/guides/architecture-guide.md`,
|
|
174
|
+
decide where the code goes as its `@placement` describes
|
|
173
175
|
- Plan only: skip this step. The following steps then apply to the project
|
|
174
176
|
management repo only.
|
|
175
177
|
|
|
@@ -238,7 +238,7 @@ export function onPrompt(input) {
|
|
|
238
238
|
started: new Date().toISOString(),
|
|
239
239
|
folder: path.basename(projectDir),
|
|
240
240
|
repos,
|
|
241
|
-
|
|
241
|
+
name: git(['-C', projectDir, 'config', 'user.name']).out,
|
|
242
242
|
targets,
|
|
243
243
|
});
|
|
244
244
|
}
|
|
@@ -299,28 +299,35 @@ export function slug(name) {
|
|
|
299
299
|
.replace(/^-+|-+$/g, '');
|
|
300
300
|
}
|
|
301
301
|
|
|
302
|
-
/**
|
|
303
|
-
|
|
304
|
-
|
|
302
|
+
/**
|
|
303
|
+
* The first name in [peopleMd] for the git user name [gitName]: the person
|
|
304
|
+
* whose `Git` line lists it, else the person whose first name is the git
|
|
305
|
+
* name or its first word. E-mail addresses play no part.
|
|
306
|
+
*/
|
|
307
|
+
export function personOf(gitName, peopleMd) {
|
|
308
|
+
const wanted = (gitName ?? '').trim().toLowerCase();
|
|
309
|
+
if (!wanted) return '';
|
|
310
|
+
const byFirstName = new Map();
|
|
305
311
|
let name = '';
|
|
306
312
|
for (const line of peopleMd.split(/\r?\n/)) {
|
|
307
313
|
const heading = line.match(/^##\s+(.+?)\s*$/);
|
|
308
314
|
if (heading) {
|
|
309
315
|
name = heading[1];
|
|
316
|
+
byFirstName.set(name.toLowerCase(), name);
|
|
310
317
|
continue;
|
|
311
318
|
}
|
|
312
|
-
const
|
|
319
|
+
const names = line.match(/^\s*-\s*Git:\s*(.+)$/i);
|
|
313
320
|
if (
|
|
314
321
|
name &&
|
|
315
|
-
|
|
316
|
-
|
|
317
|
-
.split(/[,;\s]+/)
|
|
318
|
-
.some((e) => e.toLowerCase() === email.toLowerCase())
|
|
322
|
+
names &&
|
|
323
|
+
names[1].split(/[,;]/).some((n) => n.trim().toLowerCase() === wanted)
|
|
319
324
|
) {
|
|
320
325
|
return name;
|
|
321
326
|
}
|
|
322
327
|
}
|
|
323
|
-
return
|
|
328
|
+
return (
|
|
329
|
+
byFirstName.get(wanted) ?? byFirstName.get(wanted.split(/\s+/)[0]) ?? ''
|
|
330
|
+
);
|
|
324
331
|
}
|
|
325
332
|
|
|
326
333
|
/** Where the prompts of a session go in the project management repo. */
|
|
@@ -336,7 +343,7 @@ export function renderHead(meta, person) {
|
|
|
336
343
|
const lines = [
|
|
337
344
|
`# ${localDate(meta.started)} · ${meta.folder} · ${String(meta.session).slice(0, 8)}`,
|
|
338
345
|
'',
|
|
339
|
-
`- Person: ${person || meta.
|
|
346
|
+
`- Person: ${person || meta.name || 'unknown'}`,
|
|
340
347
|
];
|
|
341
348
|
const repos = meta.repos ?? [];
|
|
342
349
|
if (repos.length === 1 && repos[0] === meta.folder) {
|
|
@@ -399,16 +406,15 @@ function fetchBranch(dir) {
|
|
|
399
406
|
return git(['-C', dir, 'rev-parse', ref]).out;
|
|
400
407
|
}
|
|
401
408
|
|
|
402
|
-
|
|
403
|
-
|
|
404
|
-
|
|
405
|
-
|
|
406
|
-
|
|
407
|
-
|
|
408
|
-
|
|
409
|
-
|
|
410
|
-
|
|
411
|
-
}
|
|
409
|
+
// The prompts are committed under a neutral identity, so the e-mail address
|
|
410
|
+
// of the developer never reaches the project management repo.
|
|
411
|
+
const identityEnv = {
|
|
412
|
+
...gitEnv,
|
|
413
|
+
GIT_AUTHOR_NAME: 'pm-prompts',
|
|
414
|
+
GIT_COMMITTER_NAME: 'pm-prompts',
|
|
415
|
+
GIT_AUTHOR_EMAIL: 'pm-prompts@localhost',
|
|
416
|
+
GIT_COMMITTER_EMAIL: 'pm-prompts@localhost',
|
|
417
|
+
};
|
|
412
418
|
|
|
413
419
|
// Commits the not yet pushed prompts of [sessions] to the prompts branch of
|
|
414
420
|
// [url]. Returns how many prompts of each session the branch now holds.
|
|
@@ -421,7 +427,7 @@ function pushTarget(url, sessions) {
|
|
|
421
427
|
os.tmpdir(),
|
|
422
428
|
`pm-prompts-${process.pid}-${Date.now()}.index`,
|
|
423
429
|
);
|
|
424
|
-
const env = { ...identityEnv
|
|
430
|
+
const env = { ...identityEnv, GIT_INDEX_FILE: index };
|
|
425
431
|
try {
|
|
426
432
|
const read = base
|
|
427
433
|
? git(['-C', dir, 'read-tree', base], { env })
|
|
@@ -433,8 +439,8 @@ function pushTarget(url, sessions) {
|
|
|
433
439
|
const fresh = session.prompts.slice(pushed);
|
|
434
440
|
done.set(file, session.prompts.length);
|
|
435
441
|
if (!fresh.length) continue;
|
|
436
|
-
const person = personOf(session.meta.
|
|
437
|
-
names.add(person || session.meta.
|
|
442
|
+
const person = personOf(session.meta.name, people);
|
|
443
|
+
names.add(person || session.meta.name || 'unknown');
|
|
438
444
|
const target = promptsPath(session.meta, person);
|
|
439
445
|
const existing = base
|
|
440
446
|
? git(['-C', dir, 'cat-file', '-p', `${base}:${target}`])
|