diff --git a/bun.lock b/bun.lock index c8c717b..72b46b8 100644 --- a/bun.lock +++ b/bun.lock @@ -52,9 +52,34 @@ "vitest": "^3.2.4", }, }, + "packages/core/examples/github-actions": { + "name": "jules-github-actions-example", + "version": "1.0.0", + "dependencies": { + "@actions/core": "^1.10.1", + "@actions/github": "^6.0.0", + "@google/jules-sdk": "workspace:*", + }, + "devDependencies": { + "@types/node": "^20.0.0", + "typescript": "^5.0.0", + }, + }, + "packages/core/examples/webhook": { + "name": "webhook", + "version": "1.0.0", + "dependencies": { + "@google/jules-sdk": "workspace:*", + "@hono/node-server": "^1.11.1", + "hono": "^4.3.11", + }, + "devDependencies": { + "bun-types": "^1.1.8", + }, + }, "packages/fleet": { "name": "@google/jules-fleet", - "version": "0.0.1-experimental.27", + "version": "0.0.1-experimental.31", "bin": { "jules-fleet": "dist/cli/index.mjs", }, @@ -136,6 +161,16 @@ "packages": { "@acemir/cssom": ["@acemir/cssom@0.9.31", "", {}, "sha512-ZnR3GSaH+/vJ0YlHau21FjfLYjMpYVIzTD8M8vIEQvIGxeOXyXdzCI140rrCY862p/C/BbzWsjc1dgnM9mkoTA=="], + "@actions/core": ["@actions/core@1.11.1", "", { "dependencies": { "@actions/exec": "^1.1.1", "@actions/http-client": "^2.0.1" } }, "sha512-hXJCSrkwfA46Vd9Z3q4cpEpHB1rL5NG04+/rbqW9d3+CSvtB1tYe8UTpAlixa1vj0m/ULglfEK2UKxMGxCxv5A=="], + + "@actions/exec": ["@actions/exec@1.1.1", "", { "dependencies": { "@actions/io": "^1.0.1" } }, "sha512-+sCcHHbVdk93a0XT19ECtO/gIXoxvdsgQLzb2fE2/5sIZmWQuluYyjPQtrtTHdU1YzTZ7bAPN4sITq2xi1679w=="], + + "@actions/github": ["@actions/github@6.0.1", "", { "dependencies": { "@actions/http-client": "^2.2.0", "@octokit/core": "^5.0.1", "@octokit/plugin-paginate-rest": "^9.2.2", "@octokit/plugin-rest-endpoint-methods": "^10.4.0", "@octokit/request": "^8.4.1", "@octokit/request-error": "^5.1.1", "undici": "^5.28.5" } }, "sha512-xbZVcaqD4XnQAe35qSQqskb3SqIAfRyLBrHMd/8TuL7hJSz2QtbDwnNM8zWx4zO5l2fnGtseNE3MbEvD7BxVMw=="], + + "@actions/http-client": ["@actions/http-client@2.2.3", "", { "dependencies": { "tunnel": "^0.0.6", "undici": "^5.25.4" } }, "sha512-mx8hyJi/hjFvbPokCg4uRd4ZX78t+YyRPtnKWwIl+RzNaVuFpQHfmlGVfsKEJN8LwTCvL+DfVgAM04XaHkm6bA=="], + + "@actions/io": ["@actions/io@1.1.3", "", {}, "sha512-wi9JjgKLYS7U/z8PPbco+PvTb/nRWjeoFlJ1Qer83k/3C5PHQi28hiVdeE2kHXmIL99mQFawx8qt/JPjZilJ8Q=="], + "@asamuzakjp/css-color": ["@asamuzakjp/css-color@4.1.1", "", { "dependencies": { "@csstools/css-calc": "^2.1.4", "@csstools/css-color-parser": "^3.1.0", "@csstools/css-parser-algorithms": "^3.0.5", "@csstools/css-tokenizer": "^3.0.4", "lru-cache": "^11.2.4" } }, "sha512-B0Hv6G3gWGMn0xKJ0txEi/jM5iFpT3MfDxmhZFb4W047GvytCf1DHQ1D69W3zHI4yWe2aTZAA0JnbMZ7Xc8DuQ=="], "@asamuzakjp/dom-selector": ["@asamuzakjp/dom-selector@6.7.6", "", { "dependencies": { "@asamuzakjp/nwsapi": "^2.3.9", "bidi-js": "^1.0.3", "css-tree": "^3.1.0", "is-potential-custom-element-name": "^1.0.1", "lru-cache": "^11.2.4" } }, "sha512-hBaJER6A9MpdG3WgdlOolHmbOYvSk46y7IQN/1+iqiCuUu6iWdQrs9DGKF8ocqsEqWujWf/V7b7vaDgiUmIvUg=="], @@ -220,6 +255,8 @@ "@exodus/bytes": ["@exodus/bytes@1.10.0", "", { "peerDependencies": { "@noble/hashes": "^1.8.0 || ^2.0.0" }, "optionalPeers": ["@noble/hashes"] }, "sha512-tf8YdcbirXdPnJ+Nd4UN1EXnz+IP2DI45YVEr3vvzcVTOyrApkmIB4zvOQVd3XPr7RXnfBtAx+PXImXOIU0Ajg=="], + "@fastify/busboy": ["@fastify/busboy@2.1.1", "", {}, "sha512-vBZP4NlzfOlerQTnba4aqZoMhE/a9HY7HRqoOPaETQcSQuWEIyZMHGfVu6w9wGtGK5fED5qRs2DteVCjOH60sA=="], + "@google/jules-fleet": ["@google/jules-fleet@workspace:packages/fleet"], "@google/jules-mcp": ["@google/jules-mcp@workspace:packages/mcp"], @@ -580,6 +617,8 @@ "depd": ["depd@2.0.0", "", {}, "sha512-g7nH6P6dyDioJogAAGprGpCtVImJhpPk/roCzdb3fIh61/s/nPsfR6onyMwkCAR/OlC3yBC0lESvUoQEAssIrw=="], + "deprecation": ["deprecation@2.3.1", "", {}, "sha512-xmHIy4F3scKVwMsQ4WnVaS8bHOx0DmVwRywosKhaILI0ywMDWPtBSku2HNxRvF7jtwDRsoEwYQSfbxj8b7RlJQ=="], + "dequal": ["dequal@2.0.3", "", {}, "sha512-0je+qPKHEMohvfRTCEo3CrPG6cAzAYgmzKyxRiYSSDkS6eGJdyVJm7WaYA5ECaAD9wLB2T4EEeymA5aFVcYXCA=="], "devlop": ["devlop@1.1.0", "", { "dependencies": { "dequal": "^2.0.0" } }, "sha512-RWmIqhcFf1lRYBvNmr7qTNuyCt/7/ns2jbpp1+PalgE/rDQcBT0fioSMUpJ93irlUhC5hrg4cYqe6U+0ImW0rA=="], @@ -732,6 +771,8 @@ "jsonfile": ["jsonfile@6.2.0", "", { "dependencies": { "universalify": "^2.0.0" }, "optionalDependencies": { "graceful-fs": "^4.1.6" } }, "sha512-FGuPw30AdOIUTRMC2OMRtQV+jkVj2cfPqSeWXv1NEAJ1qZ5zb1X6z1mFhbfOB/iy3ssJCD+3KuZ8r8C3uVFlAg=="], + "jules-github-actions-example": ["jules-github-actions-example@workspace:packages/core/examples/github-actions"], + "jules-sdk-example": ["jules-sdk-example@workspace:examples/simple"], "kolorist": ["kolorist@1.8.0", "", {}, "sha512-Y+60/zizpJ3HRH8DCss+q95yr6145JXZo46OTpFvDZWLfRCE4qChOyk1b26nMaNpfHHgxagk9dXT5OP0Tfe+dQ=="], @@ -980,6 +1021,8 @@ "tsx": ["tsx@4.21.0", "", { "dependencies": { "esbuild": "~0.27.0", "get-tsconfig": "^4.7.5" }, "optionalDependencies": { "fsevents": "~2.3.3" }, "bin": { "tsx": "dist/cli.mjs" } }, "sha512-5C1sg4USs1lfG0GFb2RLXsdpXqBSEhAaA/0kPL01wxzpMqLILNxIxIOKiILz+cdg/pLnOUxFYOR5yhHU666wbw=="], + "tunnel": ["tunnel@0.0.6", "", {}, "sha512-1h/Lnq9yajKY2PEbBadPXj3VxsDDu844OnaAo52UVmIzIvwwtBPIuNvkjuzBlTWpfJyUbG3ez0KSBibQkj4ojg=="], + "turbo": ["turbo@2.8.0", "", { "optionalDependencies": { "turbo-darwin-64": "2.8.0", "turbo-darwin-arm64": "2.8.0", "turbo-linux-64": "2.8.0", "turbo-linux-arm64": "2.8.0", "turbo-windows-64": "2.8.0", "turbo-windows-arm64": "2.8.0" }, "bin": { "turbo": "bin/turbo" } }, "sha512-hYbxnLEdvJF+DLALS+Ia+PbfNtn0sDP0hH2u9AFoskSUDmcVHSrtwHpzdX94MrRJKo9D9tYxY3MyP20gnlrWyA=="], "turbo-darwin-64": ["turbo-darwin-64@2.8.0", "", { "os": "darwin", "cpu": "x64" }, "sha512-N7f4PYqz25yk8c5kituk09bJ89tE4wPPqKXgYccT6nbEQnGnrdvlyCHLyqViNObTgjjrddqjb1hmDkv7VcxE0g=="], @@ -1002,6 +1045,8 @@ "ufo": ["ufo@1.6.3", "", {}, "sha512-yDJTmhydvl5lJzBmy/hyOAA0d+aqCBuwl818haVdYCRrWV84o7YyeVm4QlVHStqNrrJSTb6jKuFAVqAFsr+K3Q=="], + "undici": ["undici@5.29.0", "", { "dependencies": { "@fastify/busboy": "^2.0.0" } }, "sha512-raqeBD6NQK4SkWhQzeYKd1KmIG6dllBOTt55Rmkt4HtI9mwdWtJljnrXjAFUBLTSN67HWrOIZ3EPF4kjUw80Bg=="], + "undici-types": ["undici-types@6.21.0", "", {}, "sha512-iwDZqg0QAGrg9Rav5H4n0M64c3mkR59cJ6wQp+7C4nI0gsmExaedaYLNO44eT4AtBBwjbTiGPMlt2Md0T9H9JQ=="], "unicorn-magic": ["unicorn-magic@0.3.0", "", {}, "sha512-+QBBXBCvifc56fsbuxZQ6Sic3wqqc3WWaqxs58gvJrcOuN83HGTCwz3oS5phzU9LthRNE9VrJCFCLUgHeeFnfA=="], @@ -1046,6 +1091,8 @@ "w3c-xmlserializer": ["w3c-xmlserializer@5.0.0", "", { "dependencies": { "xml-name-validator": "^5.0.0" } }, "sha512-o8qghlI8NZHU1lLPrpi2+Uq7abh4GGPpYANlalzWxyWteJOCsr/P+oPBA49TOLu5FTZO4d3F9MnWJfiMo4BkmA=="], + "webhook": ["webhook@workspace:packages/core/examples/webhook"], + "webidl-conversions": ["webidl-conversions@8.0.1", "", {}, "sha512-BMhLD/Sw+GbJC21C/UgyaZX41nPt8bUTg+jWyDeg7e7YN4xOM05YPSIXceACnXVtqyEw/LMClUQMtMZ+PGGpqQ=="], "whatwg-mimetype": ["whatwg-mimetype@4.0.0", "", {}, "sha512-QaKxh0eNIi2mE9p2vEdzfagOKHCcj1pJ56EEHGQOVxp8r9/iszLUUV7v89x9O1p/T+NlTM5W7jW6+cz4Fq1YVg=="], @@ -1086,6 +1133,16 @@ "zwitch": ["zwitch@2.0.4", "", {}, "sha512-bXE4cR/kVZhKZX/RjPEflHaKVhUVl85noU3v6b8apfQEc1x4A+zBxjZ4lN8LqGd6WZ3dl98pY4o717VFmoPp+A=="], + "@actions/github/@octokit/core": ["@octokit/core@5.2.2", "", { "dependencies": { "@octokit/auth-token": "^4.0.0", "@octokit/graphql": "^7.1.0", "@octokit/request": "^8.4.1", "@octokit/request-error": "^5.1.1", "@octokit/types": "^13.0.0", "before-after-hook": "^2.2.0", "universal-user-agent": "^6.0.0" } }, "sha512-/g2d4sW9nUDJOMz3mabVQvOGhVa4e/BN/Um7yca9Bb2XTzPPnfTWHWQg+IsEYO7M3Vx+EXvaM/I2pJWIMun1bg=="], + + "@actions/github/@octokit/plugin-paginate-rest": ["@octokit/plugin-paginate-rest@9.2.2", "", { "dependencies": { "@octokit/types": "^12.6.0" }, "peerDependencies": { "@octokit/core": "5" } }, "sha512-u3KYkGF7GcZnSD/3UP0S7K5XUFT2FkOQdcfXZGZQPGv3lm4F2Xbf71lvjldr8c1H3nNbF+33cLEkWYbokGWqiQ=="], + + "@actions/github/@octokit/plugin-rest-endpoint-methods": ["@octokit/plugin-rest-endpoint-methods@10.4.1", "", { "dependencies": { "@octokit/types": "^12.6.0" }, "peerDependencies": { "@octokit/core": "5" } }, "sha512-xV1b+ceKV9KytQe3zCVqjg+8GTGfDYwaT1ATU5isiUyVtlVAO3HNdzpS4sr4GBx4hxQ46s7ITtZrAsxG22+rVg=="], + + "@actions/github/@octokit/request": ["@octokit/request@8.4.1", "", { "dependencies": { "@octokit/endpoint": "^9.0.6", "@octokit/request-error": "^5.1.1", "@octokit/types": "^13.1.0", "universal-user-agent": "^6.0.0" } }, "sha512-qnB2+SY3hkCmBxZsR/MPCybNmbJe4KAlfWErXq+rBKkQJlbjdJeS85VI9r8UqeLYLvnAenU8Q1okM/0MBsAGXw=="], + + "@actions/github/@octokit/request-error": ["@octokit/request-error@5.1.1", "", { "dependencies": { "@octokit/types": "^13.1.0", "deprecation": "^2.0.0", "once": "^1.4.0" } }, "sha512-v9iyEQJH6ZntoENr9/yXxjuezh4My67CBSu9r6Ve/05Iu5gNgnisNWOsoJHTP6k0Rr0+HQIpnH+kyammu90q/g=="], + "@google/jules-fleet/@google/jules-merge": ["@google/jules-merge@0.0.2", "", { "dependencies": { "@google/jules-sdk": "^0.1.0", "@octokit/auth-app": "^8.2.0", "@octokit/rest": "^21.0.0", "citty": "^0.1.6", "zod": "^3.25.0" }, "peerDependencies": { "@modelcontextprotocol/sdk": "^1.25.1" }, "optionalPeers": ["@modelcontextprotocol/sdk"], "bin": { "jules-merge": "dist/cli/index.mjs" } }, "sha512-VPpbdBt48AbmFByg5RGztv2sQPPJ5fFJARXTvX41lY/b9M+qdyZPp19+ay3qfxEHgj1EvnRMwf/HFOrMMXZ7vQ=="], "@google/jules-fleet/glob": ["glob@13.0.6", "", { "dependencies": { "minimatch": "^10.2.2", "minipass": "^7.1.3", "path-scurry": "^2.0.2" } }, "sha512-Wjlyrolmm8uDpm/ogGyXZXb1Z+Ca2B8NbJwqBVg0axK9GbBeoS7yGV6vjXnYdGm6X53iehEuxxbyiKp8QmN4Vw=="], @@ -1156,6 +1213,8 @@ "express/cookie": ["cookie@0.7.2", "", {}, "sha512-yki5XnKuf750l50uGTllt6kKILY4nQ1eNIQatoXEByZ5dWgnKqbnqmTrBE5B4N7lrMJKQ2ytWMiTO2o0v6Ew/w=="], + "jules-github-actions-example/@types/node": ["@types/node@20.19.37", "", { "dependencies": { "undici-types": "~6.21.0" } }, "sha512-8kzdPJ3FsNsVIurqBs7oodNnCEVbni9yUEkaHbgptDACOPW04jimGagZ51E6+lXUwJjgnBw+hyko/lkFWCldqw=="], + "mlly/pkg-types": ["pkg-types@1.3.1", "", { "dependencies": { "confbox": "^0.1.8", "mlly": "^1.7.4", "pathe": "^2.0.1" } }, "sha512-/Jm5M4RvtBFVkKWRu2BLUTNP8/M2a+UwuAX+ae4770q1qVGtfjG+WTCupoZixokjmHiry8uI+dlY8KXYV5HVVQ=="], "octokit/@octokit/request-error": ["@octokit/request-error@6.1.8", "", { "dependencies": { "@octokit/types": "^14.0.0" } }, "sha512-WEi/R0Jmq+IJKydWlKDmryPcmdYSVjL3ekaiEL1L9eo1sUnqMJ+grqmC9cjk7CA7+b2/T397tO5d8YLOH3qYpQ=="], @@ -1170,6 +1229,28 @@ "wrap-ansi/strip-ansi": ["strip-ansi@6.0.1", "", { "dependencies": { "ansi-regex": "^5.0.1" } }, "sha512-Y38VPSHcqkFrCpFnQ9vuSXmquuv5oXOKpGeT6aGrr3o3Gc9AlVa6JBfUSOCnbxGGZF+/0ooI7KrPuUSztUdU5A=="], + "@actions/github/@octokit/core/@octokit/auth-token": ["@octokit/auth-token@4.0.0", "", {}, "sha512-tY/msAuJo6ARbK6SPIxZrPBms3xPbfwBrulZe0Wtr/DIY9lje2HeV1uoebShn6mx7SjCHif6EjMvoREj+gZ+SA=="], + + "@actions/github/@octokit/core/@octokit/graphql": ["@octokit/graphql@7.1.1", "", { "dependencies": { "@octokit/request": "^8.4.1", "@octokit/types": "^13.0.0", "universal-user-agent": "^6.0.0" } }, "sha512-3mkDltSfcDUoa176nlGoA32RGjeWjl3K7F/BwHwRMJUW/IteSa4bnSV8p2ThNkcIcZU2umkZWxwETSSCJf2Q7g=="], + + "@actions/github/@octokit/core/@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="], + + "@actions/github/@octokit/core/before-after-hook": ["before-after-hook@2.2.3", "", {}, "sha512-NzUnlZexiaH/46WDhANlyR2bXRopNg4F/zuSA3OpZnllCUgRaOF2znDioDWrmbNVsuZk6l9pMquQB38cfBZwkQ=="], + + "@actions/github/@octokit/core/universal-user-agent": ["universal-user-agent@6.0.1", "", {}, "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="], + + "@actions/github/@octokit/plugin-paginate-rest/@octokit/types": ["@octokit/types@12.6.0", "", { "dependencies": { "@octokit/openapi-types": "^20.0.0" } }, "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw=="], + + "@actions/github/@octokit/plugin-rest-endpoint-methods/@octokit/types": ["@octokit/types@12.6.0", "", { "dependencies": { "@octokit/openapi-types": "^20.0.0" } }, "sha512-1rhSOfRa6H9w4YwK0yrf5faDaDTb+yLyBUKOCV4xtCDB5VmIPqd/v9yr9o6SAzOAlRxMiRiCic6JVM1/kunVkw=="], + + "@actions/github/@octokit/request/@octokit/endpoint": ["@octokit/endpoint@9.0.6", "", { "dependencies": { "@octokit/types": "^13.1.0", "universal-user-agent": "^6.0.0" } }, "sha512-H1fNTMA57HbkFESSt3Y9+FBICv+0jFceJFPWDePYlR/iMGrwM5ph+Dd4XRQs+8X+PUFURLQgX9ChPfhJ/1uNQw=="], + + "@actions/github/@octokit/request/@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="], + + "@actions/github/@octokit/request/universal-user-agent": ["universal-user-agent@6.0.1", "", {}, "sha512-yCzhz6FN2wU1NiiQRogkTQszlQSlpWaw8SvVegAc+bDxbzHgh1vX8uIe8OYyMH6DwH+sdTJsgMl36+mSMdRJIQ=="], + + "@actions/github/@octokit/request-error/@octokit/types": ["@octokit/types@13.10.0", "", { "dependencies": { "@octokit/openapi-types": "^24.2.0" } }, "sha512-ifLaO34EbbPj0Xgro4G5lP5asESjwHracYJvVaPIyXMuiuXLlhic3S47cBdTb+jfODkTE5YtGCLt3Ay3+J97sA=="], + "@google/jules-fleet/glob/minimatch": ["minimatch@10.2.4", "", { "dependencies": { "brace-expansion": "^5.0.2" } }, "sha512-oRjTw/97aTBN0RHbYCdtF1MQfvusSIBQM0IZEgzl6426+8jSC0nF1a/GmnVLpfB9yyr6g6FTqWqiZVbxrtaCIg=="], "@google/jules-fleet/glob/minipass": ["minipass@7.1.3", "", {}, "sha512-tEBHqDnIoM/1rXME1zgka9g6Q2lcoCkxHLuc7ODJ5BxbP5d4c2Z5cGgtXAku59200Cx7diuHTOYfSBD8n6mm8A=="], @@ -1246,6 +1327,16 @@ "wrap-ansi/strip-ansi/ansi-regex": ["ansi-regex@5.0.1", "", {}, "sha512-quJQXlTSUGL2LH9SUXo8VwsY4soanhgo6LNSm84E1LBcE8s3O0wpdiRzyR9z/ZZJMlMWv37qOOb9pdJlMUEKFQ=="], + "@actions/github/@octokit/core/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="], + + "@actions/github/@octokit/plugin-paginate-rest/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@20.0.0", "", {}, "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA=="], + + "@actions/github/@octokit/plugin-rest-endpoint-methods/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@20.0.0", "", {}, "sha512-EtqRBEjp1dL/15V7WiX5LJMIxxkdiGJnabzYx5Apx4FkQIFgAfKumXeYAqqJCj1s+BMX4cPFIFC4OLCR6stlnA=="], + + "@actions/github/@octokit/request-error/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="], + + "@actions/github/@octokit/request/@octokit/types/@octokit/openapi-types": ["@octokit/openapi-types@24.2.0", "", {}, "sha512-9sIH3nSUttelJSXUrmGzl7QUBFul0/mB8HRYl3fOlgHbIWG+WnYDXU3v/2zMtAvuzZ/ed00Ei6on975FhBfzrg=="], + "@octokit/app/@octokit/auth-app/@octokit/auth-oauth-app/@octokit/auth-oauth-device": ["@octokit/auth-oauth-device@7.1.5", "", { "dependencies": { "@octokit/oauth-methods": "^5.1.5", "@octokit/request": "^9.2.3", "@octokit/types": "^14.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-lR00+k7+N6xeECj0JuXeULQ2TSBB/zjTAmNF2+vyGPDEFx1dgk1hTDmL13MjbSmzusuAmuJD8Pu39rjp9jH6yw=="], "@octokit/app/@octokit/auth-app/@octokit/auth-oauth-user/@octokit/auth-oauth-device": ["@octokit/auth-oauth-device@7.1.5", "", { "dependencies": { "@octokit/oauth-methods": "^5.1.5", "@octokit/request": "^9.2.3", "@octokit/types": "^14.0.0", "universal-user-agent": "^7.0.0" } }, "sha512-lR00+k7+N6xeECj0JuXeULQ2TSBB/zjTAmNF2+vyGPDEFx1dgk1hTDmL13MjbSmzusuAmuJD8Pu39rjp9jH6yw=="], diff --git a/package.json b/package.json index 318da0e..a3ce86d 100644 --- a/package.json +++ b/package.json @@ -9,7 +9,8 @@ }, "workspaces": [ "packages/*", - "examples/*" + "examples/*", + "packages/core/examples/*" ], "description": "Official Jules TypeScript SDK", "scripts": { diff --git a/packages/core/README.md b/packages/core/README.md index 48c4673..9428f4a 100644 --- a/packages/core/README.md +++ b/packages/core/README.md @@ -4,6 +4,14 @@ Orchestrate complex, long-running coding tasks to an ephemeral cloud environment integrated with a GitHub repo. +## Examples + +- [Basic Session](./examples/basic-session/README.md) +- [Advanced Session](./examples/advanced-session/README.md) +- [Agent Workflow](./examples/agent/README.md) +- [Webhook Integration](./examples/webhook/README.md) +- [GitHub Actions](./examples/github-actions/README.md) + ## Send work to a Cloud based session ```ts diff --git a/packages/core/examples/advanced-session/README.md b/packages/core/examples/advanced-session/README.md new file mode 100644 index 0000000..6d7cbe3 --- /dev/null +++ b/packages/core/examples/advanced-session/README.md @@ -0,0 +1,14 @@ +# Advanced Session Example + +This example demonstrates how to use the Jules SDK to run a session, interact with it, wait for plan approvals, and monitor stream progress while parsing the output for artifacts. + +## Running + +Ensure you have your `JULES_API_KEY` set. +You can run the script via: + +```sh +bun run index.ts +``` + +This will run the advanced session and stream activities. diff --git a/packages/core/examples/advanced-session/index.ts b/packages/core/examples/advanced-session/index.ts new file mode 100644 index 0000000..cbfaeff --- /dev/null +++ b/packages/core/examples/advanced-session/index.ts @@ -0,0 +1,81 @@ +import { jules, JulesError } from '@google/jules-sdk'; + +/** + * Advanced Session Example + * + * Demonstrates: + * - Interactive session creation + * - Waiting for plan approval + * - Monitoring progress via reactive streams + * - Handling code diffs (changeSet) + */ +async function runAdvancedSession() { + try { + console.log('Starting advanced session...'); + + // Interactive Sessions allow you to provide feedback and guide the process + const session = await jules.session({ + prompt: `Create a simple python script that prints 'Hello Advanced Session!' and test it.`, + // For a repoless session, we don't provide a source + }); + + console.log(`Session created: ${session.id}`); + + // Wait for the plan to be generated and ready for approval + console.log('Waiting for plan approval...'); + await session.waitFor('awaitingPlanApproval'); + + console.log('Plan is ready. Approving it now.'); + await session.approve(); + + // Stream activities and artifacts + for await (const activity of session.stream()) { + switch (activity.type) { + case 'planGenerated': + console.log( + 'Plan:', + activity.plan?.steps.map((s) => s.title) + ); + break; + case 'agentMessaged': + console.log('Agent says:', activity.message); + break; + case 'progressUpdated': + console.log(`Progress: ${activity.title}`); + break; + case 'sessionCompleted': + console.log('Session complete!'); + break; + } + + // Check artifacts + for (const artifact of activity.artifacts ?? []) { + if (artifact.type === 'bashOutput') { + console.log(`[BASH] ${artifact.toString()}`); + } + if (artifact.type === 'changeSet') { + const parsed = artifact.parsed(); + for (const file of parsed.files) { + console.log( + `[DIFF] ${file.path}: +${file.additions} -${file.deletions}` + ); + } + } + } + } + + const outcome = await session.result(); + console.log(`Session finished with state: ${outcome.state}`); + + } catch (error) { + if (error instanceof JulesError) { + console.error(`SDK error: ${error.message}`); + } else { + console.error('Unknown error:', error); + } + } +} + +if (require.main === module) { + runAdvancedSession(); +} diff --git a/packages/core/examples/agent/README.md b/packages/core/examples/agent/README.md new file mode 100644 index 0000000..be5f35f --- /dev/null +++ b/packages/core/examples/agent/README.md @@ -0,0 +1,65 @@ +# Agent Workflow Example + +This example demonstrates how to use the `jules.all()` API to create an AI agent workflow that manages multiple tasks concurrently. It orchestrates complex, long-running coding tasks to an ephemeral cloud environment. + +## Overview + +The example runs multiple prompts in parallel using `jules.all()`: + +1. Analyzing a repository for improvements. +2. Writing an automation script. +3. Suggesting test cases. + +It demonstrates how to configure concurrency, handle errors without stopping the whole process, and process the results (like reading generated files) from each session. + +## Prerequisites + +- Node.js or Bun installed. +- A Jules API Key. Set it using: + ```bash + export JULES_API_KEY= + ``` + +## Running the Example + +You can run this example using `bun`, `tsx`, or `ts-node`: + +### Using Bun + +```bash +bun run index.ts +``` + +### Using Node.js and TSX + +If you don't have `bun` installed, you can run the example using `tsx`: + +```bash +npm install -g tsx +tsx index.ts +``` + +## Example Output + +```text +Starting Agent Workflow Example... +Creating 3 sessions... +Finished creating 3 sessions. + +Session jules:session:12345: + State: succeeded + Generated 1 files. + - improvements.md + +Session jules:session:67890: + State: succeeded + Generated 1 files. + - deploy.sh + +Session jules:session:54321: + State: succeeded + Generated 1 files. + - test_cases.md + +Workflow complete. +``` diff --git a/packages/core/examples/agent/index.ts b/packages/core/examples/agent/index.ts new file mode 100644 index 0000000..d31a81d --- /dev/null +++ b/packages/core/examples/agent/index.ts @@ -0,0 +1,75 @@ +import { jules } from '@google/jules-sdk'; + +/** + * Agent Workflow Example + * + * This example demonstrates how to use `jules.all()` to orchestrate + * multiple agent sessions concurrently. + */ +async function main() { + console.log('Starting Agent Workflow Example...'); + + // Define a list of tasks for the agents to complete + const tasks = [ + 'Analyze the repository and create a list of potential improvements', + 'Write a script to automate the deployment process', + 'Review the existing test suite and suggest additional test cases', + ]; + + console.log(`Creating ${tasks.length} sessions...`); + + // Use jules.all() to run sessions concurrently + const sessions = await jules.all( + tasks, + (task) => ({ + prompt: task, + // In a real scenario, you would provide a source repository: + // source: { github: 'your-org/your-repo', baseBranch: 'main' }, + }), + { + concurrency: 2, // Limit concurrency to 2 + stopOnError: false, // Continue processing even if one session fails + }, + ); + + console.log(`Finished creating ${sessions.length} sessions.`); + + // Process the results + for (const session of sessions) { + console.log(`\nSession ${session.id}:`); + + // Wait for the session to complete and get the outcome + try { + const outcome = await session.result(); + console.log(` State: ${outcome.state}`); + + if (outcome.state === 'failed') { + console.log(` Failed. Check logs or session stream for details.`); + } else { + // Retrieve generated files + const files = outcome.generatedFiles(); + if (files.size > 0) { + console.log(` Generated ${files.size} files.`); + for (const [path, _] of files.entries()) { + console.log(` - ${path}`); + } + } else { + console.log(' No files generated.'); + } + } + } catch (error) { + console.error(` Error processing session ${session.id}:`, error); + } + } + + console.log('\nWorkflow complete.'); +} + +// Ensure JULES_API_KEY is set +if (!process.env.JULES_API_KEY) { + console.error('Error: JULES_API_KEY environment variable is missing.'); + console.log('Please set it using: export JULES_API_KEY='); + process.exit(1); +} + +main().catch(console.error); diff --git a/packages/core/examples/basic-session/README.md b/packages/core/examples/basic-session/README.md new file mode 100644 index 0000000..a421980 --- /dev/null +++ b/packages/core/examples/basic-session/README.md @@ -0,0 +1,36 @@ +# Basic Session Example + +This example demonstrates how to use the Jules SDK to create a simple interactive session. It will use the `jules.session` method to connect to the Jules API, create a session without a specific repository context (a "Repoless" session), provide a prompt to an AI agent, and wait for the results. + +## Requirements + +- Node.js >= 18 or Bun +- A Jules API Key (`JULES_API_KEY` environment variable) + +## Setup + +1. Make sure you have installed the SDK dependencies in the project root. + +2. Export your Jules API key: + +```bash +export JULES_API_KEY="your-api-key-here" +``` + +## Running the Example + +Using `bun`: + +```bash +bun run index.ts +``` + +Using `npm` and `tsx` (or similar TypeScript runner): + +```bash +npx tsx index.ts +``` + +## What it does + +The script creates a session using `jules.session` and asks the agent to write a haiku. It then waits for the result and retrieves the output. This is a basic demonstration of the isolated core Jules API. diff --git a/packages/core/examples/basic-session/index.ts b/packages/core/examples/basic-session/index.ts new file mode 100644 index 0000000..66c1cbf --- /dev/null +++ b/packages/core/examples/basic-session/index.ts @@ -0,0 +1,75 @@ +import { jules } from '@google/jules-sdk'; + +/** + * Basic Session Example + * + * Demonstrates a simple interaction with the Jules SDK. + * It creates a repoless session (no GitHub source), provides a simple prompt, + * and awaits the final outcome. + */ +async function main() { + // Ensure the JULES_API_KEY environment variable is set. + if (!process.env.JULES_API_KEY) { + console.error('Error: JULES_API_KEY environment variable is not set.'); + console.error('Please set it using: export JULES_API_KEY="your-api-key"'); + process.exit(1); + } + + console.log('Creating a new Jules session...'); + + try { + // 1. Create a basic session + // We use a repoless session (no source) for this simple demonstration. + const session = await jules.session({ + prompt: 'Write a haiku about artificial intelligence programming itself.', + }); + + console.log(`Session created! ID: ${session.id}`); + console.log('Waiting for the agent to complete the task...'); + + // 2. Await the result of the session + // This will poll the API until the session reaches a terminal state (completed or failed). + const outcome = await session.result(); + + console.log('\n--- Session Result ---'); + console.log(`State: ${outcome.state}`); + + if (outcome.state === 'completed') { + // 3. Retrieve and display the final message from the agent + // Since it's a haiku, we expect it in the generated files or the agent's messages. + // Often, the agent writes its final output to a file or answers in a message. + // Let's print out the latest agent message. + const activities = await jules.select({ + from: 'activities', + where: { type: 'agentMessaged', 'session.id': session.id }, + order: 'desc', + limit: 1, + }); + + if (activities.length > 0) { + console.log('\nAgent Message:'); + console.log(activities[0].message); + } else { + console.log('\nThe agent did not leave a final message.'); + + // Let's check generated files + const files = outcome.generatedFiles(); + if (files.size > 0) { + console.log('\nGenerated Files:'); + for (const [filename, content] of files.entries()) { + console.log(`\nFile: ${filename}`); + console.log(content.content); + } + } + } + } else { + console.error('The session did not complete successfully.'); + } + + } catch (error) { + console.error('An error occurred during the session:', error); + } +} + +// Run the example +main(); diff --git a/packages/core/examples/github-actions/README.md b/packages/core/examples/github-actions/README.md new file mode 100644 index 0000000..c963b2a --- /dev/null +++ b/packages/core/examples/github-actions/README.md @@ -0,0 +1,59 @@ +# GitHub Actions Example + +This example demonstrates how to use the Jules SDK within a GitHub Action to automate workflows. + +## Overview + +This example creates a custom GitHub Action that: +1. Takes a `prompt` input. +2. Reads the `JULES_API_KEY` from the environment. +3. Automatically uses the current repository and branch as context. +4. Starts a Jules session to perform the task. +5. Monitors the progress and outputs the resulting Pull Request URL. + +## Files + +- `index.ts`: The main action logic using the Jules SDK. +- `action.yml`: The metadata file that defines the action inputs, outputs, and runtime. +- `package.json`: Dependencies for the action (`@actions/core`, `@actions/github`, `@google/jules-sdk`). + +## Usage + +You can use this action in your own GitHub workflows by referencing its path or publishing it. + +Here is an example workflow file (`.github/workflows/jules.yml`) that triggers the agent whenever an issue is labeled `agent-fix`: + +```yaml +name: Jules Agent Workflow + +on: + issues: + types: [labeled] + +jobs: + run-jules: + if: github.event.label.name == 'agent-fix' + runs-on: ubuntu-latest + steps: + - name: Checkout repository + uses: actions/checkout@v4 + + - name: Run Jules Agent + uses: ./packages/core/examples/github-actions # Path to where this action is located + env: + JULES_API_KEY: ${{ secrets.JULES_API_KEY }} + with: + prompt: "Fix the following issue: ${{ github.event.issue.title }}\n\n${{ github.event.issue.body }}" +``` + +## Running the Example Locally + +To compile the TypeScript action: + +```bash +cd packages/core/examples/github-actions +npm install +npm run build +``` + +The compiled JavaScript will be placed in `dist/index.js`, which is what GitHub Actions will execute. diff --git a/packages/core/examples/github-actions/action.yml b/packages/core/examples/github-actions/action.yml new file mode 100644 index 0000000..3b233b9 --- /dev/null +++ b/packages/core/examples/github-actions/action.yml @@ -0,0 +1,13 @@ +name: 'Jules Agent Action' +description: 'Run a Jules coding agent session on your repository' +author: 'Google' +inputs: + prompt: + description: 'The instructions for the Jules agent' + required: true +outputs: + pr-url: + description: 'The URL of the Pull Request created by the agent, if any' +runs: + using: 'node20' + main: 'dist/index.js' diff --git a/packages/core/examples/github-actions/index.ts b/packages/core/examples/github-actions/index.ts new file mode 100644 index 0000000..a12dcdf --- /dev/null +++ b/packages/core/examples/github-actions/index.ts @@ -0,0 +1,89 @@ +import * as core from '@actions/core'; +import * as github from '@actions/github'; +import { jules } from '@google/jules-sdk'; + +async function run() { + try { + // 1. Read inputs defined in action.yml + const prompt = core.getInput('prompt', { required: true }); + + // 2. The Jules SDK requires JULES_API_KEY environment variable. + // GitHub Actions can pass this via `env:` or `with:` which sets an input. + // If you prefer not to use the environment variable, you can initialize + // the client specifically: + // const julesClient = jules.with({ apiKey: core.getInput('api-key') }); + + // We will assume JULES_API_KEY is available in the environment, + // which is the default behavior of the `jules` instance. + if (!process.env.JULES_API_KEY) { + throw new Error('JULES_API_KEY environment variable is missing.'); + } + + // 3. Get context about the current repository from the GitHub Action payload + const context = github.context; + const owner = context.repo.owner; + const repo = context.repo.repo; + const ref = context.ref; + + // Convert refs/heads/main to main + let baseBranch = 'main'; + if (ref.startsWith('refs/heads/')) { + baseBranch = ref.replace('refs/heads/', ''); + } + + core.info(`Starting Jules session for ${owner}/${repo} on branch ${baseBranch}`); + core.info(`Prompt: ${prompt}`); + + // 4. Create a new Jules session + const session = await jules.session({ + prompt: prompt, + source: { + github: `${owner}/${repo}`, + baseBranch: baseBranch, + }, + // Automatically create a PR when the session is complete + autoPr: true, + }); + + core.info(`Session created successfully. ID: ${session.id}`); + + // 5. Monitor the progress + for await (const activity of session.stream()) { + switch (activity.type) { + case 'planGenerated': + core.info(`[Plan Generated] ${activity.plan.steps.length} steps.`); + break; + case 'progressUpdated': + core.info(`[Progress Updated] ${activity.title}`); + break; + case 'sessionCompleted': + core.info(`[Session Completed]`); + break; + } + } + + // 6. Wait for the final outcome + const outcome = await session.result(); + + if (outcome.state === 'failed') { + core.setFailed(`Session failed.`); + return; + } + + core.info(`Session finished successfully.`); + + if (outcome.pullRequest) { + core.info(`Pull Request created: ${outcome.pullRequest.url}`); + // Set an output that other steps in the workflow can use + core.setOutput('pr-url', outcome.pullRequest.url); + } + } catch (error) { + if (error instanceof Error) { + core.setFailed(`Action failed with error: ${error.message}`); + } else { + core.setFailed(`Action failed with an unknown error.`); + } + } +} + +run(); diff --git a/packages/core/examples/github-actions/package.json b/packages/core/examples/github-actions/package.json new file mode 100644 index 0000000..d4a944d --- /dev/null +++ b/packages/core/examples/github-actions/package.json @@ -0,0 +1,18 @@ +{ + "name": "jules-github-actions-example", + "version": "1.0.0", + "description": "An example of using the Jules SDK in a GitHub Action", + "main": "dist/index.js", + "scripts": { + "build": "tsc" + }, + "dependencies": { + "@actions/core": "^1.10.1", + "@actions/github": "^6.0.0", + "@google/jules-sdk": "workspace:*" + }, + "devDependencies": { + "@types/node": "^20.0.0", + "typescript": "^5.0.0" + } +} diff --git a/packages/core/examples/github-actions/tsconfig.json b/packages/core/examples/github-actions/tsconfig.json new file mode 100644 index 0000000..487a581 --- /dev/null +++ b/packages/core/examples/github-actions/tsconfig.json @@ -0,0 +1,13 @@ +{ + "compilerOptions": { + "target": "ES2022", + "module": "CommonJS", + "moduleResolution": "node", + "strict": true, + "esModuleInterop": true, + "skipLibCheck": true, + "forceConsistentCasingInFileNames": true, + "outDir": "./dist" + }, + "include": ["index.ts"] +} diff --git a/packages/core/examples/webhook/README.md b/packages/core/examples/webhook/README.md new file mode 100644 index 0000000..2b40959 --- /dev/null +++ b/packages/core/examples/webhook/README.md @@ -0,0 +1,36 @@ +# Webhook Integration Example + +This example demonstrates how to create a simple webhook server using [Hono](https://hono.dev/) that listens for incoming HTTP `POST` requests and automatically creates a new Jules session. + +This is particularly useful for event-driven workflows, such as automatically running an agent when a specific event occurs in another system (e.g., a GitHub issue being created, a new row added to a database, or a custom application event). + +## Prerequisites + +- Ensure you have [Bun](https://bun.sh/) installed, or another compatible runtime like Node.js. +- Ensure you have your `JULES_API_KEY` set as an environment variable. + +## Running the Example + +1. Start the webhook server: + + ```bash + bun install + bun run index.ts + ``` + +2. The server will start and listen on port `3000`. + +3. Send a test webhook payload using `curl` (or your preferred tool like Postman): + + ```bash + curl -X POST http://localhost:3000/webhook \ + -H "Content-Type: application/json" \ + -d '{"event": "bug_report", "description": "Fix typo in README"}' + ``` + +4. Check the server console logs. You should see the incoming payload and the ID of the newly created Jules session. + +## Notes + +- In a real-world scenario, you should validate the incoming webhook payload to ensure it comes from a trusted source (e.g., verifying a signature or secret token). +- You can customize the `prompt` and `source` in `index.ts` to match your specific requirements and target repository. diff --git a/packages/core/examples/webhook/index.ts b/packages/core/examples/webhook/index.ts new file mode 100644 index 0000000..3e7782f --- /dev/null +++ b/packages/core/examples/webhook/index.ts @@ -0,0 +1,42 @@ +import { serve } from '@hono/node-server'; +import { Hono } from 'hono'; +import { jules } from '@google/jules-sdk'; + +const app = new Hono(); + +app.post('/webhook', async (c) => { + try { + const payload = await c.req.json(); + console.log('Received webhook payload:', payload); + + // Create a new Jules session triggered by the webhook + const session = await jules.session({ + prompt: `Process this webhook payload: ${JSON.stringify(payload)}`, + // Provide a default repository or adapt to your needs + source: { github: 'davideast/dataprompt', baseBranch: 'main' }, + }); + + console.log(`Created Jules session: ${session.id}`); + + return c.json({ + success: true, + message: 'Webhook processed and session created successfully', + sessionId: session.id, + }, 200); + + } catch (error) { + console.error('Error processing webhook:', error); + return c.json({ + success: false, + message: 'Failed to process webhook', + }, 500); + } +}); + +const port = 3000; +console.log(`Server is running on port ${port}`); + +serve({ + fetch: app.fetch, + port, +}); diff --git a/packages/core/examples/webhook/package.json b/packages/core/examples/webhook/package.json new file mode 100644 index 0000000..fe3e326 --- /dev/null +++ b/packages/core/examples/webhook/package.json @@ -0,0 +1,17 @@ +{ + "name": "webhook", + "version": "1.0.0", + "description": "Example demonstrating how to trigger a Jules session via a webhook.", + "main": "index.ts", + "scripts": { + "start": "bun run index.ts" + }, + "dependencies": { + "@google/jules-sdk": "workspace:*", + "@hono/node-server": "^1.11.1", + "hono": "^4.3.11" + }, + "devDependencies": { + "bun-types": "^1.1.8" + } +}