@ihelpee/prumo-plugin-speckit 0.0.0-stage → 0.18.2
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/LICENSE +51 -0
- package/README.md +59 -2
- package/dist/catalog.d.ts +4 -0
- package/dist/catalog.d.ts.map +1 -0
- package/dist/catalog.js +134 -0
- package/dist/cli.d.ts +10 -0
- package/dist/cli.d.ts.map +1 -0
- package/dist/cli.js +10 -0
- package/dist/index.d.ts +11 -0
- package/dist/index.d.ts.map +1 -0
- package/dist/index.js +17 -0
- package/dist/messages.d.ts +3 -0
- package/dist/messages.d.ts.map +1 -0
- package/dist/messages.js +10 -0
- package/dist/rules.d.ts +5 -0
- package/dist/rules.d.ts.map +1 -0
- package/dist/rules.js +26 -0
- package/dist/scaffold.d.ts +7 -0
- package/dist/scaffold.d.ts.map +1 -0
- package/dist/scaffold.js +52 -0
- package/dist/skills.d.ts +5 -0
- package/dist/skills.d.ts.map +1 -0
- package/dist/skills.js +56 -0
- package/dist/status.d.ts +6 -0
- package/dist/status.d.ts.map +1 -0
- package/dist/status.js +15 -0
- package/package.json +57 -3
package/LICENSE
ADDED
|
@@ -0,0 +1,51 @@
|
|
|
1
|
+
Prumo Software License
|
|
2
|
+
|
|
3
|
+
Copyright (c) 2026 IHELPEE TECNOLOGIA LTDA (https://ihelpee.com). All rights reserved.
|
|
4
|
+
|
|
5
|
+
This license applies to Prumo version 0.17.0 and later: the @ihelpee/prumo
|
|
6
|
+
package, its plugins and i18n packages, and their documentation (the
|
|
7
|
+
"Software"). Versions published before 0.17.0 remain under the license each
|
|
8
|
+
one was published with (MIT or Apache-2.0); this license does not change them.
|
|
9
|
+
|
|
10
|
+
1. Grant. IHELPEE TECNOLOGIA LTDA ("IHELPEE") grants you a free,
|
|
11
|
+
non-exclusive, non-transferable, revocable license to install and run the
|
|
12
|
+
Software, as published by IHELPEE, to check your own projects. Your
|
|
13
|
+
projects may be commercial: a company may use the Software on the code of
|
|
14
|
+
the products it sells.
|
|
15
|
+
|
|
16
|
+
2. Commercial exploitation is reserved. Only IHELPEE may make money from the
|
|
17
|
+
Software itself. Unless IHELPEE agrees in writing, you may not charge for,
|
|
18
|
+
or receive any payment or other consideration for, the Software or any
|
|
19
|
+
product or service whose value comes mainly from it, such as reselling
|
|
20
|
+
it, bundling it, hosting it, or paid consulting, training, support,
|
|
21
|
+
setup or certification built on it.
|
|
22
|
+
|
|
23
|
+
3. Restrictions. Unless IHELPEE agrees in writing, you may not:
|
|
24
|
+
a. copy, modify, translate or create derivative works of the Software,
|
|
25
|
+
except copies made by installing and running it;
|
|
26
|
+
b. redistribute, sell, sublicense, rent or publish the Software, alone or
|
|
27
|
+
as part of another product;
|
|
28
|
+
c. offer the Software, or a substantial part of its functionality, to
|
|
29
|
+
third parties as a hosted or managed service;
|
|
30
|
+
d. reverse engineer, decompile or disassemble the Software, except where
|
|
31
|
+
the law allows it despite this restriction;
|
|
32
|
+
e. remove or alter any copyright, trademark or license notice.
|
|
33
|
+
|
|
34
|
+
4. Trademarks. This license grants no right to the "Prumo" name, logo or
|
|
35
|
+
other marks. See docs/TRADEMARK.md.
|
|
36
|
+
|
|
37
|
+
5. Termination. This license ends automatically if you breach it. On
|
|
38
|
+
termination you must stop using the Software and delete your copies.
|
|
39
|
+
|
|
40
|
+
6. No warranty. THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY
|
|
41
|
+
KIND, EXPRESS OR IMPLIED, INCLUDING MERCHANTABILITY, FITNESS FOR A
|
|
42
|
+
PARTICULAR PURPOSE AND NON-INFRINGEMENT.
|
|
43
|
+
|
|
44
|
+
7. Limitation of liability. TO THE EXTENT PERMITTED BY LAW, IHELPEE IS NOT
|
|
45
|
+
LIABLE FOR ANY DAMAGES ARISING FROM THE USE OF, OR INABILITY TO USE, THE
|
|
46
|
+
SOFTWARE.
|
|
47
|
+
|
|
48
|
+
8. Governing law. This license is governed by the laws of the Federative
|
|
49
|
+
Republic of Brazil.
|
|
50
|
+
|
|
51
|
+
Other licensing: alexgotardi@gmail.com
|
package/README.md
CHANGED
|
@@ -1,3 +1,60 @@
|
|
|
1
|
-
#
|
|
1
|
+
# @ihelpee/prumo-plugin-speckit
|
|
2
2
|
|
|
3
|
-
|
|
3
|
+
Experimental planning and interview plugin for Prumo. Speckit helps an agent turn an unclear
|
|
4
|
+
request into a human-approved intent before implementation. It does not write application code
|
|
5
|
+
or approve decisions on the person's behalf.
|
|
6
|
+
|
|
7
|
+
## What it adds
|
|
8
|
+
|
|
9
|
+
- The `prumo/spec-interviewer` and `prumo/speckit-foreman` skills, available after the project
|
|
10
|
+
harness is synchronized.
|
|
11
|
+
- An interview catalog with starter questions for common architecture and validation findings.
|
|
12
|
+
- A status provider that reports `speckitPhase` as `sem-intent`, `intent-rascunho`,
|
|
13
|
+
`intent-congelado` or `implementando`.
|
|
14
|
+
- An optional `speckit-intent-mapped` rule when the plugin is configured with code globs.
|
|
15
|
+
- A starter grill-me intent template for use with the plugin's scaffold API.
|
|
16
|
+
|
|
17
|
+
The catalog is a starting point, not a substitute for decisions specific to the project. The
|
|
18
|
+
human must approve the resulting intent; Speckit does not freeze contracts or implement the
|
|
19
|
+
feature.
|
|
20
|
+
|
|
21
|
+
## Installation
|
|
22
|
+
|
|
23
|
+
Install the plugin alongside Prumo at matching versions:
|
|
24
|
+
|
|
25
|
+
```bash
|
|
26
|
+
pnpm add -D @ihelpee/prumo @ihelpee/prumo-plugin-speckit
|
|
27
|
+
```
|
|
28
|
+
|
|
29
|
+
## Configuration
|
|
30
|
+
|
|
31
|
+
Register the plugin in `prumo.config.ts`:
|
|
32
|
+
|
|
33
|
+
```ts
|
|
34
|
+
import { defineConfig } from '@ihelpee/prumo';
|
|
35
|
+
import speckit from '@ihelpee/prumo-plugin-speckit';
|
|
36
|
+
|
|
37
|
+
export default defineConfig({ plugins: [speckit] });
|
|
38
|
+
```
|
|
39
|
+
|
|
40
|
+
Then synchronize the agent harness and start an interview:
|
|
41
|
+
|
|
42
|
+
```bash
|
|
43
|
+
npx prumo harness sync
|
|
44
|
+
npx prumo interview
|
|
45
|
+
```
|
|
46
|
+
|
|
47
|
+
The plugin contributes to Prumo's existing interview and status commands. It does not replace
|
|
48
|
+
the core gate or its verdict.
|
|
49
|
+
|
|
50
|
+
## Extension API
|
|
51
|
+
|
|
52
|
+
The package exports its catalog, skills, status provider and rule factory for integrations.
|
|
53
|
+
`createSpeckitRules({ codeGlobs })` returns no rule when no globs are supplied; with globs, it
|
|
54
|
+
reports matching source files when the project has no `.prumo/intent/*.md` file. The scaffold
|
|
55
|
+
helper writes the starter `speckit_grill_me.md` under `.prumo/intent/` in the selected locale.
|
|
56
|
+
|
|
57
|
+
## Compatibility
|
|
58
|
+
|
|
59
|
+
This plugin is experimental. Keep it on the same release version as `@ihelpee/prumo`; its
|
|
60
|
+
catalog and skill APIs may change between minor releases.
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"catalog.d.ts","sourceRoot":"","sources":["../src/catalog.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAE5D,+DAA+D;AAC/D,eAAO,MAAM,yBAAyB,EAAE,qBAAqB,EA8I5D,CAAC"}
|
package/dist/catalog.js
ADDED
|
@@ -0,0 +1,134 @@
|
|
|
1
|
+
/** Canonical English; `translations` carries other locales. */
|
|
2
|
+
export const SPECKIT_INTERVIEW_CATALOG = [
|
|
3
|
+
{
|
|
4
|
+
id: 'mutation-guards',
|
|
5
|
+
category: 'security',
|
|
6
|
+
title: 'Required Guard on Mutation Routes',
|
|
7
|
+
question: '{count} mutation route(s) (POST/PUT/PATCH/DELETE) were found without an authentication guard. Should state-changing routes always require authorization/authentication guards?',
|
|
8
|
+
options: [
|
|
9
|
+
'Yes, every mutation requires a guard (except routes explicitly declared public)',
|
|
10
|
+
'No, some mutations may be public without a guard',
|
|
11
|
+
],
|
|
12
|
+
defaultOptionIndex: 0,
|
|
13
|
+
suggestedRuleId: 'mutation-routes-guarded',
|
|
14
|
+
moduleName: 'api',
|
|
15
|
+
trigger: { kind: 'finding', rule: 'mutation-routes-guarded' },
|
|
16
|
+
roles: ['engineer', 'qa'],
|
|
17
|
+
translations: {
|
|
18
|
+
'pt-BR': {
|
|
19
|
+
title: 'Guarda Obrigatória em Rotas de Mutação',
|
|
20
|
+
question: 'Foram detectadas {count} rota(s) de mutação (POST/PUT/PATCH/DELETE) sem guard de autenticação. Rotas que alteram estado devem sempre exigir guards de autorização/autenticação?',
|
|
21
|
+
options: [
|
|
22
|
+
'Sim, toda mutação exige guard (exceto rotas públicas explicitamente declaradas)',
|
|
23
|
+
'Não, algumas mutações podem ser públicas sem restrição de guard',
|
|
24
|
+
],
|
|
25
|
+
},
|
|
26
|
+
},
|
|
27
|
+
},
|
|
28
|
+
{
|
|
29
|
+
id: 'cross-feature-imports',
|
|
30
|
+
category: 'architecture',
|
|
31
|
+
title: 'Boundaries and Isolation Between Features',
|
|
32
|
+
question: 'Direct imports crossing module boundaries were found (e.g. orders -> internal kyc). Should features communicate only through frozen public contracts?',
|
|
33
|
+
options: [
|
|
34
|
+
'Yes, sibling modules may not import each other\'s internal files (public contracts only)',
|
|
35
|
+
'Allow free imports between feature folders',
|
|
36
|
+
],
|
|
37
|
+
defaultOptionIndex: 0,
|
|
38
|
+
suggestedRuleId: 'no-cross-feature-import',
|
|
39
|
+
moduleName: 'architecture',
|
|
40
|
+
trigger: { kind: 'finding', rule: 'no-cross-feature-import' },
|
|
41
|
+
roles: ['engineer', 'qa'],
|
|
42
|
+
translations: {
|
|
43
|
+
'pt-BR': {
|
|
44
|
+
title: 'Fronteiras e Isolamento entre Features',
|
|
45
|
+
question: 'Foram detectados imports diretos atravessando fronteiras de módulos (ex: orders -> kyc interno). Features devem se comunicar exclusivamente via contratos públicos congelados?',
|
|
46
|
+
options: [
|
|
47
|
+
'Sim, módulos irmãos não podem importar arquivos internos entre si (apenas contratos públicos)',
|
|
48
|
+
'Permitir importação livre entre pastas de features',
|
|
49
|
+
],
|
|
50
|
+
},
|
|
51
|
+
},
|
|
52
|
+
},
|
|
53
|
+
{
|
|
54
|
+
id: 'monetary-precision',
|
|
55
|
+
category: 'data-integrity',
|
|
56
|
+
title: 'Integer Monetary Precision (Cents)',
|
|
57
|
+
question: 'Should monetary values (prices, totals, balances) be stored and handled strictly as integer cents (no floats)?',
|
|
58
|
+
options: [
|
|
59
|
+
'Yes, every monetary value is strictly an integer in cents (amountCents / totalCents)',
|
|
60
|
+
'No, the system will keep accepting float numbers with decimals',
|
|
61
|
+
],
|
|
62
|
+
defaultOptionIndex: 0,
|
|
63
|
+
suggestedRuleId: 'monetary-is-integer',
|
|
64
|
+
moduleName: 'finance',
|
|
65
|
+
trigger: {
|
|
66
|
+
kind: 'finding-or-src',
|
|
67
|
+
rule: 'monetary-is-integer',
|
|
68
|
+
srcSubstrings: ['order', 'payment'],
|
|
69
|
+
fallbackEvidence: 'Numeric fields found in order/payment entities',
|
|
70
|
+
},
|
|
71
|
+
roles: ['engineer', 'qa', 'po', 'stakeholder'],
|
|
72
|
+
translations: {
|
|
73
|
+
'pt-BR': {
|
|
74
|
+
title: 'Precisão Monetária Inteira (Centavos)',
|
|
75
|
+
question: 'Valores monetários (preços, totais, saldos) devem ser armazenados e manipulados estritamente como inteiros em centavos (sem floats)?',
|
|
76
|
+
options: [
|
|
77
|
+
'Sim, todo valor monetário é estritamente inteiro em centavos (amountCents / totalCents)',
|
|
78
|
+
'Não, o sistema continuará aceitando números float com casas decimais',
|
|
79
|
+
],
|
|
80
|
+
fallbackEvidence: 'Campos numéricos detectados em entidades de pedidos/pagamentos',
|
|
81
|
+
},
|
|
82
|
+
},
|
|
83
|
+
},
|
|
84
|
+
{
|
|
85
|
+
id: 'dto-validation',
|
|
86
|
+
category: 'validation',
|
|
87
|
+
title: 'Strict Validation of Input Parameters (DTOs)',
|
|
88
|
+
question: 'DTOs received in the request body (@Body()) were found without validation decorators. Should every inbound payload have strict schema/property validation?',
|
|
89
|
+
options: [
|
|
90
|
+
'Yes, unvalidated parameters must be rejected before reaching domain services',
|
|
91
|
+
'No, free parameters without validation are allowed',
|
|
92
|
+
],
|
|
93
|
+
defaultOptionIndex: 0,
|
|
94
|
+
suggestedRuleId: 'dto-has-validation',
|
|
95
|
+
moduleName: 'validation',
|
|
96
|
+
trigger: { kind: 'finding', rule: 'dto-has-validation' },
|
|
97
|
+
roles: ['engineer', 'qa'],
|
|
98
|
+
translations: {
|
|
99
|
+
'pt-BR': {
|
|
100
|
+
title: 'Validação Rígida de Parâmetros de Entrada (DTOs)',
|
|
101
|
+
question: 'Foram detectados DTOs recebidos no corpo de requisições (@Body()) sem decoradores de validação. Todo payload de entrada deve conter validação estrita de schema/propriedades?',
|
|
102
|
+
options: [
|
|
103
|
+
'Sim, parâmetros não validados devem ser rejeitados antes de alcançar os serviços de domínio',
|
|
104
|
+
'Não, parâmetros livres sem validação são permitidos',
|
|
105
|
+
],
|
|
106
|
+
},
|
|
107
|
+
},
|
|
108
|
+
},
|
|
109
|
+
{
|
|
110
|
+
id: 'architectural-baseline',
|
|
111
|
+
category: 'architecture',
|
|
112
|
+
title: 'Engineering Constitutional Baseline',
|
|
113
|
+
question: 'No critical anomaly was found right away. Do you want to make oracle isolation and frozen contracts the project standard?',
|
|
114
|
+
options: [
|
|
115
|
+
'Yes, establish frozen contracts and oracle isolation under .prumo/',
|
|
116
|
+
'Only audit, without generating extra rules',
|
|
117
|
+
],
|
|
118
|
+
defaultOptionIndex: 0,
|
|
119
|
+
suggestedRuleId: 'oracle-no-src',
|
|
120
|
+
moduleName: 'core',
|
|
121
|
+
trigger: { kind: 'baseline' },
|
|
122
|
+
roles: ['engineer', 'qa', 'po', 'stakeholder'],
|
|
123
|
+
translations: {
|
|
124
|
+
'pt-BR': {
|
|
125
|
+
title: 'Linha de Base Constitucional de Engenharia',
|
|
126
|
+
question: 'Nenhuma anomalia crítica foi encontrada de imediato. Deseja estabelecer o isolamento oracular e congelamento de contratos como padrão do projeto?',
|
|
127
|
+
options: [
|
|
128
|
+
'Sim, estabelecer contratos congelados e isolamento de oráculos sob .prumo/',
|
|
129
|
+
'Apenas auditar sem gerar regras adicionais',
|
|
130
|
+
],
|
|
131
|
+
},
|
|
132
|
+
},
|
|
133
|
+
},
|
|
134
|
+
];
|
package/dist/cli.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"cli.d.ts","sourceRoot":"","sources":["../src/cli.ts"],"names":[],"mappings":"AAAA,wBAAgB,QAAQ,CAAC,OAAO,EAAE;IAChC,WAAW,EAAE,CAAC,IAAI,EAAE,MAAM,KAAK;QAC7B,MAAM,EAAE,CAAC,EAAE,EAAE,MAAM,IAAI,KAAK,IAAI,CAAC;KAClC,CAAC;CACH,GAAG,IAAI,CAMP;;;;AAED,wBAEE"}
|
package/dist/cli.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
export function register(program) {
|
|
2
|
+
program
|
|
3
|
+
.description('Speckit Prompt Zero and grill-me interview helpers')
|
|
4
|
+
.action(() => {
|
|
5
|
+
console.log('Speckit plugin active. Run `prumo interview` or activate skill prumo/spec-interviewer.');
|
|
6
|
+
});
|
|
7
|
+
}
|
|
8
|
+
export default {
|
|
9
|
+
register,
|
|
10
|
+
};
|
package/dist/index.d.ts
ADDED
|
@@ -0,0 +1,11 @@
|
|
|
1
|
+
export * from './catalog.js';
|
|
2
|
+
export * from './skills.js';
|
|
3
|
+
export * from './status.js';
|
|
4
|
+
export * from './rules.js';
|
|
5
|
+
export * from './scaffold.js';
|
|
6
|
+
export declare function activate(): void;
|
|
7
|
+
declare const _default: {
|
|
8
|
+
activate: typeof activate;
|
|
9
|
+
};
|
|
10
|
+
export default _default;
|
|
11
|
+
//# sourceMappingURL=index.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"index.d.ts","sourceRoot":"","sources":["../src/index.ts"],"names":[],"mappings":"AAKA,cAAc,cAAc,CAAC;AAC7B,cAAc,aAAa,CAAC;AAC5B,cAAc,aAAa,CAAC;AAC5B,cAAc,YAAY,CAAC;AAC3B,cAAc,eAAe,CAAC;AAE9B,wBAAgB,QAAQ,IAAI,IAAI,CAI/B;;;;AAED,wBAEE"}
|
package/dist/index.js
ADDED
|
@@ -0,0 +1,17 @@
|
|
|
1
|
+
import { registerInterviewCatalog, registerHarnessSkills, registerStatusProvider } from '@ihelpee/prumo';
|
|
2
|
+
import { SPECKIT_INTERVIEW_CATALOG } from './catalog.js';
|
|
3
|
+
import { SPECKIT_SKILLS } from './skills.js';
|
|
4
|
+
import { speckitStatusProvider } from './status.js';
|
|
5
|
+
export * from './catalog.js';
|
|
6
|
+
export * from './skills.js';
|
|
7
|
+
export * from './status.js';
|
|
8
|
+
export * from './rules.js';
|
|
9
|
+
export * from './scaffold.js';
|
|
10
|
+
export function activate() {
|
|
11
|
+
registerInterviewCatalog('speckit', SPECKIT_INTERVIEW_CATALOG);
|
|
12
|
+
registerHarnessSkills('speckit', SPECKIT_SKILLS, 'prumo/');
|
|
13
|
+
registerStatusProvider('speckit', speckitStatusProvider);
|
|
14
|
+
}
|
|
15
|
+
export default {
|
|
16
|
+
activate,
|
|
17
|
+
};
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"messages.d.ts","sourceRoot":"","sources":["../src/messages.ts"],"names":[],"mappings":"AAEA,kFAAkF;AAClF,eAAO,MAAM,QAAQ,mEAOnB,CAAC"}
|
package/dist/messages.js
ADDED
|
@@ -0,0 +1,10 @@
|
|
|
1
|
+
import { defineMessages } from '@ihelpee/prumo/core';
|
|
2
|
+
/** Rule messages. English is canonical; other locales fall back to it per key. */
|
|
3
|
+
export const messages = defineMessages({
|
|
4
|
+
en: {
|
|
5
|
+
'speckit-intent-mapped': 'code in codeGlobs requires a matching intent spec in .prumo/intent/',
|
|
6
|
+
},
|
|
7
|
+
'pt-BR': {
|
|
8
|
+
'speckit-intent-mapped': 'Código em codeGlobs requer especificação de intent correspondente em .prumo/intent/',
|
|
9
|
+
},
|
|
10
|
+
});
|
package/dist/rules.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"rules.d.ts","sourceRoot":"","sources":["../src/rules.ts"],"names":[],"mappings":"AAAA,OAAO,EAAe,KAAK,OAAO,EAAoB,MAAM,gBAAgB,CAAC;AAG7E,wBAAgB,kBAAkB,CAAC,OAAO,GAAE;IAAE,SAAS,CAAC,EAAE,MAAM,EAAE,CAAA;CAAO,GAAG,OAAO,EAAE,CAyBpF"}
|
package/dist/rules.js
ADDED
|
@@ -0,0 +1,26 @@
|
|
|
1
|
+
import { RuleBuilder } from '@ihelpee/prumo';
|
|
2
|
+
import { messages } from './messages.js';
|
|
3
|
+
export function createSpeckitRules(options = {}) {
|
|
4
|
+
if (!options.codeGlobs || options.codeGlobs.length === 0) {
|
|
5
|
+
return [];
|
|
6
|
+
}
|
|
7
|
+
const globs = options.codeGlobs;
|
|
8
|
+
const rule = new RuleBuilder('speckit-intent-mapped')
|
|
9
|
+
.severity('error')
|
|
10
|
+
.message(messages.text('speckit-intent-mapped'))
|
|
11
|
+
.needsData('declared')
|
|
12
|
+
.assert(async (ctx) => {
|
|
13
|
+
const targets = [];
|
|
14
|
+
const hasIntents = ctx.files.some((f) => f.includes('.prumo/intent') && f.endsWith('.md'));
|
|
15
|
+
if (!hasIntents) {
|
|
16
|
+
for (const file of ctx.files) {
|
|
17
|
+
if (globs.some((g) => file.includes(g.replace(/\*+/g, '')))) {
|
|
18
|
+
targets.push({ target: file, location: file });
|
|
19
|
+
}
|
|
20
|
+
}
|
|
21
|
+
}
|
|
22
|
+
return targets;
|
|
23
|
+
})
|
|
24
|
+
.build();
|
|
25
|
+
return [rule];
|
|
26
|
+
}
|
|
@@ -0,0 +1,7 @@
|
|
|
1
|
+
import { type SupportedLocale } from '@ihelpee/prumo/core';
|
|
2
|
+
/** The grill-me intent template in `locale`, falling back to English. */
|
|
3
|
+
export declare function speckitGrillMeTemplate(locale?: SupportedLocale): string;
|
|
4
|
+
/** Canonical English template. */
|
|
5
|
+
export declare const SPECKIT_GRILL_ME_TEMPLATE: string;
|
|
6
|
+
export declare function scaffoldSpeckit(root: string, locale?: SupportedLocale): Promise<string[]>;
|
|
7
|
+
//# sourceMappingURL=scaffold.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"scaffold.d.ts","sourceRoot":"","sources":["../src/scaffold.ts"],"names":[],"mappings":"AAEA,OAAO,EAAiB,KAAK,eAAe,EAAE,MAAM,qBAAqB,CAAC;AAuC1E,yEAAyE;AACzE,wBAAgB,sBAAsB,CAAC,MAAM,CAAC,EAAE,eAAe,GAAG,MAAM,CAEvE;AAED,kCAAkC;AAClC,eAAO,MAAM,yBAAyB,QAAe,CAAC;AAEtD,wBAAsB,eAAe,CAAC,IAAI,EAAE,MAAM,EAAE,MAAM,GAAE,eAAiC,GAAG,OAAO,CAAC,MAAM,EAAE,CAAC,CAMhH"}
|
package/dist/scaffold.js
ADDED
|
@@ -0,0 +1,52 @@
|
|
|
1
|
+
import { writeFile, mkdir } from 'node:fs/promises';
|
|
2
|
+
import { join } from 'node:path';
|
|
3
|
+
import { resolveLocale } from '@ihelpee/prumo/core';
|
|
4
|
+
const TEMPLATES = {
|
|
5
|
+
en: `# Intent — Prumo Speckit (grill-me = plan mode / Prompt Zero)
|
|
6
|
+
|
|
7
|
+
Authority for **specification driven by human decisions** before any code is implemented.
|
|
8
|
+
|
|
9
|
+
<!-- prumo:rule: speckit-is-plan-mode -->
|
|
10
|
+
## 1. Plan mode = grill-me, not implementation
|
|
11
|
+
|
|
12
|
+
When the human asks to plan, for Prompt Zero, or for discovery:
|
|
13
|
+
1. Activate the \`prumo/spec-interviewer\` skill (or \`prumo interview\`).
|
|
14
|
+
2. Run grill-me: clear multiple-choice questions until decisions are recorded. No invented defaults.
|
|
15
|
+
3. Forbidden: editing \`src/**\` or tests before the intent is frozen.
|
|
16
|
+
|
|
17
|
+
## 2. Speckit outputs
|
|
18
|
+
1. \`.prumo/intent/<scope>.md\`
|
|
19
|
+
2. \`.prumo/invariants/<id>.ts\` (mechanical invariants only)
|
|
20
|
+
3. \`.prumo/contract/**\` (when there is a public boundary)
|
|
21
|
+
`,
|
|
22
|
+
'pt-BR': `# Intent — Prumo Speckit (grill-me = modo plano / Prompt Zero)
|
|
23
|
+
|
|
24
|
+
Autoridade para **especificação orientada por decisões humanas** antes de qualquer implementação em código.
|
|
25
|
+
|
|
26
|
+
<!-- prumo:rule: speckit-is-plan-mode -->
|
|
27
|
+
## 1. Modo plano = grill-me, não implementação
|
|
28
|
+
|
|
29
|
+
Quando o humano pede planejar, Prompt Zero ou descoberta:
|
|
30
|
+
1. Ativar skill \`prumo/spec-interviewer\` (ou \`prumo interview\`).
|
|
31
|
+
2. Conduzir grill-me: perguntas claras de múltipla escolha até registrar decisões. Zero defaults inventados.
|
|
32
|
+
3. Proibido: editar \`src/**\` ou testes antes do intent congelado.
|
|
33
|
+
|
|
34
|
+
## 2. Saídas do Speckit
|
|
35
|
+
1. \`.prumo/intent/<escopo>.md\`
|
|
36
|
+
2. \`.prumo/invariants/<id>.ts\` (apenas invariantes mecânicos)
|
|
37
|
+
3. \`.prumo/contract/**\` (se houver fronteira pública)
|
|
38
|
+
`,
|
|
39
|
+
};
|
|
40
|
+
/** The grill-me intent template in `locale`, falling back to English. */
|
|
41
|
+
export function speckitGrillMeTemplate(locale) {
|
|
42
|
+
return (locale && TEMPLATES[locale]) || TEMPLATES.en;
|
|
43
|
+
}
|
|
44
|
+
/** Canonical English template. */
|
|
45
|
+
export const SPECKIT_GRILL_ME_TEMPLATE = TEMPLATES.en;
|
|
46
|
+
export async function scaffoldSpeckit(root, locale = resolveLocale()) {
|
|
47
|
+
const intentDir = join(root, '.prumo', 'intent');
|
|
48
|
+
await mkdir(intentDir, { recursive: true });
|
|
49
|
+
const grillMePath = join(intentDir, 'speckit_grill_me.md');
|
|
50
|
+
await writeFile(grillMePath, speckitGrillMeTemplate(locale), 'utf8');
|
|
51
|
+
return [grillMePath];
|
|
52
|
+
}
|
package/dist/skills.d.ts
ADDED
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"skills.d.ts","sourceRoot":"","sources":["../src/skills.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,KAAK,EAAE,MAAM,gBAAgB,CAAC;AAE5C,eAAO,MAAM,sBAAsB,EAAE,KAkCpC,CAAC;AAEF,eAAO,MAAM,qBAAqB,EAAE,KAoBnC,CAAC;AAEF,eAAO,MAAM,cAAc,EAAE,KAAK,EAGjC,CAAC"}
|
package/dist/skills.js
ADDED
|
@@ -0,0 +1,56 @@
|
|
|
1
|
+
export const SPEC_INTERVIEWER_SKILL = {
|
|
2
|
+
name: 'spec-interviewer',
|
|
3
|
+
purpose: 'Conduct focused architectural interviews to derive intent specifications and executable AST rules.',
|
|
4
|
+
allowedReads: ['src/**', '.prumo/constitution.md', '.prumo/intent/**', 'AGENTS.md', '.agents/**', 'docs/**', 'public/docs/**'],
|
|
5
|
+
forbiddenReads: [],
|
|
6
|
+
emits: ['.prumo/intent/**', '.prumo/invariants/**', '.prumo/waivers/**'],
|
|
7
|
+
rationale: 'Resolves architectural ambiguities with the human developer before writing code, ' +
|
|
8
|
+
'capturing intent in docs and invariants simultaneously with strict boundary separation.',
|
|
9
|
+
gate: 'prumo interview',
|
|
10
|
+
titleEn: 'Spec Interviewer (Prumo Speckit)',
|
|
11
|
+
descriptionEn: 'Prumo Speckit: the plan / Prompt Zero path. Interactive grill-me interviews to derive human intent (.prumo/intent/) ' +
|
|
12
|
+
'and mechanical AST rules (.prumo/invariants/) only — then hand off to contract-author and oracle-author. ' +
|
|
13
|
+
'Replaces ad-hoc planning with decision-backed specs before any implementation brick.',
|
|
14
|
+
workflowEn: [
|
|
15
|
+
'This skill IS the Prumo plan mode. When the user says plan, specify, or discover: stay in Speckit until intent exists — no src/** or packages/*/src/** edits.',
|
|
16
|
+
'Read `packages/core/.prumo/intent/speckit_grill_me.md`, the root constitution, AGENTS.md, and existing intents; for framework work, align with product intents.',
|
|
17
|
+
'Brownfield: start from `npx prumo gaps <path>` — its questions come from the code (exported functions, optional fields of observed contracts). Ask them one at a time and wait for each answer; findings are interview input, not excuses to skip human decisions.',
|
|
18
|
+
'Before asking, read the effective `locale` from the nearest `prumo.config.ts` that owns the target scope (`en` when unset). Use it for every part of every question, regardless of the chat language: title, subtitle, introduction, facts, diagram, examples, counter-examples, options and recommendation. Keep code identifiers literal when translating them would make them incorrect.',
|
|
19
|
+
'Ask one decision at a time. Make each question self-contained so the human can answer without looking anything up: title (the decision); subtitle (module/function and location); introduction (what happens today and why the decision matters); facts needed to judge, grounded in code/intents and never assumed; a diagram when order/flow/structure matters; and options that state guarantees, an example, a counter-example and the consequence (rule enforced by oracle/gate or implementation detail). Put the recommended option first, marked "(Recommended)", and explain why.',
|
|
20
|
+
'Put the COMPLETE briefing and the decision inside the same question-tool payload. Never leave essential context only in preceding chat commentary: it can collapse or separate from the question card. If the tool exposes only `title` and `options`, make `title` a multiline briefing with labeled sections and put the full choice explanation in each option string; do not reduce options to bare labels. If the tool has separate description fields, place the relevant context there. If diagrams cannot render, use a compact text diagram inside the question payload.',
|
|
21
|
+
'If the payload is too large, remove repetition or split it into separate decisions; do not move essential facts outside the question or ask the human to consult external sources. Commentary may announce progress, but must not be the only place containing question context.',
|
|
22
|
+
'When resuming an interrupted interview or correcting its format, preserve answers already given and start at the next unresolved decision. Do not ask an answered decision again unless the human explicitly asks to revisit it.',
|
|
23
|
+
'Then submit the question through the question tool in the configured locale. If the human replies with a message instead of choosing an option, that message is the answer: record it and do not repeat the question.',
|
|
24
|
+
'Turn each answer into one rule: `<!-- prumo:rule id="R-<domain>-NNN" -->` with the statement, an example and a counter-example. If the human cannot give a counter-example, the rule is still vague: ask again.',
|
|
25
|
+
'Write the intent as `status: draft` with `covers: <module>` in its frontmatter. Show it and ask for approval; only an explicit yes sets `status: approved` and adds `<!-- prumo:approval by="<person>" -->` under each approved rule.',
|
|
26
|
+
'For each <!-- prumo:decision status=open --> in intent: MUST use the editor question tool — Cursor AskQuestion, Claude Code AskUserQuestion (one call per decision, options from <!-- option: id | label -->). Forbidden: "A or B?" only in chat prose. After human choice, write <!-- prumo:decision-resolved id=... choice=... --> in the intent file.',
|
|
27
|
+
'Grill-me without decision blocks: still use the question tool with explicit options; record outcomes in intent — never invent defaults (Art. IV).',
|
|
28
|
+
'Emit `.prumo/intent/<scope>.md` with acceptance criteria, fatia boundaries if large, and `<!-- prumo:rule id="..." -->` links where rules already exist.',
|
|
29
|
+
'Emit `.prumo/invariants/<id>.ts` (export default [rule]) ONLY for mechanical AST (guards, import boundaries, decorators). One file per rule. Business rules stay in intent + oracle/**.',
|
|
30
|
+
'Waivers: `.prumo/waivers/<id>.json` with rule, target, reason, expiry and approver (`approvedBy`) when the human approves debt.',
|
|
31
|
+
'Handoff: tell the human Speckit is complete; next agent step is contract-author and/or oracle-author per intent — then reference-implementer. Run `npx prumo gate` before claiming spec done.',
|
|
32
|
+
],
|
|
33
|
+
};
|
|
34
|
+
export const SPECKIT_FOREMAN_SKILL = {
|
|
35
|
+
name: 'speckit-foreman',
|
|
36
|
+
purpose: 'Enforce Prompt Zero to Speckit interview conduction before any implementation touches code.',
|
|
37
|
+
allowedReads: ['.prumo/**', 'docs/**', 'public/docs/**', 'AGENTS.md', '.cursor/rules/**'],
|
|
38
|
+
forbiddenReads: [],
|
|
39
|
+
emits: [],
|
|
40
|
+
rationale: 'Agents attempting Prompt Zero without Speckit default to hallucinating unverified build plans. ' +
|
|
41
|
+
'This skill routes planning straight into spec-interviewer and speckit_grill_me.md.',
|
|
42
|
+
gate: 'prumo status',
|
|
43
|
+
titleEn: 'Speckit Foreman (Prompt Zero Conductor)',
|
|
44
|
+
descriptionEn: 'Dedicated conductor for Prompt Zero and early feature planning. Enforces that planning queries route ' +
|
|
45
|
+
'directly to spec-interviewer, preventing premature code generation and hallucinated requirements.',
|
|
46
|
+
workflowEn: [
|
|
47
|
+
'At Prompt Zero (new feature, redesign, or vague user prompt): activate `prumo/spec-interviewer` or run `prumo interview`.',
|
|
48
|
+
'Consult `packages/core/.prumo/intent/speckit_grill_me.md` for constitutional grill-me rules.',
|
|
49
|
+
'Halt all implementation (no edits under src/**, test/**, or oracle/**) until the human specification is committed in .prumo/intent/.',
|
|
50
|
+
'Confirm that open decision markers are resolved before handing off to contract-author.',
|
|
51
|
+
],
|
|
52
|
+
};
|
|
53
|
+
export const SPECKIT_SKILLS = [
|
|
54
|
+
SPEC_INTERVIEWER_SKILL,
|
|
55
|
+
SPECKIT_FOREMAN_SKILL,
|
|
56
|
+
];
|
package/dist/status.d.ts
ADDED
|
@@ -0,0 +1,6 @@
|
|
|
1
|
+
import type { StatusProviderContext } from '@ihelpee/prumo';
|
|
2
|
+
export type SpeckitPhase = 'sem-intent' | 'intent-rascunho' | 'intent-congelado' | 'implementando';
|
|
3
|
+
export declare function speckitStatusProvider(ctx: StatusProviderContext): Promise<{
|
|
4
|
+
speckitPhase: SpeckitPhase;
|
|
5
|
+
}>;
|
|
6
|
+
//# sourceMappingURL=status.d.ts.map
|
|
@@ -0,0 +1 @@
|
|
|
1
|
+
{"version":3,"file":"status.d.ts","sourceRoot":"","sources":["../src/status.ts"],"names":[],"mappings":"AAAA,OAAO,KAAK,EAAE,qBAAqB,EAAE,MAAM,gBAAgB,CAAC;AAE5D,MAAM,MAAM,YAAY,GAAG,YAAY,GAAG,iBAAiB,GAAG,kBAAkB,GAAG,eAAe,CAAC;AAEnG,wBAAsB,qBAAqB,CAAC,GAAG,EAAE,qBAAqB,GAAG,OAAO,CAAC;IAAE,YAAY,EAAE,YAAY,CAAA;CAAE,CAAC,CAkB/G"}
|
package/dist/status.js
ADDED
|
@@ -0,0 +1,15 @@
|
|
|
1
|
+
export async function speckitStatusProvider(ctx) {
|
|
2
|
+
const { snapshot, status } = ctx;
|
|
3
|
+
if (snapshot.intentCount === 0) {
|
|
4
|
+
return { speckitPhase: 'sem-intent' };
|
|
5
|
+
}
|
|
6
|
+
const hasOpenDecisions = snapshot.intentSpecs.some((s) => /<!--\s*prumo:decision\s+status=open/i.test(s.raw));
|
|
7
|
+
const hasSuggested = status.decisoes.some((d) => d.proveniencia === 'suggested');
|
|
8
|
+
if (hasOpenDecisions || hasSuggested) {
|
|
9
|
+
return { speckitPhase: 'intent-rascunho' };
|
|
10
|
+
}
|
|
11
|
+
if (status.etapa === 'execução' || status.etapa === 'verificação') {
|
|
12
|
+
return { speckitPhase: 'implementando' };
|
|
13
|
+
}
|
|
14
|
+
return { speckitPhase: 'intent-congelado' };
|
|
15
|
+
}
|
package/package.json
CHANGED
|
@@ -1,6 +1,60 @@
|
|
|
1
1
|
{
|
|
2
2
|
"name": "@ihelpee/prumo-plugin-speckit",
|
|
3
|
-
"version": "0.
|
|
4
|
-
"
|
|
5
|
-
"description": "
|
|
3
|
+
"version": "0.18.2",
|
|
4
|
+
"type": "module",
|
|
5
|
+
"description": "Speckit plugin for Prumo: spec-interviewer, Prompt Zero foreman, interview catalog, and intent phase status.",
|
|
6
|
+
"author": "Alex Gotardi <alexgotardi@gmail.com> (https://github.com/alexgotardi)",
|
|
7
|
+
"license": "SEE LICENSE IN LICENSE",
|
|
8
|
+
"homepage": "https://github.com/ihelpee/prumo#readme",
|
|
9
|
+
"repository": {
|
|
10
|
+
"type": "git",
|
|
11
|
+
"url": "git+https://github.com/ihelpee/prumo.git"
|
|
12
|
+
},
|
|
13
|
+
"bugs": {
|
|
14
|
+
"url": "https://github.com/ihelpee/prumo/issues"
|
|
15
|
+
},
|
|
16
|
+
"maturity": "experimental",
|
|
17
|
+
"main": "./dist/index.js",
|
|
18
|
+
"types": "./dist/index.d.ts",
|
|
19
|
+
"exports": {
|
|
20
|
+
".": {
|
|
21
|
+
"types": "./dist/index.d.ts",
|
|
22
|
+
"import": "./dist/index.js"
|
|
23
|
+
}
|
|
24
|
+
},
|
|
25
|
+
"files": [
|
|
26
|
+
"dist",
|
|
27
|
+
"package.json",
|
|
28
|
+
"README.md",
|
|
29
|
+
"LICENSE"
|
|
30
|
+
],
|
|
31
|
+
"publishConfig": {
|
|
32
|
+
"access": "public"
|
|
33
|
+
},
|
|
34
|
+
"prumo": ">=0.12.0",
|
|
35
|
+
"contributes": {
|
|
36
|
+
"activate": "./dist/index.js",
|
|
37
|
+
"rules": "./dist/rules.js",
|
|
38
|
+
"cliCommands": "./dist/cli.js",
|
|
39
|
+
"statusProviders": "./dist/status.js",
|
|
40
|
+
"harness": {
|
|
41
|
+
"skills": "./dist/skills.js"
|
|
42
|
+
},
|
|
43
|
+
"description": "Speckit plugin for Prumo: spec-interviewer, Prompt Zero foreman, interview catalog, and intent phase status.",
|
|
44
|
+
"commands": [
|
|
45
|
+
"prumo interview",
|
|
46
|
+
"prumo status"
|
|
47
|
+
]
|
|
48
|
+
},
|
|
49
|
+
"peerDependencies": {
|
|
50
|
+
"@ihelpee/prumo": "^0.18.2"
|
|
51
|
+
},
|
|
52
|
+
"devDependencies": {
|
|
53
|
+
"@ihelpee/prumo": "0.18.2",
|
|
54
|
+
"@ihelpee/prumo-plugin-typescript": "0.18.2"
|
|
55
|
+
},
|
|
56
|
+
"scripts": {
|
|
57
|
+
"build": "tsc -p tsconfig.json",
|
|
58
|
+
"verify": "prumo gate --root ."
|
|
59
|
+
}
|
|
6
60
|
}
|