@mmnto/cli 2.0.0 → 2.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/dist/commands/describe.d.ts +13 -1
- package/dist/commands/describe.d.ts.map +1 -1
- package/dist/commands/describe.js +29 -1
- package/dist/commands/describe.js.map +1 -1
- package/dist/commands/describe.test.js +86 -3
- package/dist/commands/describe.test.js.map +1 -1
- package/dist/commands/init-templates.d.ts +2 -2
- package/dist/commands/init-templates.d.ts.map +1 -1
- package/dist/commands/init-templates.js +2 -2
- package/dist/commands/install-hooks.d.ts.map +1 -1
- package/dist/commands/install-hooks.js +159 -27
- package/dist/commands/install-hooks.js.map +1 -1
- package/dist/commands/install-hooks.test.js +460 -12
- package/dist/commands/install-hooks.test.js.map +1 -1
- package/dist/commands/legs.d.ts +35 -7
- package/dist/commands/legs.d.ts.map +1 -1
- package/dist/commands/legs.js +26 -7
- package/dist/commands/legs.js.map +1 -1
- package/dist/commands/legs.test.js +87 -0
- package/dist/commands/legs.test.js.map +1 -1
- package/dist/commands/release-train-shape.test.d.ts +2 -0
- package/dist/commands/release-train-shape.test.d.ts.map +1 -0
- package/dist/commands/release-train-shape.test.js +226 -0
- package/dist/commands/release-train-shape.test.js.map +1 -0
- package/dist/commands/tools-hook-parity.test.js +200 -0
- package/dist/commands/tools-hook-parity.test.js.map +1 -1
- package/package.json +2 -2
|
@@ -1,4 +1,16 @@
|
|
|
1
|
+
import type { ProjectDescription } from '@mmnto/totem';
|
|
1
2
|
export type { ProjectDescription } from '@mmnto/totem';
|
|
2
|
-
|
|
3
|
+
/**
|
|
4
|
+
* The banner's rules line (mmnto-ai/totem#2765): the ACTIVE count leads — it is
|
|
5
|
+
* the number lint enforces and status reports — and the inert split renders
|
|
6
|
+
* only when it is non-trivial, so `Rules: 385 active of 485 compiled (93
|
|
7
|
+
* archived, 7 untested-against-codebase)` on this repo and `Rules: 12 active`
|
|
8
|
+
* on a repo with nothing inert. Never a bare "N compiled": that was the raw
|
|
9
|
+
* total posing as the enforced set. A missing file says so, and a file the
|
|
10
|
+
* loader refused says `unreadable` — a 0 the reader could mistake for an
|
|
11
|
+
* honestly empty set is the sensor-trust class this line exists to end.
|
|
12
|
+
*/
|
|
13
|
+
export declare function formatRulesLine(d: Pick<ProjectDescription, 'rules' | 'rulesCompiled' | 'rulesArchived' | 'rulesUntested' | 'rulesPendingVerification' | 'rulesSource'>): string;
|
|
14
|
+
export declare function getProjectDescription(cwd: string): Promise<ProjectDescription>;
|
|
3
15
|
export declare function describeCommand(): Promise<void>;
|
|
4
16
|
//# sourceMappingURL=describe.d.ts.map
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"describe.d.ts","sourceRoot":"","sources":["../../src/commands/describe.ts"],"names":[],"mappings":"AAAA,YAAY,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAEvD,wBAAsB,qBAAqB,CAAC,GAAG,EAAE,MAAM
|
|
1
|
+
{"version":3,"file":"describe.d.ts","sourceRoot":"","sources":["../../src/commands/describe.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAEvD,YAAY,EAAE,kBAAkB,EAAE,MAAM,cAAc,CAAC;AAEvD;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAC7B,CAAC,EAAE,IAAI,CACL,kBAAkB,EAChB,OAAO,GACP,eAAe,GACf,eAAe,GACf,eAAe,GACf,0BAA0B,GAC1B,aAAa,CAChB,GACA,MAAM,CAcR;AAED,wBAAsB,qBAAqB,CAAC,GAAG,EAAE,MAAM,+BAUtD;AAED,wBAAsB,eAAe,IAAI,OAAO,CAAC,IAAI,CAAC,CA4BrD"}
|
|
@@ -1,3 +1,31 @@
|
|
|
1
|
+
/**
|
|
2
|
+
* The banner's rules line (mmnto-ai/totem#2765): the ACTIVE count leads — it is
|
|
3
|
+
* the number lint enforces and status reports — and the inert split renders
|
|
4
|
+
* only when it is non-trivial, so `Rules: 385 active of 485 compiled (93
|
|
5
|
+
* archived, 7 untested-against-codebase)` on this repo and `Rules: 12 active`
|
|
6
|
+
* on a repo with nothing inert. Never a bare "N compiled": that was the raw
|
|
7
|
+
* total posing as the enforced set. A missing file says so, and a file the
|
|
8
|
+
* loader refused says `unreadable` — a 0 the reader could mistake for an
|
|
9
|
+
* honestly empty set is the sensor-trust class this line exists to end.
|
|
10
|
+
*/
|
|
11
|
+
export function formatRulesLine(d) {
|
|
12
|
+
if (d.rulesSource === 'absent')
|
|
13
|
+
return `Rules: ${d.rules} active (no compiled-rules.json)`;
|
|
14
|
+
if (d.rulesSource === 'unreadable') {
|
|
15
|
+
return `Rules: ${d.rules} active — compiled-rules.json unreadable (run 'totem lint' for the parse error)`;
|
|
16
|
+
}
|
|
17
|
+
const inert = [];
|
|
18
|
+
if (d.rulesArchived > 0)
|
|
19
|
+
inert.push(`${d.rulesArchived} archived`);
|
|
20
|
+
if (d.rulesUntested > 0)
|
|
21
|
+
inert.push(`${d.rulesUntested} untested-against-codebase`);
|
|
22
|
+
if (d.rulesPendingVerification > 0) {
|
|
23
|
+
inert.push(`${d.rulesPendingVerification} pending-verification`);
|
|
24
|
+
}
|
|
25
|
+
return inert.length === 0
|
|
26
|
+
? `Rules: ${d.rules} active`
|
|
27
|
+
: `Rules: ${d.rules} active of ${d.rulesCompiled} compiled (${inert.join(', ')})`;
|
|
28
|
+
}
|
|
1
29
|
export async function getProjectDescription(cwd) {
|
|
2
30
|
const path = await import('node:path');
|
|
3
31
|
const { describeProject } = await import('@mmnto/totem');
|
|
@@ -20,7 +48,7 @@ export async function describeCommand() {
|
|
|
20
48
|
if (result.description)
|
|
21
49
|
log.info('[Describe]', `Description: ${result.description}`);
|
|
22
50
|
log.info('[Describe]', `Tier: ${result.tier}`);
|
|
23
|
-
log.info('[Describe]',
|
|
51
|
+
log.info('[Describe]', formatRulesLine(result));
|
|
24
52
|
log.info('[Describe]', `Lessons: ${result.lessons}`);
|
|
25
53
|
log.info('[Describe]', `Targets: ${result.targets.length}`);
|
|
26
54
|
for (const t of result.targets) {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"describe.js","sourceRoot":"","sources":["../../src/commands/describe.ts"],"names":[],"mappings":"
|
|
1
|
+
{"version":3,"file":"describe.js","sourceRoot":"","sources":["../../src/commands/describe.ts"],"names":[],"mappings":"AAIA;;;;;;;;;GASG;AACH,MAAM,UAAU,eAAe,CAC7B,CAQC;IAED,IAAI,CAAC,CAAC,WAAW,KAAK,QAAQ;QAAE,OAAO,UAAU,CAAC,CAAC,KAAK,kCAAkC,CAAC;IAC3F,IAAI,CAAC,CAAC,WAAW,KAAK,YAAY,EAAE,CAAC;QACnC,OAAO,UAAU,CAAC,CAAC,KAAK,iFAAiF,CAAC;IAC5G,CAAC;IACD,MAAM,KAAK,GAAa,EAAE,CAAC;IAC3B,IAAI,CAAC,CAAC,aAAa,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,aAAa,WAAW,CAAC,CAAC;IACnE,IAAI,CAAC,CAAC,aAAa,GAAG,CAAC;QAAE,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,aAAa,4BAA4B,CAAC,CAAC;IACpF,IAAI,CAAC,CAAC,wBAAwB,GAAG,CAAC,EAAE,CAAC;QACnC,KAAK,CAAC,IAAI,CAAC,GAAG,CAAC,CAAC,wBAAwB,uBAAuB,CAAC,CAAC;IACnE,CAAC;IACD,OAAO,KAAK,CAAC,MAAM,KAAK,CAAC;QACvB,CAAC,CAAC,UAAU,CAAC,CAAC,KAAK,SAAS;QAC5B,CAAC,CAAC,UAAU,CAAC,CAAC,KAAK,cAAc,CAAC,CAAC,aAAa,cAAc,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,GAAG,CAAC;AACtF,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,qBAAqB,CAAC,GAAW;IACrD,MAAM,IAAI,GAAG,MAAM,MAAM,CAAC,WAAW,CAAC,CAAC;IACvC,MAAM,EAAE,eAAe,EAAE,GAAG,MAAM,MAAM,CAAC,cAAc,CAAC,CAAC;IACzD,MAAM,EAAE,UAAU,EAAE,iBAAiB,EAAE,GAAG,MAAM,MAAM,CAAC,aAAa,CAAC,CAAC;IAEtE,MAAM,UAAU,GAAG,iBAAiB,CAAC,GAAG,CAAC,CAAC;IAC1C,MAAM,UAAU,GAAG,IAAI,CAAC,OAAO,CAAC,UAAU,CAAC,CAAC;IAC5C,MAAM,MAAM,GAAG,MAAM,UAAU,CAAC,UAAU,CAAC,CAAC;IAE5C,OAAO,eAAe,CAAC,MAAM,EAAE,UAAU,CAAC,CAAC;AAC7C,CAAC;AAED,MAAM,CAAC,KAAK,UAAU,eAAe;IACnC,MAAM,EAAE,GAAG,EAAE,GAAG,MAAM,MAAM,CAAC,UAAU,CAAC,CAAC;IACzC,MAAM,EAAE,UAAU,EAAE,SAAS,EAAE,GAAG,MAAM,MAAM,CAAC,mBAAmB,CAAC,CAAC;IAEpE,MAAM,GAAG,GAAG,OAAO,CAAC,GAAG,EAAE,CAAC;IAC1B,MAAM,MAAM,GAAG,MAAM,qBAAqB,CAAC,GAAG,CAAC,CAAC;IAEhD,IAAI,UAAU,EAAE,EAAE,CAAC;QACjB,SAAS,CAAC,EAAE,MAAM,EAAE,SAAS,EAAE,OAAO,EAAE,UAAU,EAAE,IAAI,EAAE,MAAM,EAAE,CAAC,CAAC;QACpE,OAAO;IACT,CAAC;IAED,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,YAAY,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IACrD,IAAI,MAAM,CAAC,WAAW;QAAE,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,gBAAgB,MAAM,CAAC,WAAW,EAAE,CAAC,CAAC;IACrF,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,SAAS,MAAM,CAAC,IAAI,EAAE,CAAC,CAAC;IAC/C,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,eAAe,CAAC,MAAM,CAAC,CAAC,CAAC;IAChD,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,YAAY,MAAM,CAAC,OAAO,EAAE,CAAC,CAAC;IACrD,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,YAAY,MAAM,CAAC,OAAO,CAAC,MAAM,EAAE,CAAC,CAAC;IAC5D,KAAK,MAAM,CAAC,IAAI,MAAM,CAAC,OAAO,EAAE,CAAC;QAC/B,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,KAAK,CAAC,EAAE,CAAC,CAAC;IACnC,CAAC;IACD,MAAM,cAAc,GAAG,MAAM,CAAC,IAAI,CAAC,MAAM,CAAC,UAAU,CAAC,CAAC;IACtD,IAAI,cAAc,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC9B,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,eAAe,cAAc,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IACrE,CAAC;IACD,IAAI,MAAM,CAAC,KAAK,CAAC,MAAM,GAAG,CAAC,EAAE,CAAC;QAC5B,GAAG,CAAC,IAAI,CAAC,YAAY,EAAE,UAAU,MAAM,CAAC,KAAK,CAAC,IAAI,CAAC,IAAI,CAAC,EAAE,CAAC,CAAC;IAC9D,CAAC;AACH,CAAC"}
|
|
@@ -1,8 +1,8 @@
|
|
|
1
1
|
import * as fs from 'node:fs';
|
|
2
2
|
import * as os from 'node:os';
|
|
3
3
|
import * as path from 'node:path';
|
|
4
|
-
import { describe, expect, it } from 'vitest';
|
|
5
|
-
import { getProjectDescription } from './describe.js';
|
|
4
|
+
import { describe, expect, it, vi } from 'vitest';
|
|
5
|
+
import { formatRulesLine, getProjectDescription } from './describe.js';
|
|
6
6
|
function makeTmpDir() {
|
|
7
7
|
return fs.mkdtempSync(path.join(os.tmpdir(), 'totem-describe-'));
|
|
8
8
|
}
|
|
@@ -33,9 +33,25 @@ function scaffoldProject(dir, opts = {}) {
|
|
|
33
33
|
// (`{ version, rules: [...] }`) matching `loadCompiledRulesFile` and
|
|
34
34
|
// the rest of the codebase. Prior versions of this helper wrote a bare
|
|
35
35
|
// array, which masked the rule-count bug fixed in mmnto-ai/totem#1884.
|
|
36
|
+
// Entries are SCHEMA-VALID compiled rules since mmnto-ai/totem#2765: describe
|
|
37
|
+
// now counts through the same validating loader lint and status use, so a
|
|
38
|
+
// `{ id }` stub would (correctly) count as nothing. `archived` marks the
|
|
39
|
+
// first N entries inert.
|
|
36
40
|
const rulesCount = opts.rules ?? 0;
|
|
37
41
|
if (rulesCount > 0) {
|
|
38
|
-
const rules = Array.from({ length: rulesCount }, (_, i) => ({
|
|
42
|
+
const rules = Array.from({ length: rulesCount }, (_, i) => ({
|
|
43
|
+
lessonHash: `hash${String(i).padStart(8, '0')}`,
|
|
44
|
+
lessonHeading: `Rule ${i}`,
|
|
45
|
+
pattern: 'dummy',
|
|
46
|
+
message: `Rule ${i} message`,
|
|
47
|
+
engine: 'regex',
|
|
48
|
+
compiledAt: '2026-05-11T00:00:00Z',
|
|
49
|
+
...(i < (opts.archived ?? 0)
|
|
50
|
+
? { status: 'archived' }
|
|
51
|
+
: i < (opts.archived ?? 0) + (opts.untested ?? 0)
|
|
52
|
+
? { status: 'untested-against-codebase' }
|
|
53
|
+
: {}),
|
|
54
|
+
}));
|
|
39
55
|
fs.writeFileSync(path.join(dir, '.totem', 'compiled-rules.json'), JSON.stringify({ version: 1, rules, nonCompilable: [] }));
|
|
40
56
|
}
|
|
41
57
|
}
|
|
@@ -80,11 +96,78 @@ describe('getProjectDescription', () => {
|
|
|
80
96
|
scaffoldProject(dir, { rules: 10 });
|
|
81
97
|
const result = await getProjectDescription(dir);
|
|
82
98
|
expect(result.rules).toBe(10);
|
|
99
|
+
expect(result.rulesCompiled).toBe(10);
|
|
83
100
|
}
|
|
84
101
|
finally {
|
|
85
102
|
cleanTmpDir(dir);
|
|
86
103
|
}
|
|
87
104
|
});
|
|
105
|
+
it('counts the ACTIVE set, not the raw total, and renders the split (mmnto-ai/totem#2765)', async () => {
|
|
106
|
+
const dir = makeTmpDir();
|
|
107
|
+
try {
|
|
108
|
+
scaffoldProject(dir, { rules: 10, archived: 3 });
|
|
109
|
+
const result = await getProjectDescription(dir);
|
|
110
|
+
expect(result.rules).toBe(7);
|
|
111
|
+
expect(result.rulesCompiled).toBe(10);
|
|
112
|
+
expect(result.rulesArchived).toBe(3);
|
|
113
|
+
expect(formatRulesLine(result)).toBe('Rules: 7 active of 10 compiled (3 archived)');
|
|
114
|
+
}
|
|
115
|
+
finally {
|
|
116
|
+
cleanTmpDir(dir);
|
|
117
|
+
}
|
|
118
|
+
});
|
|
119
|
+
it('formatRulesLine: the split renders only when non-trivial, and names every inert status', () => {
|
|
120
|
+
const base = {
|
|
121
|
+
rules: 12,
|
|
122
|
+
rulesCompiled: 12,
|
|
123
|
+
rulesArchived: 0,
|
|
124
|
+
rulesUntested: 0,
|
|
125
|
+
rulesPendingVerification: 0,
|
|
126
|
+
rulesSource: 'compiled-rules',
|
|
127
|
+
};
|
|
128
|
+
expect(formatRulesLine(base)).toBe('Rules: 12 active');
|
|
129
|
+
expect(formatRulesLine({
|
|
130
|
+
...base,
|
|
131
|
+
rulesCompiled: 20,
|
|
132
|
+
rulesArchived: 5,
|
|
133
|
+
rulesUntested: 2,
|
|
134
|
+
rulesPendingVerification: 1,
|
|
135
|
+
})).toBe('Rules: 12 active of 20 compiled (5 archived, 2 untested-against-codebase, 1 pending-verification)');
|
|
136
|
+
// The ACTIVE count leads; the raw total never poses as the enforced set.
|
|
137
|
+
expect(formatRulesLine({ ...base, rulesCompiled: 20, rulesArchived: 8 })).toBe('Rules: 12 active of 20 compiled (8 archived)');
|
|
138
|
+
// A zero is never left ambiguous: absent and unreadable each say so.
|
|
139
|
+
const zeros = { ...base, rules: 0, rulesCompiled: 0 };
|
|
140
|
+
expect(formatRulesLine({ ...zeros, rulesSource: 'absent' })).toBe('Rules: 0 active (no compiled-rules.json)');
|
|
141
|
+
expect(formatRulesLine({ ...zeros, rulesSource: 'unreadable' })).toBe("Rules: 0 active — compiled-rules.json unreadable (run 'totem lint' for the parse error)");
|
|
142
|
+
});
|
|
143
|
+
// The issue's own contract clause, second conjunct: describe's number equals
|
|
144
|
+
// what `totem status` PRINTS (mmnto-ai/totem#2765). The two commands share no
|
|
145
|
+
// helper — status counts through `loadCompiledRules` inline, describe through
|
|
146
|
+
// `isActiveCompiledRule` — so this is the only place the two numbers meet.
|
|
147
|
+
it('describe reports the same active count that totem status prints', async () => {
|
|
148
|
+
const dir = makeTmpDir();
|
|
149
|
+
const originalCwd = process.cwd();
|
|
150
|
+
try {
|
|
151
|
+
// Archived AND untested, as the issue's clause names — untested is the
|
|
152
|
+
// status class that produced the 392-vs-385 divergence in the MCP extractor.
|
|
153
|
+
scaffoldProject(dir, { rules: 10, archived: 3, untested: 1 });
|
|
154
|
+
const description = await getProjectDescription(dir);
|
|
155
|
+
process.chdir(dir);
|
|
156
|
+
const consoleSpy = vi.spyOn(console, 'error').mockImplementation(() => { });
|
|
157
|
+
const { statusCommand } = await import('./status.js');
|
|
158
|
+
await statusCommand();
|
|
159
|
+
const output = consoleSpy.mock.calls.map((c) => String(c[0])).join('\n');
|
|
160
|
+
const printed = /Rules: (\d+) compiled/.exec(output);
|
|
161
|
+
expect(printed, output).not.toBeNull();
|
|
162
|
+
expect(Number(printed[1])).toBe(6);
|
|
163
|
+
expect(description.rules).toBe(Number(printed[1]));
|
|
164
|
+
}
|
|
165
|
+
finally {
|
|
166
|
+
process.chdir(originalCwd);
|
|
167
|
+
vi.restoreAllMocks();
|
|
168
|
+
cleanTmpDir(dir);
|
|
169
|
+
}
|
|
170
|
+
});
|
|
88
171
|
it('returns zero counts when .totem directories are missing', async () => {
|
|
89
172
|
const dir = makeTmpDir();
|
|
90
173
|
try {
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"describe.test.js","sourceRoot":"","sources":["../../src/commands/describe.test.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,EAAE,MAAM,SAAS,CAAC;AAC9B,OAAO,KAAK,IAAI,MAAM,WAAW,CAAC;AAElC,OAAO,EAAE,QAAQ,EAAE,MAAM,EAAE,EAAE,EAAE,MAAM,QAAQ,CAAC;
|
|
1
|
+
{"version":3,"file":"describe.test.js","sourceRoot":"","sources":["../../src/commands/describe.test.ts"],"names":[],"mappings":"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"}
|
|
@@ -1,11 +1,11 @@
|
|
|
1
1
|
import type { IngestTarget } from '@mmnto/totem';
|
|
2
2
|
import type { ConfigFormat, EmbeddingTier } from './init-detect.js';
|
|
3
|
-
export declare const REFLEX_VERSION =
|
|
3
|
+
export declare const REFLEX_VERSION = 14;
|
|
4
4
|
export declare const REFLEX_START = "<!-- totem:reflexes:start -->";
|
|
5
5
|
export declare const REFLEX_END = "<!-- totem:reflexes:end -->";
|
|
6
6
|
export declare const REFLEX_VERSION_RE: RegExp;
|
|
7
7
|
export declare const LEGACY_SENTINEL = "## Totem AI Integration (Auto-Generated)";
|
|
8
|
-
export declare const AI_PROMPT_BLOCK = "\n<!-- totem:reflexes:start -->\n<!-- totem:reflexes:version:
|
|
8
|
+
export declare const AI_PROMPT_BLOCK = "\n<!-- totem:reflexes:start -->\n<!-- totem:reflexes:version:14 -->\n\n## Totem AI Integration (Auto-Generated)\nYou have access to the Totem MCP for long-term project memory. You MUST operate with the following reflexes:\n\n### Memory Reflexes\n1. **BLOCKING \u2014 Pull Before Coding:** Before writing or modifying code that touches more than one file, you MUST call `search_knowledge` with a query describing what you're about to change. This is not optional. The vector DB contains traps, edge cases, and architectural constraints that prevent rework. Skip this and you risk repeating a mistake that's already been solved.\n2. **Pull Before Planning:** Before writing specs, architecture, or fixing complex bugs, use `search_knowledge` to retrieve domain constraints and past traps.\n3. **Pull on Session Start:** At the beginning of every session, call `search_knowledge` with a broad query about the current task or area of work. The vector DB is your institutional memory \u2014 use it before relying on your own context window.\n4. **Proactive Anchoring (The 3 Triggers):** You must autonomously call `add_lesson` when any of the following occur \u2014 do NOT wait for the user to ask:\n - **The Trap Trigger:** If you spend >2 turns fixing a bug caused by a framework quirk, unexpected API response, or edge case. (Anchor the symptom + fix).\n - **The Pivot Trigger:** If the user introduces a new architectural pattern or deprecates an old one. (Anchor the rule).\n - **The Handoff Trigger:** At the end of a session or when wrapping up a complex feature, extract the non-obvious lessons learned and anchor them.\n5. **Tool Preference (MCP over CLI):** Always prioritize using dedicated MCP tools (e.g., GitHub, Supabase, Vercel) over executing generic shell commands (like `gh issue view` or `curl`). MCP tools provide structured, un-truncated data optimized for your context window. Only fall back to bash execution if an MCP tool is unavailable or fails.\n\nLessons are automatically re-indexed in the background after each `add_lesson` call \u2014 no manual sync needed.\n\n### Memory Classification\nWhen deciding where to store information or rules, use this decision tree:\n- If forgetting this causes a mistake on an UNRELATED task (Core Safety): Store in your root agent memory file (e.g., CLAUDE.md or GEMINI.md).\n- If it's a stable, project-wide workflow rule: Store in project config (e.g., CLAUDE.md).\n- If it's a stable syntax/style pattern: Store in the project's styleguide or linter rules.\n- If it's domain knowledge, an edge case, or a past trap: You MUST use the Totem `add_lesson` tool to anchor it into the project's LanceDB.\n\n### Workflow Orchestrator Rituals\n[FOR LOCAL CLI/TERMINAL AGENTS ONLY] Do not attempt to run these commands if you are a headless bot or operating in a cloud PR environment (e.g., Gemini Code Assist on GitHub).\nTotem provides CLI commands that map to your development lifecycle. Use them at these moments:\n1. **Start of Session:** The SessionStart hook automatically runs `totem describe` to emit the project-orientation banner (project, tier, rule/lesson counts, targets, hooks). For richer derived project state (recent merged PRs, current branch + uncommitted files, latest strategy journal pointer, package versions, rule/lesson counts), call the MCP `describe_project` tool \u2014 the derived view replaces the retired `docs/active_work.md` convention (state is observed, not declared). For a freshness check (manifest staleness, shield drift, review state), run `totem status`. Run `totem triage` if you need to pick a new task. On a seat without the SessionStart hook (a cold start, or a vehicle that doesn't run hooks), run `totem orient` to derive in-flight and parked project state from primitives.\n2. **Before Implementation:** Run `totem spec <issue-url-or-topic>` to retrieve related context (lessons, specs, code) before writing code. Treat any generated plan as one retrieval input, never the contract \u2014 derive the actual design from primary sources (the issue, the code, project doctrine). Under the strict hook tier \u2014 which AI agents get automatically \u2014 this is REQUIRED, not optional: the pre-commit hook blocks until the checkout carries an ANCHORED `totem spec` run artifact, and prints the evidence it found. ANCHORED means the run was grounded on an ISSUE, or on a hand-authored design record bound with `totem spec --from <record>` \u2014 and that its SUBJECT carries the shape the command promises: for an issue run, every required heading with a non-empty body (or, when your project overrides the spec system prompt, just one heading with a body \u2014 a custom prompt is not held to the built-in skeleton); for a bound record, at least one heading with a body in the RECORD's own bytes, re-read from disk at commit time. A free-text topic run is NOT evidence (that is the confabulation surface the rule exists for), and neither is an artifact written before this rule \u2014 re-run it anchored. A response served from the cache writes no artifact, so add `--fresh` when the gate says there is nothing new (mmnto-ai/totem#2690, mmnto-ai/totem#2700). Under the same strict tier the pre-push hook additionally blocks a legs-owed push \u2014 a diff touching the paths in `hooks.legsOwed.globs` (doctrine, public copy, `.changeset/**` and the contract classes your project declares) \u2014 until the checkout carries a fresh leg deposit for its head, written with `totem legs deposit --sha HEAD --from <findings.json>` once the leg returns, and the gate prints the evidence it found (mmnto-ai/totem#2698). That legs gate can also be armed on its own, at any tier, with `hooks.legsOwed.enforce: 'block'` \u2014 a standard-tier install then refuses a legs-owed push too, and the gate's line names the key (mmnto-ai/totem#2771).\n3. **Before Push:** Run `totem lint` \u2014 the deterministic enforcement floor (zero LLM, ~2s). **Before PR:** `totem review` runs supplementary AI lanes over the diff (~18s) \u2014 advisory sensors, not a merge gate; known limits are disclosed in the run output (LLM window truncation on large diffs; non-code files skipped). Your team's own review discipline decides what constitutes the review of record.\n4. **End of Session:** Run `totem handoff` to generate a snapshot for the next agent session with current progress and open threads.\n5. **Managed hooks self-repair:** `totem init` distributes `.totem/prepare.cjs` and wires `package.json` `prepare` to it only when no `prepare` script exists. The wrapper runs `totem hook install` on every `pnpm install`, drift-repairing the managed Claude/Gemini hooks \u2014 no manual re-install needed.\n\n### Cloud / PR Review Bots\n[FOR CLOUD BOTS ONLY \u2014 e.g., Gemini Code Assist, GitHub Copilot PR Review]\nYou do NOT have access to the local CLI. Instead, use the Totem MCP tools directly:\n1. **Before reviewing a PR:** Call `search_knowledge` with queries about the files and patterns being changed to check for known traps and architectural constraints.\n2. **Before suggesting changes:** Call `search_knowledge` to verify your suggestion aligns with established project patterns and past lessons.\n3. **When you spot a recurring issue:** Call `add_lesson` to persist the trap so future reviews catch it automatically.\n\n### Context Management Guardrail\nYou must be highly defensive of your own context window \u2014 and you are the ONLY party holding the denominator (your model's window size and current occupancy); no Totem tool can measure it for you. Large Totem tool responses may carry a self-closing `<size-disclosure ... />` line stating that payload's measured size and cumulative session totals \u2014 a measurement, never a risk claim. Weigh it against your own occupancy and escalate to the user only when the pressure is genuinely material, suggesting `totem handoff` to capture mid-task state before clearing the chat. If you receive a `<totem_system_warning>` tag in a tool response (e.g. index staleness or degraded retrieval), read it silently and act on it or surface it naturally. Do NOT echo raw XML tags to the user.\n<!-- totem:reflexes:end -->\n";
|
|
9
9
|
export declare const TOTEM_FILE_MARKER = "// [totem] auto-generated";
|
|
10
10
|
/**
|
|
11
11
|
* The end marker that CLOSES every managed whole-file session hook template
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"init-templates.d.ts","sourceRoot":"","sources":["../../src/commands/init-templates.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAMpE,eAAO,MAAM,cAAc,KAAK,CAAC;AACjC,eAAO,MAAM,YAAY,kCAAkC,CAAC;AAC5D,eAAO,MAAM,UAAU,gCAAgC,CAAC;AACxD,eAAO,MAAM,iBAAiB,QAA0C,CAAC;AACzE,eAAO,MAAM,eAAe,6CAA6C,CAAC;AAE1E,eAAO,MAAM,eAAe,
|
|
1
|
+
{"version":3,"file":"init-templates.d.ts","sourceRoot":"","sources":["../../src/commands/init-templates.ts"],"names":[],"mappings":"AAGA,OAAO,KAAK,EAAE,YAAY,EAAE,MAAM,cAAc,CAAC;AAEjD,OAAO,KAAK,EAAE,YAAY,EAAE,aAAa,EAAE,MAAM,kBAAkB,CAAC;AAMpE,eAAO,MAAM,cAAc,KAAK,CAAC;AACjC,eAAO,MAAM,YAAY,kCAAkC,CAAC;AAC5D,eAAO,MAAM,UAAU,gCAAgC,CAAC;AACxD,eAAO,MAAM,iBAAiB,QAA0C,CAAC;AACzE,eAAO,MAAM,eAAe,6CAA6C,CAAC;AAE1E,eAAO,MAAM,eAAe,4+PA6C3B,CAAC;AAEF,eAAO,MAAM,iBAAiB,8BAA8B,CAAC;AAE7D;;;;;;;;;;;GAWG;AACH,eAAO,MAAM,cAAc,kCAAkC,CAAC;AAE9D;;;;;;;;;GASG;AACH,wBAAgB,eAAe,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,GAAG,OAAO,CAIxE;AAED;;;;;;;;;;;;GAYG;AACH,wBAAgB,kBAAkB,CAAC,OAAO,EAAE,MAAM,EAAE,MAAM,EAAE,MAAM,EAAE,SAAS,EAAE,MAAM,GAAG,OAAO,CAQ9F;AAgBD,eAAO,MAAM,qBAAqB,6CAA6C,CAAC;AAwBhF;;;;;;GAMG;AACH,eAAO,MAAM,oBAAoB,8BAA8B,CAAC;AAEhE,eAAO,MAAM,oBAAoB,8thBA8ThC,CAAC;AAEF,eAAO,MAAM,kBAAkB,QAoO9B,CAAC;AAEF,eAAO,MAAM,YAAY,4hBAUxB,CAAC;AAIF,eAAO,MAAM,kBAAkB,waAY9B,CAAC;AAEF,eAAO,MAAM,uBAAuB;;;;;;CAQnC,CAAC;AA8BF,eAAO,MAAM,qBAAqB,QAyLjC,CAAC;AAEF,eAAO,MAAM,2BAA2B;;;;;;CAQvC,CAAC;AA4BF,eAAO,MAAM,oBAAoB,+/gBA4ThC,CAAC;AAEF,eAAO,MAAM,0BAA0B;;;;;;CAQtC,CAAC;AA8CF,eAAO,MAAM,mBAAmB,iwQA6K/B,CAAC;AAiBF,eAAO,MAAM,yBAAyB;;;;;;CAQrC,CAAC;AAaF,eAAO,MAAM,kBAAkB,uBAAuB,CAAC;AACvD,eAAO,MAAM,sBAAsB,4BAA4B,CAAC;AAoBhE,eAAO,MAAM,eAAe,w/GAsF3B,CAAC;AAqBF,MAAM,WAAW,kBAAkB;IACjC,qDAAqD;IACrD,GAAG,EAAE,MAAM,CAAC;IACZ,8FAA8F;IAC9F,OAAO,EAAE,MAAM,CAAC;IAChB,yDAAyD;IACzD,MAAM,EAAE,MAAM,CAAC;IACf,iEAAiE;IACjE,SAAS,EAAE,MAAM,CAAC;CACnB;AASD,eAAO,MAAM,sBAAsB,iCAAiC,CAAC;AAMrE,eAAO,MAAM,6BAA6B,gCAAgC,CAAC;AAa3E,eAAO,MAAM,wBAAwB,mCAAmC,CAAC;AAIzE,eAAO,MAAM,+BAA+B,kCAAkC,CAAC;AAE/E,eAAO,MAAM,qBAAqB,EAAE,aAAa,CAAC,kBAAkB,CAyCnE,CAAC;AAeF,MAAM,WAAW,iBAAiB;IAChC,+EAA+E;IAC/E,SAAS,EAAE,MAAM,CAAC;IAClB,+DAA+D;IAC/D,YAAY,EAAE,MAAM,CAAC;IACrB,qFAAqF;IACrF,OAAO,EAAE,MAAM,CAAC;IAChB,8EAA8E;IAC9E,MAAM,EAAE,MAAM,CAAC;IACf,qEAAqE;IACrE,SAAS,EAAE,MAAM,CAAC;CACnB;AAED,eAAO,MAAM,4BAA4B,EAAE,aAAa,CAAC,iBAAiB,CAgBzE,CAAC;AAwBF,eAAO,MAAM,kBAAkB,+BAA+B,CAAC;AAC/D,eAAO,MAAM,gBAAgB,6BAA6B,CAAC;AAE3D,eAAO,MAAM,qBAAqB,QA0DjC,CAAC;AAEF,eAAO,MAAM,oBAAoB,ghKAoBhC,CAAC;AAEF,eAAO,MAAM,0BAA0B,owLA+EtC,CAAC;AAEF,eAAO,MAAM,yBAAyB,w+KA0CrC,CAAC;AAEF,eAAO,MAAM,yBAAyB;;;;;;;;;;;;EAK5B,CAAC;AAIX,wBAAsB,cAAc,CAClC,OAAO,EAAE,YAAY,EAAE,EACvB,aAAa,EAAE,aAAa,EAC5B,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,MAAM,CAAC,CAyCjB;AAoDD;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,YAAY,EAAE,EACvB,aAAa,EAAE,aAAa,EAC5B,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,MAAM,CAAC,CAIjB;AAED;;GAEG;AACH,wBAAsB,kBAAkB,CACtC,OAAO,EAAE,YAAY,EAAE,EACvB,aAAa,EAAE,aAAa,EAC5B,GAAG,EAAE,MAAM,GACV,OAAO,CAAC,MAAM,CAAC,CAIjB;AAED;;GAEG;AACH,wBAAsB,uBAAuB,CAC3C,MAAM,EAAE,YAAY,EACpB,OAAO,EAAE,YAAY,EAAE,EACvB,aAAa,EAAE,aAAa,EAC5B,GAAG,EAAE,MAAM,GACV,OAAO,CAAC;IAAE,OAAO,EAAE,MAAM,CAAC;IAAC,QAAQ,EAAE,MAAM,CAAA;CAAE,CAAC,CAkBhD"}
|
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
// ─── Reflex versioning ────────────────────────────────────
|
|
4
4
|
// Bump REFLEX_VERSION whenever the AI_PROMPT_BLOCK content changes materially.
|
|
5
5
|
// This allows `totem init` to detect stale blocks and offer upgrades.
|
|
6
|
-
export const REFLEX_VERSION =
|
|
6
|
+
export const REFLEX_VERSION = 14;
|
|
7
7
|
export const REFLEX_START = '<!-- totem:reflexes:start -->';
|
|
8
8
|
export const REFLEX_END = '<!-- totem:reflexes:end -->';
|
|
9
9
|
export const REFLEX_VERSION_RE = /<!-- totem:reflexes:version:(\d+) -->/;
|
|
@@ -38,7 +38,7 @@ When deciding where to store information or rules, use this decision tree:
|
|
|
38
38
|
[FOR LOCAL CLI/TERMINAL AGENTS ONLY] Do not attempt to run these commands if you are a headless bot or operating in a cloud PR environment (e.g., Gemini Code Assist on GitHub).
|
|
39
39
|
Totem provides CLI commands that map to your development lifecycle. Use them at these moments:
|
|
40
40
|
1. **Start of Session:** The SessionStart hook automatically runs \`totem describe\` to emit the project-orientation banner (project, tier, rule/lesson counts, targets, hooks). For richer derived project state (recent merged PRs, current branch + uncommitted files, latest strategy journal pointer, package versions, rule/lesson counts), call the MCP \`describe_project\` tool — the derived view replaces the retired \`docs/active_work.md\` convention (state is observed, not declared). For a freshness check (manifest staleness, shield drift, review state), run \`totem status\`. Run \`totem triage\` if you need to pick a new task. On a seat without the SessionStart hook (a cold start, or a vehicle that doesn't run hooks), run \`totem orient\` to derive in-flight and parked project state from primitives.
|
|
41
|
-
2. **Before Implementation:** Run \`totem spec <issue-url-or-topic>\` to retrieve related context (lessons, specs, code) before writing code. Treat any generated plan as one retrieval input, never the contract — derive the actual design from primary sources (the issue, the code, project doctrine). Under the strict hook tier — which AI agents get automatically — this is REQUIRED, not optional: the pre-commit hook blocks until the checkout carries an ANCHORED \`totem spec\` run artifact, and prints the evidence it found. ANCHORED means the run was grounded on an ISSUE, or on a hand-authored design record bound with \`totem spec --from <record>\` — and that its SUBJECT carries the shape the command promises: for an issue run, every required heading with a non-empty body (or, when your project overrides the spec system prompt, just one heading with a body — a custom prompt is not held to the built-in skeleton); for a bound record, at least one heading with a body in the RECORD's own bytes, re-read from disk at commit time. A free-text topic run is NOT evidence (that is the confabulation surface the rule exists for), and neither is an artifact written before this rule — re-run it anchored. A response served from the cache writes no artifact, so add \`--fresh\` when the gate says there is nothing new (mmnto-ai/totem#2690, mmnto-ai/totem#2700). Under the same strict tier the pre-push hook additionally blocks a legs-owed push — a diff touching the paths in \`hooks.legsOwed.globs\` (doctrine, public copy, \`.changeset/**\` and the contract classes your project declares) — until the checkout carries a fresh leg deposit for its head, written with \`totem legs deposit --sha HEAD --from <findings.json>\` once the leg returns, and the gate prints the evidence it found (mmnto-ai/totem#2698).
|
|
41
|
+
2. **Before Implementation:** Run \`totem spec <issue-url-or-topic>\` to retrieve related context (lessons, specs, code) before writing code. Treat any generated plan as one retrieval input, never the contract — derive the actual design from primary sources (the issue, the code, project doctrine). Under the strict hook tier — which AI agents get automatically — this is REQUIRED, not optional: the pre-commit hook blocks until the checkout carries an ANCHORED \`totem spec\` run artifact, and prints the evidence it found. ANCHORED means the run was grounded on an ISSUE, or on a hand-authored design record bound with \`totem spec --from <record>\` — and that its SUBJECT carries the shape the command promises: for an issue run, every required heading with a non-empty body (or, when your project overrides the spec system prompt, just one heading with a body — a custom prompt is not held to the built-in skeleton); for a bound record, at least one heading with a body in the RECORD's own bytes, re-read from disk at commit time. A free-text topic run is NOT evidence (that is the confabulation surface the rule exists for), and neither is an artifact written before this rule — re-run it anchored. A response served from the cache writes no artifact, so add \`--fresh\` when the gate says there is nothing new (mmnto-ai/totem#2690, mmnto-ai/totem#2700). Under the same strict tier the pre-push hook additionally blocks a legs-owed push — a diff touching the paths in \`hooks.legsOwed.globs\` (doctrine, public copy, \`.changeset/**\` and the contract classes your project declares) — until the checkout carries a fresh leg deposit for its head, written with \`totem legs deposit --sha HEAD --from <findings.json>\` once the leg returns, and the gate prints the evidence it found (mmnto-ai/totem#2698). That legs gate can also be armed on its own, at any tier, with \`hooks.legsOwed.enforce: 'block'\` — a standard-tier install then refuses a legs-owed push too, and the gate's line names the key (mmnto-ai/totem#2771).
|
|
42
42
|
3. **Before Push:** Run \`totem lint\` — the deterministic enforcement floor (zero LLM, ~2s). **Before PR:** \`totem review\` runs supplementary AI lanes over the diff (~18s) — advisory sensors, not a merge gate; known limits are disclosed in the run output (LLM window truncation on large diffs; non-code files skipped). Your team's own review discipline decides what constitutes the review of record.
|
|
43
43
|
4. **End of Session:** Run \`totem handoff\` to generate a snapshot for the next agent session with current progress and open threads.
|
|
44
44
|
5. **Managed hooks self-repair:** \`totem init\` distributes \`.totem/prepare.cjs\` and wires \`package.json\` \`prepare\` to it only when no \`prepare\` script exists. The wrapper runs \`totem hook install\` on every \`pnpm install\`, drift-repairing the managed Claude/Gemini hooks — no manual re-install needed.
|
|
@@ -1 +1 @@
|
|
|
1
|
-
{"version":3,"file":"install-hooks.d.ts","sourceRoot":"","sources":["../../src/commands/install-hooks.ts"],"names":[],"mappings":"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
|
|
1
|
+
{"version":3,"file":"install-hooks.d.ts","sourceRoot":"","sources":["../../src/commands/install-hooks.ts"],"names":[],"mappings":"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"}
|
|
@@ -938,32 +938,143 @@ if (kind !== KIND_RECORD) {
|
|
|
938
938
|
if ([65279].indexOf(subject.charCodeAt(0)) > -1) subject = subject.slice(1);
|
|
939
939
|
const lines = subject.split("\\n");
|
|
940
940
|
const tolerated = [];
|
|
941
|
+
// Fences (mmnto-ai/totem#2769), by the CommonMark rule: a line indented at most
|
|
942
|
+
// three spaces whose first run is three or more backticks or tildes OPENS a
|
|
943
|
+
// fence — a backtick run only when the rest of the line carries no backtick —
|
|
944
|
+
// and a CLOSER is the same character, at least as long, with nothing else on
|
|
945
|
+
// the line; an unclosed fence runs to the end of the draft. A delimiter line
|
|
946
|
+
// is neither a heading, a match candidate, nor body. A line inside a fence is
|
|
947
|
+
// neither a heading nor a match candidate — a promised heading quoted there
|
|
948
|
+
// (the skeleton pasted as an example) is not the section it names, and is not
|
|
949
|
+
// body for the section above it either — but any other non-blank fenced line
|
|
950
|
+
// IS body: a section whose content is one code block is a written section.
|
|
951
|
+
const TICK = String.fromCharCode(96);
|
|
952
|
+
const fenceLine = [];
|
|
953
|
+
const inFence = [];
|
|
954
|
+
const fenceOpenedAt = [];
|
|
955
|
+
let fenceChar = "";
|
|
956
|
+
let fenceLen = 0;
|
|
957
|
+
let openedAt = 0;
|
|
958
|
+
for (let i = 0; i < lines.length; i++) {
|
|
959
|
+
const line = lines[i];
|
|
960
|
+
let indent = 0;
|
|
961
|
+
while (indent < line.length && [" "].indexOf(line.charAt(indent)) > -1) indent = indent + 1;
|
|
962
|
+
const ch = line.charAt(indent);
|
|
963
|
+
let run = 0;
|
|
964
|
+
if (indent < 4 && [TICK, "~"].indexOf(ch) > -1) {
|
|
965
|
+
while (indent + run < line.length && [ch].indexOf(line.charAt(indent + run)) > -1) run = run + 1;
|
|
966
|
+
}
|
|
967
|
+
const rest = line.slice(indent + run);
|
|
968
|
+
if (fenceChar.length < 1) {
|
|
969
|
+
const opens = run >= 3 && ([TICK].indexOf(ch) < 0 || rest.indexOf(TICK) < 0);
|
|
970
|
+
if (opens) { fenceChar = ch; fenceLen = run; openedAt = i + 1; fenceLine.push(true); inFence.push(false); fenceOpenedAt.push(0); continue; }
|
|
971
|
+
fenceLine.push(false); inFence.push(false); fenceOpenedAt.push(0);
|
|
972
|
+
continue;
|
|
973
|
+
}
|
|
974
|
+
// Only spaces and tabs may follow a closer (CommonMark); JS trim() would also
|
|
975
|
+
// strip Unicode spaces such as U+00A0, so a closer that Markdown keeps open
|
|
976
|
+
// would read as closed here and a fenced skeleton after it would reach the
|
|
977
|
+
// gate (Greptile P1 on mmnto-ai/totem#2769).
|
|
978
|
+
const closes = run >= fenceLen && [fenceChar].indexOf(ch) > -1 && rest.split(" ").join("").split(" ").join("").length < 1;
|
|
979
|
+
if (closes) { fenceChar = ""; fenceLen = 0; fenceLine.push(true); inFence.push(false); fenceOpenedAt.push(0); continue; }
|
|
980
|
+
fenceLine.push(false); inFence.push(true); fenceOpenedAt.push(openedAt);
|
|
981
|
+
}
|
|
982
|
+
// A line of only # characters and whitespace (mmnto-ai/totem#2769): not a
|
|
983
|
+
// heading (no text) and not body either — it is the skeleton of one. Inside a
|
|
984
|
+
// fence it is code, and code is body.
|
|
985
|
+
function bareHashes(line) {
|
|
986
|
+
const t = line.trim();
|
|
987
|
+
return t.length > 0 && t.split("#").join("").length < 1;
|
|
988
|
+
}
|
|
989
|
+
function levelAt(i) {
|
|
990
|
+
if (fenceLine[i] || inFence[i]) return 0;
|
|
991
|
+
return headingLevel(lines[i]);
|
|
992
|
+
}
|
|
993
|
+
// A promised heading, spelled exactly or with one trailing parenthetical
|
|
994
|
+
// dropped (the same tolerance the matcher extends), whatever its indentation.
|
|
995
|
+
function promisedHeading(text) {
|
|
996
|
+
const t = text.trim();
|
|
997
|
+
if (REQUIRED.indexOf(t) > -1) return true;
|
|
998
|
+
const w = stripParen(t);
|
|
999
|
+
for (const h of REQUIRED) { if ([w].indexOf(stripParen(h)) > -1) return true; }
|
|
1000
|
+
return false;
|
|
1001
|
+
}
|
|
1002
|
+
function isBody(i) {
|
|
1003
|
+
if (fenceLine[i]) return false;
|
|
1004
|
+
if (lines[i].trim().length < 1) return false;
|
|
1005
|
+
if (inFence[i]) return !promisedHeading(lines[i]);
|
|
1006
|
+
return !bareHashes(lines[i]);
|
|
1007
|
+
}
|
|
1008
|
+
// Why a section read as empty when it was not blank: the reader says which
|
|
1009
|
+
// rule emptied it, so the cure is never a line the seat can see and not explain.
|
|
1010
|
+
function emptyReason(start, level) {
|
|
1011
|
+
let quoted = false;
|
|
1012
|
+
let hashes = false;
|
|
1013
|
+
let fences = false;
|
|
1014
|
+
for (let i = start + 1; i < lines.length; i++) {
|
|
1015
|
+
const n = levelAt(i);
|
|
1016
|
+
if (n > 0 && n <= level) break;
|
|
1017
|
+
if (n > 0) continue;
|
|
1018
|
+
if (fenceLine[i]) fences = true;
|
|
1019
|
+
else if (inFence[i] && lines[i].trim().length > 0) quoted = true;
|
|
1020
|
+
else if (bareHashes(lines[i])) hashes = true;
|
|
1021
|
+
}
|
|
1022
|
+
const found = [];
|
|
1023
|
+
if (quoted) found.push("a promised heading quoted inside a fenced code block");
|
|
1024
|
+
if (hashes) found.push("a line of # characters");
|
|
1025
|
+
if (fences && !quoted) found.push("an empty fenced code block");
|
|
1026
|
+
if (found.length < 1) return "";
|
|
1027
|
+
return " — nothing under it counts as body: " + found.join("; ");
|
|
1028
|
+
}
|
|
941
1029
|
function hasBodyAfter(start, level) {
|
|
942
1030
|
for (let i = start + 1; i < lines.length; i++) {
|
|
943
|
-
const n =
|
|
1031
|
+
const n = levelAt(i);
|
|
944
1032
|
if (n > 0 && n <= level) return false;
|
|
945
1033
|
if (n > 0) continue;
|
|
946
|
-
if (
|
|
1034
|
+
if (isBody(i)) return true;
|
|
947
1035
|
}
|
|
948
1036
|
return false;
|
|
949
1037
|
}
|
|
1038
|
+
function candidate(i) {
|
|
1039
|
+
return !fenceLine[i] && !inFence[i];
|
|
1040
|
+
}
|
|
1041
|
+
function fencedCopyOf(heading) {
|
|
1042
|
+
const want = stripParen(heading);
|
|
1043
|
+
for (let i = 0; i < lines.length; i++) {
|
|
1044
|
+
if (!inFence[i]) continue;
|
|
1045
|
+
const seen = lines[i].trim();
|
|
1046
|
+
if ([heading].indexOf(seen) > -1 || [want].indexOf(stripParen(seen)) > -1) return i;
|
|
1047
|
+
}
|
|
1048
|
+
return -1;
|
|
1049
|
+
}
|
|
1050
|
+
// The fence still open when the scan ended, if any — its copy of a heading
|
|
1051
|
+
// gets the cure that fits (close it) rather than the one that does not.
|
|
1052
|
+
const unclosedAt = fenceChar.length > 0 ? openedAt : 0;
|
|
1053
|
+
function fenceCure(openLine) {
|
|
1054
|
+
if (unclosedAt > 0 && [unclosedAt].indexOf(openLine) > -1) return " (that fence is never closed — close it with a bare closing fence: the same character, at least as long, nothing else on the line — or write the section outside it)";
|
|
1055
|
+
return " (write the section outside the fence)";
|
|
1056
|
+
}
|
|
950
1057
|
if (shape !== "DOCUMENT") {
|
|
951
1058
|
for (const heading of REQUIRED) {
|
|
952
1059
|
let at = -1;
|
|
953
|
-
for (let i = 0; i < lines.length; i++) { if ([heading].indexOf(lines[i].trimEnd()) > -1) { at = i; break; } }
|
|
1060
|
+
for (let i = 0; i < lines.length; i++) { if (candidate(i) && [heading].indexOf(lines[i].trimEnd()) > -1) { at = i; break; } }
|
|
954
1061
|
let matchedAs = "";
|
|
955
1062
|
if (at < 0) {
|
|
956
1063
|
const want = stripParen(heading);
|
|
957
|
-
for (let i = 0; i < lines.length; i++) { if ([want].indexOf(stripParen(lines[i].trimEnd())) > -1) { at = i; break; } }
|
|
1064
|
+
for (let i = 0; i < lines.length; i++) { if (candidate(i) && [want].indexOf(stripParen(lines[i].trimEnd())) > -1) { at = i; break; } }
|
|
958
1065
|
if (at > -1) { matchedAs = safe(lines[at].trimEnd()); tolerated.push(safe(heading) + " ~ " + matchedAs); }
|
|
959
1066
|
}
|
|
960
|
-
if (at < 0)
|
|
1067
|
+
if (at < 0) {
|
|
1068
|
+
const fencedAt = fencedCopyOf(heading);
|
|
1069
|
+
if (fencedAt > -1) block("the draft in " + shownFile + " is missing heading " + safe(heading) + " — it appears only inside a fenced code block opened at line " + fenceOpenedAt[fencedAt] + fenceCure(fenceOpenedAt[fencedAt]));
|
|
1070
|
+
block("the draft in " + shownFile + " is missing heading " + safe(heading));
|
|
1071
|
+
}
|
|
961
1072
|
const shownHeading = safe(heading) + (matchedAs.length > 0 ? " (matched as " + matchedAs + ")" : "");
|
|
962
|
-
if (!hasBodyAfter(at,
|
|
1073
|
+
if (!hasBodyAfter(at, levelAt(at))) block("the draft in " + shownFile + " has an empty heading " + shownHeading + emptyReason(at, levelAt(at)));
|
|
963
1074
|
}
|
|
964
1075
|
} else {
|
|
965
1076
|
let bodied = false;
|
|
966
|
-
for (let i = 0; i < lines.length; i++) { const n =
|
|
1077
|
+
for (let i = 0; i < lines.length; i++) { const n = levelAt(i); if (n > 0 && hasBodyAfter(i, n)) { bodied = true; break; } }
|
|
967
1078
|
if (!bodied && kind !== KIND_RECORD) block("the draft in " + shownFile + " has no heading with a body (custom prompt: the built-in template skeleton is not required)");
|
|
968
1079
|
if (!bodied) block("the bound record at " + shownRef + " has no heading with a body");
|
|
969
1080
|
}
|
|
@@ -1015,14 +1126,24 @@ export function buildPrePushHook(options) {
|
|
|
1015
1126
|
const { fallbackCmd, totemDir } = options;
|
|
1016
1127
|
const effectiveTier = options.tier;
|
|
1017
1128
|
assertRenderableTotemDir(totemDir);
|
|
1018
|
-
// The
|
|
1019
|
-
//
|
|
1020
|
-
//
|
|
1021
|
-
//
|
|
1022
|
-
//
|
|
1023
|
-
//
|
|
1024
|
-
//
|
|
1025
|
-
//
|
|
1129
|
+
// The review-leg floor (mmnto-ai/totem#2698; doctrine `model-tiering.md`
|
|
1130
|
+
// § Review legs — a self-authored judgment-dense diff owes one falsification
|
|
1131
|
+
// leg before it is presented). The gate itself derives everything: whether
|
|
1132
|
+
// the push is legs-owed (the changed-file set against `hooks.legsOwed.globs`,
|
|
1133
|
+
// read at RUN time so a glob edit needs no hook re-install) and whether a
|
|
1134
|
+
// deposit ancestor-or-equal of HEAD answers for it. The hook maps that
|
|
1135
|
+
// derivation onto exit codes and NOTHING else — the tier changes only which
|
|
1136
|
+
// code blocks, never a line of the text.
|
|
1137
|
+
//
|
|
1138
|
+
// Since mmnto-ai/totem#2771 the repo's `hooks.legsOwed.enforce` (read at run
|
|
1139
|
+
// time by the gate, like the globs) can arm this ONE gate at any tier
|
|
1140
|
+
// (`'block'`) or soften it at every tier (`'advisory'`) without touching the
|
|
1141
|
+
// spec-evidence and shield arms. The hook never reads the knob: it reads the
|
|
1142
|
+
// EXIT CODE the gate has already mapped through it. So 3 and 2 block on
|
|
1143
|
+
// every tier — under the advisory flag they only ever come back when the
|
|
1144
|
+
// knob says block — and only a failure before the derivation (an unloadable
|
|
1145
|
+
// config, which is also how the knob would go unread) stays strict-only,
|
|
1146
|
+
// which keeps a knob-less install byte-for-byte on its old behaviour.
|
|
1026
1147
|
//
|
|
1027
1148
|
// Slotted BEFORE the shield block deliberately: on strict this is a sub-second
|
|
1028
1149
|
// local read, and paying for the slow review gate before discovering the push
|
|
@@ -1044,29 +1165,40 @@ export function buildPrePushHook(options) {
|
|
|
1044
1165
|
// `legs gate` at all. `--advisory` is specific to this verb, so its presence
|
|
1045
1166
|
// in that output means the verb itself answered.
|
|
1046
1167
|
const legsBlock = `
|
|
1047
|
-
#
|
|
1048
|
-
# (mmnto-ai/totem#2698, doctrine/model-tiering.md § Review legs).
|
|
1168
|
+
# The review-leg floor: require a fresh falsification-leg deposit for
|
|
1169
|
+
# legs-owed pushes (mmnto-ai/totem#2698, doctrine/model-tiering.md § Review legs).
|
|
1049
1170
|
# Exit vocabulary of \`totem legs gate\`: 0 = not owed, or a deposit answers for
|
|
1050
1171
|
# this head · 3 = owed with no fresh deposit · 2 = the gate could not derive
|
|
1051
|
-
# (not a git repo, HEAD or the branch diff unresolvable).
|
|
1052
|
-
# the
|
|
1172
|
+
# (not a git repo, HEAD or the branch diff unresolvable). The strict tier and
|
|
1173
|
+
# agent seats run the bare gate; the other tiers pass --advisory, under which
|
|
1174
|
+
# the gate prints the SAME lines and exits 0 — unless the repo's
|
|
1175
|
+
# hooks.legsOwed.enforce says 'block', in which case the gate exits 3 or 2 at
|
|
1176
|
+
# any tier and this hook blocks on it (mmnto-ai/totem#2771); 'advisory' makes
|
|
1177
|
+
# it exit 0 at any tier. A status other than 0, 2 or 3 is a failure before
|
|
1178
|
+
# the derivation (an unloadable config) and blocks only on the strict arm.
|
|
1053
1179
|
if $TOTEM_CMD legs gate --help 2>/dev/null | grep -q -- '--advisory'; then
|
|
1180
|
+
legs_strict=0
|
|
1054
1181
|
if [ "$is_agent" = "1" ] || [ "$TOTEM_HOOK_TIER" = "strict" ]; then
|
|
1182
|
+
legs_strict=1
|
|
1055
1183
|
$TOTEM_CMD legs gate
|
|
1056
1184
|
legs_status=$?
|
|
1057
|
-
if [ "$legs_status" = "3" ]; then
|
|
1058
|
-
echo "[Totem] BLOCKED: this push is legs-owed and carries no fresh falsification-leg deposit — run the leg, then 'totem legs deposit --sha HEAD --from <findings.json>' (mmnto-ai/totem#2698, strict mode)"
|
|
1059
|
-
exit 1
|
|
1060
|
-
elif [ "$legs_status" != "0" ]; then
|
|
1061
|
-
echo "[Totem] BLOCKED: the legs gate could not derive (totem legs gate exit status $legs_status) — fix the checkout and retry (strict mode)"
|
|
1062
|
-
exit 1
|
|
1063
|
-
fi
|
|
1064
1185
|
else
|
|
1065
1186
|
$TOTEM_CMD legs gate --advisory
|
|
1187
|
+
legs_status=$?
|
|
1188
|
+
fi
|
|
1189
|
+
if [ "$legs_status" = "3" ]; then
|
|
1190
|
+
echo "[Totem] BLOCKED: this push is legs-owed and carries no fresh falsification-leg deposit — run the leg, then 'totem legs deposit --sha HEAD --from <findings.json>' (mmnto-ai/totem#2698; strict mode, an agent seat, or hooks.legsOwed.enforce: block)"
|
|
1191
|
+
exit 1
|
|
1192
|
+
elif [ "$legs_status" = "2" ]; then
|
|
1193
|
+
echo "[Totem] BLOCKED: the legs gate could not derive (totem legs gate exit status 2) — fix the checkout and retry (strict mode, an agent seat, or hooks.legsOwed.enforce: block)"
|
|
1194
|
+
exit 1
|
|
1195
|
+
elif [ "$legs_status" != "0" ] && [ "$legs_strict" = "1" ]; then
|
|
1196
|
+
echo "[Totem] BLOCKED: the legs gate failed before deriving (totem legs gate exit status $legs_status) — fix the config or the CLI and retry (strict mode or an agent seat)"
|
|
1197
|
+
exit 1
|
|
1066
1198
|
fi
|
|
1067
1199
|
else
|
|
1068
1200
|
if [ "$is_agent" = "1" ] || [ "$TOTEM_HOOK_TIER" = "strict" ]; then
|
|
1069
|
-
echo "[Totem] BLOCKED: this hook expects 'totem legs gate' (mmnto-ai/totem#2698) but the resolved CLI lacks it — 'npm i -g @mmnto/cli@latest' (strict mode)" >&2
|
|
1201
|
+
echo "[Totem] BLOCKED: this hook expects 'totem legs gate' (mmnto-ai/totem#2698) but the resolved CLI lacks it — 'npm i -g @mmnto/cli@latest' (strict mode or an agent seat)" >&2
|
|
1070
1202
|
exit 1
|
|
1071
1203
|
else
|
|
1072
1204
|
echo "[totem] Hook running without the legs gate (CLI predates 'totem legs'); 'npm i -g @mmnto/cli@latest' enables it." >&2
|