From 8545aa8699a4d0fa717981329c8aec7f3ac64194 Mon Sep 17 00:00:00 2001 From: geoffsee <> Date: Fri, 11 Jul 2025 16:18:34 -0400 Subject: [PATCH] add code --- .gitignore | 11 + Cargo.toml | 6 + bun.lock | 240 ++++++++ cli.ts | 332 +++++++++++ examples/README.md | 65 +++ examples/v1/healthcare-example.ts | 349 ++++++++++++ examples/v1/technology-example.ts | 531 ++++++++++++++++++ examples/v2/software-company-example.ts | 521 +++++++++++++++++ generate-template.ts | 125 +++++ index.ts | 199 +++++++ lib/__tests__/v1.test.ts | 252 +++++++++ lib/__tests__/v2.test.ts | 476 ++++++++++++++++ lib/agent-wrapper.ts | 203 +++++++ lib/components/hierarchy-generator.ts | 115 ++++ lib/components/output-formatter.ts | 278 +++++++++ lib/components/template-manager.ts | 81 +++ lib/components/templates/v1-finance.ts | 9 + lib/components/templates/v1-tech.ts | 9 + lib/components/templates/v2-edu.ts | 9 + lib/components/templates/v2-healthcare.ts | 9 + lib/components/templates/v2-tech.ts | 9 + lib/hierarchy-model.ts | 35 ++ lib/index.ts | 4 + lib/v1.ts | 41 ++ lib/v2.ts | 194 +++++++ ...hierarchy-for-banking-20250711T200150.json | 30 + ...e-hierarchy-for-banking-20250711T200150.ts | 80 +++ ...hy-for-emergency-medici-20250711T200113.ts | 142 +++++ ...erarchy-for-web-devel-20250711T200047.json | 31 + package.json | 27 + src/main.rs | 3 + tsconfig.json | 32 ++ 32 files changed, 4448 insertions(+) create mode 100644 .gitignore create mode 100644 Cargo.toml create mode 100644 bun.lock create mode 100644 cli.ts create mode 100644 examples/README.md create mode 100644 examples/v1/healthcare-example.ts create mode 100644 examples/v1/technology-example.ts create mode 100644 examples/v2/software-company-example.ts create mode 100755 generate-template.ts create mode 100644 index.ts create mode 100644 lib/__tests__/v1.test.ts create mode 100644 lib/__tests__/v2.test.ts create mode 100644 lib/agent-wrapper.ts create mode 100644 lib/components/hierarchy-generator.ts create mode 100644 lib/components/output-formatter.ts create mode 100644 lib/components/template-manager.ts create mode 100644 lib/components/templates/v1-finance.ts create mode 100644 lib/components/templates/v1-tech.ts create mode 100644 lib/components/templates/v2-edu.ts create mode 100644 lib/components/templates/v2-healthcare.ts create mode 100644 lib/components/templates/v2-tech.ts create mode 100644 lib/hierarchy-model.ts create mode 100644 lib/index.ts create mode 100644 lib/v1.ts create mode 100644 lib/v2.ts create mode 100644 output/hierarchy-create-a-finance-hierarchy-for-banking-20250711T200150.json create mode 100644 output/hierarchy-create-a-finance-hierarchy-for-banking-20250711T200150.ts create mode 100644 output/hierarchy-create-a-healthcare-hierarchy-for-emergency-medici-20250711T200113.ts create mode 100644 output/hierarchy-create-a-simple-technology-hierarchy-for-web-devel-20250711T200047.json create mode 100644 package.json create mode 100644 src/main.rs create mode 100644 tsconfig.json diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..d20ca90 --- /dev/null +++ b/.gitignore @@ -0,0 +1,11 @@ +/target +.idea +Cargo.lock +*.iml +node_modules +bun.lockb +.junie +project +.env + + diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..e15bd3e --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,6 @@ +[package] +name = "sumpin" +version = "0.1.0" +edition = "2024" + +[dependencies] diff --git a/bun.lock b/bun.lock new file mode 100644 index 0000000..122424c --- /dev/null +++ b/bun.lock @@ -0,0 +1,240 @@ +{ + "lockfileVersion": 1, + "workspaces": { + "": { + "name": "sumpin", + "dependencies": { + "@openai/agents": "^0.0.11", + "mobx": "^6.13.7", + "mobx-state-tree": "^7.0.2", + "openai": "^5.9.0", + "uuid": "^11.1.0", + "zod": "<=3.25.67", + }, + "devDependencies": { + "@types/bun": "latest", + "@types/uuid": "^10.0.0", + }, + "peerDependencies": { + "typescript": "^5.0.0", + }, + }, + }, + "packages": { + "@modelcontextprotocol/sdk": ["@modelcontextprotocol/sdk@1.15.1", "", { "dependencies": { "ajv": "^6.12.6", "content-type": "^1.0.5", "cors": "^2.8.5", "cross-spawn": "^7.0.5", "eventsource": "^3.0.2", "eventsource-parser": "^3.0.0", "express": "^5.0.1", "express-rate-limit": "^7.5.0", "pkce-challenge": "^5.0.0", "raw-body": "^3.0.0", "zod": "^3.23.8", "zod-to-json-schema": "^3.24.1" } }, "sha512-W/XlN9c528yYn+9MQkVjxiTPgPxoxt+oczfjHBDsJx0+59+O7B75Zhsp0B16Xbwbz8ANISDajh6+V7nIcPMc5w=="], + + "@openai/agents": ["@openai/agents@0.0.11", "", { "dependencies": { "@openai/agents-core": "0.0.11", "@openai/agents-openai": "0.0.11", "@openai/agents-realtime": "0.0.11", "debug": "^4.4.0", "openai": "^5.0.1" } }, "sha512-MYSuQ0PptjryTb/BzrqoZB+cajv/p31uF42uXeqkI3s9PihqRttnQBJ1YCTJS/xQCl4f5R9cIradh/o5PpbDkA=="], + + "@openai/agents-core": ["@openai/agents-core@0.0.11", "", { "dependencies": { "@openai/zod": "npm:zod@3.25.40 - 3.25.67", "debug": "^4.4.0", "openai": "^5.0.1" }, "optionalDependencies": { "@modelcontextprotocol/sdk": "^1.12.0" }, "peerDependencies": { "zod": "3.25.40 - 3.25.67" }, "optionalPeers": ["zod"] }, "sha512-kMG/B620fsFAwUe/ounmXty4FuAmWbMWgql4z/gCoER3S6h5tBqNTxffN0MAOFHV3EuPLiqTxA0kGiSdTpDwyA=="], + + "@openai/agents-openai": ["@openai/agents-openai@0.0.11", "", { "dependencies": { "@openai/agents-core": "0.0.11", "@openai/zod": "npm:zod@3.25.40 - 3.25.67", "debug": "^4.4.0", "openai": "^5.0.1" } }, "sha512-gqVVDfyD0UYYBkc4kPJgbWzFzayKCKQBHMKHnbMsReZ8/nqHKGEd/hjBiqAZGqDW0BTKNaGfzGB8XAiLWWipnw=="], + + "@openai/agents-realtime": ["@openai/agents-realtime@0.0.11", "", { "dependencies": { "@openai/agents-core": "0.0.11", "@openai/zod": "npm:zod@3.25.40 - 3.25.67", "@types/ws": "^8.18.1", "debug": "^4.4.0", "ws": "^8.18.1" } }, "sha512-gVdrKri0dPBOJfsQR6m9rdpBscRZK/efc1zLKqOA2mfmaL0RxI2/LvnyXbwrDGHQ6GEbovULkbWWQ9D4nUafow=="], + + "@openai/zod": ["zod@3.25.67", "", {}, "sha512-idA2YXwpCdqUSKRCACDE6ItZD9TZzy3OZMtpfLoh6oPR47lipysRrJfjzMqFxQ3uJuUPyUeWe1r9vLH33xO/Qw=="], + + "@types/bun": ["@types/bun@1.2.18", "", { "dependencies": { "bun-types": "1.2.18" } }, "sha512-Xf6RaWVheyemaThV0kUfaAUvCNokFr+bH8Jxp+tTZfx7dAPA8z9ePnP9S9+Vspzuxxx9JRAXhnyccRj3GyCMdQ=="], + + "@types/node": ["@types/node@24.0.13", "", { "dependencies": { "undici-types": "~7.8.0" } }, "sha512-Qm9OYVOFHFYg3wJoTSrz80hoec5Lia/dPp84do3X7dZvLikQvM1YpmvTBEdIr/e+U8HTkFjLHLnl78K/qjf+jQ=="], + + "@types/react": ["@types/react@19.1.8", "", { "dependencies": { "csstype": "^3.0.2" } }, "sha512-AwAfQ2Wa5bCx9WP8nZL2uMZWod7J7/JSplxbTmBQ5ms6QpqNYm672H0Vu9ZVKVngQ+ii4R/byguVEUZQyeg44g=="], + + "@types/uuid": ["@types/uuid@10.0.0", "", {}, "sha512-7gqG38EyHgyP1S+7+xomFtL+ZNHcKv6DwNaCZmJmo1vgMugyF3TCnXVg4t1uk89mLNwnLtnY3TpOpCOyp1/xHQ=="], + + "@types/ws": ["@types/ws@8.18.1", "", { "dependencies": { "@types/node": "*" } }, "sha512-ThVF6DCVhA8kUGy+aazFQ4kXQ7E1Ty7A3ypFOe0IcJV8O/M511G99AW24irKrW56Wt44yG9+ij8FaqoBGkuBXg=="], + + "accepts": ["accepts@2.0.0", "", { "dependencies": { "mime-types": "^3.0.0", "negotiator": "^1.0.0" } }, "sha512-5cvg6CtKwfgdmVqY1WIiXKc3Q1bkRqGLi+2W/6ao+6Y7gu/RCwRuAhGEzh5B4KlszSuTLgZYuqFqo5bImjNKng=="], + + "ajv": ["ajv@6.12.6", "", { "dependencies": { "fast-deep-equal": "^3.1.1", "fast-json-stable-stringify": "^2.0.0", "json-schema-traverse": "^0.4.1", "uri-js": "^4.2.2" } }, "sha512-j3fVLgvTo527anyYyJOGTYJbG+vnnQYvE0m5mmkc1TK+nxAppkCLMIL0aZ4dblVCNoGShhm+kzE4ZUykBoMg4g=="], + + "body-parser": ["body-parser@2.2.0", "", { "dependencies": { "bytes": "^3.1.2", "content-type": "^1.0.5", "debug": "^4.4.0", "http-errors": "^2.0.0", "iconv-lite": "^0.6.3", "on-finished": "^2.4.1", "qs": "^6.14.0", "raw-body": "^3.0.0", "type-is": "^2.0.0" } }, "sha512-02qvAaxv8tp7fBa/mw1ga98OGm+eCbqzJOKoRt70sLmfEEi+jyBYVTDGfCL/k06/4EMk/z01gCe7HoCH/f2LTg=="], + + "bun-types": ["bun-types@1.2.18", "", { "dependencies": { "@types/node": "*" }, "peerDependencies": { "@types/react": "^19" } }, "sha512-04+Eha5NP7Z0A9YgDAzMk5PHR16ZuLVa83b26kH5+cp1qZW4F6FmAURngE7INf4tKOvCE69vYvDEwoNl1tGiWw=="], + + "bytes": ["bytes@3.1.2", "", {}, "sha512-/Nf7TyzTx6S3yRJObOAV7956r8cr2+Oj8AC5dt8wSP3BQAoeX58NoHyCU8P8zGkNXStjTSi6fzO6F0pBdcYbEg=="], + + "call-bind-apply-helpers": ["call-bind-apply-helpers@1.0.2", "", { "dependencies": { "es-errors": "^1.3.0", "function-bind": "^1.1.2" } }, "sha512-Sp1ablJ0ivDkSzjcaJdxEunN5/XvksFJ2sMBFfq6x0ryhQV/2b/KwFe21cMpmHtPOSij8K99/wSfoEuTObmuMQ=="], + + "call-bound": ["call-bound@1.0.4", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "get-intrinsic": "^1.3.0" } }, "sha512-+ys997U96po4Kx/ABpBCqhA9EuxJaQWDQg7295H4hBphv3IZg0boBKuwYpt4YXp6MZ5AmZQnU/tyMTlRpaSejg=="], + + "content-disposition": ["content-disposition@1.0.0", "", { "dependencies": { "safe-buffer": "5.2.1" } }, "sha512-Au9nRL8VNUut/XSzbQA38+M78dzP4D+eqg3gfJHMIHHYa3bg067xj1KxMUWj+VULbiZMowKngFFbKczUrNJ1mg=="], + + "content-type": ["content-type@1.0.5", "", {}, "sha512-nTjqfcBFEipKdXCv4YDQWCfmcLZKm81ldF0pAopTvyrFGVbcR6P/VAAd5G7N+0tTr8QqiU0tFadD6FK4NtJwOA=="], + + "cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], + + "cookie-signature": ["cookie-signature@1.2.2", "", {}, "sha512-D76uU73ulSXrD1UXF4KE2TMxVVwhsnCgfAyTg9k8P6KGZjlXKrOLe4dJQKI3Bxi5wjesZoFXJWElNWBjPZMbhg=="], + + "cors": ["cors@2.8.5", "", { "dependencies": { "object-assign": "^4", "vary": "^1" } }, "sha512-KIHbLJqu73RGr/hnbrO9uBeixNGuvSQjul/jdFvS/KFSIH1hWVd1ng7zOHx+YrEfInLG7q4n6GHQ9cDtxv/P6g=="], + + "cross-spawn": ["cross-spawn@7.0.6", "", { "dependencies": { "path-key": "^3.1.0", "shebang-command": "^2.0.0", "which": "^2.0.1" } }, "sha512-uV2QOWP2nWzsy2aMp8aRibhi9dlzF5Hgh5SHaB9OiTGEyDTiJJyx0uy51QXdyWbtAHNua4XJzUKca3OzKUd3vA=="], + + "csstype": ["csstype@3.1.3", "", {}, "sha512-M1uQkMl8rQK/szD0LNhtqxIPLpimGm8sOBwU7lLnCpSbTyY3yeU1Vc7l4KT5zT4s/yOxHH5O7tIuuLOCnLADRw=="], + + "debug": ["debug@4.4.1", "", { "dependencies": { "ms": "^2.1.3" } }, "sha512-KcKCqiftBJcZr++7ykoDIEwSa3XWowTfNPo92BYxjXiyYEVrUQh2aLyhxBCwww+heortUFxEJYcRzosstTEBYQ=="], + + "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], + + "dunder-proto": ["dunder-proto@1.0.1", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.1", "es-errors": "^1.3.0", "gopd": "^1.2.0" } }, "sha512-KIN/nDJBQRcXw0MLVhZE9iQHmG68qAVIBg9CqmUYjmQIhgij9U5MFvrqkUL5FbtyyzZuOeOt0zdeRe4UY7ct+A=="], + + "ee-first": ["ee-first@1.1.1", "", {}, "sha512-WMwm9LhRUo+WUaRN+vRuETqG89IgZphVSNkdFgeb6sS/E4OrDIN7t48CAewSHXc6C8lefD8KKfr5vY61brQlow=="], + + "encodeurl": ["encodeurl@2.0.0", "", {}, "sha512-Q0n9HRi4m6JuGIV1eFlmvJB7ZEVxu93IrMyiMsGC0lrMJMWzRgx6WGquyfQgZVb31vhGgXnfmPNNXmxnOkRBrg=="], + + "es-define-property": ["es-define-property@1.0.1", "", {}, "sha512-e3nRfgfUZ4rNGL232gUgX06QNyyez04KdjFrF+LTRoOXmrOgFKDg4BCdsjW8EnT69eqdYGmRpJwiPVYNrCaW3g=="], + + "es-errors": ["es-errors@1.3.0", "", {}, "sha512-Zf5H2Kxt2xjTvbJvP2ZWLEICxA6j+hAmMzIlypy4xcBg1vKVnx89Wy0GbS+kf5cwCVFFzdCFh2XSCFNULS6csw=="], + + "es-object-atoms": ["es-object-atoms@1.1.1", "", { "dependencies": { "es-errors": "^1.3.0" } }, "sha512-FGgH2h8zKNim9ljj7dankFPcICIK9Cp5bm+c2gQSYePhpaG5+esrLODihIorn+Pe6FGJzWhXQotPv73jTaldXA=="], + + "escape-html": ["escape-html@1.0.3", "", {}, "sha512-NiSupZ4OeuGwr68lGIeym/ksIZMJodUGOSCZ/FSnTxcrekbvqrgdUxlJOMpijaKZVjAJrWrGs/6Jy8OMuyj9ow=="], + + "etag": ["etag@1.8.1", "", {}, "sha512-aIL5Fx7mawVa300al2BnEE4iNvo1qETxLrPI/o05L7z6go7fCw1J6EQmbK4FmJ2AS7kgVF/KEZWufBfdClMcPg=="], + + "eventsource": ["eventsource@3.0.7", "", { "dependencies": { "eventsource-parser": "^3.0.1" } }, "sha512-CRT1WTyuQoD771GW56XEZFQ/ZoSfWid1alKGDYMmkt2yl8UXrVR4pspqWNEcqKvVIzg6PAltWjxcSSPrboA4iA=="], + + "eventsource-parser": ["eventsource-parser@3.0.3", "", {}, "sha512-nVpZkTMM9rF6AQ9gPJpFsNAMt48wIzB5TQgiTLdHiuO8XEDhUgZEhqKlZWXbIzo9VmJ/HvysHqEaVeD5v9TPvA=="], + + "express": ["express@5.1.0", "", { "dependencies": { "accepts": "^2.0.0", "body-parser": "^2.2.0", "content-disposition": "^1.0.0", "content-type": "^1.0.5", "cookie": "^0.7.1", "cookie-signature": "^1.2.1", "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "finalhandler": "^2.1.0", "fresh": "^2.0.0", "http-errors": "^2.0.0", "merge-descriptors": "^2.0.0", "mime-types": "^3.0.0", "on-finished": "^2.4.1", "once": "^1.4.0", "parseurl": "^1.3.3", "proxy-addr": "^2.0.7", "qs": "^6.14.0", "range-parser": "^1.2.1", "router": "^2.2.0", "send": "^1.1.0", "serve-static": "^2.2.0", "statuses": "^2.0.1", "type-is": "^2.0.1", "vary": "^1.1.2" } }, "sha512-DT9ck5YIRU+8GYzzU5kT3eHGA5iL+1Zd0EutOmTE9Dtk+Tvuzd23VBU+ec7HPNSTxXYO55gPV/hq4pSBJDjFpA=="], + + "express-rate-limit": ["express-rate-limit@7.5.1", "", { "peerDependencies": { "express": ">= 4.11" } }, "sha512-7iN8iPMDzOMHPUYllBEsQdWVB6fPDMPqwjBaFrgr4Jgr/+okjvzAy+UHlYYL/Vs0OsOrMkwS6PJDkFlJwoxUnw=="], + + "fast-deep-equal": ["fast-deep-equal@3.1.3", "", {}, "sha512-f3qQ9oQy9j2AhBe/H9VC91wLmKBCCU/gDOnKNAYG5hswO7BLKj09Hc5HYNz9cGI++xlpDCIgDaitVs03ATR84Q=="], + + "fast-json-stable-stringify": ["fast-json-stable-stringify@2.1.0", "", {}, "sha512-lhd/wF+Lk98HZoTCtlVraHtfh5XYijIjalXck7saUtuanSDyLMxnHhSXEDJqHxD7msR8D0uCmqlkwjCV8xvwHw=="], + + "finalhandler": ["finalhandler@2.1.0", "", { "dependencies": { "debug": "^4.4.0", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "on-finished": "^2.4.1", "parseurl": "^1.3.3", "statuses": "^2.0.1" } }, "sha512-/t88Ty3d5JWQbWYgaOGCCYfXRwV1+be02WqYYlL6h0lEiUAMPM8o8qKGO01YIkOHzka2up08wvgYD0mDiI+q3Q=="], + + "forwarded": ["forwarded@0.2.0", "", {}, "sha512-buRG0fpBtRHSTCOASe6hD258tEubFoRLb4ZNA6NxMVHNw2gOcwHo9wyablzMzOA5z9xA9L1KNjk/Nt6MT9aYow=="], + + "fresh": ["fresh@2.0.0", "", {}, "sha512-Rx/WycZ60HOaqLKAi6cHRKKI7zxWbJ31MhntmtwMoaTeF7XFH9hhBp8vITaMidfljRQ6eYWCKkaTK+ykVJHP2A=="], + + "function-bind": ["function-bind@1.1.2", "", {}, "sha512-7XHNxH7qX9xG5mIwxkhumTox/MIRNcOgDrxWsMt2pAr23WHp6MrRlN7FBSFpCpr+oVO0F744iUgR82nJMfG2SA=="], + + "get-intrinsic": ["get-intrinsic@1.3.0", "", { "dependencies": { "call-bind-apply-helpers": "^1.0.2", "es-define-property": "^1.0.1", "es-errors": "^1.3.0", "es-object-atoms": "^1.1.1", "function-bind": "^1.1.2", "get-proto": "^1.0.1", "gopd": "^1.2.0", "has-symbols": "^1.1.0", "hasown": "^2.0.2", "math-intrinsics": "^1.1.0" } }, "sha512-9fSjSaos/fRIVIp+xSJlE6lfwhES7LNtKaCBIamHsjr2na1BiABJPo0mOjjz8GJDURarmCPGqaiVg5mfjb98CQ=="], + + "get-proto": ["get-proto@1.0.1", "", { "dependencies": { "dunder-proto": "^1.0.1", "es-object-atoms": "^1.0.0" } }, "sha512-sTSfBjoXBp89JvIKIefqw7U2CCebsc74kiY6awiGogKtoSGbgjYE/G/+l9sF3MWFPNc9IcoOC4ODfKHfxFmp0g=="], + + "gopd": ["gopd@1.2.0", "", {}, "sha512-ZUKRh6/kUFoAiTAtTYPZJ3hw9wNxx+BIBOijnlG9PnrJsCcSjs1wyyD6vJpaYtgnzDrKYRSqf3OO6Rfa93xsRg=="], + + "has-symbols": ["has-symbols@1.1.0", "", {}, "sha512-1cDNdwJ2Jaohmb3sg4OmKaMBwuC48sYni5HUw2DvsC8LjGTLK9h+eb1X6RyuOHe4hT0ULCW68iomhjUoKUqlPQ=="], + + "hasown": ["hasown@2.0.2", "", { "dependencies": { "function-bind": "^1.1.2" } }, "sha512-0hJU9SCPvmMzIBdZFqNPXWa6dqh7WdH0cII9y+CyS8rG3nL48Bclra9HmKhVVUHyPWNH5Y7xDwAB7bfgSjkUMQ=="], + + "http-errors": ["http-errors@2.0.0", "", { "dependencies": { "depd": "2.0.0", "inherits": "2.0.4", "setprototypeof": "1.2.0", "statuses": "2.0.1", "toidentifier": "1.0.1" } }, "sha512-FtwrG/euBzaEjYeRqOgly7G0qviiXoJWnvEH2Z1plBdXgbyjv34pHTSb9zoeHMyDy33+DWy5Wt9Wo+TURtOYSQ=="], + + "iconv-lite": ["iconv-lite@0.6.3", "", { "dependencies": { "safer-buffer": ">= 2.1.2 < 3.0.0" } }, "sha512-4fCk79wshMdzMp2rH06qWrJE4iolqLhCUH+OiuIgU++RB0+94NlDL81atO7GX55uUKueo0txHNtvEyI6D7WdMw=="], + + "inherits": ["inherits@2.0.4", "", {}, "sha512-k/vGaX4/Yla3WzyMCvTQOXYeIHvqOKtnqBduzTHpzpQZzAskKMhZ2K+EnBiSM9zGSoIFeMpXKxa4dYeZIQqewQ=="], + + "ipaddr.js": ["ipaddr.js@1.9.1", "", {}, "sha512-0KI/607xoxSToH7GjN1FfSbLoU0+btTicjsQSWQlh/hZykN8KpmMf7uYwPW3R+akZ6R/w18ZlXSHBYXiYUPO3g=="], + + "is-promise": ["is-promise@4.0.0", "", {}, "sha512-hvpoI6korhJMnej285dSg6nu1+e6uxs7zG3BYAm5byqDsgJNWwxzM6z6iZiAgQR4TJ30JmBTOwqZUw3WlyH3AQ=="], + + "isexe": ["isexe@2.0.0", "", {}, "sha512-RHxMLp9lnKHGHRng9QFhRCMbYAcVpn69smSGcq3f36xjgVVWThj4qqLbTLlq7Ssj8B+fIQ1EuCEGI2lKsyQeIw=="], + + "json-schema-traverse": ["json-schema-traverse@0.4.1", "", {}, "sha512-xbbCH5dCYU5T8LcEhhuh7HJ88HXuW3qsI3Y0zOZFKfZEHcpWiHU/Jxzk629Brsab/mMiHQti9wMP+845RPe3Vg=="], + + "math-intrinsics": ["math-intrinsics@1.1.0", "", {}, "sha512-/IXtbwEk5HTPyEwyKX6hGkYXxM9nbj64B+ilVJnC/R6B0pH5G4V3b0pVbL7DBj4tkhBAppbQUlf6F6Xl9LHu1g=="], + + "media-typer": ["media-typer@1.1.0", "", {}, "sha512-aisnrDP4GNe06UcKFnV5bfMNPBUw4jsLGaWwWfnH3v02GnBuXX2MCVn5RbrWo0j3pczUilYblq7fQ7Nw2t5XKw=="], + + "merge-descriptors": ["merge-descriptors@2.0.0", "", {}, "sha512-Snk314V5ayFLhp3fkUREub6WtjBfPdCPY1Ln8/8munuLuiYhsABgBVWsozAG+MWMbVEvcdcpbi9R7ww22l9Q3g=="], + + "mime-db": ["mime-db@1.54.0", "", {}, "sha512-aU5EJuIN2WDemCcAp2vFBfp/m4EAhWJnUNSSw0ixs7/kXbd6Pg64EmwJkNdFhB8aWt1sH2CTXrLxo/iAGV3oPQ=="], + + "mime-types": ["mime-types@3.0.1", "", { "dependencies": { "mime-db": "^1.54.0" } }, "sha512-xRc4oEhT6eaBpU1XF7AjpOFD+xQmXNB5OVKwp4tqCuBpHLS/ZbBDrc07mYTDqVMg6PfxUjjNp85O6Cd2Z/5HWA=="], + + "mobx": ["mobx@6.13.7", "", {}, "sha512-aChaVU/DO5aRPmk1GX8L+whocagUUpBQqoPtJk+cm7UOXUk87J4PeWCh6nNmTTIfEhiR9DI/+FnA8dln/hTK7g=="], + + "mobx-state-tree": ["mobx-state-tree@7.0.2", "", { "dependencies": { "ts-essentials": "^9.4.1" }, "peerDependencies": { "mobx": "^6.3.0" } }, "sha512-Qmqgo2Ho1/JRTquo0EWw0ZA/k4wTUNPMIBg98ALGN1V/0Gupic7dg4GDYUhNbiLsYHpp48VgpaCDpDIKV+jNkQ=="], + + "ms": ["ms@2.1.3", "", {}, "sha512-6FlzubTLZG3J2a/NVCAleEhjzq5oxgHyaCU9yYXvcLsvoVaHJq/s5xXI6/XXP6tz7R9xAOtHnSO/tXtF3WRTlA=="], + + "negotiator": ["negotiator@1.0.0", "", {}, "sha512-8Ofs/AUQh8MaEcrlq5xOX0CQ9ypTF5dl78mjlMNfOK08fzpgTHQRQPBxcPlEtIw0yRpws+Zo/3r+5WRby7u3Gg=="], + + "object-assign": ["object-assign@4.1.1", "", {}, "sha512-rJgTQnkUnH1sFw8yT6VSU3zD3sWmu6sZhIseY8VX+GRu3P6F7Fu+JNDoXfklElbLJSnc3FUQHVe4cU5hj+BcUg=="], + + "object-inspect": ["object-inspect@1.13.4", "", {}, "sha512-W67iLl4J2EXEGTbfeHCffrjDfitvLANg0UlX3wFUUSTx92KXRFegMHUVgSqE+wvhAbi4WqjGg9czysTV2Epbew=="], + + "on-finished": ["on-finished@2.4.1", "", { "dependencies": { "ee-first": "1.1.1" } }, "sha512-oVlzkg3ENAhCk2zdv7IJwd/QUD4z2RxRwpkcGY8psCVcCYZNq4wYnVWALHM+brtuJjePWiYF/ClmuDr8Ch5+kg=="], + + "once": ["once@1.4.0", "", { "dependencies": { "wrappy": "1" } }, "sha512-lNaJgI+2Q5URQBkccEKHTQOPaXdUxnZZElQTZY0MFUAuaEqe1E+Nyvgdz/aIyNi6Z9MzO5dv1H8n58/GELp3+w=="], + + "openai": ["openai@5.9.0", "", { "peerDependencies": { "ws": "^8.18.0", "zod": "^3.23.8" }, "optionalPeers": ["ws", "zod"], "bin": { "openai": "bin/cli" } }, "sha512-cmLC0pfqLLhBGxE4aZPyRPjydgYCncppV2ClQkKmW79hNjCvmzkfhz8rN5/YVDmjVQlFV+UsF1JIuNjNgeagyQ=="], + + "parseurl": ["parseurl@1.3.3", "", {}, "sha512-CiyeOxFT/JZyN5m0z9PfXw4SCBJ6Sygz1Dpl0wqjlhDEGGBP1GnsUVEL0p63hoG1fcj3fHynXi9NYO4nWOL+qQ=="], + + "path-key": ["path-key@3.1.1", "", {}, "sha512-ojmeN0qd+y0jszEtoY48r0Peq5dwMEkIlCOu6Q5f41lfkswXuKtYrhgoTpLnyIcHm24Uhqx+5Tqm2InSwLhE6Q=="], + + "path-to-regexp": ["path-to-regexp@8.2.0", "", {}, "sha512-TdrF7fW9Rphjq4RjrW0Kp2AW0Ahwu9sRGTkS6bvDi0SCwZlEZYmcfDbEsTz8RVk0EHIS/Vd1bv3JhG+1xZuAyQ=="], + + "pkce-challenge": ["pkce-challenge@5.0.0", "", {}, "sha512-ueGLflrrnvwB3xuo/uGob5pd5FN7l0MsLf0Z87o/UQmRtwjvfylfc9MurIxRAWywCYTgrvpXBcqjV4OfCYGCIQ=="], + + "proxy-addr": ["proxy-addr@2.0.7", "", { "dependencies": { "forwarded": "0.2.0", "ipaddr.js": "1.9.1" } }, "sha512-llQsMLSUDUPT44jdrU/O37qlnifitDP+ZwrmmZcoSKyLKvtZxpyV0n2/bD/N4tBAAZ/gJEdZU7KMraoK1+XYAg=="], + + "punycode": ["punycode@2.3.1", "", {}, "sha512-vYt7UD1U9Wg6138shLtLOvdAu+8DsC/ilFtEVHcH+wydcSpNE20AfSOduf6MkRFahL5FY7X1oU7nKVZFtfq8Fg=="], + + "qs": ["qs@6.14.0", "", { "dependencies": { "side-channel": "^1.1.0" } }, "sha512-YWWTjgABSKcvs/nWBi9PycY/JiPJqOD4JA6o9Sej2AtvSGarXxKC3OQSk4pAarbdQlKAh5D4FCQkJNkW+GAn3w=="], + + "range-parser": ["range-parser@1.2.1", "", {}, "sha512-Hrgsx+orqoygnmhFbKaHE6c296J+HTAQXoxEF6gNupROmmGJRoyzfG3ccAveqCBrwr/2yxQ5BVd/GTl5agOwSg=="], + + "raw-body": ["raw-body@3.0.0", "", { "dependencies": { "bytes": "3.1.2", "http-errors": "2.0.0", "iconv-lite": "0.6.3", "unpipe": "1.0.0" } }, "sha512-RmkhL8CAyCRPXCE28MMH0z2PNWQBNk2Q09ZdxM9IOOXwxwZbN+qbWaatPkdkWIKL2ZVDImrN/pK5HTRz2PcS4g=="], + + "router": ["router@2.2.0", "", { "dependencies": { "debug": "^4.4.0", "depd": "^2.0.0", "is-promise": "^4.0.0", "parseurl": "^1.3.3", "path-to-regexp": "^8.0.0" } }, "sha512-nLTrUKm2UyiL7rlhapu/Zl45FwNgkZGaCpZbIHajDYgwlJCOzLSk+cIPAnsEqV955GjILJnKbdQC1nVPz+gAYQ=="], + + "safe-buffer": ["safe-buffer@5.2.1", "", {}, "sha512-rp3So07KcdmmKbGvgaNxQSJr7bGVSVk5S9Eq1F+ppbRo70+YeaDxkw5Dd8NPN+GD6bjnYm2VuPuCXmpuYvmCXQ=="], + + "safer-buffer": ["safer-buffer@2.1.2", "", {}, "sha512-YZo3K82SD7Riyi0E1EQPojLz7kpepnSQI9IyPbHHg1XXXevb5dJI7tpyN2ADxGcQbHG7vcyRHk0cbwqcQriUtg=="], + + "send": ["send@1.2.0", "", { "dependencies": { "debug": "^4.3.5", "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "etag": "^1.8.1", "fresh": "^2.0.0", "http-errors": "^2.0.0", "mime-types": "^3.0.1", "ms": "^2.1.3", "on-finished": "^2.4.1", "range-parser": "^1.2.1", "statuses": "^2.0.1" } }, "sha512-uaW0WwXKpL9blXE2o0bRhoL2EGXIrZxQ2ZQ4mgcfoBxdFmQold+qWsD2jLrfZ0trjKL6vOw0j//eAwcALFjKSw=="], + + "serve-static": ["serve-static@2.2.0", "", { "dependencies": { "encodeurl": "^2.0.0", "escape-html": "^1.0.3", "parseurl": "^1.3.3", "send": "^1.2.0" } }, "sha512-61g9pCh0Vnh7IutZjtLGGpTA355+OPn2TyDv/6ivP2h/AdAVX9azsoxmg2/M6nZeQZNYBEwIcsne1mJd9oQItQ=="], + + "setprototypeof": ["setprototypeof@1.2.0", "", {}, "sha512-E5LDX7Wrp85Kil5bhZv46j8jOeboKq5JMmYM3gVGdGH8xFpPWXUMsNrlODCrkoxMEeNi/XZIwuRvY4XNwYMJpw=="], + + "shebang-command": ["shebang-command@2.0.0", "", { "dependencies": { "shebang-regex": "^3.0.0" } }, "sha512-kHxr2zZpYtdmrN1qDjrrX/Z1rR1kG8Dx+gkpK1G4eXmvXswmcE1hTWBWYUzlraYw1/yZp6YuDY77YtvbN0dmDA=="], + + "shebang-regex": ["shebang-regex@3.0.0", "", {}, "sha512-7++dFhtcx3353uBaq8DDR4NuxBetBzC7ZQOhmTQInHEd6bSrXdiEyzCvG07Z44UYdLShWUyXt5M/yhz8ekcb1A=="], + + "side-channel": ["side-channel@1.1.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3", "side-channel-list": "^1.0.0", "side-channel-map": "^1.0.1", "side-channel-weakmap": "^1.0.2" } }, "sha512-ZX99e6tRweoUXqR+VBrslhda51Nh5MTQwou5tnUDgbtyM0dBgmhEDtWGP/xbKn6hqfPRHujUNwz5fy/wbbhnpw=="], + + "side-channel-list": ["side-channel-list@1.0.0", "", { "dependencies": { "es-errors": "^1.3.0", "object-inspect": "^1.13.3" } }, "sha512-FCLHtRD/gnpCiCHEiJLOwdmFP+wzCmDEkc9y7NsYxeF4u7Btsn1ZuwgwJGxImImHicJArLP4R0yX4c2KCrMrTA=="], + + "side-channel-map": ["side-channel-map@1.0.1", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3" } }, "sha512-VCjCNfgMsby3tTdo02nbjtM/ewra6jPHmpThenkTYh8pG9ucZ/1P8So4u4FGBek/BjpOVsDCMoLA/iuBKIFXRA=="], + + "side-channel-weakmap": ["side-channel-weakmap@1.0.2", "", { "dependencies": { "call-bound": "^1.0.2", "es-errors": "^1.3.0", "get-intrinsic": "^1.2.5", "object-inspect": "^1.13.3", "side-channel-map": "^1.0.1" } }, "sha512-WPS/HvHQTYnHisLo9McqBHOJk2FkHO/tlpvldyrnem4aeQp4hai3gythswg6p01oSoTl58rcpiFAjF2br2Ak2A=="], + + "statuses": ["statuses@2.0.2", "", {}, "sha512-DvEy55V3DB7uknRo+4iOGT5fP1slR8wQohVdknigZPMpMstaKJQWhwiYBACJE3Ul2pTnATihhBYnRhZQHGBiRw=="], + + "toidentifier": ["toidentifier@1.0.1", "", {}, "sha512-o5sSPKEkg/DIQNmH43V0/uerLrpzVedkUh8tGNvaeXpfpuwjKenlSox/2O/BTlZUtEe+JG7s5YhEz608PlAHRA=="], + + "ts-essentials": ["ts-essentials@9.4.2", "", { "peerDependencies": { "typescript": ">=4.1.0" }, "optionalPeers": ["typescript"] }, "sha512-mB/cDhOvD7pg3YCLk2rOtejHjjdSi9in/IBYE13S+8WA5FBSraYf4V/ws55uvs0IvQ/l0wBOlXy5yBNZ9Bl8ZQ=="], + + "type-is": ["type-is@2.0.1", "", { "dependencies": { "content-type": "^1.0.5", "media-typer": "^1.1.0", "mime-types": "^3.0.0" } }, "sha512-OZs6gsjF4vMp32qrCbiVSkrFmXtG/AZhY3t0iAMrMBiAZyV9oALtXO8hsrHbMXF9x6L3grlFuwW2oAz7cav+Gw=="], + + "typescript": ["typescript@5.8.3", "", { "bin": { "tsc": "bin/tsc", "tsserver": "bin/tsserver" } }, "sha512-p1diW6TqL9L07nNxvRMM7hMMw4c5XOo/1ibL4aAIGmSAt9slTE1Xgw5KWuof2uTOvCg9BY7ZRi+GaF+7sfgPeQ=="], + + "undici-types": ["undici-types@7.8.0", "", {}, "sha512-9UJ2xGDvQ43tYyVMpuHlsgApydB8ZKfVYTsLDhXkFL/6gfkp+U8xTGdh8pMJv1SpZna0zxG1DwsKZsreLbXBxw=="], + + "unpipe": ["unpipe@1.0.0", "", {}, "sha512-pjy2bYhSsufwWlKwPc+l3cN7+wuJlK6uz0YdJEOlQDbl6jo/YlPi4mb8agUkVC8BF7V8NuzeyPNqRksA3hztKQ=="], + + "uri-js": ["uri-js@4.4.1", "", { "dependencies": { "punycode": "^2.1.0" } }, "sha512-7rKUyy33Q1yc98pQ1DAmLtwX109F7TIfWlW1Ydo8Wl1ii1SeHieeh0HHfPeL2fMXK6z0s8ecKs9frCuLJvndBg=="], + + "uuid": ["uuid@11.1.0", "", { "bin": { "uuid": "dist/esm/bin/uuid" } }, "sha512-0/A9rDy9P7cJ+8w1c9WD9V//9Wj15Ce2MPz8Ri6032usz+NfePxx5AcN3bN+r6ZL6jEo066/yNYB3tn4pQEx+A=="], + + "vary": ["vary@1.1.2", "", {}, "sha512-BNGbWLfd0eUPabhkXUVm0j8uuvREyTh5ovRa/dyow/BqAbZJyC+5fU+IzQOzmAKzYqYRAISoRhdQr3eIZ/PXqg=="], + + "which": ["which@2.0.2", "", { "dependencies": { "isexe": "^2.0.0" }, "bin": { "node-which": "./bin/node-which" } }, "sha512-BLI3Tl1TW3Pvl70l3yq3Y64i+awpwXqsGBYWkkqMtnbXgrMD+yj7rhW0kuEDxzJaYXGjEW5ogapKNMEKNMjibA=="], + + "wrappy": ["wrappy@1.0.2", "", {}, "sha512-l4Sp/DRseor9wL6EvV2+TuQn63dMkPjZ/sp9XkghTEbV9KlPS1xUsZ3u7/IQO4wxtcFB4bgpQPRcR3QCvezPcQ=="], + + "ws": ["ws@8.18.3", "", { "peerDependencies": { "bufferutil": "^4.0.1", "utf-8-validate": ">=5.0.2" }, "optionalPeers": ["bufferutil", "utf-8-validate"] }, "sha512-PEIGCY5tSlUt50cqyMXfCzX+oOPqN0vuGqWzbcJ2xvnkzkq46oOpz7dQaTDBdfICb4N14+GARUDw2XV2N4tvzg=="], + + "zod": ["zod@3.25.67", "", {}, "sha512-idA2YXwpCdqUSKRCACDE6ItZD9TZzy3OZMtpfLoh6oPR47lipysRrJfjzMqFxQ3uJuUPyUeWe1r9vLH33xO/Qw=="], + + "zod-to-json-schema": ["zod-to-json-schema@3.24.6", "", { "peerDependencies": { "zod": "^3.24.1" } }, "sha512-h/z3PKvcTcTetyjl1fkj79MHNEjm+HpD6NXheWjzOekY7kV+lwDYnHw+ivHkijnCSMz1yJaWBD9vu/Fcmk+vEg=="], + + "http-errors/statuses": ["statuses@2.0.1", "", {}, "sha512-RwNA9Z/7PrK06rYLIzFMlaF+l73iwpzsqRIFgbMLbTcLD6cOao82TaWefPXQvB2fOC4AjuYSEndS7N/mTCbkdQ=="], + } +} diff --git a/cli.ts b/cli.ts new file mode 100644 index 0000000..6678256 --- /dev/null +++ b/cli.ts @@ -0,0 +1,332 @@ +#!/usr/bin/env bun + +/** + * Sumpin CLI - Professional Hierarchy Generator + * + * A command-line interface for generating professional hierarchies from natural language specifications. + * Leverages the existing hierarchy generation infrastructure to provide a clean, professional CLI experience. + */ + +import { parseArgs } from 'util'; +import { writeFileSync, mkdirSync, existsSync } from 'fs'; +import { join, resolve } from 'path'; +import { generateHierarchy } from './generate-template'; +import HierarchyAgent from './lib/agent-wrapper'; + +const CLI_VERSION = '1.0.0'; +const DEFAULT_OUTPUT_DIR = './output'; + +interface CLIOptions { + help?: boolean; + version?: boolean; + output?: string; + format?: 'json' | 'typescript' | 'both'; + complexity?: 'simple' | 'medium' | 'complex'; + hierarchyVersion?: 'v1' | 'v2'; + stream?: boolean; + quiet?: boolean; + skills?: boolean; + tools?: boolean; + examples?: boolean; +} + +const HELP_TEXT = ` +Sumpin CLI v${CLI_VERSION} - Professional Hierarchy Generator + +USAGE: + bun cli.ts [OPTIONS] "" + +DESCRIPTION: + Generate professional hierarchies from natural language descriptions. + Supports both simple JSON output and full TypeScript code generation. + +ARGUMENTS: + specification Natural language description of the hierarchy to generate + Example: "Create a healthcare hierarchy for mental health services" + +OPTIONS: + -h, --help Show this help message + -v, --version Show version information + -o, --output DIR Output directory (default: ./output) + -f, --format FORMAT Output format: json, typescript, both (default: json) + -c, --complexity LEVEL Complexity level: simple, medium, complex (default: medium) + --hierarchy-version VER Hierarchy version: v1, v2 (default: v2) + --stream Enable streaming output for real-time feedback + --quiet Suppress progress messages + --skills Include skills and competencies (default: true) + --tools Include tools and technologies (default: true) + --examples Include practical examples (default: true) + +EXAMPLES: + # Basic usage - generate JSON hierarchy + bun cli.ts "Create a technology hierarchy for AI development" + + # Generate TypeScript code with streaming + bun cli.ts --format typescript --stream "Healthcare hierarchy for emergency medicine" + + # Complex v1 hierarchy with custom output directory + bun cli.ts -o ./my-hierarchies -c complex --hierarchy-version v1 "Finance hierarchy for investment banking" + + # Generate both formats quietly + bun cli.ts --format both --quiet "Education hierarchy for online learning platforms" + +OUTPUT: + Generated files will be saved to the specified output directory with descriptive names. + JSON format: Creates .json files with the hierarchy data + TypeScript format: Creates .ts files with executable TypeScript code +`; + +// Parse command line arguments +function parseCliArgs(): { options: CLIOptions; specification: string } { + const { values, positionals } = parseArgs({ + args: process.argv.slice(2), + options: { + help: { type: 'boolean', short: 'h' }, + version: { type: 'boolean', short: 'v' }, + output: { type: 'string', short: 'o' }, + format: { type: 'string', short: 'f' }, + complexity: { type: 'string', short: 'c' }, + 'hierarchy-version': { type: 'string' }, + stream: { type: 'boolean' }, + quiet: { type: 'boolean' }, + skills: { type: 'boolean' }, + tools: { type: 'boolean' }, + examples: { type: 'boolean' }, + }, + allowPositionals: true, + }); + + const options: CLIOptions = { + help: values.help, + version: values.version, + output: values.output || DEFAULT_OUTPUT_DIR, + format: (values.format as any) || 'json', + complexity: (values.complexity as any) || 'medium', + hierarchyVersion: (values['hierarchy-version'] as any) || 'v2', + stream: values.stream || false, + quiet: values.quiet || false, + skills: values.skills !== false, + tools: values.tools !== false, + examples: values.examples !== false, + }; + + const specification = positionals.join(' '); + + return { options, specification }; +} + +// Validate CLI options +function validateOptions(options: CLIOptions, specification: string): void { + if (!['json', 'typescript', 'both'].includes(options.format!)) { + console.error('❌ Error: Invalid format. Must be one of: json, typescript, both'); + process.exit(1); + } + + if (!['simple', 'medium', 'complex'].includes(options.complexity!)) { + console.error('❌ Error: Invalid complexity. Must be one of: simple, medium, complex'); + process.exit(1); + } + + if (!['v1', 'v2'].includes(options.hierarchyVersion!)) { + console.error('❌ Error: Invalid hierarchy version. Must be one of: v1, v2'); + process.exit(1); + } + + if (!specification.trim()) { + console.error('❌ Error: Natural language specification is required'); + console.error('Use --help for usage information'); + process.exit(1); + } +} + +// Generate filename from specification +function generateFilename(specification: string, format: string): string { + const cleanSpec = specification + .toLowerCase() + .replace(/[^a-z0-9\s]/g, '') + .replace(/\s+/g, '-') + .substring(0, 50); + + const timestamp = new Date().toISOString().slice(0, 19).replace(/[:-]/g, ''); + return `hierarchy-${cleanSpec}-${timestamp}`; +} + +// Generate hierarchy using the simple JSON approach +async function generateJsonHierarchy(specification: string, options: CLIOptions): Promise { + if (!options.quiet) { + console.log('πŸ”„ Generating hierarchy using JSON approach...'); + } + + const hierarchy = await generateHierarchy(specification); + return hierarchy.toJSON(); +} + +// Generate hierarchy using the agent-based TypeScript approach +async function generateTypescriptHierarchy(specification: string, options: CLIOptions): Promise { + if (!options.quiet) { + console.log('πŸ”„ Generating hierarchy using TypeScript agent approach...'); + } + + const hierarchyAgent = new HierarchyAgent({ + name: 'CLI Hierarchy Generator', + instructions: `Generate professional hierarchy TypeScript code based on user specifications. + Focus on creating clean, implementable code that demonstrates real-world organizational structures.`, + }); + + const generationOptions = { + domain: extractDomain(specification), + version: options.hierarchyVersion!, + complexity: options.complexity!, + includeSkills: options.skills!, + includeTools: options.tools!, + includeExamples: options.examples!, + }; + + if (options.stream) { + return await hierarchyAgent.generateHierarchyWithStreaming( + generationOptions, + options.quiet ? undefined : (event) => { + if (event.type === 'raw_model_stream_event' && event.delta?.content) { + process.stdout.write('.'); + } + } + ).then(result => result.content); + } else { + const result = await hierarchyAgent.generateHierarchy(generationOptions); + return result.content; + } +} + +// Extract domain from specification (simple heuristic) +function extractDomain(specification: string): string { + const words = specification.toLowerCase().split(/\s+/); + + // Look for domain keywords + const domainKeywords = [ + 'healthcare', 'technology', 'finance', 'education', 'manufacturing', + 'retail', 'consulting', 'media', 'logistics', 'legal', 'construction', + 'hospitality', 'automotive', 'aerospace', 'energy', 'agriculture' + ]; + + for (const keyword of domainKeywords) { + if (words.some(word => word.includes(keyword))) { + return keyword; + } + } + + // Fallback: use first meaningful word + const meaningfulWords = words.filter(word => + word.length > 3 && + !['create', 'generate', 'build', 'make', 'hierarchy', 'for', 'the', 'and', 'with'].includes(word) + ); + + return meaningfulWords[0] || 'general'; +} + +// Save output to files +async function saveOutput( + content: any, + filename: string, + format: string, + outputDir: string, + quiet: boolean +): Promise { + // Ensure output directory exists + if (!existsSync(outputDir)) { + mkdirSync(outputDir, { recursive: true }); + } + + const outputPath = resolve(outputDir); + + if (format === 'json' || format === 'both') { + const jsonFile = join(outputPath, `${filename}.json`); + const jsonContent = typeof content === 'string' ? content : JSON.stringify(content, null, 2); + writeFileSync(jsonFile, jsonContent); + if (!quiet) { + console.log(`βœ… JSON hierarchy saved: ${jsonFile}`); + } + } + + if (format === 'typescript' || format === 'both') { + const tsFile = join(outputPath, `${filename}.ts`); + const tsContent = typeof content === 'string' ? content : `// Generated hierarchy\nexport const hierarchy = ${JSON.stringify(content, null, 2)};`; + writeFileSync(tsFile, tsContent); + if (!quiet) { + console.log(`βœ… TypeScript hierarchy saved: ${tsFile}`); + } + } +} + +// Main CLI function +async function main(): Promise { + try { + const { options, specification } = parseCliArgs(); + + // Handle help and version + if (options.help) { + console.log(HELP_TEXT); + process.exit(0); + } + + if (options.version) { + console.log(`Sumpin CLI v${CLI_VERSION}`); + process.exit(0); + } + + // Validate options + validateOptions(options, specification); + + if (!options.quiet) { + console.log(`πŸš€ Sumpin CLI v${CLI_VERSION} - Professional Hierarchy Generator`); + console.log(`πŸ“ Specification: "${specification}"`); + console.log(`βš™οΈ Configuration:`); + console.log(` Format: ${options.format}`); + console.log(` Complexity: ${options.complexity}`); + console.log(` Version: ${options.hierarchyVersion}`); + console.log(` Output: ${options.output}`); + console.log(); + } + + const filename = generateFilename(specification, options.format!); + let content: any; + + // Generate based on format preference + if (options.format === 'json') { + content = await generateJsonHierarchy(specification, options); + } else if (options.format === 'typescript') { + content = await generateTypescriptHierarchy(specification, options); + } else if (options.format === 'both') { + // Generate both formats + const jsonContent = await generateJsonHierarchy(specification, options); + const tsContent = await generateTypescriptHierarchy(specification, options); + + await saveOutput(jsonContent, filename, 'json', options.output!, options.quiet!); + await saveOutput(tsContent, filename, 'typescript', options.output!, options.quiet!); + + if (!options.quiet) { + console.log('\nπŸŽ‰ Hierarchy generation complete!'); + console.log(`πŸ“ Files saved to: ${resolve(options.output!)}`); + } + return; + } + + // Save single format output + await saveOutput(content, filename, options.format!, options.output!, options.quiet!); + + if (!options.quiet) { + console.log('\nπŸŽ‰ Hierarchy generation complete!'); + console.log(`πŸ“ Files saved to: ${resolve(options.output!)}`); + } + + } catch (error) { + console.error('❌ Error:', error instanceof Error ? error.message : String(error)); + process.exit(1); + } +} + +// Run CLI if this file is executed directly +if (import.meta.main) { + main(); +} + +export { main as runCLI }; \ No newline at end of file diff --git a/examples/README.md b/examples/README.md new file mode 100644 index 0000000..c1b92f0 --- /dev/null +++ b/examples/README.md @@ -0,0 +1,65 @@ +# Examples Directory + +This directory contains comprehensive examples demonstrating how to use both versions of the professional hierarchy models. + +## Structure + +- `v1/` - Examples for the simpler 4-layer hierarchy model (Domain β†’ Specialization β†’ Role β†’ Responsibility) +- `v2/` - Examples for the advanced 6-layer hierarchy model (Domain β†’ Industry β†’ Profession β†’ Field β†’ Role β†’ Task) + +## Prerequisites + +Make sure you have the required dependencies installed: + +```bash +bun install +``` + +For v1 and v2 examples, you'll also need: +```bash +bun add mobx-state-tree mobx uuid +bun add -d @types/uuid +``` + +## Running Examples + +Each example can be run independently using Bun: + +```bash +# Run v1 examples +bun run examples/v1/healthcare-example.ts +bun run examples/v1/technology-example.ts + +# Run v2 examples +bun run examples/v2/software-company-example.ts +bun run examples/v2/healthcare-system-example.ts +``` + +## Testing Examples + +You can also run the test files to see the examples in action: + +```bash +# Test v1 examples +bun test examples/v1/ + +# Test v2 examples +bun test examples/v2/ +``` + +## Example Scenarios + +### V1 Examples (4-layer hierarchy) +- **Healthcare Example**: Models medical professionals with specializations, roles, and responsibilities +- **Technology Example**: Models software engineering domain with various specializations + +### V2 Examples (6-layer hierarchy) +- **Software Company Example**: Complete modeling of a tech company's professional structure +- **Healthcare System Example**: Comprehensive healthcare organization modeling + +Each example demonstrates: +- Creating and structuring hierarchies +- Adding attributes/skills/tools +- CRUD operations +- Querying and traversing the hierarchy +- Real-world use cases and best practices \ No newline at end of file diff --git a/examples/v1/healthcare-example.ts b/examples/v1/healthcare-example.ts new file mode 100644 index 0000000..638c9fd --- /dev/null +++ b/examples/v1/healthcare-example.ts @@ -0,0 +1,349 @@ +import { ProfessionModel, Domain, Specialization, Role, Responsibility, Attribute } from "../../lib/v1"; + +console.log("=== Healthcare Professional Hierarchy Example (V1) ===\n"); + +const professionModel = ProfessionModel.create({ + domains: [] +}); + +// Create the Healthcare domain +const healthcareDomain = Domain.create({ + name: "Healthcare", + description: "Medical and health services domain", + specializations: [], + coreAttributes: [ + { + name: "Medical Ethics", + type: "Trait", + description: "Understanding of medical ethics and patient care principles" + }, + { + name: "Communication", + type: "Skill", + description: "Effective communication with patients and colleagues" + }, + { + name: "Electronic Health Records", + type: "Tool", + description: "Proficiency with EHR systems" + } + ] +}); + +// Add specializations to Healthcare domain +const cardiology = Specialization.create({ + name: "Cardiology", + focus: "Heart and cardiovascular system disorders", + coreAttributes: [ + { + name: "Cardiac Catheterization", + type: "Skill", + description: "Performing cardiac catheterization procedures" + }, + { + name: "ECG Interpretation", + type: "Skill", + description: "Reading and interpreting electrocardiograms" + }, + { + name: "Echocardiogram Machine", + type: "Tool", + description: "Operating echocardiogram equipment" + } + ], + roles: [] +}); + +const pediatrics = Specialization.create({ + name: "Pediatrics", + focus: "Medical care of infants, children, and adolescents", + coreAttributes: [ + { + name: "Child Psychology", + type: "Skill", + description: "Understanding child development and psychology" + }, + { + name: "Vaccination Protocols", + type: "Skill", + description: "Knowledge of pediatric vaccination schedules" + }, + { + name: "Pediatric Stethoscope", + type: "Tool", + description: "Specialized stethoscope for children" + } + ], + roles: [] +}); + +// Create roles for Cardiology +const cardiologist = Role.create({ + title: "Cardiologist", + seniority: "Senior", + responsibilities: [], + requiredAttributes: [ + { + name: "Board Certification", + type: "Trait", + description: "Board certified in cardiology" + }, + { + name: "Surgical Skills", + type: "Skill", + description: "Advanced surgical techniques for cardiac procedures" + } + ] +}); + +const cardiacNurse = Role.create({ + title: "Cardiac Nurse", + seniority: "Mid", + responsibilities: [], + requiredAttributes: [ + { + name: "Critical Care Experience", + type: "Trait", + description: "Experience in critical care environments" + }, + { + name: "Medication Administration", + type: "Skill", + description: "Safe administration of cardiac medications" + } + ] +}); + +// Create responsibilities for Cardiologist +const diagnosisResponsibility = Responsibility.create({ + title: "Cardiac Diagnosis", + outcome: "Accurate diagnosis of cardiovascular conditions", + requiredAttributes: [ + { + name: "Diagnostic Imaging", + type: "Skill", + description: "Interpreting cardiac imaging studies" + }, + { + name: "Clinical Assessment", + type: "Skill", + description: "Comprehensive cardiovascular examination" + } + ] +}); + +const treatmentPlanningResponsibility = Responsibility.create({ + title: "Treatment Planning", + outcome: "Comprehensive treatment plans for cardiac patients", + requiredAttributes: [ + { + name: "Evidence-Based Medicine", + type: "Skill", + description: "Applying current research to treatment decisions" + }, + { + name: "Risk Assessment", + type: "Skill", + description: "Evaluating patient risk factors" + } + ] +}); + +// Create responsibilities for Cardiac Nurse +const patientMonitoringResponsibility = Responsibility.create({ + title: "Patient Monitoring", + outcome: "Continuous monitoring of cardiac patients' vital signs and condition", + requiredAttributes: [ + { + name: "Telemetry Monitoring", + type: "Skill", + description: "Monitoring cardiac rhythms via telemetry" + }, + { + name: "Cardiac Monitor", + type: "Tool", + description: "Operating cardiac monitoring equipment" + } + ] +}); + +// Create roles for Pediatrics +const pediatrician = Role.create({ + title: "Pediatrician", + seniority: "Senior", + responsibilities: [], + requiredAttributes: [ + { + name: "Pediatric Board Certification", + type: "Trait", + description: "Board certified in pediatrics" + }, + { + name: "Developmental Assessment", + type: "Skill", + description: "Assessing child development milestones" + } + ] +}); + +const pediatricNurse = Role.create({ + title: "Pediatric Nurse", + seniority: "Mid", + responsibilities: [], + requiredAttributes: [ + { + name: "Pediatric Nursing Certification", + type: "Trait", + description: "Certified in pediatric nursing" + }, + { + name: "Family Communication", + type: "Skill", + description: "Communicating effectively with children and families" + } + ] +}); + +// Create responsibilities for Pediatrician +const wellChildExamResponsibility = Responsibility.create({ + title: "Well-Child Examinations", + outcome: "Regular health assessments and preventive care for children", + requiredAttributes: [ + { + name: "Growth Assessment", + type: "Skill", + description: "Evaluating child growth patterns" + }, + { + name: "Immunization Knowledge", + type: "Skill", + description: "Current knowledge of vaccination schedules" + } + ] +}); + +const developmentalScreeningResponsibility = Responsibility.create({ + title: "Developmental Screening", + outcome: "Early identification of developmental delays or disorders", + requiredAttributes: [ + { + name: "Screening Tools", + type: "Tool", + description: "Standardized developmental screening instruments" + }, + { + name: "Behavioral Assessment", + type: "Skill", + description: "Assessing child behavior and development" + } + ] +}); + +// Assemble the hierarchy +cardiologist.responsibilities.push(diagnosisResponsibility, treatmentPlanningResponsibility); +cardiacNurse.responsibilities.push(patientMonitoringResponsibility); +pediatrician.responsibilities.push(wellChildExamResponsibility, developmentalScreeningResponsibility); + +cardiology.roles.push(cardiologist, cardiacNurse); +pediatrics.roles.push(pediatrician, pediatricNurse); + +healthcareDomain.specializations.push(cardiology, pediatrics); +professionModel.domains.push(healthcareDomain); + +// Demonstrate the hierarchy +console.log("πŸ₯ Healthcare Domain Structure:"); +console.log(`Domain: ${healthcareDomain.name}`); +console.log(`Description: ${healthcareDomain.description}`); +console.log(`Core Attributes: ${healthcareDomain.coreAttributes.length}`); + +healthcareDomain.coreAttributes.forEach(attr => { + console.log(` - ${attr.name} (${attr.type}): ${attr.description}`); +}); + +console.log(`\nSpecializations: ${healthcareDomain.specializations.length}`); + +healthcareDomain.specializations.forEach(spec => { + console.log(`\nπŸ“‹ ${spec.name}`); + console.log(` Focus: ${spec.focus}`); + console.log(` Core Attributes: ${spec.coreAttributes.length}`); + + spec.coreAttributes.forEach(attr => { + console.log(` - ${attr.name} (${attr.type}): ${attr.description}`); + }); + + console.log(` Roles: ${spec.roles.length}`); + + spec.roles.forEach(role => { + console.log(`\n πŸ‘¨β€βš•οΈ ${role.title} (${role.seniority} Level)`); + console.log(` Required Attributes: ${role.requiredAttributes.length}`); + + role.requiredAttributes.forEach(attr => { + console.log(` - ${attr.name} (${attr.type}): ${attr.description}`); + }); + + console.log(` Responsibilities: ${role.responsibilities.length}`); + + role.responsibilities.forEach(resp => { + console.log(`\n πŸ“ ${resp.title}`); + console.log(` Outcome: ${resp.outcome}`); + console.log(` Required Attributes: ${resp.requiredAttributes.length}`); + + resp.requiredAttributes.forEach(attr => { + console.log(` - ${attr.name} (${attr.type}): ${attr.description}`); + }); + }); + }); +}); + +// Demonstrate querying capabilities +console.log("\n" + "=".repeat(60)); +console.log("πŸ” QUERYING EXAMPLES"); +console.log("=".repeat(60)); + +// Find all skills across the domain +const allSkills = healthcareDomain.specializations + .flatMap(spec => [ + ...spec.coreAttributes.filter(attr => attr.type === "Skill"), + ...spec.roles.flatMap(role => [ + ...role.requiredAttributes.filter(attr => attr.type === "Skill"), + ...role.responsibilities.flatMap(resp => + resp.requiredAttributes.filter(attr => attr.type === "Skill") + ) + ]) + ]); + +console.log(`\nπŸ’ͺ All Skills in Healthcare Domain (${allSkills.length}):`); +allSkills.forEach(skill => { + console.log(` - ${skill.name}: ${skill.description}`); +}); + +// Find all tools +const allTools = healthcareDomain.specializations + .flatMap(spec => [ + ...spec.coreAttributes.filter(attr => attr.type === "Tool"), + ...spec.roles.flatMap(role => [ + ...role.requiredAttributes.filter(attr => attr.type === "Tool"), + ...role.responsibilities.flatMap(resp => + resp.requiredAttributes.filter(attr => attr.type === "Tool") + ) + ]) + ]); + +console.log(`\nπŸ› οΈ All Tools in Healthcare Domain (${allTools.length}):`); +allTools.forEach(tool => { + console.log(` - ${tool.name}: ${tool.description}`); +}); + +// Find all senior-level roles +const seniorRoles = healthcareDomain.specializations + .flatMap(spec => spec.roles) + .filter(role => role.seniority === "Senior"); + +console.log(`\nπŸŽ–οΈ Senior-Level Roles (${seniorRoles.length}):`); +seniorRoles.forEach(role => { + console.log(` - ${role.title}`); +}); + +console.log("\n" + "=".repeat(60)); +console.log("βœ… Healthcare example completed successfully!"); +console.log("=".repeat(60)); \ No newline at end of file diff --git a/examples/v1/technology-example.ts b/examples/v1/technology-example.ts new file mode 100644 index 0000000..294d59c --- /dev/null +++ b/examples/v1/technology-example.ts @@ -0,0 +1,531 @@ +import { ProfessionModel, Domain, Specialization, Role, Responsibility, Attribute } from "../../lib/v1"; + +console.log("=== Technology Professional Hierarchy Example (V1) ===\n"); + +const professionModel = ProfessionModel.create({ + domains: [] +}); + +// Create the Technology domain +const technologyDomain = Domain.create({ + name: "Technology", + description: "Software development and technology services domain", + specializations: [], + coreAttributes: [ + { + name: "Problem Solving", + type: "Skill", + description: "Analytical thinking and systematic problem-solving approach" + }, + { + name: "Version Control", + type: "Tool", + description: "Proficiency with Git and version control systems" + }, + { + name: "Continuous Learning", + type: "Trait", + description: "Commitment to staying current with technology trends" + }, + { + name: "Agile Methodology", + type: "Skill", + description: "Understanding of Agile/Scrum development processes" + } + ] +}); + +// Create Web Development specialization +const webDevelopment = Specialization.create({ + name: "Web Development", + focus: "Building web applications and websites", + coreAttributes: [ + { + name: "HTML/CSS", + type: "Skill", + description: "Markup and styling for web interfaces" + }, + { + name: "JavaScript", + type: "Skill", + description: "Client-side and server-side JavaScript programming" + }, + { + name: "Web Browser DevTools", + type: "Tool", + description: "Browser developer tools for debugging and optimization" + }, + { + name: "Responsive Design", + type: "Skill", + description: "Creating mobile-friendly and adaptive layouts" + } + ], + roles: [] +}); + +// Create Data Science specialization +const dataScience = Specialization.create({ + name: "Data Science", + focus: "Extracting insights from data using statistical and machine learning methods", + coreAttributes: [ + { + name: "Statistical Analysis", + type: "Skill", + description: "Statistical methods and hypothesis testing" + }, + { + name: "Python/R", + type: "Skill", + description: "Programming languages for data analysis" + }, + { + name: "Jupyter Notebooks", + type: "Tool", + description: "Interactive development environment for data science" + }, + { + name: "Data Visualization", + type: "Skill", + description: "Creating meaningful visual representations of data" + } + ], + roles: [] +}); + +// Create Mobile Development specialization +const mobileDevelopment = Specialization.create({ + name: "Mobile Development", + focus: "Building native and cross-platform mobile applications", + coreAttributes: [ + { + name: "Mobile UI/UX", + type: "Skill", + description: "Designing user interfaces for mobile devices" + }, + { + name: "App Store Guidelines", + type: "Skill", + description: "Understanding platform-specific app store requirements" + }, + { + name: "Mobile Testing Frameworks", + type: "Tool", + description: "Tools for testing mobile applications" + } + ], + roles: [] +}); + +// Create roles for Web Development +const frontendDeveloper = Role.create({ + title: "Frontend Developer", + seniority: "Mid", + responsibilities: [], + requiredAttributes: [ + { + name: "React/Vue/Angular", + type: "Skill", + description: "Modern frontend frameworks" + }, + { + name: "Cross-browser Compatibility", + type: "Skill", + description: "Ensuring consistent behavior across different browsers" + }, + { + name: "Performance Optimization", + type: "Skill", + description: "Optimizing web application performance" + } + ] +}); + +const fullStackDeveloper = Role.create({ + title: "Full Stack Developer", + seniority: "Senior", + responsibilities: [], + requiredAttributes: [ + { + name: "Backend Development", + type: "Skill", + description: "Server-side programming and API development" + }, + { + name: "Database Design", + type: "Skill", + description: "Designing and optimizing database schemas" + }, + { + name: "Cloud Platforms", + type: "Tool", + description: "AWS, Azure, or Google Cloud Platform" + } + ] +}); + +// Create roles for Data Science +const dataAnalyst = Role.create({ + title: "Data Analyst", + seniority: "Junior", + responsibilities: [], + requiredAttributes: [ + { + name: "SQL", + type: "Skill", + description: "Database querying and data manipulation" + }, + { + name: "Excel/Spreadsheets", + type: "Tool", + description: "Advanced spreadsheet analysis" + }, + { + name: "Business Intelligence Tools", + type: "Tool", + description: "Tableau, Power BI, or similar BI tools" + } + ] +}); + +const machineLearningEngineer = Role.create({ + title: "Machine Learning Engineer", + seniority: "Senior", + responsibilities: [], + requiredAttributes: [ + { + name: "Machine Learning Algorithms", + type: "Skill", + description: "Understanding of ML algorithms and their applications" + }, + { + name: "Model Deployment", + type: "Skill", + description: "Deploying ML models to production environments" + }, + { + name: "TensorFlow/PyTorch", + type: "Tool", + description: "Deep learning frameworks" + } + ] +}); + +// Create roles for Mobile Development +const iosDeveloper = Role.create({ + title: "iOS Developer", + seniority: "Mid", + responsibilities: [], + requiredAttributes: [ + { + name: "Swift/Objective-C", + type: "Skill", + description: "iOS native programming languages" + }, + { + name: "Xcode", + type: "Tool", + description: "Apple's integrated development environment" + }, + { + name: "iOS SDK", + type: "Skill", + description: "iOS Software Development Kit and frameworks" + } + ] +}); + +// Create responsibilities for Frontend Developer +const uiImplementationResponsibility = Responsibility.create({ + title: "User Interface Implementation", + outcome: "Pixel-perfect, responsive user interfaces that match design specifications", + requiredAttributes: [ + { + name: "CSS Frameworks", + type: "Tool", + description: "Bootstrap, Tailwind CSS, or similar frameworks" + }, + { + name: "Design Systems", + type: "Skill", + description: "Implementing and maintaining design system components" + } + ] +}); + +const frontendTestingResponsibility = Responsibility.create({ + title: "Frontend Testing", + outcome: "Comprehensive test coverage for user interface components", + requiredAttributes: [ + { + name: "Jest/Cypress", + type: "Tool", + description: "Frontend testing frameworks" + }, + { + name: "Test-Driven Development", + type: "Skill", + description: "Writing tests before implementation" + } + ] +}); + +// Create responsibilities for Full Stack Developer +const apiDevelopmentResponsibility = Responsibility.create({ + title: "API Development", + outcome: "Robust, scalable APIs that serve frontend applications", + requiredAttributes: [ + { + name: "RESTful Services", + type: "Skill", + description: "Designing and implementing REST APIs" + }, + { + name: "API Documentation", + type: "Skill", + description: "Creating comprehensive API documentation" + }, + { + name: "Postman/Insomnia", + type: "Tool", + description: "API testing and documentation tools" + } + ] +}); + +const systemArchitectureResponsibility = Responsibility.create({ + title: "System Architecture", + outcome: "Scalable, maintainable system architecture decisions", + requiredAttributes: [ + { + name: "Microservices", + type: "Skill", + description: "Designing microservice architectures" + }, + { + name: "Load Balancing", + type: "Skill", + description: "Implementing load balancing strategies" + }, + { + name: "Docker/Kubernetes", + type: "Tool", + description: "Containerization and orchestration tools" + } + ] +}); + +// Create responsibilities for Data Analyst +const dataExplorationResponsibility = Responsibility.create({ + title: "Data Exploration", + outcome: "Comprehensive understanding of data patterns and anomalies", + requiredAttributes: [ + { + name: "Exploratory Data Analysis", + type: "Skill", + description: "Systematic approach to exploring datasets" + }, + { + name: "Data Cleaning", + type: "Skill", + description: "Identifying and correcting data quality issues" + } + ] +}); + +// Create responsibilities for Machine Learning Engineer +const modelDevelopmentResponsibility = Responsibility.create({ + title: "Model Development", + outcome: "Accurate, efficient machine learning models for production use", + requiredAttributes: [ + { + name: "Feature Engineering", + type: "Skill", + description: "Creating and selecting relevant features for ML models" + }, + { + name: "Model Validation", + type: "Skill", + description: "Cross-validation and performance evaluation techniques" + }, + { + name: "MLflow/Kubeflow", + type: "Tool", + description: "ML pipeline and experiment tracking tools" + } + ] +}); + +// Create responsibilities for iOS Developer +const iosAppDevelopmentResponsibility = Responsibility.create({ + title: "iOS App Development", + outcome: "High-quality iOS applications that meet App Store standards", + requiredAttributes: [ + { + name: "UIKit/SwiftUI", + type: "Skill", + description: "iOS user interface frameworks" + }, + { + name: "Core Data", + type: "Skill", + description: "iOS data persistence framework" + }, + { + name: "App Store Connect", + type: "Tool", + description: "Apple's app distribution platform" + } + ] +}); + +// Assemble the hierarchy +frontendDeveloper.responsibilities.push(uiImplementationResponsibility, frontendTestingResponsibility); +fullStackDeveloper.responsibilities.push(apiDevelopmentResponsibility, systemArchitectureResponsibility); +dataAnalyst.responsibilities.push(dataExplorationResponsibility); +machineLearningEngineer.responsibilities.push(modelDevelopmentResponsibility); +iosDeveloper.responsibilities.push(iosAppDevelopmentResponsibility); + +webDevelopment.roles.push(frontendDeveloper, fullStackDeveloper); +dataScience.roles.push(dataAnalyst, machineLearningEngineer); +mobileDevelopment.roles.push(iosDeveloper); + +technologyDomain.specializations.push(webDevelopment, dataScience, mobileDevelopment); +professionModel.domains.push(technologyDomain); + +// Demonstrate the hierarchy +console.log("πŸ’» Technology Domain Structure:"); +console.log(`Domain: ${technologyDomain.name}`); +console.log(`Description: ${technologyDomain.description}`); +console.log(`Core Attributes: ${technologyDomain.coreAttributes.length}`); + +technologyDomain.coreAttributes.forEach(attr => { + console.log(` - ${attr.name} (${attr.type}): ${attr.description}`); +}); + +console.log(`\nSpecializations: ${technologyDomain.specializations.length}`); + +technologyDomain.specializations.forEach(spec => { + console.log(`\nπŸ”§ ${spec.name}`); + console.log(` Focus: ${spec.focus}`); + console.log(` Core Attributes: ${spec.coreAttributes.length}`); + + spec.coreAttributes.forEach(attr => { + console.log(` - ${attr.name} (${attr.type}): ${attr.description}`); + }); + + console.log(` Roles: ${spec.roles.length}`); + + spec.roles.forEach(role => { + console.log(`\n πŸ‘¨β€πŸ’» ${role.title} (${role.seniority} Level)`); + console.log(` Required Attributes: ${role.requiredAttributes.length}`); + + role.requiredAttributes.forEach(attr => { + console.log(` - ${attr.name} (${attr.type}): ${attr.description}`); + }); + + console.log(` Responsibilities: ${role.responsibilities.length}`); + + role.responsibilities.forEach(resp => { + console.log(`\n πŸ“‹ ${resp.title}`); + console.log(` Outcome: ${resp.outcome}`); + console.log(` Required Attributes: ${resp.requiredAttributes.length}`); + + resp.requiredAttributes.forEach(attr => { + console.log(` - ${attr.name} (${attr.type}): ${attr.description}`); + }); + }); + }); +}); + +// Demonstrate advanced querying capabilities +console.log("\n" + "=".repeat(60)); +console.log("πŸ” ADVANCED QUERYING EXAMPLES"); +console.log("=".repeat(60)); + +// Find all programming languages/frameworks (skills containing common tech terms) +const programmingSkills = technologyDomain.specializations + .flatMap(spec => [ + ...spec.coreAttributes.filter(attr => attr.type === "Skill"), + ...spec.roles.flatMap(role => [ + ...role.requiredAttributes.filter(attr => attr.type === "Skill"), + ...role.responsibilities.flatMap(resp => + resp.requiredAttributes.filter(attr => attr.type === "Skill") + ) + ]) + ]) + .filter(skill => + skill.name.includes("/") || + skill.name.includes("JavaScript") || + skill.name.includes("Python") || + skill.name.includes("Swift") || + skill.name.includes("SQL") + ); + +console.log(`\nπŸš€ Programming Languages & Frameworks (${programmingSkills.length}):`); +programmingSkills.forEach(skill => { + console.log(` - ${skill.name}: ${skill.description}`); +}); + +// Find all development tools +const developmentTools = technologyDomain.specializations + .flatMap(spec => [ + ...spec.coreAttributes.filter(attr => attr.type === "Tool"), + ...spec.roles.flatMap(role => [ + ...role.requiredAttributes.filter(attr => attr.type === "Tool"), + ...role.responsibilities.flatMap(resp => + resp.requiredAttributes.filter(attr => attr.type === "Tool") + ) + ]) + ]); + +console.log(`\nπŸ› οΈ Development Tools (${developmentTools.length}):`); +developmentTools.forEach(tool => { + console.log(` - ${tool.name}: ${tool.description}`); +}); + +// Find roles by seniority level +const seniorityLevels = ["Junior", "Mid", "Senior"]; +seniorityLevels.forEach(level => { + const rolesAtLevel = technologyDomain.specializations + .flatMap(spec => spec.roles) + .filter(role => role.seniority === level); + + if (rolesAtLevel.length > 0) { + console.log(`\n🎯 ${level} Level Roles (${rolesAtLevel.length}):`); + rolesAtLevel.forEach(role => { + console.log(` - ${role.title}`); + }); + } +}); + +// Find specializations with the most roles +const specializationsByRoleCount = technologyDomain.specializations + .map(spec => ({ name: spec.name, roleCount: spec.roles.length })) + .sort((a, b) => b.roleCount - a.roleCount); + +console.log(`\nπŸ“Š Specializations by Role Count:`); +specializationsByRoleCount.forEach(spec => { + console.log(` - ${spec.name}: ${spec.roleCount} roles`); +}); + +// Calculate total responsibilities across the domain +const totalResponsibilities = technologyDomain.specializations + .flatMap(spec => spec.roles) + .reduce((total, role) => total + role.responsibilities.length, 0); + +console.log(`\nπŸ“ˆ Domain Statistics:`); +console.log(` - Total Specializations: ${technologyDomain.specializations.length}`); +console.log(` - Total Roles: ${technologyDomain.specializations.flatMap(spec => spec.roles).length}`); +console.log(` - Total Responsibilities: ${totalResponsibilities}`); +console.log(` - Total Attributes: ${technologyDomain.coreAttributes.length + + technologyDomain.specializations.reduce((total, spec) => + total + spec.coreAttributes.length + + spec.roles.reduce((roleTotal, role) => + roleTotal + role.requiredAttributes.length + + role.responsibilities.reduce((respTotal, resp) => + respTotal + resp.requiredAttributes.length, 0), 0), 0)}`); + +console.log("\n" + "=".repeat(60)); +console.log("βœ… Technology example completed successfully!"); +console.log("=".repeat(60)); \ No newline at end of file diff --git a/examples/v2/software-company-example.ts b/examples/v2/software-company-example.ts new file mode 100644 index 0000000..b378913 --- /dev/null +++ b/examples/v2/software-company-example.ts @@ -0,0 +1,521 @@ +import { + Enterprise, + DomainModel, + IndustryModel, + ProfessionModel, + FieldModel, + RoleModel, + TaskModel +} from "../../lib/v2"; + +console.log("=== Software Company Professional Hierarchy Example (V2) ===\n"); + +const enterprise = Enterprise.create({}); + +enterprise.addDomain({ + name: "STEM", + description: "Science, Technology, Engineering, and Mathematics domain" +}); + +const stemDomain = enterprise.domains[0]; + +stemDomain.addIndustry({ + name: "Software", + description: "Software development and technology services industry" +}); + +const softwareIndustry = stemDomain.industries[0]; + +softwareIndustry.addProfession({ + name: "Software Engineering", + description: "Design, development, and maintenance of software systems" +}); + +const softwareEngineering = softwareIndustry.professions[0]; + +const fieldData = [ + { + name: "Backend Development", + description: "Server-side application development, APIs, and database management" + }, + { + name: "Frontend Development", + description: "User interface and user experience development" + }, + { + name: "DevOps Engineering", + description: "Development operations, CI/CD, and infrastructure management" + }, + { + name: "Mobile Development", + description: "Native and cross-platform mobile application development" + }, + { + name: "Data Engineering", + description: "Data pipeline development and big data processing" + } +]; + +fieldData.forEach(field => { + softwareEngineering.addField(field); +}); + +const [backendField, frontendField, devopsField, mobileField, dataField] = softwareEngineering.fields; + +const backendRoles = [ + { + title: "Senior Backend Engineer", + summary: "Lead backend development initiatives and mentor junior developers" + }, + { + title: "API Developer", + summary: "Design and implement RESTful and GraphQL APIs" + }, + { + title: "Database Engineer", + summary: "Design, optimize, and maintain database systems" + } +]; + +backendRoles.forEach(role => { + backendField.addRole(role); +}); + +const frontendRoles = [ + { + title: "React Developer", + summary: "Build modern web applications using React ecosystem" + }, + { + title: "UI/UX Engineer", + summary: "Bridge design and development with focus on user experience" + } +]; + +frontendRoles.forEach(role => { + frontendField.addRole(role); +}); + +devopsField.addRole({ + title: "DevOps Engineer", + summary: "Manage CI/CD pipelines and cloud infrastructure" +}); + +devopsField.addRole({ + title: "Site Reliability Engineer", + summary: "Ensure system reliability, monitoring, and incident response" +}); + +mobileField.addRole({ + title: "iOS Developer", + summary: "Develop native iOS applications using Swift and iOS SDK" +}); + +mobileField.addRole({ + title: "React Native Developer", + summary: "Build cross-platform mobile apps using React Native" +}); + +dataField.addRole({ + title: "Data Pipeline Engineer", + summary: "Build and maintain data processing pipelines" +}); + +const seniorBackendEngineer = backendField.roles[0]; +const apiDeveloper = backendField.roles[1]; +const databaseEngineer = backendField.roles[2]; + +const seniorBackendTasks = [ + { + name: "Design system architecture", + description: "Create scalable and maintainable system architecture designs" + }, + { + name: "Code review and mentoring", + description: "Review code submissions and mentor junior team members" + }, + { + name: "Performance optimization", + description: "Identify and resolve performance bottlenecks in backend systems" + }, + { + name: "Technical documentation", + description: "Create and maintain comprehensive technical documentation" + } +]; + +seniorBackendTasks.forEach(task => { + seniorBackendEngineer.addTask(task); +}); + +const apiDeveloperTasks = [ + { + name: "Design REST endpoints", + description: "Create RESTful API endpoints following best practices" + }, + { + name: "Implement GraphQL resolvers", + description: "Build GraphQL schema and resolver functions" + }, + { + name: "API documentation", + description: "Document API endpoints using OpenAPI/Swagger specifications" + }, + { + name: "API testing", + description: "Write comprehensive tests for API endpoints" + } +]; + +apiDeveloperTasks.forEach(task => { + apiDeveloper.addTask(task); +}); + +const databaseEngineerTasks = [ + { + name: "Database schema design", + description: "Design efficient and normalized database schemas" + }, + { + name: "Query optimization", + description: "Optimize database queries for better performance" + }, + { + name: "Database migration scripts", + description: "Create and manage database migration scripts" + }, + { + name: "Backup and recovery procedures", + description: "Implement and maintain database backup and recovery strategies" + } +]; + +databaseEngineerTasks.forEach(task => { + databaseEngineer.addTask(task); +}); + +const reactDeveloper = frontendField.roles[0]; +const uiuxEngineer = frontendField.roles[1]; + +const reactDeveloperTasks = [ + { + name: "Build React components", + description: "Create reusable and performant React components" + }, + { + name: "State management implementation", + description: "Implement state management using Redux, Zustand, or Context API" + }, + { + name: "Frontend testing", + description: "Write unit and integration tests for React components" + }, + { + name: "Bundle optimization", + description: "Optimize webpack bundles for better performance" + } +]; + +reactDeveloperTasks.forEach(task => { + reactDeveloper.addTask(task); +}); + +const uiuxEngineerTasks = [ + { + name: "Design system implementation", + description: "Implement and maintain design system components" + }, + { + name: "Accessibility compliance", + description: "Ensure applications meet WCAG accessibility standards" + }, + { + name: "User experience optimization", + description: "Analyze and improve user interaction patterns" + } +]; + +uiuxEngineerTasks.forEach(task => { + uiuxEngineer.addTask(task); +}); + +const devopsEngineer = devopsField.roles[0]; +const sreEngineer = devopsField.roles[1]; + +const devopsEngineerTasks = [ + { + name: "CI/CD pipeline setup", + description: "Configure continuous integration and deployment pipelines" + }, + { + name: "Infrastructure as Code", + description: "Manage infrastructure using Terraform, CloudFormation, or similar tools" + }, + { + name: "Container orchestration", + description: "Deploy and manage applications using Docker and Kubernetes" + }, + { + name: "Cloud resource management", + description: "Optimize cloud resource usage and costs" + } +]; + +devopsEngineerTasks.forEach(task => { + devopsEngineer.addTask(task); +}); + +const sreEngineerTasks = [ + { + name: "Monitoring and alerting", + description: "Set up comprehensive monitoring and alerting systems" + }, + { + name: "Incident response", + description: "Respond to and resolve production incidents" + }, + { + name: "Capacity planning", + description: "Plan and manage system capacity and scaling" + }, + { + name: "Post-mortem analysis", + description: "Conduct post-incident analysis and implement improvements" + } +]; + +sreEngineerTasks.forEach(task => { + sreEngineer.addTask(task); +}); + +const iosDeveloper = mobileField.roles[0]; +const reactNativeDeveloper = mobileField.roles[1]; + +const iosDeveloperTasks = [ + { + name: "iOS app development", + description: "Build native iOS applications using Swift and UIKit/SwiftUI" + }, + { + name: "App Store submission", + description: "Prepare and submit apps to the Apple App Store" + }, + { + name: "iOS performance optimization", + description: "Optimize app performance and memory usage" + } +]; + +iosDeveloperTasks.forEach(task => { + iosDeveloper.addTask(task); +}); + +const reactNativeDeveloperTasks = [ + { + name: "Cross-platform development", + description: "Build apps that work on both iOS and Android platforms" + }, + { + name: "Native module integration", + description: "Integrate native iOS and Android modules when needed" + }, + { + name: "App performance tuning", + description: "Optimize React Native app performance and bundle size" + } +]; + +reactNativeDeveloperTasks.forEach(task => { + reactNativeDeveloper.addTask(task); +}); + +const dataPipelineEngineer = dataField.roles[0]; + +const dataPipelineEngineerTasks = [ + { + name: "ETL pipeline development", + description: "Build Extract, Transform, Load pipelines for data processing" + }, + { + name: "Data quality monitoring", + description: "Implement data quality checks and monitoring systems" + }, + { + name: "Big data processing", + description: "Process large datasets using Spark, Hadoop, or similar technologies" + }, + { + name: "Data warehouse management", + description: "Design and maintain data warehouse schemas and processes" + } +]; + +dataPipelineEngineerTasks.forEach(task => { + dataPipelineEngineer.addTask(task); +}); + +console.log("🏒 Software Company Hierarchy Structure:"); +console.log("=".repeat(60)); + +console.log(`\n🌐 Domain: ${stemDomain.name}`); +console.log(` Description: ${stemDomain.description}`); +console.log(` Industries: ${stemDomain.industries.length}`); + +stemDomain.industries.forEach(industry => { + console.log(`\n 🏭 Industry: ${industry.name}`); + console.log(` Description: ${industry.description}`); + console.log(` Professions: ${industry.professions.length}`); + + industry.professions.forEach(profession => { + console.log(`\n πŸ‘¨β€πŸ’Ό Profession: ${profession.name}`); + console.log(` Description: ${profession.description}`); + console.log(` Fields: ${profession.fields.length}`); + + profession.fields.forEach(field => { + console.log(`\n πŸ”§ Field: ${field.name}`); + console.log(` Description: ${field.description}`); + console.log(` Roles: ${field.roles.length}`); + + field.roles.forEach(role => { + console.log(`\n πŸ‘€ Role: ${role.title}`); + console.log(` Summary: ${role.summary}`); + console.log(` Tasks: ${role.tasks.length}`); + + role.tasks.forEach((task, index) => { + console.log(` ${index + 1}. ${task.name}`); + if (task.description) { + console.log(` β†’ ${task.description}`); + } + }); + }); + }); + }); +}); + +console.log("\n" + "=".repeat(60)); +console.log("πŸ” V2 ADVANCED FEATURES DEMONSTRATION"); +console.log("=".repeat(60)); + +console.log("\nπŸ†” UUID Identifiers:"); +console.log(`Domain ID: ${stemDomain.id}`); +console.log(`Industry ID: ${softwareIndustry.id}`); +console.log(`Profession ID: ${softwareEngineering.id}`); +console.log(`First Field ID: ${backendField.id}`); +console.log(`First Role ID: ${seniorBackendEngineer.id}`); +console.log(`First Task ID: ${seniorBackendEngineer.tasks[0].id}`); + +console.log(`\nπŸ“Š All Tasks in Software Industry (${softwareIndustry.allTasks.length}):`); +softwareIndustry.allTasks.forEach((task, index) => { + console.log(`${index + 1}. ${task.name}`); +}); + +console.log(`\nπŸ”§ Tasks by Field:`); +softwareEngineering.fields.forEach(field => { + console.log(`${field.name}: ${field.allTasks.length} tasks`); +}); + +console.log("\n⚑ CRUD Operations Demonstration:"); + +console.log("\nβž• Adding new field: 'Quality Assurance'"); +softwareEngineering.addField({ + name: "Quality Assurance", + description: "Software testing and quality assurance" +}); + +const qaField = softwareEngineering.fields[softwareEngineering.fields.length - 1]; +console.log(`βœ… Added field: ${qaField.name} (ID: ${qaField.id})`); + +qaField.addRole({ + title: "QA Engineer", + summary: "Ensure software quality through comprehensive testing" +}); + +const qaEngineer = qaField.roles[0]; +console.log(`βœ… Added role: ${qaEngineer.title} (ID: ${qaEngineer.id})`); + +const qaTasks = [ + { + name: "Test case development", + description: "Create comprehensive test cases for software features" + }, + { + name: "Automated testing", + description: "Develop and maintain automated test suites" + }, + { + name: "Bug reporting and tracking", + description: "Identify, document, and track software defects" + } +]; + +qaTasks.forEach(task => { + qaEngineer.addTask(task); +}); + +console.log(`βœ… Added ${qaTasks.length} tasks to QA Engineer`); + +const firstQATask = qaEngineer.tasks[0]; +console.log(`\n✏️ Updating task: "${firstQATask.name}"`); +firstQATask.update({ + name: "Comprehensive Test Case Development", + description: "Create detailed test cases covering functional, integration, and edge cases" +}); +console.log(`βœ… Updated to: "${firstQATask.name}"`); + +console.log(`\nπŸ—‘οΈ Removing last task from QA Engineer`); +const taskToRemove = qaEngineer.tasks[qaEngineer.tasks.length - 1]; +console.log(`Removing: "${taskToRemove.name}"`); +qaEngineer.removeTask(taskToRemove); +console.log(`βœ… Task removed. QA Engineer now has ${qaEngineer.tasks.length} tasks`); + +console.log("\nπŸ” Advanced Querying:"); + +const engineerRoles = softwareEngineering.fields + .flatMap(field => field.roles) + .filter(role => role.title.includes("Engineer")); + +console.log(`\nπŸ‘· Roles with "Engineer" in title (${engineerRoles.length}):`); +engineerRoles.forEach(role => { + console.log(` - ${role.title}`); +}); + +const fieldTaskCounts = softwareEngineering.fields + .map(field => ({ + name: field.name, + taskCount: field.allTasks.length + })) + .sort((a, b) => b.taskCount - a.taskCount); + +console.log(`\nπŸ“ˆ Fields by Task Count:`); +fieldTaskCounts.forEach(field => { + console.log(` - ${field.name}: ${field.taskCount} tasks`); +}); + +const developmentTasks = enterprise.allTasks + .filter(task => + task.name.toLowerCase().includes("develop") || + task.description?.toLowerCase().includes("develop") + ); + +console.log(`\nπŸ’» Development-related Tasks (${developmentTasks.length}):`); +developmentTasks.forEach(task => { + console.log(` - ${task.name}`); +}); + +console.log("\nπŸ“Š Complete Hierarchy Statistics:"); +console.log(` - Domains: ${enterprise.domains.length}`); +console.log(` - Industries: ${enterprise.domains.reduce((sum, d) => sum + d.industries.length, 0)}`); +console.log(` - Professions: ${enterprise.domains.reduce((sum, d) => sum + d.industries.reduce((sum2, i) => sum2 + i.professions.length, 0), 0)}`); +console.log(` - Fields: ${enterprise.domains.reduce((sum, d) => sum + d.industries.reduce((sum2, i) => sum2 + i.professions.reduce((sum3, p) => sum3 + p.fields.length, 0), 0), 0)}`); +console.log(` - Roles: ${enterprise.domains.reduce((sum, d) => sum + d.industries.reduce((sum2, i) => sum2 + i.professions.reduce((sum3, p) => sum3 + p.fields.reduce((sum4, f) => sum4 + f.roles.length, 0), 0), 0), 0)}`); +console.log(` - Tasks: ${enterprise.allTasks.length}`); + +console.log("\n" + "=".repeat(60)); +console.log("βœ… Software Company example completed successfully!"); +console.log("This example demonstrates the full 6-layer hierarchy with:"); +console.log(" β€’ UUID-based identifiers for distributed systems"); +console.log(" β€’ Comprehensive CRUD operations"); +console.log(" β€’ Compositional queries and views"); +console.log(" β€’ Real-world software company structure"); +console.log(" β€’ Advanced querying capabilities"); +console.log("=".repeat(60)); \ No newline at end of file diff --git a/generate-template.ts b/generate-template.ts new file mode 100755 index 0000000..71268e3 --- /dev/null +++ b/generate-template.ts @@ -0,0 +1,125 @@ +#!/usr/bin/env bun + +/* + * hierarchyGenerator.ts + * ------------------------------------------------------------ + * A tiny OpenAI‑powered helper that turns natural‑language prompts + * into domain hierarchies matching `HierarchyModel` (mobx‑state‑tree). + * ------------------------------------------------------------ + * Usage example: + * import { generateHierarchy } from "./hierarchyGenerator"; + * const hierarchy = await generateHierarchy("Create a v2 Healthcare hierarchy for mental health services"); + * + * The function returns a live MST instance of `HierarchyModel` so it + * can be plugged straight into your state tree or persisted as JSON. + */ + +import OpenAI from "openai"; +import { HierarchyModel } from "./lib/hierarchy-model.ts"; +import type { Instance } from "mobx-state-tree"; + +// --------------------------------------------------------------------------- +// Type Definitions +// --------------------------------------------------------------------------- + +/** + * Shape produced by the LLM and accepted by `HierarchyModel`. + */ +export interface Hierarchy { + version: "v1" | "v2"; + domain: string; // e.g. "Finance", "Technology" + structure: string[]; // ordered list of hierarchy labels + description: string; // plain‑text description + commonSkills: string[]; + commonTools: string[]; + examples: string[]; +} + +// --------------------------------------------------------------------------- +// OpenAI client configuration +// --------------------------------------------------------------------------- + +const openai = new OpenAI({ + // Rely on OPENAI_API_KEY env var or pass explicit key here + apiKey: process.env.OPENAI_API_KEY, +}); + +// System prompt used for every request. Keeps the model focused on +// emitting strict JSON with NO extra text. +const SYS_PROMPT = ` +You are an API that converts natural‑language descriptions into JSON +objects that conform **exactly** to the following TypeScript interface. +Return the JSON only – no markdown, comments, or additional keys. +If a field is missing in the user's request, make a sensible inference. + +interface Hierarchy { + version: "v1" | "v2"; // one of the two schema versions + domain: string; // high‑level sector name + structure: string[]; // ordered labels, 4 elements for v1, 6 for v2 + description: string; // concise explanation of the hierarchy + commonSkills: string[]; // 3‑7 bullet items + commonTools: string[]; // 3‑7 bullet items + examples: string[]; // 3‑7 representative examples +} +`; + +// --------------------------------------------------------------------------- +// Public API +// --------------------------------------------------------------------------- + +/** + * Convert a natural‑language prompt into a fully‑typed `HierarchyModel`. + * + * @param nlPrompt – Human description, e.g. "Define a v1 hierarchy for legal services" + * @param model – (optional) Which OpenAI model to use. Defaults to GPT‑4o‑mini. + */ +export async function generateHierarchy( + nlPrompt: string, + model: string = "gpt-4o-mini" +): Promise> { + const chat = await openai.chat.completions.create({ + model, + response_format: { type: "json_object" }, // guarantees pure JSON + messages: [ + { role: "system", content: SYS_PROMPT }, + { role: "user", content: nlPrompt }, + ], + }); + + // Defensive parsing β€” in rare cases the assistant may wrap JSON in text. + const raw = chat.choices[0]?.message?.content ?? "{}"; + let data: Hierarchy; + try { + data = JSON.parse(raw) as Hierarchy; + } catch { + // Attempt to salvage JSON embedded in text + const match = raw.match(/\{[\s\S]*\}/); + if (!match) throw new Error("Failed to parse JSON from LLM response"); + data = JSON.parse(match[0]) as Hierarchy; + } + + // Validate minimal shape before creating MST instance. + if (!data.version || !data.domain || !data.structure) { + throw new Error("Incomplete hierarchy returned by LLM"); + } + + return HierarchyModel.create(data); +} + +// --------------------------------------------------------------------------- +// Helper: quick command‑line demo when run with ts‑node +// --------------------------------------------------------------------------- + +if (require.main === module) { + (async () => { + const prompt = process.argv.slice(2).join(" ") || + "Create a v2 Technology hierarchy focused on AI safety"; + try { + const hierarchy = await generateHierarchy(prompt); + console.log(JSON.stringify(hierarchy.toJSON(), null, 2)); + } catch (err) { + console.error("Error generating hierarchy:", err); + process.exitCode = 1; + } + })(); +} diff --git a/index.ts b/index.ts new file mode 100644 index 0000000..220bb8b --- /dev/null +++ b/index.ts @@ -0,0 +1,199 @@ +import HierarchyAgent from './lib/agent-wrapper'; +import { writeFileSync, mkdirSync } from 'fs'; +import { join } from 'path'; + +// Create the hierarchy agent with enhanced instructions +const hierarchyAgent = new HierarchyAgent({ + name: 'Professional Hierarchy Generator', + instructions: `You are an expert at creating professional hierarchy models. + You understand organizational structures, job roles, skills, and professional development paths. + Generate comprehensive, realistic examples that demonstrate best practices in professional modeling. + + Focus on creating practical, implementable hierarchies that reflect real-world organizational structures. + Include relevant skills, tools, and technologies for each role. + Provide clear examples of how the hierarchy can be used in practice.`, +}); + +// Demonstrate the modular agent capabilities +async function demonstrateAgentCapabilities() { + console.log('πŸš€ Demonstrating Professional Hierarchy Agent Capabilities...\n'); + + // Show available templates + console.log('πŸ“‹ Available Templates:'); + const templates = hierarchyAgent.getAvailableTemplates(); + templates.forEach(template => { + console.log(` - ${template.domain} (${template.version}): ${template.description}`); + }); + console.log(); + + // Generate examples using different approaches + const examples = [ + { + name: 'Education Domain (using template)', + options: { + domain: 'education', + templateKey: 'education-v2', + complexity: 'complex' as const, + includeSkills: true, + includeTools: true, + includeExamples: true + } + }, + { + name: 'Manufacturing Domain (custom generation)', + options: { + domain: 'manufacturing', + version: 'v2' as const, + complexity: 'medium' as const, + includeSkills: true, + includeTools: true, + includeExamples: true + } + }, + { + name: 'Retail Domain (simple v1)', + options: { + domain: 'retail', + version: 'v1' as const, + complexity: 'simple' as const, + includeSkills: false, + includeTools: false, + includeExamples: true + } + } + ]; + + // Create examples directory + const examplesDir = join(process.cwd(), 'examples', 'generated'); + mkdirSync(examplesDir, { recursive: true }); + + // Generate each example with streaming for visibility + for (const example of examples) { + try { + console.log(`πŸ“Š Generating: ${example.name}...`); + console.log('πŸ” Watch the agent work in real-time:\n'); + + // Use streaming to show what the agent is doing + const result = await hierarchyAgent.generateHierarchyWithStreaming( + example.options, + (event) => { + // Enhanced trace information for agent activities + if (event.type === 'agent_updated_stream_event') { + console.log(`[TRACE] πŸ€– Agent: ${event.agent?.name || 'Unknown'} - Status updated`); + } else if (event.type === 'run_item_stream_event') { + if (event.item?.type === 'tool_call_item') { + console.log(`[TRACE] πŸ”§ Tool Call: ${event.item.tool_call?.function?.name || 'Unknown tool'}`); + if (event.item.tool_call?.function?.arguments) { + try { + const args = JSON.parse(event.item.tool_call.function.arguments); + console.log(`[TRACE] πŸ“‹ Tool Arguments: ${JSON.stringify(args, null, 2)}`); + } catch (e) { + console.log(`[TRACE] πŸ“‹ Tool Arguments: ${event.item.tool_call.function.arguments}`); + } + } + } else if (event.item?.type === 'tool_call_output_item') { + console.log(`[TRACE] βœ… Tool Output: Received response`); + } else if (event.item?.type === 'message_output_item') { + console.log(`[TRACE] πŸ’¬ Message: Generating response content`); + } + } else if (event.type === 'raw_model_stream_event' && event.delta?.content) { + // Show partial content being generated (throttled) + process.stdout.write('.'); + } else if (event.type === 'run_started_stream_event') { + console.log(`[TRACE] πŸš€ Run Started: Beginning agent execution`); + } else if (event.type === 'run_completed_stream_event') { + console.log(`[TRACE] 🏁 Run Completed: Agent execution finished`); + } + } + ); + + console.log(); // New line after dots + + // Write the generated example to a file + const filepath = join(examplesDir, `${result.filename}.${result.extension}`); + writeFileSync(filepath, result.content); + + console.log(`βœ… Generated: ${filepath}`); + console.log(` Format: typescript (default)`); + console.log(` Complexity: ${example.options.complexity}`); + console.log(); + + } catch (error) { + console.error(`❌ Error generating ${example.name}:`, error); + } + } + + // Demonstrate batch generation with streaming + console.log('πŸ”„ Demonstrating batch generation with streaming...'); + const batchDomains = ['logistics', 'consulting', 'media']; + + const batchResults = []; + for (const domain of batchDomains) { + try { + console.log(`πŸ“Š Batch generating: ${domain} domain...`); + console.log('πŸ” Streaming agent progress:\n'); + + const result = await hierarchyAgent.generateHierarchyWithStreaming({ + domain, + version: 'v2', + complexity: 'medium', + includeSkills: true, + includeTools: true, + includeExamples: true + }, (event) => { + // Enhanced trace information for batch generation + if (event.type === 'agent_updated_stream_event') { + console.log(`[BATCH TRACE] πŸ€– Agent: ${event.agent?.name || 'Unknown'} - Status updated`); + } else if (event.type === 'run_item_stream_event') { + if (event.item?.type === 'tool_call_item') { + console.log(`[BATCH TRACE] πŸ”§ Tool Call: ${event.item.tool_call?.function?.name || 'Unknown tool'}`); + if (event.item.tool_call?.function?.arguments) { + try { + const args = JSON.parse(event.item.tool_call.function.arguments); + console.log(`[BATCH TRACE] πŸ“‹ Tool Arguments: ${JSON.stringify(args, null, 2)}`); + } catch (e) { + console.log(`[BATCH TRACE] πŸ“‹ Tool Arguments: ${event.item.tool_call.function.arguments}`); + } + } + } else if (event.item?.type === 'tool_call_output_item') { + console.log(`[BATCH TRACE] βœ… Tool Output: Received response`); + } else if (event.item?.type === 'message_output_item') { + console.log(`[BATCH TRACE] πŸ’¬ Message: Generating response content`); + } + } else if (event.type === 'raw_model_stream_event' && event.delta?.content) { + // Show partial content being generated (throttled) + process.stdout.write('.'); + } else if (event.type === 'run_started_stream_event') { + console.log(`[BATCH TRACE] πŸš€ Run Started: Beginning agent execution for ${domain}`); + } else if (event.type === 'run_completed_stream_event') { + console.log(`[BATCH TRACE] 🏁 Run Completed: Agent execution finished for ${domain}`); + } + }); + + console.log(); // New line after dots + batchResults.push(result); + + // Save batch result immediately + const filepath = join(examplesDir, `batch-${result.filename}.${result.extension}`); + writeFileSync(filepath, result.content); + console.log(`βœ… Batch generated: ${filepath}`); + console.log(); + + } catch (error) { + console.error(`❌ Error in batch generation for ${domain}:`, error); + } + } + + console.log('\nπŸŽ‰ Agent capability demonstration complete!'); + console.log(`πŸ“ All examples saved to: ${examplesDir}`); + + // Show summary + console.log('\nπŸ“Š Generation Summary:'); + console.log(` Individual examples: ${examples.length}`); + console.log(` Batch examples: ${batchResults.length}`); + console.log(` Total files generated: ${examples.length + batchResults.length}`); + console.log(` Available templates: ${templates.length}`); +} + +// Run the demonstration +demonstrateAgentCapabilities().catch(console.error); diff --git a/lib/__tests__/v1.test.ts b/lib/__tests__/v1.test.ts new file mode 100644 index 0000000..ebd5f59 --- /dev/null +++ b/lib/__tests__/v1.test.ts @@ -0,0 +1,252 @@ +import { expect, test, describe } from "bun:test"; +import { ProfessionModel, Domain, Specialization, Role, Responsibility, Attribute } from "../v1.ts"; + +describe("V1 Professional Hierarchy Model", () => { + describe("Attribute Model", () => { + test("should create an attribute with required fields", () => { + const attribute = Attribute.create({ + name: "JavaScript", + type: "Skill" + }); + + expect(attribute.name).toBe("JavaScript"); + expect(attribute.type).toBe("Skill"); + expect(attribute.description).toBe(""); + }); + + test("should create an attribute with description", () => { + const attribute = Attribute.create({ + name: "React", + type: "Tool", + description: "Frontend library for building user interfaces" + }); + + expect(attribute.name).toBe("React"); + expect(attribute.type).toBe("Tool"); + expect(attribute.description).toBe("Frontend library for building user interfaces"); + }); + + test("should accept all valid attribute types", () => { + const skill = Attribute.create({ name: "Problem Solving", type: "Skill" }); + const tool = Attribute.create({ name: "VS Code", type: "Tool" }); + const trait = Attribute.create({ name: "Leadership", type: "Trait" }); + + expect(skill.type).toBe("Skill"); + expect(tool.type).toBe("Tool"); + expect(trait.type).toBe("Trait"); + }); + }); + + describe("Responsibility Model", () => { + test("should create a responsibility with required attributes", () => { + const jsAttribute = Attribute.create({ name: "JavaScript", type: "Skill" }); + const reactAttribute = Attribute.create({ name: "React", type: "Tool" }); + + const responsibility = Responsibility.create({ + title: "Build User Interfaces", + outcome: "Functional and responsive web applications", + requiredAttributes: [jsAttribute, reactAttribute] + }); + + expect(responsibility.title).toBe("Build User Interfaces"); + expect(responsibility.outcome).toBe("Functional and responsive web applications"); + expect(responsibility.requiredAttributes).toHaveLength(2); + expect(responsibility.requiredAttributes[0].name).toBe("JavaScript"); + expect(responsibility.requiredAttributes[1].name).toBe("React"); + }); + + test("should create a responsibility with empty attributes array", () => { + const responsibility = Responsibility.create({ + title: "Code Review", + outcome: "High quality code", + requiredAttributes: [] + }); + + expect(responsibility.requiredAttributes).toHaveLength(0); + }); + }); + + describe("Role Model", () => { + test("should create a role with all seniority levels", () => { + const seniorityLevels = ["Intern", "Junior", "Mid", "Senior", "Lead", "Principal"]; + + seniorityLevels.forEach(level => { + const role = Role.create({ + title: `${level} Developer`, + responsibilities: [], + requiredAttributes: [], + seniority: level as any + }); + + expect(role.seniority).toBe(level); + }); + }); + + test("should create a role with responsibilities and attributes", () => { + const attributeForResponsibility = Attribute.create({ name: "TypeScript", type: "Skill" }); + const attributeForRole = Attribute.create({ name: "TypeScript", type: "Skill" }); + const responsibility = Responsibility.create({ + title: "Develop Features", + outcome: "Working software features", + requiredAttributes: [attributeForResponsibility] + }); + + const role = Role.create({ + title: "Frontend Developer", + responsibilities: [responsibility], + requiredAttributes: [attributeForRole], + seniority: "Mid" + }); + + expect(role.title).toBe("Frontend Developer"); + expect(role.responsibilities).toHaveLength(1); + expect(role.requiredAttributes).toHaveLength(1); + expect(role.seniority).toBe("Mid"); + }); + }); + + describe("Specialization Model", () => { + test("should create a specialization with roles and attributes", () => { + const coreAttribute = Attribute.create({ name: "Web Development", type: "Skill" }); + const role = Role.create({ + title: "Web Developer", + responsibilities: [], + requiredAttributes: [], + seniority: "Mid" + }); + + const specialization = Specialization.create({ + name: "Frontend Development", + focus: "User interface and experience", + coreAttributes: [coreAttribute], + roles: [role] + }); + + expect(specialization.name).toBe("Frontend Development"); + expect(specialization.focus).toBe("User interface and experience"); + expect(specialization.coreAttributes).toHaveLength(1); + expect(specialization.roles).toHaveLength(1); + }); + }); + + describe("Domain Model", () => { + test("should create a domain with specializations", () => { + const attribute = Attribute.create({ name: "Programming", type: "Skill" }); + const specialization = Specialization.create({ + name: "Software Engineering", + focus: "Building software systems", + coreAttributes: [], + roles: [] + }); + + const domain = Domain.create({ + name: "Technology", + description: "Technology and software development", + specializations: [specialization], + coreAttributes: [attribute] + }); + + expect(domain.name).toBe("Technology"); + expect(domain.description).toBe("Technology and software development"); + expect(domain.specializations).toHaveLength(1); + expect(domain.coreAttributes).toHaveLength(1); + }); + + test("should create a domain with empty description", () => { + const domain = Domain.create({ + name: "Engineering", + specializations: [], + coreAttributes: [] + }); + + expect(domain.description).toBe(""); + }); + }); + + describe("ProfessionModel", () => { + test("should create a profession model with domains", () => { + const domain = Domain.create({ + name: "Healthcare", + specializations: [], + coreAttributes: [] + }); + + const professionModel = ProfessionModel.create({ + domains: [domain] + }); + + expect(professionModel.domains).toHaveLength(1); + expect(professionModel.domains[0].name).toBe("Healthcare"); + }); + + test("should create an empty profession model", () => { + const professionModel = ProfessionModel.create({ + domains: [] + }); + + expect(professionModel.domains).toHaveLength(0); + }); + }); + + describe("Complete Hierarchy Integration", () => { + test("should create a complete professional hierarchy", () => { + const jsSkillForResponsibility = Attribute.create({ name: "JavaScript", type: "Skill" }); + const reactToolForResponsibility = Attribute.create({ name: "React", type: "Tool" }); + + // Create attributes for role + const jsSkillForRole = Attribute.create({ name: "JavaScript", type: "Skill" }); + const reactToolForRole = Attribute.create({ name: "React", type: "Tool" }); + const leadershipTrait = Attribute.create({ name: "Leadership", type: "Trait" }); + + const jsSkillForSpecialization = Attribute.create({ name: "JavaScript", type: "Skill" }); + const reactToolForSpecialization = Attribute.create({ name: "React", type: "Tool" }); + + const jsSkillForDomain = Attribute.create({ name: "JavaScript", type: "Skill" }); + + const responsibility = Responsibility.create({ + title: "Build React Applications", + outcome: "Scalable web applications", + requiredAttributes: [jsSkillForResponsibility, reactToolForResponsibility] + }); + + // Create role + const role = Role.create({ + title: "Senior Frontend Developer", + responsibilities: [responsibility], + requiredAttributes: [jsSkillForRole, reactToolForRole, leadershipTrait], + seniority: "Senior" + }); + + const specialization = Specialization.create({ + name: "Frontend Development", + focus: "User interfaces and client-side applications", + coreAttributes: [jsSkillForSpecialization, reactToolForSpecialization], + roles: [role] + }); + + // Create domain + const domain = Domain.create({ + name: "Software Engineering", + description: "Building software systems and applications", + specializations: [specialization], + coreAttributes: [jsSkillForDomain] + }); + + const professionModel = ProfessionModel.create({ + domains: [domain] + }); + + // Verify the complete hierarchy + expect(professionModel.domains).toHaveLength(1); + expect(professionModel.domains[0].specializations).toHaveLength(1); + expect(professionModel.domains[0].specializations[0].roles).toHaveLength(1); + expect(professionModel.domains[0].specializations[0].roles[0].responsibilities).toHaveLength(1); + + const retrievedRole = professionModel.domains[0].specializations[0].roles[0]; + expect(retrievedRole.title).toBe("Senior Frontend Developer"); + expect(retrievedRole.seniority).toBe("Senior"); + expect(retrievedRole.responsibilities[0].title).toBe("Build React Applications"); + expect(retrievedRole.requiredAttributes).toHaveLength(3); + }); + }); +}); diff --git a/lib/__tests__/v2.test.ts b/lib/__tests__/v2.test.ts new file mode 100644 index 0000000..7601812 --- /dev/null +++ b/lib/__tests__/v2.test.ts @@ -0,0 +1,476 @@ +import { expect, test, describe, beforeEach } from "bun:test"; +import { + TaskModel, + RoleModel, + FieldModel, + ProfessionModel, + IndustryModel, + DomainModel, + Enterprise, + Task, + Role, + Field, + Profession, + Industry, + Domain, + IRootStore +} from "../v2.ts"; + +describe("V2 Professional Hierarchy Model", () => { + describe("TaskModel", () => { + test("should create a task with UUID identifier", () => { + const task = TaskModel.create({ + name: "Design REST endpoints" + }); + + expect(task.name).toBe("Design REST endpoints"); + expect(task.id).toBeDefined(); + expect(typeof task.id).toBe("string"); + expect(task.id.length).toBeGreaterThan(0); + expect(task.description).toBeUndefined(); + }); + + test("should create a task with description", () => { + const task = TaskModel.create({ + name: "Write unit tests", + description: "Create comprehensive test coverage for new features" + }); + + expect(task.name).toBe("Write unit tests"); + expect(task.description).toBe("Create comprehensive test coverage for new features"); + }); + + test("should update task properties", () => { + const task = TaskModel.create({ + name: "Initial task" + }); + + task.update({ + name: "Updated task", + description: "Updated description" + }); + + expect(task.name).toBe("Updated task"); + expect(task.description).toBe("Updated description"); + }); + + test("should have unique IDs for different tasks", () => { + const task1 = TaskModel.create({ name: "Task 1" }); + const task2 = TaskModel.create({ name: "Task 2" }); + + expect(task1.id).not.toBe(task2.id); + }); + }); + + describe("RoleModel", () => { + test("should create a role with tasks", () => { + const role = RoleModel.create({ + title: "API Engineer", + summary: "Designs and implements REST APIs" + }); + + expect(role.title).toBe("API Engineer"); + expect(role.summary).toBe("Designs and implements REST APIs"); + expect(role.tasks).toHaveLength(0); + expect(role.id).toBeDefined(); + }); + + test("should add and remove tasks", () => { + const role = RoleModel.create({ + title: "Backend Developer" + }); + + role.addTask({ name: "Design database schema" }); + role.addTask({ name: "Implement API endpoints" }); + + expect(role.tasks).toHaveLength(2); + expect((role.tasks[0] as any).name).toBe("Design database schema"); + expect((role.tasks[1] as any).name ).toBe("Implement API endpoints"); + + // Remove a task + const taskToRemove = role.tasks[0]; + role.removeTask(taskToRemove); + + expect(role.tasks).toHaveLength(1); + expect((role.tasks[0] as any).name).toBe("Implement API endpoints"); + }); + + test("should return all tasks through view", () => { + const role = RoleModel.create({ + title: "Frontend Developer" + }); + + role.addTask({ name: "Build components" }); + role.addTask({ name: "Write tests" }); + + const allTasks = role.allTasks; + expect(allTasks).toHaveLength(2); + expect(allTasks[0].name).toBe("Build components"); + expect(allTasks[1].name).toBe("Write tests"); + }); + }); + + describe("FieldModel", () => { + test("should create a field with roles", () => { + const field = FieldModel.create({ + name: "Backend Development", + description: "Server-side application development" + }); + + expect(field.name).toBe("Backend Development"); + expect(field.description).toBe("Server-side application development"); + expect(field.roles).toHaveLength(0); + }); + + test("should add and remove roles", () => { + const field = FieldModel.create({ + name: "Frontend Development" + }); + + field.addRole({ title: "React Developer" }); + field.addRole({ title: "Vue Developer" }); + + expect(field.roles).toHaveLength(2); + expect(field.roles[0].title).toBe("React Developer"); + expect(field.roles[1].title).toBe("Vue Developer"); + + const roleToRemove = field.roles[0]; + field.removeRole(roleToRemove); + + expect(field.roles).toHaveLength(1); + expect(field.roles[0].title).toBe("Vue Developer"); + }); + + test("should return all tasks from nested roles", () => { + const field = FieldModel.create({ + name: "Full Stack Development" + }); + + field.addRole({ title: "Frontend Developer" }); + field.addRole({ title: "Backend Developer" }); + + // Add tasks to roles + field.roles[0].addTask({ name: "Build UI components" }); + field.roles[0].addTask({ name: "Handle user interactions" }); + field.roles[1].addTask({ name: "Design APIs" }); + + const allTasks = field.allTasks; + expect(allTasks).toHaveLength(3); + expect(allTasks.map(t => t.name)).toContain("Build UI components"); + expect(allTasks.map(t => t.name)).toContain("Handle user interactions"); + expect(allTasks.map(t => t.name)).toContain("Design APIs"); + }); + }); + + describe("ProfessionModel", () => { + test("should create a profession with fields", () => { + const profession = ProfessionModel.create({ + name: "Software Engineering", + description: "Building software systems and applications" + }); + + expect(profession.name).toBe("Software Engineering"); + expect(profession.description).toBe("Building software systems and applications"); + expect(profession.fields).toHaveLength(0); + }); + + test("should add and remove fields", () => { + const profession = ProfessionModel.create({ + name: "Web Development" + }); + + profession.addField({ name: "Frontend" }); + profession.addField({ name: "Backend" }); + + expect(profession.fields).toHaveLength(2); + expect(profession.fields[0].name).toBe("Frontend"); + expect(profession.fields[1].name).toBe("Backend"); + + const fieldToRemove = profession.fields[0]; + profession.removeField(fieldToRemove); + + expect(profession.fields).toHaveLength(1); + expect(profession.fields[0].name).toBe("Backend"); + }); + + test("should return all tasks from nested hierarchy", () => { + const profession = ProfessionModel.create({ + name: "Software Engineering" + }); + + profession.addField({ name: "Backend" }); + profession.fields[0].addRole({ title: "API Developer" }); + profession.fields[0].roles[0].addTask({ name: "Design REST endpoints" }); + profession.fields[0].roles[0].addTask({ name: "Implement authentication" }); + + const allTasks = profession.allTasks; + expect(allTasks).toHaveLength(2); + expect(allTasks.map(t => t.name)).toContain("Design REST endpoints"); + expect(allTasks.map(t => t.name)).toContain("Implement authentication"); + }); + }); + + describe("IndustryModel", () => { + test("should create an industry with professions", () => { + const industry = IndustryModel.create({ + name: "Software", + description: "Software development and technology" + }); + + expect(industry.name).toBe("Software"); + expect(industry.description).toBe("Software development and technology"); + expect(industry.professions).toHaveLength(0); + }); + + test("should add and remove professions", () => { + const industry = IndustryModel.create({ + name: "Technology" + }); + + industry.addProfession({ name: "Software Engineering" }); + industry.addProfession({ name: "Data Science" }); + + expect(industry.professions).toHaveLength(2); + expect(industry.professions[0].name).toBe("Software Engineering"); + expect(industry.professions[1].name).toBe("Data Science"); + + // Remove a profession + const professionToRemove = industry.professions[0]; + industry.removeProfession(professionToRemove); + + expect(industry.professions).toHaveLength(1); + expect(industry.professions[0].name).toBe("Data Science"); + }); + + test("should return all tasks from nested hierarchy", () => { + const industry = IndustryModel.create({ + name: "Software" + }); + + industry.addProfession({ name: "Web Development" }); + industry.professions[0].addField({ name: "Frontend" }); + industry.professions[0].fields[0].addRole({ title: "React Developer" }); + industry.professions[0].fields[0].roles[0].addTask({ name: "Build components" }); + industry.professions[0].fields[0].roles[0].addTask({ name: "Manage state" }); + + const allTasks = industry.allTasks; + expect(allTasks).toHaveLength(2); + expect(allTasks.map(t => t.name)).toContain("Build components"); + expect(allTasks.map(t => t.name)).toContain("Manage state"); + }); + }); + + describe("DomainModel", () => { + test("should create a domain with industries", () => { + const domain = DomainModel.create({ + name: "STEM", + description: "Science, Technology, Engineering, and Mathematics" + }); + + expect(domain.name).toBe("STEM"); + expect(domain.description).toBe("Science, Technology, Engineering, and Mathematics"); + expect(domain.industries).toHaveLength(0); + }); + + test("should add and remove industries", () => { + const domain = DomainModel.create({ + name: "Technology" + }); + + domain.addIndustry({ name: "Software" }); + domain.addIndustry({ name: "Hardware" }); + + expect(domain.industries).toHaveLength(2); + expect(domain.industries[0].name).toBe("Software"); + expect(domain.industries[1].name).toBe("Hardware"); + + const industryToRemove = domain.industries[0]; + domain.removeIndustry(industryToRemove); + + expect(domain.industries).toHaveLength(1); + expect(domain.industries[0].name).toBe("Hardware"); + }); + + test("should return all tasks from nested hierarchy", () => { + const domain = DomainModel.create({ + name: "STEM" + }); + + domain.addIndustry({ name: "Software" }); + domain.industries[0].addProfession({ name: "Software Engineering" }); + domain.industries[0].professions[0].addField({ name: "Backend" }); + domain.industries[0].professions[0].fields[0].addRole({ title: "API Engineer" }); + domain.industries[0].professions[0].fields[0].roles[0].addTask({ name: "Design REST endpoints" }); + + const allTasks = domain.allTasks; + expect(allTasks).toHaveLength(1); + expect(allTasks[0].name).toBe("Design REST endpoints"); + }); + }); + + describe("Enterprise", () => { + let store: IRootStore; + + beforeEach(() => { + store = Enterprise.create({}); + }); + + test("should create an empty root store", () => { + expect(store.domains).toHaveLength(0); + }); + + test("should add domains", () => { + store.addDomain({ name: "STEM" }); + store.addDomain({ name: "Arts" }); + + expect(store.domains).toHaveLength(2); + expect(store.domains[0].name).toBe("STEM"); + expect(store.domains[1].name).toBe("Arts"); + }); + + test("should return all tasks from entire hierarchy", () => { + store.addDomain({ name: "STEM" }); + store.domains[0].addIndustry({ name: "Software" }); + store.domains[0].industries[0].addProfession({ name: "Software Engineering" }); + store.domains[0].industries[0].professions[0].addField({ name: "Backend" }); + store.domains[0].industries[0].professions[0].fields[0].addRole({ title: "API Engineer" }); + store.domains[0].industries[0].professions[0].fields[0].roles[0].addTask({ name: "Design REST endpoints" }); + store.domains[0].industries[0].professions[0].fields[0].roles[0].addTask({ name: "Implement authentication" }); + + const allTasks = store.allTasks; + expect(allTasks).toHaveLength(2); + expect(allTasks.map(t => t.name)).toContain("Design REST endpoints"); + expect(allTasks.map(t => t.name)).toContain("Implement authentication"); + }); + }); + + describe("Complete Hierarchy Integration", () => { + test("should create and manipulate a complete 6-layer hierarchy", () => { + const store = Enterprise.create({}); + + // Build the complete hierarchy as shown in the example + store.addDomain({ name: "STEM" }); + store.domains[0].addIndustry({ name: "Software" }); + store.domains[0].industries[0].addProfession({ name: "Software Engineering" }); + store.domains[0].industries[0].professions[0].addField({ name: "Backend" }); + store.domains[0].industries[0].professions[0].fields[0].addRole({ title: "API Engineer" }); + store.domains[0].industries[0].professions[0].fields[0].roles[0].addTask({ name: "Design REST endpoints" }); + + expect(store.domains).toHaveLength(1); + expect(store.domains[0].industries).toHaveLength(1); + expect(store.domains[0].industries[0].professions).toHaveLength(1); + expect(store.domains[0].industries[0].professions[0].fields).toHaveLength(1); + expect(store.domains[0].industries[0].professions[0].fields[0].roles).toHaveLength(1); + expect(store.domains[0].industries[0].professions[0].fields[0].roles[0].tasks).toHaveLength(1); + + // Verify data integrity through the hierarchy + const task = store.domains[0].industries[0].professions[0].fields[0].roles[0].tasks[0]; + expect(task.name).toBe("Design REST endpoints"); + + expect(store.allTasks).toHaveLength(1); + expect(store.domains[0].allTasks).toHaveLength(1); + expect(store.domains[0].industries[0].allTasks).toHaveLength(1); + expect(store.domains[0].industries[0].professions[0].allTasks).toHaveLength(1); + expect(store.domains[0].industries[0].professions[0].fields[0].allTasks).toHaveLength(1); + + // Add more tasks and verify aggregation + store.domains[0].industries[0].professions[0].fields[0].roles[0].addTask({ name: "Implement authentication" }); + store.domains[0].industries[0].professions[0].fields[0].addRole({ title: "Database Engineer" }); + store.domains[0].industries[0].professions[0].fields[0].roles[1].addTask({ name: "Design database schema" }); + + expect(store.allTasks).toHaveLength(3); + expect(store.domains[0].industries[0].professions[0].fields[0].allTasks).toHaveLength(3); + }); + + test("should handle multiple parallel hierarchies", () => { + const store = Enterprise.create({}); + + store.addDomain({ name: "STEM" }); + store.domains[0].addIndustry({ name: "Software" }); + store.domains[0].industries[0].addProfession({ name: "Web Development" }); + store.domains[0].industries[0].professions[0].addField({ name: "Frontend" }); + store.domains[0].industries[0].professions[0].fields[0].addRole({ title: "React Developer" }); + store.domains[0].industries[0].professions[0].fields[0].roles[0].addTask({ name: "Build components" }); + + // Create second hierarchy branch + store.addDomain({ name: "Arts" }); + store.domains[1].addIndustry({ name: "Digital Media" }); + store.domains[1].industries[0].addProfession({ name: "Graphic Design" }); + store.domains[1].industries[0].professions[0].addField({ name: "Web Design" }); + store.domains[1].industries[0].professions[0].fields[0].addRole({ title: "UI Designer" }); + store.domains[1].industries[0].professions[0].fields[0].roles[0].addTask({ name: "Create mockups" }); + + expect(store.domains).toHaveLength(2); + expect(store.allTasks).toHaveLength(2); + expect(store.allTasks.map(t => t.name)).toContain("Build components"); + expect(store.allTasks.map(t => t.name)).toContain("Create mockups"); + + // Verify each domain has its own tasks + expect(store.domains[0].allTasks).toHaveLength(1); + expect(store.domains[1].allTasks).toHaveLength(1); + expect(store.domains[0].allTasks[0].name).toBe("Build components"); + expect(store.domains[1].allTasks[0].name).toBe("Create mockups"); + }); + }); + + describe("CRUD Operations", () => { + test("should support task updates and removal", () => { + const role = RoleModel.create({ title: "Developer" }); + role.addTask({ name: "Initial task", description: "Initial description" }); + + const task = role.tasks[0]; + const originalId = task.id; + + task.update({ name: "Updated task", description: "Updated description" }); + expect(task.name).toBe("Updated task"); + expect(task.description).toBe("Updated description"); + expect(task.id).toBe(originalId); // ID should remain the same + + // Remove task through parent + expect(role.tasks).toHaveLength(1); + role.removeTask(task); + expect(role.tasks).toHaveLength(0); + }); + + test("should support role removal", () => { + const field = FieldModel.create({ name: "Development" }); + field.addRole({ title: "Developer" }); + + expect(field.roles).toHaveLength(1); + const role = field.roles[0]; + field.removeRole(role); + expect(field.roles).toHaveLength(0); + }); + + test("should support field removal", () => { + const profession = ProfessionModel.create({ name: "Engineering" }); + profession.addField({ name: "Software" }); + + expect(profession.fields).toHaveLength(1); + const field = profession.fields[0]; + profession.removeField(field); + expect(profession.fields).toHaveLength(0); + }); + + test("should support profession removal", () => { + const industry = IndustryModel.create({ name: "Tech" }); + industry.addProfession({ name: "Software Engineering" }); + + expect(industry.professions).toHaveLength(1); + const profession = industry.professions[0]; + industry.removeProfession(profession); + expect(industry.professions).toHaveLength(0); + }); + + test("should support industry removal", () => { + const domain = DomainModel.create({ name: "STEM" }); + domain.addIndustry({ name: "Software" }); + + expect(domain.industries).toHaveLength(1); + const industry = domain.industries[0]; + domain.removeIndustry(industry); + expect(domain.industries).toHaveLength(0); + }); + + }); +}); diff --git a/lib/agent-wrapper.ts b/lib/agent-wrapper.ts new file mode 100644 index 0000000..a317d16 --- /dev/null +++ b/lib/agent-wrapper.ts @@ -0,0 +1,203 @@ +import { Agent, StreamedRunResult } from '@openai/agents'; +import HierarchyGenerator, { GenerationParams } from './components/hierarchy-generator'; +import TemplateManager, { DomainTemplate } from './components/template-manager'; +import OutputFormatter, { OutputOptions, FormattedOutput } from './components/output-formatter'; + +export interface AgentConfig { + name: string; + instructions: string; + model?: string; +} + +export interface HierarchyGenerationOptions extends GenerationParams { + outputFormat?: OutputOptions; + templateKey?: string; + stream?: boolean; +} + +export class HierarchyAgent { + private agent: Agent; + private generator: HierarchyGenerator; + private templateManager: TemplateManager; + private outputFormatter: OutputFormatter; + + constructor(config: AgentConfig) { + this.agent = new Agent({ + name: config.name, + instructions: config.instructions, + model: config.model || 'gpt-4o-mini' + }); + + this.generator = new HierarchyGenerator(this.agent); + this.templateManager = new TemplateManager(); + this.outputFormatter = new OutputFormatter(); + } + + async generateHierarchy(options: HierarchyGenerationOptions): Promise { + let template: DomainTemplate; + + if (options.templateKey) { + template = this.templateManager.getTemplate(options.templateKey); + if (!template) { + throw new Error(`Template not found: ${options.templateKey}`); + } + } else { + // Create a default template for the domain + const version = options.version || 'v2'; + template = this.templateManager.createCustomTemplate( + `${options.domain}-${version}`, + options.domain, + version + ); + } + + const generationParams: GenerationParams = { + domain: options.domain, + complexity: options.complexity || 'medium', + includeSkills: options.includeSkills ?? true, + includeTools: options.includeTools ?? true, + includeExamples: options.includeExamples ?? true, + stream: options.stream + }; + + const content = await this.generator.generateFromTemplate(template, generationParams); + + // If streaming, return the stream directly + if (options.stream && content instanceof Object && 'toStream' in content) { + return content as StreamedRunResult; + } + + const outputOptions = options.outputFormat || this.outputFormatter.getDefaultOptions(); + const formattedOutput = this.outputFormatter.formatOutput( + content as string, + options.domain, + template.version, + outputOptions + ); + + return formattedOutput; + } + + // New method for streaming with enhanced visibility + async generateHierarchyWithStreaming( + options: HierarchyGenerationOptions, + onStreamEvent?: (event: any) => void + ): Promise { + let template: DomainTemplate; + + if (options.templateKey) { + template = this.templateManager.getTemplate(options.templateKey); + if (!template) { + throw new Error(`Template not found: ${options.templateKey}`); + } + } else { + // Create a default template for the domain + const version = options.version || 'v2'; + template = this.templateManager.createCustomTemplate( + `${options.domain}-${version}`, + options.domain, + version + ); + } + + const generationParams: GenerationParams = { + domain: options.domain, + complexity: options.complexity || 'medium', + includeSkills: options.includeSkills ?? true, + includeTools: options.includeTools ?? true, + includeExamples: options.includeExamples ?? true + }; + + const content = await this.generator.generateFromTemplateWithStreaming( + template, + generationParams, + onStreamEvent + ); + + // Format the output + const outputOptions = options.outputFormat || this.outputFormatter.getDefaultOptions(); + const formattedOutput = this.outputFormatter.formatOutput( + content, + options.domain, + template.version, + outputOptions + ); + + return formattedOutput; + } + + async generateExample( + domain: string, + version: 'v1' | 'v2' = 'v2', + complexity: 'simple' | 'medium' | 'complex' = 'medium' + ): Promise { + return this.generateHierarchy({ + domain, + version, + complexity, + includeSkills: true, + includeTools: true, + includeExamples: true + }); + } + + // Template management methods + getAvailableTemplates(): DomainTemplate[] { + return this.templateManager.getAllTemplates(); + } + + getTemplatesByDomain(domain: string): DomainTemplate[] { + return this.templateManager.getTemplatesByDomain(domain); + } + + getTemplatesByVersion(version: 'v1' | 'v2'): DomainTemplate[] { + return this.templateManager.getTemplatesByVersion(version); + } + + addCustomTemplate(key: string, template: DomainTemplate): void { + this.templateManager.addTemplate(key, template); + } + + // Validation and optimization methods + async validateHierarchy(hierarchyData: any): Promise { + // TODO: Implement validation logic using the agent + // Could validate structure, naming conventions, completeness, etc. + return true; + } + + async optimizeHierarchy(hierarchyData: any): Promise { + // TODO: Implement optimization logic using the agent + // Could suggest improvements, fill gaps, optimize structure, etc. + return hierarchyData; + } + + // Batch generation methods + async generateMultipleExamples( + domains: string[], + version: 'v1' | 'v2' = 'v2', + outputFormat?: OutputOptions + ): Promise { + const results: FormattedOutput[] = []; + + for (const domain of domains) { + try { + const result = await this.generateHierarchy({ + domain, + version, + complexity: 'medium', + includeSkills: true, + includeTools: true, + includeExamples: true, + outputFormat + }); + results.push(result); + } catch (error) { + console.error(`Error generating example for ${domain}:`, error); + } + } + + return results; + } +} + +export default HierarchyAgent; diff --git a/lib/components/hierarchy-generator.ts b/lib/components/hierarchy-generator.ts new file mode 100644 index 0000000..d7b7bda --- /dev/null +++ b/lib/components/hierarchy-generator.ts @@ -0,0 +1,115 @@ +import { Agent, run, StreamedRunResult } from '@openai/agents'; + +export interface HierarchyTemplate { + version: 'v1' | 'v2'; + structure: string[]; + description: string; +} + +export interface GenerationParams { + domain: string; + complexity: 'simple' | 'medium' | 'complex'; + includeSkills: boolean; + includeTools: boolean; + includeExamples: boolean; + stream?: boolean; +} + +export class HierarchyGenerator { + private agent: Agent; + + constructor(agent: Agent) { + this.agent = agent; + } + + async generateFromTemplate(template: HierarchyTemplate, params: GenerationParams): Promise { + const prompt = this.buildPrompt(template, params); + + if (params.stream) { + return await run(this.agent, prompt, { stream: true }); + } else { + const result = await run(this.agent, prompt); + return result.finalOutput; + } + } + + // Helper method to stream and collect final output + async generateFromTemplateWithStreaming( + template: HierarchyTemplate, + params: GenerationParams, + onStreamEvent?: (event: any) => void + ): Promise { + const prompt = this.buildPrompt(template, params); + console.log('πŸ”„ Starting hierarchy generation...'); + + const stream = await run(this.agent, prompt, { stream: true }); + let content = ''; + + for await (const event of stream) { + if (event.type === 'raw_model_stream_event' && event.data.delta) { + // console.log(event.data.delta) + content += event.delta; + process.stdout.write(event.data.delta); + } + + if (event.type === 'agent_updated_stream_event') { + console.log(`\nπŸ“ Agent: ${event.agent.name} is processing...`); + } else if (event.type === 'run_item_stream_event') { + if (event.item.type === 'tool_call_item') { + console.log('\nπŸ”§ Tool being called...'); + } else if (event.item.type === 'message_output_item') { + console.log('\nπŸ’¬ Generating response...'); + } + } + + // Allow custom event handling + if (onStreamEvent) { + onStreamEvent(event); + } + } + + console.log('\nβœ… Hierarchy generation complete!'); + return stream.finalOutput; + } + + private buildPrompt(template: HierarchyTemplate, params: GenerationParams): string { + const structureDescription = template.version === 'v1' + ? 'Domain β†’ Specialization β†’ Role β†’ Responsibility' + : 'Domain β†’ Industry β†’ Profession β†’ Field β†’ Role β†’ Task'; + + const importStatement = template.version === 'v1' + ? 'import { Enterprise, DomainModel, SpecializationModel, RoleModel, ResponsibilityModel } from "../../lib/v1";' + : 'import { Enterprise, DomainModel, IndustryModel, ProfessionModel, FieldModel, RoleModel, TaskModel } from "../../lib/v2";'; + + return ` +Generate ONLY TypeScript code for a professional hierarchy in the ${params.domain} domain using the ${template.version} structure. + +Structure: ${structureDescription} +Complexity Level: ${params.complexity} +${params.includeSkills ? 'βœ“ Include relevant skills and competencies' : ''} +${params.includeTools ? 'βœ“ Include tools and technologies' : ''} +${params.includeExamples ? 'βœ“ Include practical examples and use cases' : ''} + +IMPORTANT: Output ONLY valid TypeScript code. Do not include any markdown, explanations, or comments outside of TypeScript comments. + +Requirements: +1. Start with the import statement: ${importStatement} +2. Create a realistic, comprehensive hierarchy using MobX State Tree models +3. Use appropriate professional terminology +4. Ensure logical relationships between levels +5. ${params.complexity === 'complex' ? 'Include multiple branches and detailed attributes' : + params.complexity === 'medium' ? 'Include moderate detail with key attributes' : + 'Keep it simple with essential elements only'} + +The code should demonstrate: +- Creating the hierarchy structure using the imported models +- Adding relevant attributes (skills, tools, examples) +- Basic operations (create, read, update) +- Real-world application examples as TypeScript code + +Output format: Pure TypeScript code only, no markdown or explanations. +`; + } +} + +export default HierarchyGenerator; diff --git a/lib/components/output-formatter.ts b/lib/components/output-formatter.ts new file mode 100644 index 0000000..67ce7b5 --- /dev/null +++ b/lib/components/output-formatter.ts @@ -0,0 +1,278 @@ +export interface OutputOptions { + format: 'typescript' | 'markdown' | 'json' | 'yaml'; + includeMetadata: boolean; + includeTimestamp: boolean; + includeComments: boolean; +} + +export interface FormattedOutput { + content: string; + filename: string; + extension: string; + metadata?: any; +} + +export class OutputFormatter { + formatOutput( + content: string, + domain: string, + version: 'v1' | 'v2', + options: OutputOptions + ): FormattedOutput { + switch (options.format) { + case 'typescript': + return this.formatTypeScript(content, domain, version, options); + case 'markdown': + return this.formatMarkdown(content, domain, version, options); + case 'json': + return this.formatJSON(content, domain, version, options); + case 'yaml': + return this.formatYAML(content, domain, version, options); + default: + throw new Error(`Unsupported format: ${options.format}`); + } + } + + private formatTypeScript( + content: string, + domain: string, + version: 'v1' | 'v2', + options: OutputOptions + ): FormattedOutput { + const header = options.includeComments ? `/** + * ${domain} Professional Hierarchy Example + * Generated using OpenAI Agents SDK and Sumpin Professional Hierarchy Models + * Model Version: ${version} (${version === 'v1' ? '4-layer' : '6-layer'} hierarchy) + * ${options.includeTimestamp ? `Generated on: ${new Date().toISOString()}` : ''} + */ + +` : ''; + + const imports = `import { + Enterprise, + ${version === 'v1' ? 'DomainModel, SpecializationModel, RoleModel, ResponsibilityModel' : 'DomainModel, IndustryModel, ProfessionModel, FieldModel, RoleModel, TaskModel'} +} from "../../lib/${version}"; + +`; + + const cleanedContent = this.extractTypeScriptCode(content); + + return { + content: header + imports + cleanedContent, + filename: `${domain.toLowerCase()}-hierarchy-example`, + extension: 'ts', + metadata: { + domain, + version, + generatedAt: options.includeTimestamp ? new Date().toISOString() : undefined + } + }; + } + + private extractTypeScriptCode(content: string): string { + let cleaned = content; + + cleaned = cleaned.replace(/^#{1,6}\s+.*$/gm, ''); + + cleaned = cleaned.replace(/\*\*([^*]+)\*\*/g, '$1'); + cleaned = cleaned.replace(/\*([^*]+)\*/g, '$1'); + + // Remove markdown lists that aren't TypeScript code + cleaned = cleaned.replace(/^[\s]*[-*+]\s+\*\*([^*]+)\*\*$/gm, ''); + cleaned = cleaned.replace(/^[\s]*[-*+]\s+([^:]+):$/gm, ''); + + // Extract TypeScript code blocks + const codeBlockRegex = /```typescript\s*([\s\S]*?)```/g; + const codeBlocks = []; + let match; + + while ((match = codeBlockRegex.exec(content)) !== null) { + codeBlocks.push(match[1].trim()); + } + + // If we found code blocks, use them + if (codeBlocks.length > 0) { + return codeBlocks.join('\n\n'); + } + + // Otherwise, try to extract TypeScript-like content + const lines = cleaned.split('\n'); + const tsLines = []; + let inCodeSection = false; + + for (const line of lines) { + const trimmed = line.trim(); + + // Skip empty lines and markdown-like content + if (!trimmed || + trimmed.startsWith('#') || + trimmed.startsWith('*') || + trimmed.startsWith('-') || + trimmed.includes('Below is') || + trimmed.includes('Here\'s') || + trimmed.includes('TypeScript Code') || + trimmed.includes('Professional Hierarchy')) { + continue; + } + + // Look for TypeScript patterns + if (trimmed.includes('interface ') || + trimmed.includes('class ') || + trimmed.includes('type ') || + trimmed.includes('const ') || + trimmed.includes('let ') || + trimmed.includes('var ') || + trimmed.includes('function ') || + trimmed.includes('export ') || + trimmed.includes('import ') || + trimmed.includes('{') || + trimmed.includes('}') || + trimmed.includes(';') || + inCodeSection) { + + tsLines.push(line); + inCodeSection = true; + + // End code section on certain patterns + if (trimmed === '}' && !line.includes(',')) { + inCodeSection = false; + } + } + } + + return tsLines.join('\n').trim() || cleaned.trim(); + } + + private formatMarkdown( + content: string, + domain: string, + version: 'v1' | 'v2', + options: OutputOptions + ): FormattedOutput { + const header = `# ${domain.charAt(0).toUpperCase() + domain.slice(1)} Professional Hierarchy Example + +Generated using OpenAI Agents SDK and Sumpin Professional Hierarchy Models + +## Overview + +This example demonstrates a ${version} professional hierarchy model for the ${domain} domain. + +**Model Version:** ${version} (${version === 'v1' ? '4-layer' : '6-layer'} hierarchy) +${options.includeTimestamp ? `**Generated on:** ${new Date().toISOString()}` : ''} + +## Structure + +${version === 'v1' ? 'Domain β†’ Specialization β†’ Role β†’ Responsibility' : 'Domain β†’ Industry β†’ Profession β†’ Field β†’ Role β†’ Task'} + +## Generated Content + +\`\`\`typescript +${content} +\`\`\` + +## Usage + +To use this example: + +1. Ensure you have the required dependencies installed: + \`\`\`bash + bun add mobx-state-tree mobx uuid + bun add -d @types/uuid + \`\`\` + +2. Run the example: + \`\`\`bash + bun run examples/generated/${domain.toLowerCase()}-hierarchy-example.ts + \`\`\` + +--- +*This example was generated automatically and demonstrates best practices for professional hierarchy modeling.* +`; + + return { + content: header, + filename: `${domain.toLowerCase()}-hierarchy-example`, + extension: 'md', + metadata: { + domain, + version, + generatedAt: options.includeTimestamp ? new Date().toISOString() : undefined + } + }; + } + + private formatJSON( + content: string, + domain: string, + version: 'v1' | 'v2', + options: OutputOptions + ): FormattedOutput { + const data = { + domain, + version, + structure: version === 'v1' + ? ['Domain', 'Specialization', 'Role', 'Responsibility'] + : ['Domain', 'Industry', 'Profession', 'Field', 'Role', 'Task'], + generatedContent: content, + ...(options.includeMetadata && { + metadata: { + generatedAt: options.includeTimestamp ? new Date().toISOString() : undefined, + generator: 'OpenAI Agents SDK + Sumpin', + hierarchyType: `${version === 'v1' ? '4' : '6'}-layer hierarchy` + } + }) + }; + + return { + content: JSON.stringify(data, null, 2), + filename: `${domain.toLowerCase()}-hierarchy-example`, + extension: 'json', + metadata: data.metadata + }; + } + + private formatYAML( + content: string, + domain: string, + version: 'v1' | 'v2', + options: OutputOptions + ): FormattedOutput { + const yamlContent = `domain: ${domain} +version: ${version} +structure: +${(version === 'v1' + ? ['Domain', 'Specialization', 'Role', 'Responsibility'] + : ['Domain', 'Industry', 'Profession', 'Field', 'Role', 'Task'] + ).map(item => ` - ${item}`).join('\n')} + +generated_content: | +${content.split('\n').map(line => ` ${line}`).join('\n')} + +${options.includeMetadata ? `metadata: + generated_at: ${options.includeTimestamp ? new Date().toISOString() : 'null'} + generator: "OpenAI Agents SDK + Sumpin" + hierarchy_type: "${version === 'v1' ? '4' : '6'}-layer hierarchy"` : ''}`; + + return { + content: yamlContent, + filename: `${domain.toLowerCase()}-hierarchy-example`, + extension: 'yaml', + metadata: { + domain, + version, + generatedAt: options.includeTimestamp ? new Date().toISOString() : undefined + } + }; + } + + getDefaultOptions(): OutputOptions { + return { + format: 'typescript', + includeMetadata: true, + includeTimestamp: true, + includeComments: true + }; + } +} + +export default OutputFormatter; diff --git a/lib/components/template-manager.ts b/lib/components/template-manager.ts new file mode 100644 index 0000000..6b73fd1 --- /dev/null +++ b/lib/components/template-manager.ts @@ -0,0 +1,81 @@ +import { HierarchyTemplate } from './hierarchy-generator'; +import v1Finance from "./templates/v1-finance.ts"; +import v1Tech from "./templates/v1-tech.ts"; +import v2Edu from "./templates/v2-edu.ts"; +import v2Healthcare from "./templates/v2-healthcare.ts"; +import v2Tech from "./templates/v2-tech.ts"; + +export interface DomainTemplate extends HierarchyTemplate { + domain: string; + commonSkills: string[]; + commonTools: string[]; + examples: string[]; +} + +export class TemplateManager { + private templates: Map = new Map(); + + constructor() { + this.initializeDefaultTemplates(); + } + + private initializeDefaultTemplates() { + // V2 Templates (6-layer hierarchy) + this.addTemplate('technology-v2', v2Tech); + this.addTemplate('healthcare-v2', v2Healthcare); + this.addTemplate('education-v2', v2Edu); + + // V1 Templates (4-layer hierarchy) + this.addTemplate('technology-v1', v1Tech); + this.addTemplate('finance-v1', v1Finance); + } + + addTemplate(key: string, template: DomainTemplate): void { + this.templates.set(key, template); + } + + getTemplate(key: string): DomainTemplate | undefined { + return this.templates.get(key); + } + + getTemplatesByVersion(version: 'v1' | 'v2'): DomainTemplate[] { + return Array.from(this.templates.values()).filter(t => t.version === version); + } + + getTemplatesByDomain(domain: string): DomainTemplate[] { + return Array.from(this.templates.values()).filter(t => + t.domain.toLowerCase().includes(domain.toLowerCase()) + ); + } + + getAllTemplates(): DomainTemplate[] { + return Array.from(this.templates.values()); + } + + createCustomTemplate( + key: string, + domain: string, + version: 'v1' | 'v2', + options: Partial = {} + ): DomainTemplate { + const structure = version === 'v1' + ? ['Domain', 'Specialization', 'Role', 'Responsibility'] + : ['Domain', 'Industry', 'Profession', 'Field', 'Role', 'Task']; + + const template: DomainTemplate = { + version, + domain, + structure, + description: `${domain} professional hierarchy`, + commonSkills: [], + commonTools: [], + examples: [], + ...options + }; + + this.addTemplate(key, template); + return template; + } +} + +export default TemplateManager; \ No newline at end of file diff --git a/lib/components/templates/v1-finance.ts b/lib/components/templates/v1-finance.ts new file mode 100644 index 0000000..f7f1beb --- /dev/null +++ b/lib/components/templates/v1-finance.ts @@ -0,0 +1,9 @@ +export default { + version: 'v1', + domain: 'Finance', + structure: ['Domain', 'Specialization', 'Role', 'Responsibility'], + description: 'Simplified finance sector hierarchy', + commonSkills: ['Financial Analysis', 'Risk Assessment', 'Compliance', 'Reporting'], + commonTools: ['Excel', 'Financial Software', 'Analytics Tools', 'Reporting Systems'], + examples: ['Investment Banking', 'Corporate Finance', 'Risk Management', 'Accounting'] +} \ No newline at end of file diff --git a/lib/components/templates/v1-tech.ts b/lib/components/templates/v1-tech.ts new file mode 100644 index 0000000..8c48374 --- /dev/null +++ b/lib/components/templates/v1-tech.ts @@ -0,0 +1,9 @@ +export default { + version: 'v1', + domain: 'Technology', + structure: ['Domain', 'Specialization', 'Role', 'Responsibility'], + description: 'Simplified technology sector hierarchy', + commonSkills: ['Programming', 'System Design', 'Testing', 'Documentation'], + commonTools: ['Code Editors', 'Version Control', 'Build Tools', 'Monitoring'], + examples: ['Web Development', 'Mobile Development', 'Backend Systems', 'Frontend UI'] +} \ No newline at end of file diff --git a/lib/components/templates/v2-edu.ts b/lib/components/templates/v2-edu.ts new file mode 100644 index 0000000..15b06c1 --- /dev/null +++ b/lib/components/templates/v2-edu.ts @@ -0,0 +1,9 @@ +export default { + version: 'v2', + domain: 'Education', + structure: ['Domain', 'Industry', 'Profession', 'Field', 'Role', 'Task'], + description: 'Comprehensive education sector hierarchy', + commonSkills: ['Teaching', 'Curriculum Development', 'Assessment', 'Student Engagement'], + commonTools: ['LMS', 'Educational Software', 'Assessment Tools', 'Communication Platforms'], + examples: ['K-12 Education', 'Higher Education', 'Corporate Training', 'Online Learning'] +} \ No newline at end of file diff --git a/lib/components/templates/v2-healthcare.ts b/lib/components/templates/v2-healthcare.ts new file mode 100644 index 0000000..5a97443 --- /dev/null +++ b/lib/components/templates/v2-healthcare.ts @@ -0,0 +1,9 @@ +export default { + version: 'v2', + domain: 'Healthcare', + structure: ['Domain', 'Industry', 'Profession', 'Field', 'Role', 'Task'], + description: 'Comprehensive healthcare sector hierarchy', + commonSkills: ['Patient Care', 'Medical Knowledge', 'Communication', 'Empathy'], + commonTools: ['EMR Systems', 'Medical Devices', 'Diagnostic Tools', 'Communication Systems'], + examples: ['Clinical Care', 'Medical Research', 'Healthcare Administration', 'Public Health'] +} \ No newline at end of file diff --git a/lib/components/templates/v2-tech.ts b/lib/components/templates/v2-tech.ts new file mode 100644 index 0000000..4d9e73b --- /dev/null +++ b/lib/components/templates/v2-tech.ts @@ -0,0 +1,9 @@ +export default { + version: 'v2', + domain: 'Technology', + structure: ['Domain', 'Industry', 'Profession', 'Field', 'Role', 'Task'], + description: 'Comprehensive technology sector hierarchy', + commonSkills: ['Problem Solving', 'Critical Thinking', 'Communication', 'Collaboration'], + commonTools: ['Git', 'IDE', 'Testing Frameworks', 'Documentation Tools'], + examples: ['Software Development', 'DevOps', 'Data Science', 'Cybersecurity'] +} \ No newline at end of file diff --git a/lib/hierarchy-model.ts b/lib/hierarchy-model.ts new file mode 100644 index 0000000..a6ad03f --- /dev/null +++ b/lib/hierarchy-model.ts @@ -0,0 +1,35 @@ +import { types } from "mobx-state-tree"; + +/** + * Reusable abstraction for a domain/sector hierarchy. + * Works for both v1 and v2 + */ +export const HierarchyModel = types.model("HierarchyModel", { + version: types.string, // "v1" | "v2" + domain: types.string, // e.g. "Finance", "Technology" + structure: types.array(types.string), // ordered hierarchy labels + description: types.string, // plain-text description + commonSkills: types.array(types.string), + commonTools: types.array(types.string), + examples: types.array(types.string) +}); + +/* ------------------------------------------------------------------ * + * Example usage + * ------------------------------------------------------------------ */ + +// Create individual instances +// import { HierarchyModel } from "./hierarchy-model"; +// +// const finance = HierarchyModel.create(v1Finance); +// const tech = HierarchyModel.create(v2Tech); + +export const HierarchyStore = types + .model("HierarchyStore", { + items: types.map(HierarchyModel) // keyed by domain name + }) + .actions(self => ({ + add(h: Instance) { + self.items.set(h.domain, h); + } + })); \ No newline at end of file diff --git a/lib/index.ts b/lib/index.ts new file mode 100644 index 0000000..6de05a5 --- /dev/null +++ b/lib/index.ts @@ -0,0 +1,4 @@ +import v1 from './v1'; +import v2 from './v2'; + +export { v1, v2 }; \ No newline at end of file diff --git a/lib/v1.ts b/lib/v1.ts new file mode 100644 index 0000000..1d5bd76 --- /dev/null +++ b/lib/v1.ts @@ -0,0 +1,41 @@ +import { types } from "mobx-state-tree" + +const Attribute = types.model("Attribute", { + name: types.string, + type: types.enumeration("AttributeType", ["Skill", "Tool", "Trait"]), + description: types.optional(types.string, "") +}) + +const Responsibility = types.model("Responsibility", { + title: types.string, + outcome: types.string, + requiredAttributes: types.array(Attribute) +}) + +const Role = types.model("Role", { + title: types.string, + responsibilities: types.array(Responsibility), + requiredAttributes: types.array(Attribute), + seniority: types.enumeration("Seniority", ["Intern", "Junior", "Mid", "Senior", "Lead", "Principal"]) +}) + +// Specialization within a domain (e.g., cardiologist within medicine) +const Specialization = types.model("Specialization", { + name: types.string, + focus: types.string, + coreAttributes: types.array(Attribute), + roles: types.array(Role) +}) + +const Domain = types.model("Domain", { + name: types.string, + description: types.optional(types.string, ""), + specializations: types.array(Specialization), + coreAttributes: types.array(Attribute) +}) + +const ProfessionModel = types.model("ProfessionModel", { + domains: types.array(Domain) +}); + +export { ProfessionModel, Domain, Specialization, Role, Responsibility, Attribute } diff --git a/lib/v2.ts b/lib/v2.ts new file mode 100644 index 0000000..556d109 --- /dev/null +++ b/lib/v2.ts @@ -0,0 +1,194 @@ +// Profession Hierarchy Model using mobx-state-tree (MST) +// ----------------------------------------------------- +// This file defines a generic, extensible hierarchy that captures the essence +// of professions. It intentionally separates concerns across six conceptual +// layers, from the broad Domain level down to atomic Tasks. Each layer owns +// its children through strongly‑typed arrays, enabling fine‑grained reactivity, +// traversal, and manipulation. +// +// Layering +// β”Œ Domain – e.g. "STEM", "Arts", "Public Service" +// β”‚ β”” Industry – e.g. "Software", "Healthcare", "Finance" +// β”‚ β”” Profession – e.g. "Software Engineering", "Nursing" +// β”‚ β”” Field – e.g. "Backend", "Pediatrics" +// β”‚ β”” Role – e.g. "API Engineer", "Pediatric Nurse" +// β”‚ β”” Task – e.g. "Design REST endpoints", "Administer vaccine" +// +// Each model exposes actions to mutate its children as well as compositional +// views to rapidly surface nested information (e.g., all tasks under an +// Industry). Identifiers are UUID‑v4 strings to guarantee uniqueness across +// distributed systems. +// ----------------------------------------------------- + +import { types, Instance, SnapshotIn, getParent, destroy } from "mobx-state-tree"; +import { v4 as uuidv4 } from "uuid"; + +/* Utility --------------------------------------------------------------- */ +const withId = >(modelName: string, definition: T) => + types.model(modelName, { + id: types.optional(types.identifier, uuidv4), + ...definition + }); + +/* Task ------------------------------------------------------------------ */ +export const TaskModel = withId("Task", { + name: types.string, + description: types.maybe(types.string) +}) + .actions(self => ({ + update(attrs: Partial>) { + Object.assign(self, attrs); + }, + remove() { + destroy(self); + } + })); +export interface Task extends Instance {} + +/* Role ------------------------------------------------------------------ */ +export const RoleModel = withId("Role", { + title: types.string, + summary: types.maybe(types.string), + tasks: types.optional(types.array(TaskModel), []) +}) + .actions(self => ({ + addTask(task: SnapshotIn) { + self.tasks.push(TaskModel.create(task)); + }, + removeTask(task: Task) { + self.tasks.remove(task); + }, + remove() { + destroy(self); + } + })) + .views(self => ({ + get allTasks() { + return self.tasks.slice(); + } + })); +export interface Role extends Instance {} + +/* Field (Specialization) ------------------------------------------------- */ +export const FieldModel = withId("Field", { + name: types.string, + description: types.maybe(types.string), + roles: types.optional(types.array(RoleModel), []) +}) + .actions(self => ({ + addRole(role: SnapshotIn) { + self.roles.push(RoleModel.create(role)); + }, + removeRole(role: Role) { + self.roles.remove(role); + }, + remove() { + destroy(self); + } + })) + .views(self => ({ + get allTasks() { + return self.roles.flatMap(r => r.allTasks); + } + })); +export interface Field extends Instance {} + +/* Profession ------------------------------------------------------------ */ +export const ProfessionModel = withId("Profession", { + name: types.string, + description: types.maybe(types.string), + fields: types.optional(types.array(FieldModel), []) +}) + .actions(self => ({ + addField(field: SnapshotIn) { + self.fields.push(FieldModel.create(field)); + }, + removeField(field: Field) { + self.fields.remove(field); + }, + remove() { + destroy(self); + } + })) + .views(self => ({ + get allTasks() { + return self.fields.flatMap(f => f.allTasks); + } + })); +export interface Profession extends Instance {} + +/* Industry -------------------------------------------------------------- */ +export const IndustryModel = withId("Industry", { + name: types.string, + description: types.maybe(types.string), + professions: types.optional(types.array(ProfessionModel), []) +}) + .actions(self => ({ + addProfession(prof: SnapshotIn) { + self.professions.push(ProfessionModel.create(prof)); + }, + removeProfession(prof: Profession) { + self.professions.remove(prof); + }, + remove() { + destroy(self); + } + })) + .views(self => ({ + get allTasks() { + return self.professions.flatMap(p => p.allTasks); + } + })); +export interface Industry extends Instance {} + +/* Domain ---------------------------------------------------------------- */ +export const DomainModel = withId("Domain", { + name: types.string, + description: types.maybe(types.string), + industries: types.optional(types.array(IndustryModel), []) +}) + .actions(self => ({ + addIndustry(ind: SnapshotIn) { + self.industries.push(IndustryModel.create(ind)); + }, + removeIndustry(ind: Industry) { + self.industries.remove(ind); + }, + remove() { + destroy(self); + } + })) + .views(self => ({ + get allTasks() { + return self.industries.flatMap(i => i.allTasks); + } + })); +export interface Domain extends Instance {} + +/* Enterprise ------------------------------------------------------------- */ +export const Enterprise = types + .model("Enterprise", { + domains: types.optional(types.array(DomainModel), []) + }) + .actions(self => ({ + addDomain(domain: SnapshotIn) { + self.domains.push(DomainModel.create(domain)); + } + })) + .views(self => ({ + // Convenience: get a flat list of everything + get allTasks() { + return self.domains.flatMap(d => d.allTasks); + } + })); +export interface IRootStore extends Instance {} + +/* Example usage --------------------------------------------------------- */ +// const store = Enterprise.create({}); +// store.addDomain({ name: "STEM" }); +// store.domains[0].addIndustry({ name: "Software" }); +// store.domains[0].industries[0].addProfession({ name: "Software Engineering" }); +// store.domains[0].industries[0].professions[0].addField({ name: "Backend" }); +// store.domains[0].industries[0].professions[0].fields[0].addRole({ title: "API Engineer" }); +// store.domains[0].industries[0].professions[0].fields[0].roles[0].addTask({ name: "Design REST endpoints" }); +// console.log(store.allTasks.map(t => t.name)); // β†’ ["Design REST endpoints"] diff --git a/output/hierarchy-create-a-finance-hierarchy-for-banking-20250711T200150.json b/output/hierarchy-create-a-finance-hierarchy-for-banking-20250711T200150.json new file mode 100644 index 0000000..7e507c3 --- /dev/null +++ b/output/hierarchy-create-a-finance-hierarchy-for-banking-20250711T200150.json @@ -0,0 +1,30 @@ +{ + "version": "v1", + "domain": "Finance", + "structure": [ + "Retail Banking", + "Commercial Banking", + "Investment Banking", + "Private Banking" + ], + "description": "A hierarchy of functions and services within the banking sector, focusing on various banking operations.", + "commonSkills": [ + "Financial Analysis", + "Risk Management", + "Customer Relationship Management", + "Regulatory Compliance", + "Loan Processing" + ], + "commonTools": [ + "Financial Modeling Software", + "Customer Relationship Management (CRM) Systems", + "Investment Analysis Tools", + "Risk Assessment Software" + ], + "examples": [ + "Personal loans in Retail Banking", + "Small business loans in Commercial Banking", + "Mergers and Acquisitions in Investment Banking", + "Wealth management in Private Banking" + ] +} \ No newline at end of file diff --git a/output/hierarchy-create-a-finance-hierarchy-for-banking-20250711T200150.ts b/output/hierarchy-create-a-finance-hierarchy-for-banking-20250711T200150.ts new file mode 100644 index 0000000..a2e4c61 --- /dev/null +++ b/output/hierarchy-create-a-finance-hierarchy-for-banking-20250711T200150.ts @@ -0,0 +1,80 @@ +/** + * finance Professional Hierarchy Example + * Generated using OpenAI Agents SDK and Sumpin Professional Hierarchy Models + * Model Version: v2 (6-layer hierarchy) + * Generated on: 2025-07-11T20:02:03.514Z + */ + +import { + Enterprise, + DomainModel, IndustryModel, ProfessionModel, FieldModel, RoleModel, TaskModel +} from "../../lib/v2"; + +import { Enterprise, DomainModel, IndustryModel, ProfessionModel, FieldModel, RoleModel, TaskModel } from "../../lib/v2"; + +const financeDomain = new DomainModel({ + name: "Finance", + industries: [ + new IndustryModel({ + name: "Investment Banking", + professions: [ + new ProfessionModel({ + name: "Investment Banker", + fields: [ + new FieldModel({ + name: "Corporate Finance", + roles: [ + new RoleModel({ + name: "Analyst", + tasks: [ + new TaskModel({ + name: "Financial Modeling", + skills: ["Excel", "Financial Analysis"], + tools: ["Excel", "Bloomberg Terminal"], + example: "Building a discounted cash flow model for a merger." + }), + new TaskModel({ + name: "Market Research", + skills: ["Data Analysis", "Presentation Skills"], + tools: ["PitchBook", "Excel"], + example: "Analyzing competitor performance for a potential acquisition." + }) + ] + }), + new RoleModel({ + name: "Associate", + tasks: [ + new TaskModel({ + name: "Deal Execution", + skills: ["Negotiation", "Project Management"], + tools: ["MS Project", "Deal Management Software"], + example: "Leading a team to close a multi-million dollar equity issuance." + }) + ] + }) + ] + }) + ] + }) + ] + }) + ] +}); + +// Basic operations +const readRoleTasks = (roleName: string) => { + const role = financeDomain.industries[0].professions[0].fields[0].roles.find(r => r.name === roleName); + return role ? role.tasks : []; +}; + +const updateTaskSkill = (roleName: string, taskName: string, newSkills: string[]) => { + const role = financeDomain.industries[0].professions[0].fields[0].roles.find(r => r.name === roleName); + const task = role?.tasks.find(t => t.name === taskName); + if (task) { + task.skills = newSkills; + } +}; + +// Example usages +const analystTasks = readRoleTasks("Analyst"); +updateTaskSkill("Analyst", "Financial Modeling", ["Advanced Excel", "Financial Forecasting"]); \ No newline at end of file diff --git a/output/hierarchy-create-a-healthcare-hierarchy-for-emergency-medici-20250711T200113.ts b/output/hierarchy-create-a-healthcare-hierarchy-for-emergency-medici-20250711T200113.ts new file mode 100644 index 0000000..4cf44e7 --- /dev/null +++ b/output/hierarchy-create-a-healthcare-hierarchy-for-emergency-medici-20250711T200113.ts @@ -0,0 +1,142 @@ +/** + * healthcare Professional Hierarchy Example + * Generated using OpenAI Agents SDK and Sumpin Professional Hierarchy Models + * Model Version: v2 (6-layer hierarchy) + * Generated on: 2025-07-11T20:01:29.107Z + */ + +import { + Enterprise, + DomainModel, IndustryModel, ProfessionModel, FieldModel, RoleModel, TaskModel +} from "../../lib/v2"; + +import { Enterprise, DomainModel, IndustryModel, ProfessionModel, FieldModel, RoleModel, TaskModel } from "../../lib/v2"; +const healthcareDomain = new DomainModel({ + name: "Healthcare", + industries: [ + new IndustryModel({ + name: "Medical Services", + professions: [ + new ProfessionModel({ + name: "Nursing", + fields: [ + new FieldModel({ + name: "Clinical Nursing", + roles: [ + new RoleModel({ + name: "Registered Nurse", + competencies: [ + "Patient assessment", + "Medication administration", + "Care planning" + ], + tools: [ + "Electronic Health Records (EHR)", + "Vital signs monitors", + "Infusion pumps" + ], + tasks: [ + new TaskModel({ + name: "Patient Monitoring", + description: "Monitoring patient vitals and documenting changes.", + examples: [ + "Using EHR to log vital signs every hour.", + "Adjusting care plan based on patient observations." + ] + }), + new TaskModel({ + name: "Medication Management", + description: "Administering and managing patient medications.", + examples: [ + "Preparing and administering IV medications.", + "Educating patients on prescribed medications." + ] + }) + ] + }) + ] + }), + new FieldModel({ + name: "Nurse Practitioner", + roles: [ + new RoleModel({ + name: "Family Nurse Practitioner", + competencies: [ + "Advanced patient assessment", + "Diagnosis and treatment planning", + "Patient education" + ], + tools: [ + "Diagnostic tools (stethoscope, otoscope)", + "Telehealth platform", + "Prescription software" + ], + tasks: [ + new TaskModel({ + name: "Conducting Physical Exams", + description: "Performing comprehensive assessments for patients.", + examples: [ + "Utilizing telehealth for remote consultations.", + "Documenting findings and recommending treatments." + ] + }), + new TaskModel({ + name: "Health Promotion", + description: "Educating families about preventive care.", + examples: [ + "Organizing community health seminars.", + "Providing personalized health advice to families." + ] + }) + ] + }) + ] + }) + ] + }), + new ProfessionModel({ + name: "Healthcare Administration", + fields: [ + new FieldModel({ + name: "Hospital Administration", + roles: [ + new RoleModel({ + name: "Healthcare Administrator", + competencies: [ + "Operations management", + "Compliance and regulations", + "Financial planning" + ], + tools: [ + "Healthcare management software", + "Data analytics tools", + "Budgeting tools" + ], + tasks: [ + new TaskModel({ + name: "Budgeting and Financial Oversight", + description: "Managing hospital budgets and financial resources.", + examples: [ + "Creating annual budgets based on service demand.", + "Reviewing financial performance reports." + ] + }), + new TaskModel({ + name: "Quality Improvement Initiatives", + description: "Implementing strategies to improve healthcare delivery.", + examples: [ + "Conducting patient satisfaction surveys.", + "Analyzing workflow for efficiency." + ] + }) + ] + }) + ] + }) + ] + }) + ] + }) + ] +}); +export default healthcareDomain; \ No newline at end of file diff --git a/output/hierarchy-create-a-simple-technology-hierarchy-for-web-devel-20250711T200047.json b/output/hierarchy-create-a-simple-technology-hierarchy-for-web-devel-20250711T200047.json new file mode 100644 index 0000000..71b7800 --- /dev/null +++ b/output/hierarchy-create-a-simple-technology-hierarchy-for-web-devel-20250711T200047.json @@ -0,0 +1,31 @@ +{ + "version": "v1", + "domain": "Technology", + "structure": [ + "Front-end", + "Back-end", + "Database", + "DevOps" + ], + "description": "A hierarchy outlining the main components and roles involved in web development.", + "commonSkills": [ + "HTML/CSS", + "JavaScript", + "Responsive Design", + "Backend Programming", + "Database Management" + ], + "commonTools": [ + "Visual Studio Code", + "Git", + "Postman", + "Node.js", + "MySQL" + ], + "examples": [ + "Building a static website", + "Creating a dynamic web application", + "Developing APIs", + "Implementing user authentication" + ] +} \ No newline at end of file diff --git a/package.json b/package.json new file mode 100644 index 0000000..3844406 --- /dev/null +++ b/package.json @@ -0,0 +1,27 @@ +{ + "name": "sumpin", + "module": "index.ts", + "type": "module", + "devDependencies": { + "@types/bun": "latest", + "@types/uuid": "^10.0.0" + }, + "scripts": { + "start": "bun ./index.ts", + "cli": "bun ./cli.ts", + "sumpin": "bun ./cli.ts", + "generate": "bun ./cli.ts", + "demo": "bun ./index.ts" + }, + "peerDependencies": { + "typescript": "^5.0.0" + }, + "dependencies": { + "@openai/agents": "^0.0.11", + "mobx": "^6.13.7", + "mobx-state-tree": "^7.0.2", + "openai": "^5.9.0", + "uuid": "^11.1.0", + "zod": "<=3.25.67" + } +} diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..e7a11a9 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,3 @@ +fn main() { + println!("Hello, world!"); +} diff --git a/tsconfig.json b/tsconfig.json new file mode 100644 index 0000000..c77ac38 --- /dev/null +++ b/tsconfig.json @@ -0,0 +1,32 @@ +{ + "compilerOptions": { + // Enable latest features + "lib": ["ESNext", "DOM"], + "target": "ESNext", + "module": "ESNext", + "moduleDetection": "force", + "jsx": "react-jsx", + "allowJs": true, + + // Bundler mode + "moduleResolution": "bundler", + "allowImportingTsExtensions": true, + "verbatimModuleSyntax": true, + "noEmit": true, + + // Best practices + "strict": true, + "skipLibCheck": true, + "noFallthroughCasesInSwitch": true, + + // Some stricter flags (disabled by default) + "noUnusedLocals": false, + "noUnusedParameters": false, + "noPropertyAccessFromIndexSignature": false + }, + "include": [ + "*.ts", + "lib/**/*", + "examples/**/*" + ] +}