@meyverick/agentic 5.0.2 → 5.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.
Files changed (26) hide show
  1. package/AGENTS.md +1 -1
  2. package/CHANGELOG.md +15 -0
  3. package/README.md +2 -1
  4. package/package.json +5 -5
  5. package/scripts/{check-deps.mjs → check-deps.ts} +124 -59
  6. package/scripts/{git-dl.mjs → git-dl.ts} +11 -9
  7. package/skills/create-skill/SKILL.md +16 -16
  8. package/skills/create-skill/assets/templates/SKILL.md.template +1 -1
  9. package/skills/create-skill/evals/evals.json +4 -4
  10. package/skills/create-skill/evals/grading-template.json +1 -1
  11. package/skills/create-skill/references/component-decomposition.md +1 -1
  12. package/skills/create-skill/scripts/{audit-antipatterns.mjs → audit-antipatterns.ts} +75 -31
  13. package/skills/create-skill/scripts/{compute-benchmark.mjs → compute-benchmark.ts} +71 -30
  14. package/skills/create-skill/scripts/run-cold-eval.ts +202 -0
  15. package/skills/create-skill/scripts/{scaffold-skill.mjs → scaffold-skill.ts} +45 -25
  16. package/skills/create-skill/scripts/validate-routing.ts +218 -0
  17. package/skills/create-skill/scripts/{validate-structure.mjs → validate-structure.ts} +97 -36
  18. package/skills/okf-docs/SKILL.md +1 -1
  19. package/skills/okf-docs/evals/evals.json +2 -2
  20. package/skills/okf-docs/scripts/{validate-frontmatter.mjs → validate-frontmatter.ts} +73 -32
  21. package/skills/openspec-learn/references/evaluation-methodology.md +2 -2
  22. package/skills/openspec-pi-apply/SKILL.md +129 -0
  23. package/skills/openspec-pi-apply/references/rpc-protocol.md +43 -0
  24. package/skills/openspec-pi-apply/scripts/pi-rpc-apply.ts +421 -0
  25. package/skills/create-skill/scripts/run-cold-eval.mjs +0 -118
  26. package/skills/create-skill/scripts/validate-routing.mjs +0 -137
@@ -1,58 +1,91 @@
1
- #!/usr/bin/env node
1
+ #!/usr/bin/env bun
2
2
  /**
3
- * validate-frontmatter.mjs — OKF v0.2 frontmatter gate
4
- * Usage: node validate-frontmatter.mjs <document.md>
3
+ * validate-frontmatter.ts — OKF v0.2 frontmatter gate
4
+ * Usage: bun validate-frontmatter.ts <document.md>
5
5
  * Output: unified JSON envelope {target, pass, checks:[{id,status,detail}], summary}
6
6
  *
7
7
  * Checks: required keys (type/generated.by/at) · ISO 8601 formats · actor
8
8
  * convention values · status enum · stale_after chronology.
9
9
  */
10
10
 
11
- import { readFileSync, existsSync } from 'fs';
11
+ import { readFileSync, existsSync } from 'node:fs';
12
+
13
+ type CheckStatus = 'PASS' | 'FAIL' | 'WARN' | 'SKIP';
14
+
15
+ interface CheckEntry {
16
+ id: string;
17
+ status: CheckStatus;
18
+ detail: string;
19
+ }
20
+
21
+ interface ValidationSummary {
22
+ total: number;
23
+ pass: number;
24
+ fail: number;
25
+ warn: number;
26
+ skip: number;
27
+ }
28
+
29
+ interface ValidationReport {
30
+ target: string;
31
+ pass: boolean;
32
+ checks: CheckEntry[];
33
+ summary: ValidationSummary;
34
+ }
12
35
 
13
36
  const docPath = process.argv[2];
14
37
 
15
- if (!docPath) {
16
- console.error(JSON.stringify({ error: 'Usage: node validate-frontmatter.mjs <document.md>' }));
38
+ if (!docPath || docPath === '-h' || docPath === '--help') {
39
+ if (docPath === '-h' || docPath === '--help') {
40
+ console.log('Usage: bun validate-frontmatter.ts <document.md>');
41
+ process.exit(0);
42
+ }
43
+ console.error(JSON.stringify({ error: 'Usage: bun validate-frontmatter.ts <document.md>' }));
17
44
  process.exit(2);
18
45
  }
19
46
 
20
47
  if (!existsSync(docPath)) {
21
- console.log(JSON.stringify({
48
+ const report: ValidationReport = {
22
49
  target: docPath,
23
50
  pass: false,
24
51
  checks: [{ id: 'okf.file', status: 'FAIL', detail: 'Document not found' }],
25
52
  summary: { total: 1, pass: 0, fail: 1, warn: 0, skip: 0 }
26
- }));
53
+ };
54
+ console.log(JSON.stringify(report));
27
55
  process.exit(1);
28
56
  }
29
57
 
30
58
  const content = readFileSync(docPath, 'utf-8');
31
- const checks = [];
59
+ const checks: CheckEntry[] = [];
32
60
 
33
- const add = (id, ok, detail) => checks.push({ id, status: ok ? 'PASS' : 'FAIL', detail });
34
- const warn = (id, detail) => checks.push({ id, status: 'WARN', detail });
61
+ const add = (id: string, ok: boolean, detail: string): void => {
62
+ checks.push({ id, status: ok ? 'PASS' : 'FAIL', detail });
63
+ };
64
+ const warn = (id: string, detail: string): void => {
65
+ checks.push({ id, status: 'WARN', detail });
66
+ };
35
67
 
36
68
  // Extract frontmatter
37
69
  const fmMatch = content.match(/^---\r?\n([\s\S]*?)\r?\n---/);
38
70
  if (!fmMatch) {
39
- console.log(JSON.stringify({
71
+ const report: ValidationReport = {
40
72
  target: docPath,
41
73
  pass: false,
42
74
  checks: [{ id: 'okf.frontmatter', status: 'FAIL', detail: 'No frontmatter block found' }],
43
75
  summary: { total: 1, pass: 0, fail: 1, warn: 0, skip: 0 }
44
- }));
76
+ };
77
+ console.log(JSON.stringify(report));
45
78
  process.exit(1);
46
79
  }
47
80
  add('okf.frontmatter', true, 'Frontmatter block present');
48
81
 
49
82
  // Parse simple YAML subset (top-level + one nested level for generated)
50
83
  const fm = fmMatch[1];
51
- function get(key) {
84
+ function get(key: string): string | null {
52
85
  const m = fm.match(new RegExp(`^${key}:\\s*(.+)$`, 'm'));
53
86
  return m ? m[1].trim().replace(/^["']|["']$/g, '') : null;
54
87
  }
55
- function getNested(parent, key) {
88
+ function getNested(parent: string, key: string): string | null {
56
89
  const m = fm.match(new RegExp(`^${parent}:\\s*\\{\\s*([^}]*)\\}`, 'm'));
57
90
  if (!m) return null;
58
91
  const inner = m[1].match(new RegExp(`${key}:\\s*([^,}]+)`));
@@ -69,14 +102,22 @@ const at = getNested('generated', 'at');
69
102
  add('okf.generated-by', !!by, by ? `generated.by = ${by}` : "Missing required 'generated.by'");
70
103
 
71
104
  const actorRe = /^([a-z0-9][a-z0-9-]*\/\d+(\.\d+)*|human:[a-z0-9-]+|process:[a-z0-9-]+)$/;
72
- add('okf.actor-convention',
105
+ add(
106
+ 'okf.actor-convention',
73
107
  !!by && actorRe.test(by),
74
- by ? (actorRe.test(by) ? `Actor '${by}' matches convention` : `Actor '${by}' violates convention (<producer>/<version> | human:<id> | process:<id>)`) : 'No actor to check');
108
+ by
109
+ ? actorRe.test(by)
110
+ ? `Actor '${by}' matches convention`
111
+ : `Actor '${by}' violates convention (<producer>/<version> | human:<id> | process:<id>)`
112
+ : 'No actor to check'
113
+ );
75
114
 
76
115
  const isoRe = /^\d{4}-\d{2}-\d{2}(T\d{2}:\d{2}:\d{2}(\.\d+)?Z)?$/;
77
- add('okf.generated-at-format',
116
+ add(
117
+ 'okf.generated-at-format',
78
118
  !!at && isoRe.test(at),
79
- at ? (isoRe.test(at) ? `generated.at = ${at}` : `'${at}' is not ISO 8601`) : "Missing required 'generated.at'");
119
+ at ? (isoRe.test(at) ? `generated.at = ${at}` : `'${at}' is not ISO 8601`) : "Missing required 'generated.at'"
120
+ );
80
121
 
81
122
  // sources (WARN if missing — recommended not mandatory)
82
123
  const hasSources = /^sources:/m.test(fm);
@@ -87,13 +128,10 @@ const status = get('status');
87
128
  if (!status) {
88
129
  warn('okf.status', "Missing 'status' (draft | stable | deprecated)");
89
130
  } else if (!['draft', 'stable', 'deprecated'].includes(status)) {
90
- failStatus(status);
131
+ add('okf.status', false, `Invalid status '${status}' — must be draft | stable | deprecated`);
91
132
  } else {
92
133
  add('okf.status', true, `status = ${status}`);
93
134
  }
94
- function failStatus(value) {
95
- add('okf.status', false, `Invalid status '${value}' — must be draft | stable | deprecated`);
96
- }
97
135
 
98
136
  // stale_after chronology vs generated.at
99
137
  const stale = get('stale_after');
@@ -102,8 +140,11 @@ if (stale) {
102
140
  add('okf.stale-after', false, `stale_after '${stale}' is not YYYY-MM-DD`);
103
141
  } else if (at) {
104
142
  const genDay = at.slice(0, 10);
105
- add('okf.stale-after', stale >= genDay,
106
- stale >= genDay ? `stale_after ${stale} ≥ generated ${genDay}` : `stale_after ${stale} predates generation ${genDay}`);
143
+ add(
144
+ 'okf.stale-after',
145
+ stale >= genDay,
146
+ stale >= genDay ? `stale_after ${stale} ≥ generated ${genDay}` : `stale_after ${stale} predates generation ${genDay}`
147
+ );
107
148
  } else {
108
149
  add('okf.stale-after', true, `stale_after = ${stale} (no generated.at to compare)`);
109
150
  }
@@ -112,19 +153,19 @@ if (stale) {
112
153
  }
113
154
 
114
155
  // Unified envelope
115
- const fails = checks.filter(c => c.status === 'FAIL').length;
116
- console.log(JSON.stringify({
156
+ const fails = checks.filter((c) => c.status === 'FAIL').length;
157
+ const report: ValidationReport = {
117
158
  target: docPath,
118
159
  pass: fails === 0,
119
160
  checks,
120
161
  summary: {
121
162
  total: checks.length,
122
- pass: checks.filter(c => c.status === 'PASS').length,
163
+ pass: checks.filter((c) => c.status === 'PASS').length,
123
164
  fail: fails,
124
- warn: checks.filter(c => c.status === 'WARN').length,
125
- skip: checks.filter(c => c.status === 'SKIP').length
165
+ warn: checks.filter((c) => c.status === 'WARN').length,
166
+ skip: checks.filter((c) => c.status === 'SKIP').length
126
167
  }
127
- }));
168
+ };
128
169
 
170
+ console.log(JSON.stringify(report));
129
171
  process.exit(fails > 0 ? 1 : 0);
130
-
@@ -10,13 +10,13 @@ Before applying improvements:
10
10
 
11
11
  1. **Structural validation**:
12
12
  ```bash
13
- project/skills/create-skill/scripts/validate-structure.mjs <skill-dir>
13
+ bun project/skills/create-skill/scripts/validate-structure.ts <skill-dir>
14
14
  ```
15
15
  Extract: pass/fail, errors, warnings
16
16
 
17
17
  2. **Antipattern audit**:
18
18
  ```bash
19
- project/skills/create-skill/scripts/audit-antipatterns.mjs <skill-dir>
19
+ bun project/skills/create-skill/scripts/audit-antipatterns.ts <skill-dir>
20
20
  ```
21
21
  Extract: pass/fail, violation count, violations
22
22
 
@@ -0,0 +1,129 @@
1
+ ---
2
+ name: openspec-pi-apply
3
+ description: >
4
+ Delegate OpenSpec change task implementation to a headless pi worker agent via JSON-RPC.
5
+ Use when the user wants to apply an OpenSpec change using pi as a worker engine,
6
+ saying "pi apply", "opsx pi apply", or "apply change with pi".
7
+ Do NOT use when applying changes directly without pi (use openspec-apply-change),
8
+ or when proposing/planning changes (use openspec-propose).
9
+ allowed-tools: Bash(bun:*), Bash(openspec:*), Read, Grep
10
+ license: MIT
11
+ compatibility: Requires pi CLI, bun, and openspec CLI.
12
+ metadata:
13
+ author: agentic
14
+ version: "1.0.0"
15
+ positive_triggers:
16
+ - "apply change using pi"
17
+ - "pi apply change"
18
+ - "openspec pi apply"
19
+ - "delegate task implementation to pi"
20
+ anti_triggers:
21
+ - "implement change directly yourself"
22
+ - "apply change without pi"
23
+ - "openspec apply change"
24
+ - "propose a new change"
25
+ ---
26
+
27
+ # OpenSpec Pi Apply Workflow
28
+
29
+ Delegate task execution for an active OpenSpec change to a headless `pi` worker engine communicating over JSON-RPC. Antigravity acts as architectural supervisor, triaging worker questions and enforcing verification gates.
30
+
31
+ ## Contrast Matrix
32
+
33
+ | Dimension | Direct Supervisor (`openspec-apply-change`) | Headless Pi Worker (`openspec-pi-apply`) | Why Different |
34
+ | :--- | :--- | :--- | :--- |
35
+ | **Execution** | Supervisor edits project files directly in turn context | Child process worker (`pi -a -c --mode rpc`) executes edits | Prevents supervisor context bloat & high turn latency |
36
+ | **Supervision** | Self-directed implementation | Supervisor monitors tool events & validates completion gates | Decouples code authoring from architectural oversight |
37
+ | **Clarifications** | Halts and asks human immediately | Supervisor triages autonomously against change artifacts | Eliminates unnecessary user interruptions for specified details |
38
+
39
+ ## Anti-Examples (What NOT to do)
40
+
41
+ - **Do NOT edit project files directly** in this workflow. Task implementation is delegated to the worker process via `.agents/skills/openspec-pi-apply/scripts/pi-rpc-apply.ts`.
42
+ - **Do NOT pipe raw `pi` stdout directly** into conversational logs. Always use the bridge runner to filter high-frequency token deltas and prevent buffer stalls.
43
+ - **Do NOT guess unstated requirements** when the worker pauses for clarification. If an answer cannot be grounded in `specs/`, `design.md`, or `AGENTS.md`, escalate to the user.
44
+ - **Do NOT mark the change complete** based solely on worker claims. Verify that `openspec instructions apply --change <name> --json` confirms 0 remaining tasks.
45
+
46
+ ## Workflow — 5 Steps
47
+
48
+ ### Step 1: Pre-Flight & Change Discovery
49
+
50
+ 1. Identify target change name (from user input or active changes):
51
+ ```bash
52
+ openspec list --json
53
+ ```
54
+ 2. Verify that planning artifacts are complete:
55
+ ```bash
56
+ openspec status --change "<name>" --json
57
+ ```
58
+ Ensure `isPlanningComplete: true`. If planning is incomplete, advise completing artifacts with `/openspec-continue-change` first.
59
+
60
+ ### Step 2: Spawn Pi Worker Engine
61
+
62
+ Run the bridge runner from the workspace root:
63
+ ```bash
64
+ bun run .agents/skills/openspec-pi-apply/scripts/pi-rpc-apply.ts --change "<name>"
65
+ ```
66
+
67
+ *(For low-level RPC framing specifications, see [references/rpc-protocol.md](references/rpc-protocol.md).)*
68
+
69
+ The runner:
70
+ - Resolves workspace root and spawns `pi -a -c --mode rpc`
71
+ - Transmits `/skill:openspec-apply-change <name>` over stdin
72
+ - Filters raw token noise, emitting clean progress logs (`⚙ [pi:tool] Invoking: ...`)
73
+ - Detects `agent_settled` upon turn completion
74
+
75
+ ### Step 3: Triage Worker Settlement State
76
+
77
+ Evaluate the runner's exit status:
78
+
79
+ #### Case A: `[STATUS] COMPLETED`
80
+ All tasks in `tasks.md` are marked complete (`remaining: 0`).
81
+ - Proceed directly to **Step 5: Completion Verification**.
82
+
83
+ #### Case B: `[STATUS] PAUSED_FOR_CLARIFICATION`
84
+ Worker paused with remaining tasks or posted a question before finishing.
85
+ 1. Read the worker's question from the runner log.
86
+ 2. Cross-reference the question against:
87
+ - `openspec/changes/<name>/specs/**/*.md`
88
+ - `openspec/changes/<name>/design.md`
89
+ - `openspec/changes/<name>/proposal.md`
90
+ - `AGENTS.md`
91
+ 3. **Autonomous Resolution**:
92
+ - If the answer is documented in specifications or conventions, formulate the concise clarification grounded in the artifacts and resume worker execution:
93
+ ```bash
94
+ bun run .agents/skills/openspec-pi-apply/scripts/pi-rpc-apply.ts --change "<name>" --reply "<clarification-answer>"
95
+ ```
96
+ - Return to **Step 3** to inspect the next settlement state.
97
+ 4. **Human Escalation**:
98
+ - If the question involves domain ambiguity, product preference, or missing credentials not covered by specs:
99
+ - Ask the user directly.
100
+ - Once the user answers, resume worker execution:
101
+ ```bash
102
+ bun run .agents/skills/openspec-pi-apply/scripts/pi-rpc-apply.ts --change "<name>" --reply "<user-answer>"
103
+ ```
104
+ - Return to **Step 3**.
105
+
106
+ #### Case C: `[STATUS] FAILED`
107
+ Worker exited with an error or timed out.
108
+ - Inspect stderr and diagnostic logs.
109
+ - Report failure details to user and pause.
110
+
111
+ ### Step 4: Resume Iteration Loop
112
+
113
+ Repeat Step 3 until `[STATUS] COMPLETED` is reached or user intervention is requested.
114
+
115
+ ### Step 5: Completion Verification
116
+
117
+ 1. Run OpenSpec apply inspection:
118
+ ```bash
119
+ openspec instructions apply --change "<name>" --json
120
+ ```
121
+ 2. Confirm `progress.remaining === 0`.
122
+ 3. Run project verification suite (linters, typecheck, or tests) to confirm workspace health:
123
+ ```bash
124
+ openspec validate --change "<name>"
125
+ ```
126
+ 4. Present final implementation summary:
127
+ - Change name and status
128
+ - Completed task summary
129
+ - Prompt user to archive: "All tasks complete! You can archive this change with `/openspec-archive-change <name>`."
@@ -0,0 +1,43 @@
1
+ # Pi JSON-RPC Protocol Reference (Level 2)
2
+
3
+ This reference outlines the JSON-RPC framing and event specifications used by `scripts/pi-rpc-apply.ts` to control `pi -a -c --mode rpc`.
4
+
5
+ ## Process Invocation Flags
6
+
7
+ - `-a` (`--approve`): Auto-approves operations within the project scope, preventing interactive confirmation prompts.
8
+ - `-c` (`--continue`): Maintains conversational session memory and context across turns and process restarts.
9
+ - `--mode rpc`: Activates bidirectional JSON-RPC 2.0 streaming over standard I/O.
10
+
11
+ ## Standard Input Commands
12
+
13
+ ### Initial Apply Prompt
14
+ ```json
15
+ {
16
+ "id": "prompt-1",
17
+ "type": "prompt",
18
+ "message": "/skill:openspec-apply-change <change-name>"
19
+ }
20
+ ```
21
+ *Note*: `pi` natively expands `/skill:name` commands prior to session execution.
22
+
23
+ ### Clarification Reply
24
+ ```json
25
+ {
26
+ "id": "prompt-reply",
27
+ "type": "prompt",
28
+ "message": "<clarification-answer>"
29
+ }
30
+ ```
31
+
32
+ ## Standard Output Stream & Framing
33
+
34
+ Records are strictly formatted as single-line JSON objects separated by LF (`\n`):
35
+
36
+ 1. **`message_update` (suppressed by runner)**:
37
+ Emits streaming deltas (`text_delta`, `thinking_delta`). Filtered out to avoid context flooding.
38
+ 2. **`toolcall_start` / `toolcall_end`**:
39
+ Emitted when `pi` executes workspace tools (`read_file`, `write_to_file`, `run_command`).
40
+ 3. **`message_end`**:
41
+ Emitted when the assistant finishes a response turn. Captured to extract any worker questions.
42
+ 4. **`agent_settled`**:
43
+ Signals that the agent has settled and has no remaining automatic work.