@stackwright-pro/otters 1.0.0-alpha.2 → 1.0.0-alpha.20

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/package.json CHANGED
@@ -1,6 +1,6 @@
1
1
  {
2
2
  "name": "@stackwright-pro/otters",
3
- "version": "1.0.0-alpha.2",
3
+ "version": "1.0.0-alpha.20",
4
4
  "description": "Stackwright Pro Otter Raft - AI agents for enterprise features (CAC auth, API dashboards, government use cases)",
5
5
  "license": "MIT",
6
6
  "repository": {
@@ -8,21 +8,27 @@
8
8
  "url": "https://github.com/Per-Aspera-LLC/stackwright-pro"
9
9
  },
10
10
  "devDependencies": {
11
- "vitest": "^1.4.0",
11
+ "vitest": "^4.0.18",
12
12
  "zod": "^3.22.4"
13
13
  },
14
14
  "exports": {
15
15
  "./src": "./src",
16
- "./pro-foreman": "./src/stackwright-pro-foreman-otter.json"
16
+ "./pro-foreman": "./src/stackwright-pro-foreman-otter.json",
17
+ "./pro-workflow": "./src/stackwright-pro-workflow-otter.json"
17
18
  },
18
19
  "files": [
19
20
  "scripts",
20
21
  "src"
21
22
  ],
23
+ "publishConfig": {
24
+ "access": "public"
25
+ },
22
26
  "peerDependencies": {
23
- "@stackwright-pro/mcp": "0.2.0-alpha.0"
27
+ "@stackwright-pro/mcp": "^0.2.0-alpha.15"
24
28
  },
25
29
  "scripts": {
30
+ "generate-checksums": "node scripts/generate-checksums.js",
31
+ "verify-checksums": "node scripts/verify-checksums.js",
26
32
  "postinstall": "node scripts/install-agents.js",
27
33
  "test": "vitest run",
28
34
  "test:watch": "vitest",
@@ -0,0 +1,52 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * generate-checksums.js
4
+ * Computes SHA-256 for every *-otter.json in src/ and writes src/checksums.json
5
+ * Run: node scripts/generate-checksums.js
6
+ * Auto-run: npm prepare (before publish), npm pretest (before tests)
7
+ */
8
+
9
+ 'use strict';
10
+
11
+ const crypto = require('crypto');
12
+ const fs = require('fs');
13
+ const path = require('path');
14
+
15
+ const scriptDir = __dirname;
16
+ const packageRoot = path.resolve(scriptDir, '..');
17
+ const srcDir = path.join(packageRoot, 'src');
18
+ const outputFile = path.join(srcDir, 'checksums.json');
19
+
20
+ async function generateChecksums() {
21
+ const entries = await fs.promises.readdir(srcDir);
22
+
23
+ const otterFiles = entries
24
+ .filter((f) => f.endsWith('-otter.json'))
25
+ .sort(); // alphabetical — deterministic output, no excuses
26
+
27
+ const files = {};
28
+ for (const filename of otterFiles) {
29
+ const filePath = path.join(srcDir, filename);
30
+ const raw = await fs.promises.readFile(filePath); // raw Buffer → utf-8 bytes, no funny business
31
+ const digest = crypto.createHash('sha256').update(raw).digest('hex');
32
+ files[filename] = digest;
33
+ }
34
+
35
+ const manifest = {
36
+ version: '1.0',
37
+ algorithm: 'sha256',
38
+ files,
39
+ };
40
+
41
+ await fs.promises.writeFile(outputFile, JSON.stringify(manifest, null, 2) + '\n', 'utf8');
42
+
43
+ console.log(`✅ checksums.json written with ${otterFiles.length} entr${otterFiles.length === 1 ? 'y' : 'ies'}:`);
44
+ for (const [name, hash] of Object.entries(files)) {
45
+ console.log(` ${name}: ${hash}`);
46
+ }
47
+ }
48
+
49
+ generateChecksums().catch((err) => {
50
+ console.error('❌ generate-checksums failed:', err.message);
51
+ process.exit(1);
52
+ });
@@ -37,6 +37,14 @@ async function installAgents() {
37
37
  }
38
38
  }
39
39
 
40
+ // Also install checksums manifest (informational — Python coordinator uses hardcoded constants)
41
+ const checksumsSource = path.join(packageRoot, 'src', 'checksums.json');
42
+ const checksumsDest = path.join(AGENTS_DIR, 'otter-checksums.REFERENCE-ONLY.json');
43
+ if (fs.existsSync(checksumsSource)) {
44
+ await fs.promises.copyFile(checksumsSource, checksumsDest);
45
+ console.log('✅ Installed: otter-checksums.REFERENCE-ONLY.json');
46
+ }
47
+
40
48
  if (installedCount > 0) {
41
49
  console.log(`Installing otters from: ${srcDir}`);
42
50
  console.log(`\n🦦🦦 Pro otters installed to ${AGENTS_DIR}`);
@@ -44,9 +52,9 @@ async function installAgents() {
44
52
  console.log('⚠️ No Pro otter files found to install');
45
53
  }
46
54
  } catch (error) {
47
- // Don't fail the install if this script has issues
48
- console.warn(`⚠️ Failed to install Pro otters: ${error.message}`);
55
+ console.error(`❌ FATAL: Failed to install Pro otters: ${error.message}`);
56
+ process.exit(1); // Fail the npm install surface it early
49
57
  }
50
58
  }
51
59
 
52
- installAgents();
60
+ installAgents();
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env node
2
+ /* global console, process */
3
+
4
+ // ⚠️ DEPRECATED — This launcher has been replaced by @stackwright-pro/raft.
5
+ // Run: npx @stackwright-pro/raft
6
+ // This file is kept for users who may have cached a previous install.
7
+ // It will be removed in a future release.
8
+
9
+ console.error('⚠️ launch-raft in @stackwright-pro/otters is deprecated.');
10
+ console.error(' Use: npx @stackwright-pro/raft');
11
+ console.error('');
12
+ console.error(' Install: npm install -g @stackwright-pro/raft');
13
+ console.error(' Or run directly: npx @stackwright-pro/raft');
14
+ process.exit(1);
@@ -0,0 +1,61 @@
1
+ #!/usr/bin/env node
2
+ /**
3
+ * verify-checksums.js
4
+ * Read-only: verifies that *-otter.json files match the committed checksums.json
5
+ * Does NOT regenerate. For regeneration: node scripts/generate-checksums.js
6
+ *
7
+ * Exit codes:
8
+ * 0 = all checksums match
9
+ * 1 = one or more mismatches detected (tamper detected or file missing)
10
+ */
11
+
12
+ 'use strict';
13
+
14
+ const crypto = require('crypto');
15
+ const fs = require('fs');
16
+ const path = require('path');
17
+
18
+ const packageRoot = path.resolve(__dirname, '..');
19
+ const srcDir = path.join(packageRoot, 'src');
20
+ const checksumsPath = path.join(srcDir, 'checksums.json');
21
+
22
+ // Read checksums manifest
23
+ let manifest;
24
+ try {
25
+ manifest = JSON.parse(fs.readFileSync(checksumsPath, 'utf8'));
26
+ } catch (err) {
27
+ console.error(`❌ Cannot read checksums.json: ${err.message}`);
28
+ console.error('Run: node scripts/generate-checksums.js');
29
+ process.exit(1);
30
+ }
31
+
32
+ const expected = manifest.files || {};
33
+ let failures = 0;
34
+ let verified = 0;
35
+
36
+ for (const [filename, expectedHash] of Object.entries(expected)) {
37
+ const filePath = path.join(srcDir, filename);
38
+ try {
39
+ const raw = fs.readFileSync(filePath);
40
+ const actual = crypto.createHash('sha256').update(raw).digest('hex');
41
+ if (actual !== expectedHash) {
42
+ console.error(`❌ MISMATCH: ${filename}`);
43
+ console.error(` Expected: ${expectedHash.substring(0, 16)}...`);
44
+ console.error(` Actual: ${actual.substring(0, 16)}...`);
45
+ failures++;
46
+ } else {
47
+ console.log(`✅ ${filename}`);
48
+ verified++;
49
+ }
50
+ } catch (err) {
51
+ console.error(`❌ MISSING: ${filename} — ${err.message}`);
52
+ failures++;
53
+ }
54
+ }
55
+
56
+ if (failures > 0) {
57
+ console.error(`\n🚨 ${failures} checksum failure(s) detected. Run \`npm install @stackwright-pro/otters\` to restore.`);
58
+ process.exit(1);
59
+ } else {
60
+ console.log(`\n✅ All ${verified} otter checksums verified.`);
61
+ }
@@ -0,0 +1,15 @@
1
+ {
2
+ "version": "1.0",
3
+ "algorithm": "sha256",
4
+ "files": {
5
+ "stackwright-pro-api-otter.json": "f1cc9edf2dd1df3ebcea1d0ab33d17a358faaf8aa97ee232cd7994042f2eac0d",
6
+ "stackwright-pro-auth-otter.json": "a19e06c503209a8a35fe321d30448623545b36b48c47a6ec064d13406ad1f725",
7
+ "stackwright-pro-dashboard-otter.json": "b3cb3d7554f2e9eed3b57d5e0e3bf85d6ba5b4db5d3af5514391cf0575fcc001",
8
+ "stackwright-pro-data-otter.json": "bfacb87ae82867472a75982215554336a105a658d6cd3dd2c8b819fa1e11d7ac",
9
+ "stackwright-pro-designer-otter.json": "c58fa7c7ead9e6398074e1c7ce3f31a8ef4eb3679f5fa18cc03cae3a87878c88",
10
+ "stackwright-pro-foreman-otter.json": "f52264c1f6297b72f3da6d92d41b6d63356db776242caeab25571e6a8df628e4",
11
+ "stackwright-pro-page-otter.json": "65bec3a3a0dda6b7591bba2de9399f1e3a4fb99cfe1075342f4f4be98d917b67",
12
+ "stackwright-pro-theme-otter.json": "1f182326f1acd3d4091a38c7012085cbb4945893e95be4ca3de72318ad092767",
13
+ "stackwright-pro-workflow-otter.json": "0eec9d6a731678cf547c2a7b0b6fc338ca143c35501365a1e4e5dd2779dd5510"
14
+ }
15
+ }
@@ -3,13 +3,7 @@
3
3
  "name": "stackwright-pro-api-otter",
4
4
  "display_name": "Stackwright Pro API Otter 🦦",
5
5
  "description": "Analyzes API specs and extracts entity definitions",
6
- "tools": [
7
- "agent_run_shell_command",
8
- "list_files",
9
- "cp_list_files",
10
- "cp_read_file",
11
- "invoke_agent"
12
- ],
6
+ "tools": ["agent_run_shell_command", "list_files", "cp_list_files", "cp_read_file"],
13
7
  "user_prompt": "Hey! 🦦 I'm the API Otter. Give me an OpenAPI spec path and I'll extract what entities and endpoints it exposes.",
14
8
  "system_prompt": [
15
9
  "## YOUR JOB",
@@ -27,13 +21,78 @@
27
21
  "4. List available entities for user selection",
28
22
  "",
29
23
  "## OUTPUT FORMAT",
30
- "Report findings as a simple list:",
31
- "- Entities: {list}",
32
- "- Auth: {type}",
33
- "- Base URL: {url}",
34
24
  "",
35
- "## PASS TO DATA OTTER",
36
- "After analysis, invoke pro-data-otter to wire collections.",
25
+ "**You return a JSON artifact to the Foreman. You do NOT create files.**",
26
+ "",
27
+ "Return ONLY valid JSON \u2014 no markdown fences, no prose, no comments. Use one of these two shapes:",
28
+ "",
29
+ "SUCCESS SHAPE:",
30
+ "```json",
31
+ "{",
32
+ " \"entities\": [",
33
+ " {",
34
+ " \"name\": \"Shipment\",",
35
+ " \"endpoint\": \"/shipments\",",
36
+ " \"method\": \"GET\",",
37
+ " \"revalidate\": 60,",
38
+ " \"mutationType\": null",
39
+ " }",
40
+ " ],",
41
+ " \"auth\": {",
42
+ " \"type\": \"bearer\",",
43
+ " \"header\": \"Authorization\",",
44
+ " \"envVar\": \"MARINE_LOGISTICS_API_TOKEN\"",
45
+ " },",
46
+ " \"baseUrl\": \"https://api.marine-logistics.mil/v2\",",
47
+ " \"specPath\": \"./specs/marine-combat-logistics.yaml\"",
48
+ "}",
49
+ "```",
50
+ "",
51
+ "ERROR SHAPE (use if spec is missing, unreadable, or unsupported format):",
52
+ "```json",
53
+ "{",
54
+ " \"error\": \"Spec file not found at ./specs/missing.yaml\",",
55
+ " \"specPath\": \"./specs/missing.yaml\"",
56
+ "}",
57
+ "```",
58
+ "",
59
+ "Field notes:",
60
+ "- entities[].revalidate: seconds for ISR cache (from x-revalidate extension), or null",
61
+ "- entities[].mutationType: \"create\"|\"update\"|\"delete\" for mutations, null for GET",
62
+ "- auth.type: one of \"none\" | \"api-key\" | \"bearer\" | \"oauth2\" | \"cac\"",
63
+ " (cac = DoD Common Access Card / PKI certificate authentication)",
64
+ "- auth.envVar: environment variable name that will hold the credential",
65
+ "",
66
+ "---",
67
+ "",
68
+ "## SCOPE BOUNDARIES",
69
+ "",
70
+ "✅ **You DO:**",
71
+ "- Read and parse OpenAPI/GraphQL/AsyncAPI specs",
72
+ "- Extract entity names, endpoint paths, auth schemes, and base URLs",
73
+ "- Return a structured JSON artifact to the Foreman",
74
+ "",
75
+ "❌ **You DON'T:**",
76
+ "- Create any files (no .ts, no .js, no .json files on disk)",
77
+ "- Write TypeScript types, interfaces, or classes",
78
+ "- Write Zod schemas",
79
+ "- Generate API client classes (BaseApiClient, etc.)",
80
+ "- Write to src/generated/ or any other directory",
81
+ "",
82
+ "**WHY:** TypeScript type generation is @stackwright-pro/openapi's job at build time.",
83
+ "The otter's job is discovery and configuration — not code generation.",
84
+ "You have no file-write tools. If you find yourself constructing a file path or file content to write, STOP — return your JSON artifact as response text instead. The Foreman will handle validation and persistence.",
85
+ "Return your JSON artifact to the Foreman instead.",
86
+ "---",
87
+ "",
88
+ "## TERMINATION",
89
+ "",
90
+ "Once you have returned your JSON artifact, your job is complete.",
91
+ "Do NOT invoke other agents. Do NOT create files. Do NOT send follow-up messages.",
92
+ "The Foreman handles all routing after receiving your artifact.",
93
+ "",
94
+ "You are invoked ONE TIME by the Foreman with full context in this prompt.",
95
+ "The spec path will be provided in the prompt \u2014 you do not need to ask the user for it.",
37
96
  "",
38
97
  "---",
39
98
  "",